From 3fa217e62755d11246602ed28a5ebd8db478e14f Mon Sep 17 00:00:00 2001 From: Andrew Butt Date: Sun, 16 Jul 2023 15:22:05 -0400 Subject: [PATCH 001/189] True single port memories --- primitives/memories.futil | 30 ++++---- primitives/memories.sv | 77 ++++++++------------- tests/correctness/seq-mem-d4-add.futil | 11 +-- tests/correctness/seq-mem-dot-product.futil | 13 ++-- 4 files changed, 58 insertions(+), 73 deletions(-) diff --git a/primitives/memories.futil b/primitives/memories.futil index f83353d86..223b9fd52 100644 --- a/primitives/memories.futil +++ b/primitives/memories.futil @@ -4,14 +4,13 @@ extern "memories.sv" { @reset reset: 1, @data addr0: IDX_SIZE, // Write ports - @write_together(1) @static(1) @go(1) write_en: 1, + @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, // Read ports - @static(1) @go(2) read_en: 1 + @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, - @done(1) write_done: 1, - @done(2) read_done: 1 + @done(1) done: 1 ); primitive seq_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( @@ -20,14 +19,13 @@ extern "memories.sv" { @data addr0: D0_IDX_SIZE, @data addr1: D1_IDX_SIZE, // Write ports - @write_together(1) @static(1) @go(1) write_en: 1, + @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, // Read ports - @static(1) @go(2) read_en: 1 + @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, - @done(1) write_done: 1, - @done(2) read_done: 1 + @done(1) done: 1, ); primitive seq_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE]( @@ -37,14 +35,13 @@ extern "memories.sv" { @data addr1: D1_IDX_SIZE, @data addr2: D2_IDX_SIZE, // Write ports - @write_together(1) @static(1) @go(1) write_en: 1, + @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, // Read ports - @static(1) @go(2) read_en: 1 + @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, - @done(1) write_done: 1, - @done(2) read_done: 1 + @done(1) done: 1, ); primitive seq_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE]( @@ -55,13 +52,12 @@ extern "memories.sv" { @data addr2: D2_IDX_SIZE, @data addr3: D3_IDX_SIZE, // Write ports - @write_together(1) @static(1) @go(1) write_en: 1, + @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, // Read ports - @static(1) @go(2) read_en: 1 + @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, - @done(1) write_done: 1, - @done(2) read_done: 1 + @done(1) done: 1, ); -} \ No newline at end of file +} diff --git a/primitives/memories.sv b/primitives/memories.sv index e90a87907..43acc6869 100644 --- a/primitives/memories.sv +++ b/primitives/memories.sv @@ -14,19 +14,18 @@ module seq_mem_d1 #( input wire logic clk, input wire logic reset, input wire logic [IDX_SIZE-1:0] addr0, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [ WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - output logic write_done + input wire logic write_en ); // Internal memory - (* ram_style = "ultra" *) logic [WIDTH-1:0] mem[SIZE-1:0]; + logic [WIDTH-1:0] mem[SIZE-1:0]; // Register for the read output logic [WIDTH-1:0] read_out; @@ -36,10 +35,10 @@ module seq_mem_d1 #( always_ff @(posedge clk) begin if (reset) begin read_out <= '0; - end else if (read_en) begin + end else if (content_en && !write_en) begin /* verilator lint_off WIDTH */ read_out <= mem[addr0]; - end else if (write_en) begin + end else if (content_en && write_en) begin // Explicitly clobber the read output when a write is performed read_out <= 'x; end else begin @@ -47,38 +46,27 @@ module seq_mem_d1 #( end end - // Propagate the read_done signal + // Propagate the done signal always_ff @(posedge clk) begin if (reset) begin - read_done <= '0; - end else if (read_en) begin - read_done <= '1; + done <= '0; + end else if (content_en) begin + done <= '1; end else begin - read_done <= '0; + done <= '0; end end // Write value to the memory always_ff @(posedge clk) begin - if (!reset && write_en) + if (!reset && content_en && write_en) mem[addr0] <= write_data; end - // Propagate the write_done signal - always_ff @(posedge clk) begin - if (reset) begin - write_done <= '0; - end else if (write_en) begin - write_done <= 1'd1; - end else begin - write_done <= '0; - end - end - // Check for out of bounds access `ifdef VERILATOR always_comb begin - if (read_en) + if (content_en && !write_en) if (addr0 >= SIZE) $error( "std_mem_d1: Out of bounds access\n", @@ -86,10 +74,6 @@ module seq_mem_d1 #( "SIZE: %0d", SIZE ); end - always_comb begin - if (read_en && write_en) - $error("Simultaneous read and write attempted\n"); - end `endif endmodule @@ -105,24 +89,23 @@ module seq_mem_d2 #( input wire logic reset, input wire logic [D0_IDX_SIZE-1:0] addr0, input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE-1:0] addr; assign addr = addr0 * D1_SIZE + addr1; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); endmodule module seq_mem_d3 #( @@ -140,24 +123,23 @@ module seq_mem_d3 #( input wire logic [D0_IDX_SIZE-1:0] addr0, input wire logic [D1_IDX_SIZE-1:0] addr1, input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE-1:0] addr; assign addr = addr0 * (D1_SIZE * D2_SIZE) + addr1 * (D2_SIZE) + addr2; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); endmodule module seq_mem_d4 #( @@ -178,22 +160,21 @@ module seq_mem_d4 #( input wire logic [D1_IDX_SIZE-1:0] addr1, input wire logic [D2_IDX_SIZE-1:0] addr2, input wire logic [D3_IDX_SIZE-1:0] addr3, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE-1:0] addr; assign addr = addr0 * (D1_SIZE * D2_SIZE * D3_SIZE) + addr1 * (D2_SIZE * D3_SIZE) + addr2 * (D3_SIZE) + addr3; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE * D3_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); -endmodule \ No newline at end of file + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); +endmodule diff --git a/tests/correctness/seq-mem-d4-add.futil b/tests/correctness/seq-mem-d4-add.futil index 74d3ddd69..af173460d 100644 --- a/tests/correctness/seq-mem-d4-add.futil +++ b/tests/correctness/seq-mem-d4-add.futil @@ -74,8 +74,9 @@ component main() -> () { in1.addr1 = j.out; in1.addr2 = k.out; in1.addr3 = l.out; - in1.read_en = 1'd1; - in1_reg.write_en = in1.read_done; + in1.content_en = 1'd1; + in1.write_en = 1'd0; + in1_reg.write_en = in1.done; in1_reg.in = in1.read_data; read_in1[done] = in1_reg.done; } @@ -84,8 +85,9 @@ component main() -> () { in2.addr1 = j.out; in2.addr2 = k.out; in2.addr3 = l.out; - in2.read_en = 1'd1; - in2_reg.write_en = in2.read_done; + in2.content_en = 1'd1; + in2.write_en = 1'd0; + in2_reg.write_en = in2.done; in2_reg.in = in2.read_data; read_in2[done] = in2_reg.done; } @@ -96,6 +98,7 @@ component main() -> () { out.addr1 = j.out; out.addr2 = k.out; out.addr3 = l.out; + out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = add.out; update_val[done] = out.write_done; diff --git a/tests/correctness/seq-mem-dot-product.futil b/tests/correctness/seq-mem-dot-product.futil index fb06e03fa..0dc2175d3 100644 --- a/tests/correctness/seq-mem-dot-product.futil +++ b/tests/correctness/seq-mem-dot-product.futil @@ -38,19 +38,22 @@ component main() -> () { // Prime memories for reading group prime_in1 { - in1.read_en = 1'd1; + in1.content_en = 1'd1; + in1.write_en = 1'd0; in1.addr0 = idx.out; - prime_in1[done] = in1.read_done; + prime_in1[done] = in1.done; } group prime_in2 { - in2.read_en = 1'd1; + in2.content_en = 1'd1; + in2.write_en = 1'd0; in2.addr0 = idx.out; - prime_in2[done] = in2.read_done; + prime_in2[done] = in2.done; } // Computation group init_tmp { tmp.in = 32'd0; + tmp.content_en = 1'd1; tmp.write_en = 1'd1; init_tmp[done] = tmp.done; } @@ -58,6 +61,7 @@ component main() -> () { add.left = tmp.out; add.right = mult.out; tmp.in = add.out; + tmp.content_en = 1'd1; tmp.write_en = 1'd1; do_add[done] = tmp.done; } @@ -65,6 +69,7 @@ component main() -> () { // Write to output group write { out.addr0 = 1'd0; + out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = tmp.out; write[done] = out.write_done; From 61a45568a90471af887f3888dac0f09de0b11052 Mon Sep 17 00:00:00 2001 From: Andrew Butt Date: Sun, 16 Jul 2023 15:26:06 -0400 Subject: [PATCH 002/189] Cleanup futil declarations --- primitives/memories.futil | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/primitives/memories.futil b/primitives/memories.futil index 223b9fd52..b8b662c39 100644 --- a/primitives/memories.futil +++ b/primitives/memories.futil @@ -3,11 +3,10 @@ extern "memories.sv" { @clk clk: 1, @reset reset: 1, @data addr0: IDX_SIZE, + @static(1) @go(1) content_en: 1 // Write ports @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, - // Read ports - @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, @done(1) done: 1 @@ -18,11 +17,10 @@ extern "memories.sv" { @reset reset: 1, @data addr0: D0_IDX_SIZE, @data addr1: D1_IDX_SIZE, + @static(1) @go(1) content_en: 1 // Write ports @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, - // Read ports - @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, @done(1) done: 1, @@ -34,11 +32,10 @@ extern "memories.sv" { @data addr0: D0_IDX_SIZE, @data addr1: D1_IDX_SIZE, @data addr2: D2_IDX_SIZE, + @static(1) @go(1) content_en: 1 // Write ports @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, - // Read ports - @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, @done(1) done: 1, @@ -51,11 +48,10 @@ extern "memories.sv" { @data addr1: D1_IDX_SIZE, @data addr2: D2_IDX_SIZE, @data addr3: D3_IDX_SIZE, + @static(1) @go(1) content_en: 1 // Write ports @write_together(1) write_en: 1, @write_together(1) @data write_data: WIDTH, - // Read ports - @static(1) @go(1) content_en: 1 ) -> ( @stable read_data: WIDTH, @done(1) done: 1, From 7be913b664b6ad34a4c404f232c67944e1a79184 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Mon, 17 Jul 2023 13:46:08 -0400 Subject: [PATCH 003/189] update the interpreter versions of seq_mem --- interp/src/primitives/stateful/memories.rs | 29 ++++++++-------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/interp/src/primitives/stateful/memories.rs b/interp/src/primitives/stateful/memories.rs index 15ffa7a24..797e3c7f3 100644 --- a/interp/src/primitives/stateful/memories.rs +++ b/interp/src/primitives/stateful/memories.rs @@ -445,7 +445,6 @@ enum SeqMemAction { Read(T), Write(T, Value), Reset, - Error, } impl Default for SeqMemAction { @@ -555,10 +554,10 @@ impl Primitive for SeqMem { fn validate(&self, inputs: &[(ir::Id, &Value)]) { validate![inputs; - read_en: 1, + content_en: 1, write_en: 1, reset: 1, - r#in: self.width + write_data: self.width ]; self.mem_binder.validate(inputs); } @@ -568,7 +567,7 @@ impl Primitive for SeqMem { inputs: &[(ir::Id, &Value)], ) -> InterpreterResult> { get_inputs![inputs; - read_en [bool]: "read_en", + content_en [bool]: "content_en", write_en [bool]: "write_en", reset [bool]: "reset", input: "write_data" @@ -580,11 +579,9 @@ impl Primitive for SeqMem { self.update = if reset { SeqMemAction::Reset - } else if write_en && read_en { - SeqMemAction::Error - } else if write_en { + } else if write_en && content_en { SeqMemAction::Write(idx, input.clone()) - } else if read_en { + } else if content_en { SeqMemAction::Read(idx) } else { SeqMemAction::None @@ -606,8 +603,7 @@ impl Primitive for SeqMem { Ok(vec![ ("read_data".into(), self.read_out.clone()), - ("read_done".into(), Value::bit_high()), - ("write_done".into(), Value::bit_low()), + ("done".into(), Value::bit_high()), ]) } SeqMemAction::Write(idx, v) => { @@ -620,24 +616,20 @@ impl Primitive for SeqMem { Ok(vec![ ("read_data".into(), self.read_out.clone()), - ("read_done".into(), Value::bit_low()), - ("write_done".into(), Value::bit_high()), + ("done".into(), Value::bit_high()), ]) } SeqMemAction::Reset => { self.read_out = Value::zeroes(self.width); Ok(vec![ ("read_data".into(), self.read_out.clone()), - ("read_done".into(), Value::bit_low()), - ("write_done".into(), Value::bit_low()), + ("done".into(), Value::bit_low()), ]) } SeqMemAction::None => Ok(vec![ ("read_data".into(), self.read_out.clone()), - ("read_done".into(), Value::bit_low()), - ("write_done".into(), Value::bit_low()), + ("done".into(), Value::bit_low()), ]), - SeqMemAction::Error => Err(InterpreterError::SeqMemoryError.into()), } } @@ -649,8 +641,7 @@ impl Primitive for SeqMem { Ok(vec![ ("read_data".into(), self.read_out.clone()), - ("read_done".into(), Value::bit_low()), - ("write_done".into(), Value::bit_low()), + ("done".into(), Value::bit_low()), ]) } From 9bfa876802a257bd7d74d7a3e6af8a9198021038 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 19 Jul 2023 13:36:15 -0400 Subject: [PATCH 004/189] fix confusing comma errors --- primitives/memories.futil | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/primitives/memories.futil b/primitives/memories.futil index b8b662c39..c824530cb 100644 --- a/primitives/memories.futil +++ b/primitives/memories.futil @@ -3,10 +3,10 @@ extern "memories.sv" { @clk clk: 1, @reset reset: 1, @data addr0: IDX_SIZE, - @static(1) @go(1) content_en: 1 + @static(1) @go(1) content_en: 1, // Write ports @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH, + @write_together(1) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, @done(1) done: 1 @@ -17,13 +17,13 @@ extern "memories.sv" { @reset reset: 1, @data addr0: D0_IDX_SIZE, @data addr1: D1_IDX_SIZE, - @static(1) @go(1) content_en: 1 + @static(1) @go(1) content_en: 1, // Write ports @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH, + @write_together(1) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, - @done(1) done: 1, + @done(1) done: 1 ); primitive seq_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE]( @@ -32,13 +32,13 @@ extern "memories.sv" { @data addr0: D0_IDX_SIZE, @data addr1: D1_IDX_SIZE, @data addr2: D2_IDX_SIZE, - @static(1) @go(1) content_en: 1 + @static(1) @go(1) content_en: 1, // Write ports @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH, + @write_together(1) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, - @done(1) done: 1, + @done(1) done: 1 ); primitive seq_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE]( @@ -48,12 +48,12 @@ extern "memories.sv" { @data addr1: D1_IDX_SIZE, @data addr2: D2_IDX_SIZE, @data addr3: D3_IDX_SIZE, - @static(1) @go(1) content_en: 1 + @static(1) @go(1) content_en: 1, // Write ports @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH, + @write_together(1) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, - @done(1) done: 1, + @done(1) done: 1 ); } From d825fd31c33de1ff6bfea1ebd9bbe7316072a079 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 24 Jul 2023 21:40:19 -0400 Subject: [PATCH 005/189] remove fuzz (#1627) --- fuzz/README.md | 17 -- fuzz/do_fuzz.py | 242 --------------------------- fuzz/examples/README.md | 31 ---- fuzz/examples/add_data_template.json | 10 -- fuzz/examples/std_add.futil | 43 ----- fuzz/examples/std_sub.futil | 44 ----- 6 files changed, 387 deletions(-) delete mode 100644 fuzz/README.md delete mode 100644 fuzz/do_fuzz.py delete mode 100644 fuzz/examples/README.md delete mode 100644 fuzz/examples/add_data_template.json delete mode 100644 fuzz/examples/std_add.futil delete mode 100644 fuzz/examples/std_sub.futil diff --git a/fuzz/README.md b/fuzz/README.md deleted file mode 100644 index c399d53d4..000000000 --- a/fuzz/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Fuzz: Compiler & Interpreter Testing -Automates the process of comparing either two input files, or two backend tools. - -The input file should be convertible to Calyx, and any backends should be defined in fud to simulate/execute a program. -For the compare file functionality, two input files to be compared and a data template file are mandatory, while an input for backend tool and number of iteration are optional (icarus-verilog is the default backend tool). -For the compare backend functionality, an input file as reference, a data template, and two backend tools mandatory, but the number of iteration is optional. - -(to be changed:) The current documentation for fuzz lives [here](https://docs.calyxir.org/fud/index.html). - -## Contributing - -You can install these tools with: -``` -pip3 install fud -pip3 install argparse -pip3 install deepdiff -``` diff --git a/fuzz/do_fuzz.py b/fuzz/do_fuzz.py deleted file mode 100644 index cef75c97b..000000000 --- a/fuzz/do_fuzz.py +++ /dev/null @@ -1,242 +0,0 @@ -import json -import logging -import os -import random -from deepdiff import DeepDiff -import argparse - - -def generate_data(template): - """ - Randomly generate data based on the template - """ - with open(template) as f: - template_file = json.load(f) - for obj in template_file: - data_var = template_file[obj]["data"] - format_var = template_file[obj]["format"] - if isinstance(data_var, list): - result = revised_generate_list(data_var, format_var) - construct_json(result, obj, template) - elif isinstance(data_var, int): - result = generate_int(format_var) - construct_json(result, obj, template) - else: - raise TypeError - - -def revised_generate_list(input_data, data_format): - """ - Generate a list of data based on datatype contained in the list, data width, and sign. - """ - try: - # base case - if isinstance(input_data, int): - return generate_int(data_format) - else: - # recurrence - for i in range(len(input_data)): - input_data[i] = revised_generate_list(input_data[i], data_format) - return input_data - except Exception: - raise TypeError - - -def generate_int(data_format): - """ - Generate an integer based on the given data width and sign. - """ - is_signed = data_format["is_signed"] - width = data_format["width"] - - if is_signed: - result = random.randrange(-(2 ** (width - 1)) + 1, 2 ** (width - 1) - 1) - else: - result = random.randrange(0, 2**width - 1) - return result - - -def construct_json(data_list, obj, template): - """ - Insert the generated data to data template - """ - with open(template) as json_file: - data = json.load(json_file) - data[obj]["data"] = data_list - - with open(template, "w") as json_file: - json.dump(data, json_file) - - -def do_fuzz_file(args): - """ - Compare two files. Run data generated from input template on both input file prog and spec. - Raise exception if two files produce unequal results. - Note: prog and spec do not need to be Calyx file, but should be convertable to Calyx using fud - """ - - try: - print("Running do_fuzz_file!") - - original_prog = args.input_file_1 - original_spec = args.input_file_2 - prog_name, prog_file_type = os.path.splitext(original_prog) - spec_name, spec_file_type = os.path.splitext(original_spec) - if prog_file_type != ".futil": - args.input_file_1 = prog_name + ".futil" - os.system(f"fud e {original_prog} --to calyx > {args.input_file_1}") - - elif spec_file_type != ".futil": - args.input_file_2 = spec_name + ".futil" - os.system(f"fud e {original_spec} --to calyx > {args.input_file_2}") - - if not args.backend_tool: - args.backend_tool = "icarus-verilog" - if not args.iteration: - args.iteration = 1 - - for i in range(int(args.iteration)): - generate_data(args.data_file) - if os.stat(args.data_file).st_size == 0: - continue - os.system( - f"fud e {args.input_file_1} -s verilog.data {args.data_file} --to dat -q --through {args.backend_tool} > result1.json" - ) - os.system( - f"fud e {args.input_file_2} -s verilog.data {args.data_file} --to dat -q --through {args.backend_tool} > result2.json" - ) - with open("result1.json", "r") as f1, open("result2.json", "r") as f2: - f1_result = json.load(f1) - f2_result = json.load(f2) - obj1 = f1_result["memories"] - obj2 = f2_result["memories"] - diff = DeepDiff(obj1, obj2) - assert obj1 == obj2, f"Failed with unequal output! {diff}" - - except Exception as e: - logging.error(e) - logging.error( - f"fail unequal output for prog: {args.input_file_1}, spec: {args.input_file_2}" - ) - - -def do_fuzz_backend(args): - """ - Compare two backend tools. Run data generated from input template on same file using different backend tools. - Raise exception if two backend tools produce unequal results. - Note: file does not need to be Calyx file, but should be convertable to Calyx using fud. Backend tools should - be recognizable by fud. - """ - - try: - print("Running do_fuzz_backend!") - original_prog = args.input_file - prog_name, prog_file_type = os.path.splitext(original_prog) - if prog_file_type != ".futil": - args.input_file = prog_name + ".futil" - os.system(f"fud e {original_prog} --to calyx > {args.input_file}") - - if not args.backend_1: - args.backend_tool = "icarus-verilog" - if not args.iteration: - args.iteration = 1 - - for i in range(int(args.iteration)): - generate_data(args.data_file) - if os.stat(args.data_file).st_size == 0: - continue - os.system( - f"fud e {args.input_file} -s verilog.data {args.data_file} --to jq --through {args.backend_1} --through dat -s " - f"jq.expr '.memories' > result1.json" - ) - os.system( - f"fud e {args.input_file} -s verilog.data {args.data_file} --to jq --through {args.backend_2} --through dat -s " - f"jq.expr '.memories' > result2.json" - ) - with open("result1.json", "r") as f1, open("result2.json", "r") as f2: - f1_result = json.load(f1) - f2_result = json.load(f2) - diff = DeepDiff(f1_result, f2_result) - assert f1_result == f2_result, f"Failed with unequal output! {diff}" - - except Exception as e: - logging.error(e) - logging.error( - f"fail unequal output on file: {args.input_file} with backend tools: {args.backend_1} and {args.backend_2}" - ) - - -def conf_check_file(parser): - parser.add_argument( - "-input_1", dest="input_file_1", help="Path to the input file 1", nargs="?" - ) - parser.add_argument( - "-input_2", dest="input_file_2", help="Path to the input file 2", nargs="?" - ) - - parser.add_argument( - "-backend", - dest="backend_tool", - help="Receive the backend tool; use icarus0-verilog as " "default", - ) - parser.add_argument("-dat", dest="data_file", help="Receive data file") - - parser.add_argument("-itr", dest="iteration", help="Number of iterations") - - parser.set_defaults(command="file") - - -def conf_check_backend(parser): - parser.add_argument( - "-input", dest="input_file", help="Path to the input file", nargs="?" - ) - - parser.add_argument( - "-backend_1", dest="backend_1", help="Receive the first backend tool" - ) - parser.add_argument( - "-backend_2", dest="backend_2", help="Receive the second backend tool" - ) - - parser.add_argument("-dat", dest="data_file", help="Receive data file") - - parser.add_argument("-itr", dest="iteration", help="Number of iterations") - - parser.set_defaults(command="backend") - - -if __name__ == "__main__": - p = argparse.ArgumentParser(description="Run fuzzing on files and backends.") - sp = p.add_subparsers() - - conf_check_file(sp.add_parser("file", help="Run fuzz to compare two input files.")) - conf_check_backend( - sp.add_parser("backend", help="Run fuzz to compare two backend tools.") - ) - - args = p.parse_args() - - if "command" not in args: - p.print_help() - exit(-1) - - try: - if args.command == "file": - if not (args.input_file_1 or args.input_file_2): - p.error("Please provide two files to compare") - elif not args.data_file: - p.error("Please provide a data template file as reference") - else: - do_fuzz_file(args) - elif args.command == "backend": - if not args.input_file: - p.error("Please provide a file as reference") - elif not (args.backend_1 or args.backend_2): - p.error("Please provide two backend tools to compare") - elif not args.data_file: - p.error("Please provide a data template file as reference") - else: - do_fuzz_backend(args) - except Exception as e: - logging.error(e) - exit(-1) diff --git a/fuzz/examples/README.md b/fuzz/examples/README.md deleted file mode 100644 index 47ae0472e..000000000 --- a/fuzz/examples/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Fuzz: Example -This is a feature for fud. It is a tool that automates the process -of comparing either two input files, or two backend tools. - -The input file should be convertible to Calyx, and any backends should be defined in fud to simulate/execute a program. -For the compare file functionality, two input files to be compared and a data template file are mandatory, while an input for backend tool and number of iteration are optional (icarus-verilog is the default backend tool). -For the compare backend functionality, an input file as reference, a data template, and two backend tools mandatory, but the number of iteration is optional. - -## Compare Files -To compare two files, the command ``file`` will be used. -``` -python do_fuzz.py file -input_1 -input_2 -backend -dat -itr -``` -As an example, files ``std_add.futil`` and ``std_sub.futil`` using data template ``add_data_template.json`` are compared, with icarus-verilog as backend tool. There will be two iterations. - -The command should be: -``` -python do_fuzz.py file -input_1 std_add.futil -input_2 std_sub.futil -backend icarus-verilog -dat add_data_template.json -itr 2 -``` - -## Compare Backends -To compare two backend tools, the command ``backend`` will be used. -``` -python do_fuzz.py backend -input -backend_1 -backend_2 -dat -itr -``` -As an example, backend tools ``icarus-verilog`` and ``verilog`` are compared, with file ``std_add.futil`` and data template ``add_data_template.json`` as reference. There will be one iterations. - -The command should be: -``` -python do_fuzz.py backend -input std_add.futil -backend_1 icarus-verilog -backend_2 verilog -dat add_data_template.json -itr 1 -``` diff --git a/fuzz/examples/add_data_template.json b/fuzz/examples/add_data_template.json deleted file mode 100644 index ebfa7172a..000000000 --- a/fuzz/examples/add_data_template.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "inp": { - "data": [0, 0, 0], - "format": { - "numeric_type": "bitnum", - "is_signed": true, - "width": 32 - } - } -} diff --git a/fuzz/examples/std_add.futil b/fuzz/examples/std_add.futil deleted file mode 100644 index e4a0f8fe6..000000000 --- a/fuzz/examples/std_add.futil +++ /dev/null @@ -1,43 +0,0 @@ -import "primitives/core.futil"; - -// m[2] = m[0] + m[1]; -// r0 = m[0]; -// r1 = m[1]; -// m[2] = r0 + r1; -component main() -> () { - cells { - @external inp = std_mem_d1(32, 3, 2); - add0 = std_add(32); - r0 = std_reg(32); - r1 = std_reg(32); - } - wires { - group read_m0 { - inp.addr0 = 2'd0; - r0.in = inp.read_data; - r0.write_en = 1'd1; - read_m0[done] = r0.done; - } - group read_m1 { - inp.addr0 = 2'd1; - r1.in = inp.read_data; - r1.write_en = 1'd1; - read_m1[done] = r1.done; - } - group do_add { - add0.left = r0.out; - add0.right = r1.out; - inp.addr0 = 2'd2; - inp.write_data = add0.out; - inp.write_en = 1'd1; - do_add[done] = inp.done; - } - } - control { - seq { - read_m0; - read_m1; - do_add; - } - } -} \ No newline at end of file diff --git a/fuzz/examples/std_sub.futil b/fuzz/examples/std_sub.futil deleted file mode 100644 index d95e49eb1..000000000 --- a/fuzz/examples/std_sub.futil +++ /dev/null @@ -1,44 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; - -// m[2] = m[0] - m[1]; -// r0 = m[0]; -// r1 = m[1]; -// m[2] = r0 - r1; -component main() -> () { - cells { - @external inp = std_mem_d1(32, 3, 2); - sub0 = std_sub(32); - r0 = std_reg(32); - r1 = std_reg(32); - } - wires { - group read_m0 { - inp.addr0 = 2'd0; - r0.in = inp.read_data; - r0.write_en = 1'd1; - read_m0[done] = r0.done; - } - group read_m1 { - inp.addr0 = 2'd1; - r1.in = inp.read_data; - r1.write_en = 1'd1; - read_m1[done] = r1.done; - } - group do_sub { - sub0.left = r0.out; - sub0.right = r1.out; - inp.addr0 = 2'd2; - inp.write_data = sub0.out; - inp.write_en = 1'd1; - do_sub[done] = inp.done; - } - } - control { - seq { - read_m0; - read_m1; - do_sub; - } - } -} \ No newline at end of file From 48697493ed43f2f67ec4e9d447c0888b94e2a7a5 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:45:58 -0700 Subject: [PATCH 006/189] Builder: tidy correctness examples (#1630) --- calyx-py/calyx/builder.py | 7 + calyx-py/calyx/builder_util.py | 196 ++++++++++++++++++++ calyx-py/test/correctness/arbiter_6.py | 180 ++++++------------ calyx-py/test/correctness/reduction_tree.py | 39 +--- 4 files changed, 267 insertions(+), 155 deletions(-) create mode 100644 calyx-py/calyx/builder_util.py diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index b190d30ef..bbde0fded 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -564,6 +564,13 @@ def port(self, name: str) -> ExprBuilder: """Build a port access expression.""" return ExprBuilder(ast.Atom(ast.CompPort(self._cell.id, name))) + def is_mem_d1(self) -> bool: + """Check if the cell is a StdMemD1 cell.""" + return ( + isinstance(self._cell.comp, ast.CompInst) + and self._cell.comp.id == "std_mem_d1" + ) + @classmethod def unwrap_id(cls, obj): if isinstance(obj, cls): diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py new file mode 100644 index 000000000..927c49b73 --- /dev/null +++ b/calyx-py/calyx/builder_util.py @@ -0,0 +1,196 @@ +# pylint: disable=import-error +import calyx.builder as cb + + +def insert_comb_group(comp: cb.ComponentBuilder, left, right, cell, groupname): + """Accepts a cell that performs some computation on values {left} and {right}. + Creates a combinational group {groupname} that wires up the cell with these ports. + Returns the cell and the combintational group. + """ + with comp.comb_group(groupname) as comb_group: + cell.left = left + cell.right = right + return cell, comb_group + + +def insert_eq(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to check if {left} == {right}. + + = std_eq(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + eq_cell = comp.eq(cellname, width) + return insert_comb_group(comp, left, right, eq_cell, f"{cellname}_group") + + +def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to check if {left} < {right}. + + = std_lt(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + lt_cell = comp.lt(cellname, width) + return insert_comb_group(comp, left, right, lt_cell, f"{cellname}_group") + + +def insert_add(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to compute {left} + {right}. + + = std_add(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + add_cell = comp.add(cellname, width) + return insert_comb_group(comp, left, right, add_cell, f"{cellname}_group") + + +def insert_sub(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to compute {left} - {right}. + + = std_sub(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + sub_cell = comp.sub(cellname, width) + return insert_comb_group(comp, left, right, sub_cell, f"{cellname}_group") + + +def insert_incr(comp: cb.ComponentBuilder, reg, cellname, val=1): + """Inserts wiring into component {comp} to increment register {reg} by {val}. + 1. Within component {comp}, creates a group called {cellname}_group. + 2. Within the group, adds a cell {cellname} that computes sums. + 3. Puts the values {reg} and {val} into the cell. + 4. Then puts the answer of the computation back into {reg}. + 5. Returns the group that does this. + """ + add_cell = comp.add(cellname, 32) + with comp.group(f"{cellname}_group") as incr_group: + add_cell.left = reg.out + add_cell.right = cb.const(32, val) + reg.write_en = 1 + reg.in_ = add_cell.out + incr_group.done = reg.done + return incr_group + + +def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): + """Inserts wiring into component {comp} to decrement register {reg} by {val}. + 1. Within component {comp}, creates a group called {cellname}_group. + 2. Within the group, adds a cell {cellname} that computes differences. + 3. Puts the values {reg} and {val} into the cell. + 4. Then puts the answer of the computation back into {reg}. + 5. Returns the group that does this. + """ + sub_cell = comp.sub(cellname, 32) + with comp.group(f"{cellname}_group") as decr_group: + sub_cell.left = reg.out + sub_cell.right = cb.const(32, val) + reg.write_en = 1 + reg.in_ = sub_cell.out + decr_group.done = reg.done + return decr_group + + +def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): + """Stores a value in a register. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, sets the register {reg} to {val}. + 3. Returns the group that does this. + """ + with comp.group(group) as store_grp: + reg.in_ = val + reg.write_en = 1 + store_grp.done = reg.done + return store_grp + + +def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): + """Loads a value from one std_mem_d1 memory into another. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from memory {mem} at address {i}. + 3. Writes the value into memory {ans} at address {j}. + 4. Returns the group that does this. + """ + assert mem.is_mem_d1() and ans.is_mem_d1() + with comp.group(group) as load_grp: + mem.addr0 = i + ans.write_en = 1 + ans.addr0 = j + ans.write_data = mem.read_data + load_grp.done = ans.done + return load_grp + + +def insert_add_store_in_reg( + comp: cb.ComponentBuilder, + cellname, + left, + right, + ans_reg=None, +): + """Inserts wiring into component {comp} to compute {left} + {right} and + store it in {ans_reg}. + 1. Within component {comp}, creates a group called {cellname}_group. + 2. Within {group}, create a cell {cellname} that computes sums. + 3. Puts the values of {left} and {right} into the cell. + 4. Then puts the answer of the computation into {ans_reg}. + 4. Returns the summing group and the register. + """ + add_cell = comp.add(cellname, 32) + ans_reg = ans_reg or comp.reg(f"reg_{cellname}", 32) + with comp.group(f"{cellname}_group") as adder_group: + add_cell.left = left + add_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = add_cell.out + adder_group.done = ans_reg.done + return adder_group, ans_reg + + +def insert_sub_store_in_reg( + comp: cb.ComponentBuilder, + left, + right, + cellname, + width, + ans_reg=None, +): + """Adds wiring into component {comp} to compute {left} - {right} + and store it in {ans_reg}. + 1. Within component {comp}, creates a group called {cellname}_group. + 2. Within {group}, create a cell {cellname} that computes differences. + 3. Puts the values of {left} and {right} into {cell}. + 4. Then puts the answer of the computation into {ans_reg}. + 4. Returns the subtracting group and the register. + """ + sub_cell = comp.sub(cellname, width) + ans_reg = ans_reg or comp.reg(f"reg_{cellname}", width) + with comp.group(f"{cellname}_group") as sub_group: + sub_cell.left = left + sub_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = sub_cell.out + sub_group.done = ans_reg.done + return sub_group, ans_reg diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index a9857a209..294f77856 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -1,84 +1,8 @@ # pylint: disable=import-error +import calyx.builder_util as util import calyx.builder as cb -def add_eq(comp: cb.ComponentBuilder, port, const, cell, group): - """Adds wiring into component {comp} to check if {port} == {const}. - 1. Within {comp}, creates a group called {group}. - 2. Within {group}, creates a cell called {cell} that checks equality. - 3. Puts the values of {port} and {const} into {cell}. - 4. Returns the equality-checking cell and the equality-checking group. - """ - eq_cell = comp.eq(cell, 32) - with comp.comb_group(group) as eq_group: - eq_cell.left = port - eq_cell.right = const - return eq_cell, eq_group - - -def add_lt(comp: cb.ComponentBuilder, port, const, cell, group): - """Adds wiring into component {comp} to check if {port} < {const}. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, creates a cell called {cell} that checks for less-than. - 3. Puts the values of {port} and {const} into {cell}. - 4. Returns the less-than-checking cell and the less-than-checking group. - """ - lt_cell = comp.lt(cell, 32) - with comp.comb_group(group) as lt_group: - lt_cell.left = port - lt_cell.right = const - return lt_cell, lt_group - - -def add_sub(comp: cb.ComponentBuilder, port, const, sub_cell, ans_reg, group): - """Adds wiring into component {comp} to compute {port} - {const}. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, assumes there is a cell {cell} that computes differences. - 3. Puts the values of {port} and {const} into {cell}. - 4. Then puts the answer of the computation into {ans_reg}. - 4. Returns the sub-checking group. - """ - # Note, this one is a little different than the others. - # 1. We assume the subtraction cell already exists. - # 2. We're not returning the cell, because we don't need to. - # 3. We write the answer into `ans_reg`. - - with comp.group(group) as sub_group: - sub_cell.left = port - sub_cell.right = const - ans_reg.write_en = 1 - ans_reg.in_ = sub_cell.out - sub_group.done = ans_reg.done - return sub_group - - -def add_mem_load(comp: cb.ComponentBuilder, mem, i, ans, group): - """Loads a value from one memory into another. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from memory {mem} at address {i}. - 3. Writes the value into memory {ans} at address 0. - 4. Returns the group that does this. - """ - with comp.group(group) as load_grp: - mem.addr0 = i - ans.write_en = 1 - ans.write_data = mem.read_data - load_grp.done = ans.done - return load_grp - - -def add_reg_load(comp: cb.ComponentBuilder, port, ans_reg, group): - """Creates a group called {group}. - In that group, loads the value of {port} into {ans_reg}. - Returns the group. - """ - with comp.group(group) as grp: - ans_reg.write_en = 1 - ans_reg.in_ = port - grp.done = ans_reg.done - return grp - - def add_wrap2(prog): """Inserts the component `wrap2` into the program. @@ -106,59 +30,64 @@ def add_wrap2(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells and groups to compute equality and lt - eq0cell, eq0grp = add_eq(wrap, i, 0, "eq0", "i_eq_0") - eq1cell, eq1grp = add_eq(wrap, i, 1, "eq1", "i_eq_1") - lt1cell, lt1grp = add_lt(wrap, j, 4, "lt1", "j_lt_4") - lt2cell, lt2grp = add_lt(wrap, j, 8, "lt2", "j_lt_8") + i_eq_0_cell, i_eq_0_grp = util.insert_eq(wrap, i, 0, "i_eq_0", 32) + i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, "i_eq_1", 32) + j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, "j_lt_4", 32) + j_lt_8_cell, j_lt_8_group = util.insert_lt(wrap, j, 8, "j_lt_8", 32) # Load `j` unchanged into `j_mod_4`. - unchanged = add_reg_load(wrap, j, j_mod_4, "j_unchanged") + unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") - # A subtraction cell and wiring to perform j-4 and j-8. - sub_cell = wrap.sub("sub", 32) - sub1cell = add_sub(wrap, j, cb.const(32, 4), sub_cell, j_mod_4, "j_minus_4") - sub2cell = add_sub(wrap, j, cb.const(32, 8), sub_cell, j_mod_4, "j_minus_8") + # Wiring to perform j-4 and j-8. Either of these will store the result in `j_mod_4`. + j_minus_4, j_mod_4 = util.insert_sub_store_in_reg( + wrap, j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 + ) + j_minus_8, j_mod_4 = util.insert_sub_store_in_reg( + wrap, j, cb.const(32, 8), "j_minus_8", 32, j_mod_4 + ) load_from_mems = [ # Add wiring to load the value `j_mod_4` from all of the memory cells. # We'll have to invoke the correct one of these groups later on. - add_mem_load(wrap, mems[i], j_mod_4.out, ans, f"load_from_mem{i}") + util.insert_mem_load_to_mem( + wrap, mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" + ) for i in range(6) ] wrap.control += [ cb.if_( - lt1cell.out, - lt1grp, + j_lt_4_cell.out, + j_lt_4_group, unchanged, - cb.if_(lt2cell.out, lt2grp, sub1cell, sub2cell), + cb.if_(j_lt_8_cell.out, j_lt_8_group, j_minus_4, j_minus_8), ), cb.par( cb.if_( - eq0cell.out, - eq0grp, + i_eq_0_cell.out, + i_eq_0_grp, cb.if_( - lt1cell.out, - lt1grp, + j_lt_4_cell.out, + j_lt_4_group, load_from_mems[0], cb.if_( - lt2cell.out, - lt2grp, + j_lt_8_cell.out, + j_lt_8_group, load_from_mems[1], load_from_mems[2], ), ), ), cb.if_( - eq1cell.out, - eq1grp, + i_eq_1_cell.out, + i_eq_1_group, cb.if_( - lt1cell.out, - lt1grp, + j_lt_4_cell.out, + j_lt_4_group, load_from_mems[3], cb.if_( - lt2cell.out, - lt2grp, + j_lt_8_cell.out, + j_lt_8_group, load_from_mems[4], load_from_mems[5], ), @@ -197,40 +126,49 @@ def add_wrap3(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells to compute equality, and lt - eq0cell, eq0grp = add_eq(wrap, i, 0, "eq0", "i_eq_0") - eq1cell, eq1grp = add_eq(wrap, i, 1, "eq1", "i_eq_1") - eq2cell, eq2grp = add_eq(wrap, i, 2, "eq2", "i_eq_2") - ltcell, ltgrp = add_lt(wrap, j, 4, "lt", "j_lt_4") + i_eq_0_cell, i_eq_0_group = util.insert_eq(wrap, i, 0, "i_eq_0", 32) + i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, "i_eq_1", 32) + i_eq_2_cell, i_eq_2_group = util.insert_eq(wrap, i, 2, "i_eq_2", 32) + j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, "j_lt_4", 32) # Load `j` unchanged into `j_mod_4`. - unchanged = add_reg_load(wrap, j, j_mod_4, "j_unchanged") + unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") - # A subtraction cell and wiring to perform j-4. - sub_cell = wrap.sub("sub", 32) - subcell = add_sub(wrap, j, cb.const(32, 4), sub_cell, j_mod_4, "j_minus_4") + # Wiring to perform j-4 and store the result in `j_mod_4`. + subcell, j_mod_4 = util.insert_sub_store_in_reg( + wrap, j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 + ) emit_from_mems = [ - add_mem_load(wrap, mems[i], j_mod_4.out, ans, f"load_from_mem{i}") + util.insert_mem_load_to_mem( + wrap, mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" + ) for i in range(6) ] wrap.control += [ - cb.if_(ltcell.out, ltgrp, unchanged, subcell), + cb.if_(j_lt_4_cell.out, j_lt_4_group, unchanged, subcell), cb.par( cb.if_( - eq0cell.out, - eq0grp, - cb.if_(ltcell.out, ltgrp, emit_from_mems[0], emit_from_mems[1]), + i_eq_0_cell.out, + i_eq_0_group, + cb.if_( + j_lt_4_cell.out, j_lt_4_group, emit_from_mems[0], emit_from_mems[1] + ), ), cb.if_( - eq1cell.out, - eq1grp, - cb.if_(ltcell.out, ltgrp, emit_from_mems[2], emit_from_mems[3]), + i_eq_1_cell.out, + i_eq_1_group, + cb.if_( + j_lt_4_cell.out, j_lt_4_group, emit_from_mems[2], emit_from_mems[3] + ), ), cb.if_( - eq2cell.out, - eq2grp, - cb.if_(ltcell.out, ltgrp, emit_from_mems[4], emit_from_mems[5]), + i_eq_2_cell.out, + i_eq_2_group, + cb.if_( + j_lt_4_cell.out, j_lt_4_group, emit_from_mems[4], emit_from_mems[5] + ), ), ), ] diff --git a/calyx-py/test/correctness/reduction_tree.py b/calyx-py/test/correctness/reduction_tree.py index a48989a7d..c32eaa1ed 100644 --- a/calyx-py/test/correctness/reduction_tree.py +++ b/calyx-py/test/correctness/reduction_tree.py @@ -1,31 +1,9 @@ # pylint: disable=import-error from typing import List +import calyx.builder_util as util import calyx.builder as cb -def add_adder( - comp: cb.ComponentBuilder, - adder: cb.CellBuilder, - group, - port_l, - port_r, - ans_reg, -): - """To component {comp}, adds wiring for an group called {group}. - Assumes the adder cell {adder} is in the component. - In {group}, puts {port_l} and {port_r} into the {adder} cell. - Then puts the output of {adder} into the memory register {ans_reg}. - Returns the group. - """ - with comp.group(group) as adder_group: - adder.left = port_l - adder.right = port_r - ans_reg.write_en = 1 - ans_reg.in_ = adder.out - adder_group.done = ans_reg.done - return adder_group - - def add_tree(prog): """Inserts the component `tree` into the program. It has: @@ -43,20 +21,13 @@ def add_tree(prog): # Add the output port. tree.output("sum", 32) - # Add three registers and two adders. - root = tree.reg("root", 32) - left = tree.reg("left_node", 32) - right = tree.reg("right_node", 32) - add1 = tree.add("add1", 32) - add2 = tree.add("add2", 32) - # Into the component `tree`, add the wiring for three adder groups that will # use the tree to perform their additions. # These need to be orchestrated in the control below. - add_l0_l1 = add_adder(tree, add1, "add_l0_l1", leaf0, leaf1, left) - add_l2_l3 = add_adder(tree, add2, "add_l2_l3", leaf2, leaf3, right) - add_l_r_nodes = add_adder( - tree, add1, "add_left_right_nodes", left.out, right.out, root + add_l0_l1, left = util.insert_add_store_in_reg(tree, "add_l0_l1", leaf0, leaf1) + add_l2_l3, right = util.insert_add_store_in_reg(tree, "add_l2_l3", leaf2, leaf3) + add_l_r_nodes, root = util.insert_add_store_in_reg( + tree, "add_l_r", left.out, right.out ) # Continuously output the value of the root register. From e6ac6771bd801b4ea245e6ae121e754dfd97a9c7 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 25 Jul 2023 11:47:10 -0700 Subject: [PATCH 007/189] Docs: fix two links (#1639) I found broken links to fud and the interpreter. Easy fixes! --- docs/debug/cider.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/debug/cider.md b/docs/debug/cider.md index 2e8d676c3..3cf675a4d 100644 --- a/docs/debug/cider.md +++ b/docs/debug/cider.md @@ -277,5 +277,6 @@ much of the execution is occurring in parallel at any given point. Use `help` to see all commands. Use `exit` to exit the debugger. -[fud]: /fud/index.md +[fud]: ../fud/index.md [gdb]: https://sourceware.org/gdb/ +[interp]: ../interpreter.md From 43393756738872207f26634d73e608ef1eb07d7d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 26 Jul 2023 14:18:13 -0400 Subject: [PATCH 008/189] Dont require `@clk` and `@reset` ports in comb components (#1641) * comb components in clk and reset insertion * update changelog --- CHANGELOG.md | 1 + calyx-opt/src/passes/clk_insertion.rs | 39 +++++++++++++++++------- calyx-opt/src/passes/reset_insertion.rs | 40 +++++++++++++++++-------- tests/passes/clk-insertion.expect | 21 +++++++++++++ tests/passes/clk-insertion.futil | 22 ++++++++++++++ 5 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 tests/passes/clk-insertion.expect create mode 100644 tests/passes/clk-insertion.futil diff --git a/CHANGELOG.md b/CHANGELOG.md index 29d61441e..ddb240cbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## Unreleased +- Don't require `@clk` and `@reset` ports in `comb` components ## 0.4.0 diff --git a/calyx-opt/src/passes/clk_insertion.rs b/calyx-opt/src/passes/clk_insertion.rs index 8e4fb9e52..e0ca0dbea 100644 --- a/calyx-opt/src/passes/clk_insertion.rs +++ b/calyx-opt/src/passes/clk_insertion.rs @@ -1,5 +1,6 @@ use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures}; +use calyx_utils::Error; use std::rc::Rc; #[derive(Default)] @@ -25,22 +26,38 @@ impl Visitor for ClkInsertion { _comps: &[ir::Component], ) -> VisResult { let builder = ir::Builder::new(comp, sigs); + // Find @clk port in the component. If it doesn't exist, + // then we don't need to do anything. let clk = builder .component .signature .borrow() - .get_with_attr(ir::BoolAttr::Clk); + .find_with_attr(ir::BoolAttr::Clk); - for cell_ref in builder.component.cells.iter() { - let cell = cell_ref.borrow(); - if let Some(port) = cell.find_with_attr(ir::BoolAttr::Clk) { - builder.component.continuous_assignments.push( - builder.build_assignment( - port, - Rc::clone(&clk), - ir::Guard::True, - ), - ) + if let Some(clk) = clk { + for cell_ref in builder.component.cells.iter() { + let cell = cell_ref.borrow(); + if let Some(port) = cell.find_with_attr(ir::BoolAttr::Clk) { + builder.component.continuous_assignments.push( + builder.build_assignment( + port, + Rc::clone(&clk), + ir::Guard::True, + ), + ) + } + } + } else { + for cell_ref in builder.component.cells.iter() { + let cell = cell_ref.borrow(); + if cell.find_with_attr(ir::BoolAttr::Clk).is_some() { + return Err(Error::malformed_structure(format!( + "Cell `{}' in component `{}' has a clk port, \ + but the component does not have a clk port.", + cell.name(), + builder.component.name + ))); + } } } diff --git a/calyx-opt/src/passes/reset_insertion.rs b/calyx-opt/src/passes/reset_insertion.rs index b2040af3a..ef105404d 100644 --- a/calyx-opt/src/passes/reset_insertion.rs +++ b/calyx-opt/src/passes/reset_insertion.rs @@ -1,7 +1,7 @@ -use std::rc::Rc; - use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures}; +use calyx_utils::Error; +use std::rc::Rc; #[derive(Default)] /// Adds assignments from a components `reset` port to every @@ -30,18 +30,32 @@ impl Visitor for ResetInsertion { .component .signature .borrow() - .get_with_attr(ir::BoolAttr::Reset); + .find_with_attr(ir::BoolAttr::Reset); - for cell_ref in builder.component.cells.iter() { - let cell = cell_ref.borrow(); - if let Some(port) = cell.find_with_attr(ir::BoolAttr::Reset) { - builder.component.continuous_assignments.push( - builder.build_assignment( - port, - Rc::clone(&reset), - ir::Guard::True, - ), - ) + if let Some(reset) = reset { + for cell_ref in builder.component.cells.iter() { + let cell = cell_ref.borrow(); + if let Some(port) = cell.find_with_attr(ir::BoolAttr::Reset) { + builder.component.continuous_assignments.push( + builder.build_assignment( + port, + Rc::clone(&reset), + ir::Guard::True, + ), + ) + } + } + } else { + for cell_ref in builder.component.cells.iter() { + let cell = cell_ref.borrow(); + if cell.find_with_attr(ir::BoolAttr::Reset).is_some() { + return Err(Error::malformed_structure(format!( + "Cell `{}' in component `{}' has a reset port, \ + but the component does not have a reset port.", + cell.name(), + builder.component.name + ))); + } } } diff --git a/tests/passes/clk-insertion.expect b/tests/passes/clk-insertion.expect new file mode 100644 index 000000000..1bfaf0d00 --- /dev/null +++ b/tests/passes/clk-insertion.expect @@ -0,0 +1,21 @@ +import "primitives/core.futil"; +comb component layout_hw0() -> (flat_port_addr0: 4) { + cells { + add_0 = std_add(4); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = 4'd1; + add_0.right = 4'd2; + } +} +component main(@clk clk: 1, @go go: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r = std_reg(32); + } + wires { + out = r.out; + r.clk = clk; + } + control {} +} diff --git a/tests/passes/clk-insertion.futil b/tests/passes/clk-insertion.futil new file mode 100644 index 000000000..ac7131248 --- /dev/null +++ b/tests/passes/clk-insertion.futil @@ -0,0 +1,22 @@ +// -p well-formed -p clk-insertion +import "primitives/core.futil"; +comb component layout_hw0() -> (flat_port_addr0: 4) { + cells { + add_0 = std_add(4); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = 4'd1; + add_0.right = 4'd2; + } +} + +component main(@clk clk: 1) -> (out: 32) { + cells { + r = std_reg(32); + } + wires { + out = r.out; + } + control {} +} \ No newline at end of file From 9b602057664f3d14f3027f53a5e2e92f124d42ff Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 28 Jul 2023 08:32:08 -0400 Subject: [PATCH 009/189] Systolic Array takes dynamic contraction dimension (#1642) * variable k works now * dynamic k value for systolic array * formatting / rewrote test cases --- calyx-py/calyx/builder.py | 16 + frontends/systolic-lang/gen-systolic.py | 390 +++++-- .../systolic/output/array-2-3-4.expect | 2 +- .../systolic/output/array-8.expect | 2 +- tests/correctness/systolic/pe/array-1.expect | 2 +- .../systolic/pe/array-1.systolic.jq | 2 +- tests/correctness/systolic/pe/array-2.expect | 2 +- .../systolic/pe/array-2.systolic.jq | 2 +- tests/correctness/systolic/pe/array-3.expect | 2 +- .../systolic/pe/array-3.systolic.jq | 2 +- tests/frontend/systolic/array-1.expect | 281 +++-- tests/frontend/systolic/array-2.expect | 647 +++++++---- tests/frontend/systolic/array-3.expect | 1011 ++++++++++------- 13 files changed, 1531 insertions(+), 830 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index bbde0fded..7ee0f55ed 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -108,6 +108,15 @@ def control(self, builder: Union[ast.Control, ControlBuilder]): else: self.component.controls = builder + def get_port_width(self, name: str) -> int: + for input in self.component.inputs: + if input.id.name == name: + return input.width + for output in self.component.outputs: + if output.id.name == name: + return output.width + raise Exception(f"couldn't find port {name} on component {self.component.name}") + def get_cell(self, name: str) -> CellBuilder: """Retrieve a cell builder by name.""" out = self.index.get(name) @@ -218,6 +227,10 @@ def reg(self, name: str, size: int, is_ref=False) -> CellBuilder: """Generate a StdReg cell.""" return self.cell(name, ast.Stdlib.register(size), False, is_ref) + def slice(self, name: str, in_width: int, out_width, is_ref=False) -> CellBuilder: + """Generate a StdReg cell.""" + return self.cell(name, ast.Stdlib.slice(in_width, out_width), False, is_ref) + def const(self, name: str, width: int, value: int) -> CellBuilder: """Generate a StdConstant cell.""" return self.cell(name, ast.Stdlib.constant(width, value)) @@ -713,6 +726,9 @@ def infer_width(expr): # Otherwise, it's a `cell.port` lookup. assert isinstance(expr, ast.Atom) + if isinstance(expr.item, ast.ThisPort): + name = expr.item.id.name + return group_builder.comp.get_port_width(name) cell_name = expr.item.id.name port_name = expr.item.name diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index e2dc7323b..19abcba3d 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -10,6 +10,42 @@ # Name of the ouput array OUT_MEM = "out_mem" PE_NAME = "mac_pe" +DEPTH = "depth" + + +class CalyxAdd: + """ + A class that represents addition in Calyx between a port and a constant + """ + + def __init__(self, port, const): + self.port = port + self.const = const + + def __eq__(self, other): + if type(other) != CalyxAdd: + return False + return ( + cb.ExprBuilder.unwrap(self.port) == cb.ExprBuilder.unwrap(other.port) + and self.const == other.const + ) + + def __hash__(self): + return hash(self.const) + + def __repr__(self): + return ( + str(cb.ExprBuilder.unwrap(self.port).item.id.name) + + "_plus_" + + str(self.const) + ) + + def __str__(self): + return ( + str(cb.ExprBuilder.unwrap(self.port).item.id.name) + + "_plus_" + + str(self.const) + ) def pe(prog: cb.Builder): @@ -91,6 +127,25 @@ def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuil return reg +def add_read_mem_argument(comp: cb.ComponentBuilder, name, addr_width): + """ + Add arguments to component `comp` if we want to read from a mem named `name` wth + width of `addr_width` + """ + comp.input(f"{name}_read_data", BITWIDTH) + comp.output(f"{name}_addr0", addr_width) + + +def add_write_mem_argument(comp: cb.ComponentBuilder, name, addr_width): + """ + Add arguments to component `comp` if we want to write to a mem named `name` wth + width of `addr_width` + """ + comp.output(f"{name}_addr0", addr_width) + comp.output(f"{name}_write_data", BITWIDTH) + comp.output(f"{name}_write_en", 1) + + def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): """ Instantiates: @@ -110,21 +165,18 @@ def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): idx_width = bits_needed(size) # Instantiate the memory - mem = comp.mem_d1( - name, - BITWIDTH, - size, - idx_width, - is_external=True, - ) + add_read_mem_argument(comp, name, idx_width) + this = comp.this() + addr0_port = cb.ExprBuilder.unwrap(this.port(name + "_addr0")) + read_data_port = this.port(name + "_read_data") # Instantiate the indexing register idx = instantiate_indexor(comp, name, idx_width) # Register to save the value from the memory. Defined by [[instantiate_pe]]. target = comp.get_cell(target_reg) group_name = NAME_SCHEME["memory move"].format(prefix=name) - with comp.static_group(group_name, 1): - mem.addr0 = idx.out - target.in_ = mem.read_data + with comp.static_group(group_name, 1) as g: + g.asgn(addr0_port, idx.out) + target.in_ = read_data_port target.write_en = 1 @@ -171,14 +223,20 @@ def instantiate_output_move(comp: cb.ComponentBuilder, row, col, cols): """ group_name = NAME_SCHEME["out mem move"].format(pe=f"pe_{row}_{col}") pe = comp.get_cell(f"pe_{row}_{col}") - out = comp.get_cell(OUT_MEM + f"_{row}") - with comp.static_group(group_name, 1): - out.addr0 = col - out.write_data = pe.out - out.write_en = 1 - - -def gen_schedules(top_length, top_depth, left_length, left_depth): + this = comp.this() + mem_name = OUT_MEM + f"_{row}" + addr0_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_addr0")) + write_data_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_data")) + write_en_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_en")) + with comp.static_group(group_name, 1) as g: + g.asgn(addr0_port, col) + g.asgn(write_data_port, pe.out) + g.asgn(write_en_port, 1) + + +def gen_schedules( + top_length, top_depth, left_length, left_depth, comp: cb.ComponentBuilder +): """ Generates 5 arrays that are the same size as the output (systolic) array Each entry in the array has tuple [start, end) that indicates the cycles that @@ -193,6 +251,9 @@ def gen_schedules(top_length, top_depth, left_length, left_depth): `pe_write_sched` contains when to "write" the PE value into memory (i.e., when the PE is "finished") """ + depth_port = comp.this().depth + min_depth_4_port = comp.get_cell("min_depth_4").port("out") + schedules = {} update_sched = np.zeros((left_length, top_length), dtype=object) pe_fill_sched = np.zeros((left_length, top_length), dtype=object) pe_accum_sched = np.zeros((left_length, top_length), dtype=object) @@ -201,12 +262,20 @@ def gen_schedules(top_length, top_depth, left_length, left_depth): for row in range(0, left_length): for col in range(0, top_length): pos = row + col - update_sched[row][col] = (pos, pos + left_depth) - pe_fill_sched[row][col] = (pos + 1, pos + min(4, left_depth) + 1) - pe_accum_sched[row][col] = (pos + 5, pos + left_depth + 5) - pe_move_sched[row][col] = (pos + 1, pos + left_depth + 1) - pe_write_sched[row][col] = (pos + left_depth + 5, pos + left_depth + 6) - return (update_sched, pe_fill_sched, pe_accum_sched, pe_move_sched, pe_write_sched) + update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) + pe_fill_sched[row][col] = (pos + 1, CalyxAdd(min_depth_4_port, pos + 1)) + pe_accum_sched[row][col] = (pos + 5, CalyxAdd(depth_port, pos + 5)) + pe_move_sched[row][col] = (pos + 1, CalyxAdd(depth_port, pos + 1)) + pe_write_sched[row][col] = ( + CalyxAdd(depth_port, pos + 5), + CalyxAdd(depth_port, pos + 6), + ) + schedules["update_sched"] = update_sched + schedules["fill_sched"] = pe_fill_sched + schedules["accum_sched"] = pe_accum_sched + schedules["move_sched"] = pe_move_sched + schedules["write_sched"] = pe_write_sched + return schedules def accum_nec_ranges(nec_ranges, schedule): @@ -226,12 +295,48 @@ def accum_nec_ranges(nec_ranges, schedule): return nec_ranges -def instantiate_idx_groups(comp: cb.ComponentBuilder, width, limit): +def build_calyx_add(comp, obj): """ - Builds groups that instantiate idx to 0 and increment idx + Attempts to build an adder for obj, with name str(obj) and group name + str(obj) + "_group" that adds obj.port and obj.const + Returns true if we actually build it + Returns false otherwise + """ + if type(obj) == CalyxAdd: + add_str = str(obj) + if comp.try_get_cell(add_str) is None: + add = comp.add(add_str, BITWIDTH) + with comp.static_group(add_str + "_group", 1): + add.left = obj.port + add.right = obj.const + return True + return False + + +def instantiate_calyx_adds(comp, nec_ranges): + """ + Instantiates the CalyxAdds objects to adders and actual groups that add things + """ + depth_adders = [] + for lo, hi in nec_ranges: + if build_calyx_add(comp, lo): + depth_adders.append(str(lo) + "_group") + if build_calyx_add(comp, hi): + depth_adders.append(str(hi) + "_group") + return depth_adders + + +def instantiate_idx_cond_groups(comp: cb.ComponentBuilder): """ - idx = comp.reg("idx", width) - add = comp.add("idx_add", width) + Builds groups that instantiate idx to 0 and increment idx + Also builds groups that set cond_reg to 1 (runs before the while loop) + and that sets cond_reg to idx + 1 < iter_limit + """ + idx = comp.reg("idx", BITWIDTH) + add = comp.add("idx_add", BITWIDTH) + iter_limit = comp.get_cell("iter_limit") + lt_iter_limit = comp.lt("lt_iter_limit", BITWIDTH) + cond_reg = comp.reg("cond_reg", 1) with comp.static_group("init_idx", 1): idx.in_ = 0 idx.write_en = 1 @@ -240,9 +345,40 @@ def instantiate_idx_groups(comp: cb.ComponentBuilder, width, limit): add.right = 1 idx.in_ = add.out idx.write_en = 1 - - -def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi, width) -> list: + with comp.static_group("lt_iter_limit_group", 1): + lt_iter_limit.left = add.out + lt_iter_limit.right = iter_limit.out + cond_reg.in_ = lt_iter_limit.out + cond_reg.write_en = 1 + with comp.static_group("init_cond_reg", 1): + cond_reg.in_ = 1 + cond_reg.write_en = 1 + + +def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit): + """ + Builds group that instantiates the dynamic/runtime values for the systolic + array: its depth and iteration limit/count (since its iteration limit depends on + its depth). + """ + min_depth_4 = comp.reg("min_depth_4", BITWIDTH) + lt_depth_4 = comp.lt("lt_depth_4", BITWIDTH) + iter_limit = comp.reg("iter_limit", BITWIDTH) + iter_limit_add = comp.add("iter_limit_add", BITWIDTH) + with comp.static_group("init_min_depth", 1): + lt_depth_4.left = depth_port + lt_depth_4.right = 4 + min_depth_4.in_ = lt_depth_4.out @ depth_port + min_depth_4.in_ = ~lt_depth_4.out @ 4 + min_depth_4.write_en = 1 + with comp.static_group("init_iter_limit", 1): + iter_limit_add.left = rem_iter_limit + iter_limit_add.right = depth_port + iter_limit.in_ = iter_limit_add.out + iter_limit.write_en = 1 + + +def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: """ Instantiates a static group and register called "idx_between_{lo}_{hi}_reg/group" that should output whether idx is between [lo, hi). That is, whether lo <= idx < hi. @@ -250,23 +386,31 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi, width) -> list: Note: If you're trying to understand why this works, we are checking `idx_add` which is one higher than idx. This offsets the cycle it takes to update the register. """ + if type(hi) == CalyxAdd: + hi_value = comp.get_cell(str(hi)).port("out") + else: + hi_value = hi + if type(lo) == CalyxAdd: + lo_value = comp.get_cell(str(lo)).port("out") + else: + lo_value = lo idx_add = comp.get_cell("idx_add") reg_str = f"idx_between_{lo}_{hi}_reg" comb_str = f"idx_between_{lo}_{hi}_comb" group_str = f"idx_between_{lo}_{hi}_group" - index_lt = f"index_lt_{hi}" - index_ge = f"index_ge_{lo}" + index_lt = f"index_lt_{str(hi)}" + index_ge = f"index_ge_{str(lo)}" reg = comp.reg(reg_str, 1) lt = ( comp.get_cell(index_lt) if comp.try_get_cell(index_lt) is not None - else comp.lt(index_lt, width) + else comp.lt(index_lt, BITWIDTH) ) # if lo == 0, then only need to check if reg < hi - if lo == 0: + if type(lo) == int and lo == 0: with comp.static_group(group_str, 1): lt.left = idx_add.out - lt.right = hi + lt.right = hi_value reg.in_ = lt.out reg.write_en = 1 # need to check if reg >= lo and reg < hi @@ -274,14 +418,14 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi, width) -> list: ge = ( comp.get_cell(index_ge) if comp.try_get_cell(index_ge) is not None - else comp.ge(index_ge, width) + else comp.ge(index_ge, BITWIDTH) ) and_ = comp.and_(comb_str, 1) with comp.static_group(group_str, 1): ge.left = idx_add.out - ge.right = lo + ge.right = lo_value lt.left = idx_add.out - lt.right = hi + lt.right = hi_value and_.left = ge.out and_.right = lt.out reg.in_ = and_.out @@ -376,11 +520,8 @@ def generate_control( top_depth, left_length, left_depth, - update_sched, - fill_sched, - accum_sched, - move_sched, - write_sched, + schedules, + depth_adders, nec_ranges, ): """ @@ -407,7 +548,12 @@ def generate_control( py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"l{idx}")) for idx in range(left_length) ] - + [py_ast.Enable("init_idx")] + + [ + py_ast.Enable("init_idx"), + py_ast.Enable("init_min_depth"), + py_ast.Enable("init_iter_limit"), + py_ast.Enable("init_cond_reg"), + ] + [py_ast.Enable(f"init_idx_between_{lo}_{hi}") for (lo, hi) in (nec_ranges)] ) control.append(py_ast.StaticParComp(init_indices)) @@ -425,38 +571,38 @@ def counter(): # end source pos init control_stmts = [] - incr_stmts = [py_ast.Enable("incr_idx")] + incr_stmts = [py_ast.Enable("incr_idx"), py_ast.Enable("lt_iter_limit_group")] for r in range(left_length): for c in range(top_length): # build 4 if stmts for the 4 schedules that we need to account for input_mem_updates = execute_if_between( comp, - update_sched[r][c][0], - update_sched[r][c][1], + schedules["update_sched"][r][c][0], + schedules["update_sched"][r][c][1], get_memory_updates(r, c), ) pe_fills = execute_if_between( comp, - fill_sched[r][c][0], - fill_sched[r][c][1], + schedules["fill_sched"][r][c][0], + schedules["fill_sched"][r][c][1], [get_pe_invoke(r, c, top_length, left_length, 0)], ) pe_moves = execute_if_between( comp, - move_sched[r][c][0], - move_sched[r][c][1], + schedules["move_sched"][r][c][0], + schedules["move_sched"][r][c][1], get_pe_moves(r, c, top_length, left_length), ) pe_accums = execute_if_between( comp, - accum_sched[r][c][0], - accum_sched[r][c][1], + schedules["accum_sched"][r][c][0], + schedules["accum_sched"][r][c][1], [get_pe_invoke(r, c, top_length, left_length, 1)], ) pe_writes = execute_if_between( comp, - write_sched[r][c][0], - write_sched[r][c][1], + schedules["write_sched"][r][c][0], + schedules["write_sched"][r][c][1], [py_ast.Enable(NAME_SCHEME["out mem move"].format(pe=f"pe_{r}_{c}"))], ) pe_control = input_mem_updates + pe_fills + pe_moves + pe_accums + pe_writes @@ -465,26 +611,28 @@ def counter(): tag = counter() source_map[ tag - ] = f"pe_{r}_{c} filling: [{fill_sched[r][c][0]},{fill_sched[r][c][1]}) \ -accumulating: [{accum_sched[r][c][0]} {accum_sched[r][c][1]})" + ] = f"pe_{r}_{c} filling: [{schedules['fill_sched'][r][c][0]},\ +{schedules['fill_sched'][r][c][1]}) accumulating: [{schedules['accum_sched'][r][c][0]} \ +{schedules['accum_sched'][r][c][1]})" for start, end in nec_ranges: # build the control stmts that assign correct values to # idx_between_{start}_{end}_reg, which is what the if stmts above^ rely on incr_stmts.append(py_ast.Enable(f"idx_between_{start}_{end}_group")) + for depth_adder_group in depth_adders: + incr_stmts.append(py_ast.Enable(depth_adder_group)) - repeat_body = py_ast.StaticParComp( + while_body = py_ast.StaticParComp( [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] ) - # build the static repeat + # build the while loop with condition cond_reg. # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 - static_repeat = cb.static_repeat( - top_length + left_length + top_depth + 4, repeat_body - ) + cond_reg_port = comp.get_cell("cond_reg").port("out") + while_loop = cb.while_(cond_reg_port, None, while_body) - control.append(static_repeat) + control.append(while_loop) - return py_ast.StaticSeqComp(stmts=control), source_map + return py_ast.SeqComp(stmts=control), source_map def create_systolic_array( @@ -502,79 +650,119 @@ def create_systolic_array( f"{top_length}x{top_depth} and {left_depth}x{left_length}" ) - (update_sched, fill_sched, accum_sched, move_sched, write_sched) = gen_schedules( - top_length, top_depth, left_length, left_depth + computational_unit = prog.component("systolic_array_comp") + depth_port = computational_unit.input("depth", BITWIDTH) + init_dyn_vals(computational_unit, depth_port, top_length + left_length + 4) + + schedules = gen_schedules( + top_length, top_depth, left_length, left_depth, computational_unit ) nec_ranges = set() - accum_nec_ranges(nec_ranges, update_sched) - accum_nec_ranges(nec_ranges, fill_sched) - accum_nec_ranges(nec_ranges, accum_sched) - accum_nec_ranges(nec_ranges, move_sched) - accum_nec_ranges(nec_ranges, write_sched) - - main = prog.component("main") + for sched in schedules.values(): + accum_nec_ranges(nec_ranges, sched) + depth_adders = instantiate_calyx_adds(computational_unit, nec_ranges) for row in range(left_length): for col in range(top_length): # Instantiate the PEs and surronding registers - instantiate_pe(main, row, col) + instantiate_pe(computational_unit, row, col) # Instantiate all the memories for r in range(top_length): - instantiate_memory(main, "top", r, top_depth) + instantiate_memory(computational_unit, "top", r, top_depth) for col in range(left_length): - instantiate_memory(main, "left", col, left_depth) + instantiate_memory(computational_unit, "left", col, left_depth) + idx_width = BITWIDTH # Instantiate output memory - out_idx_size = bits_needed(top_length) for i in range(left_length): - main.mem_d1( - OUT_MEM + f"_{i}", - BITWIDTH, - top_length, - out_idx_size, - is_external=True, - ) + add_write_mem_argument(computational_unit, OUT_MEM + f"_{i}", idx_width) # Instantiate all the PEs for row in range(left_length): for col in range(top_length): # Instantiate the mover fabric instantiate_data_move( - main, row, col, col == top_length - 1, row == left_length - 1 + computational_unit, + row, + col, + col == top_length - 1, + row == left_length - 1, ) # Instantiate output movement structure - instantiate_output_move(main, row, col, top_length) - - iter_limit = top_length + left_length + top_depth + 4 - iter_idx_size = bits_needed(iter_limit) - # instantiate groups that initialize idx to 0 and increment it - instantiate_idx_groups(main, iter_idx_size, iter_limit) + instantiate_output_move(computational_unit, row, col, top_length) + # instantiate groups that handle cond_reg and idx variables + instantiate_idx_cond_groups(computational_unit) for start, end in nec_ranges: # create the groups that create for idx_in_between registers - instantiate_idx_between(main, start, end, iter_idx_size) - instantiate_init_group(main, start, end) + instantiate_idx_between(computational_unit, start, end) + instantiate_init_group(computational_unit, start, end) # Generate the control and set the source map control, source_map = generate_control( - main, + computational_unit, top_length, top_depth, left_length, left_depth, - update_sched, - fill_sched, - accum_sched, - move_sched, - write_sched, + schedules, + depth_adders, nec_ranges, ) - main.control = control + computational_unit.control = control prog.program.meta = source_map + # build the main component + # instantaites the systolic array/computational_unit and the mems, + # and then invokes it + main = prog.component("main") + systolic_array = main.cell("systolic_array", computational_unit) + invoke_args = {} + invoke_args["in_depth"] = py_ast.ConstantPort(BITWIDTH, left_depth) + for r in range(top_length): + name = f"t{r}" + idx_width = bits_needed(top_depth) + mem = main.mem_d1( + name, + BITWIDTH, + top_depth, + idx_width, + is_external=True, + ) + invoke_args[f"in_{name}_read_data"] = mem.read_data + invoke_args[f"out_{name}_addr0"] = mem.addr0 + for col in range(left_length): + name = f"l{col}" + idx_width = bits_needed(left_depth) + mem = main.mem_d1( + name, + BITWIDTH, + left_depth, + idx_width, + is_external=True, + ) + invoke_args[f"in_{name}_read_data"] = mem.read_data + invoke_args[f"out_{name}_addr0"] = mem.addr0 + + for i in range(left_length): + name = OUT_MEM + f"_{i}" + mem = main.mem_d1( + name, + BITWIDTH, + top_length, + BITWIDTH, + is_external=True, + ) + invoke_args[f"out_{name}_addr0"] = mem.addr0 + invoke_args[f"out_{name}_write_data"] = mem.write_data + invoke_args[f"out_{name}_write_en"] = mem.write_en + + invoke = cb.invoke(systolic_array, **invoke_args) + main.control = invoke + if __name__ == "__main__": import argparse diff --git a/tests/correctness/systolic/output/array-2-3-4.expect b/tests/correctness/systolic/output/array-2-3-4.expect index cfe7d6ab9..aa115c188 100644 --- a/tests/correctness/systolic/output/array-2-3-4.expect +++ b/tests/correctness/systolic/output/array-2-3-4.expect @@ -1,5 +1,5 @@ { - "cycles": 14, + "cycles": 16, "memories": { "l0": [ 62, diff --git a/tests/correctness/systolic/output/array-8.expect b/tests/correctness/systolic/output/array-8.expect index 4cc6701e6..944548e5a 100644 --- a/tests/correctness/systolic/output/array-8.expect +++ b/tests/correctness/systolic/output/array-8.expect @@ -1,5 +1,5 @@ { - "cycles": 29, + "cycles": 31, "memories": { "l0": [ 26, diff --git a/tests/correctness/systolic/pe/array-1.expect b/tests/correctness/systolic/pe/array-1.expect index ce98de82e..df8dfe978 100644 --- a/tests/correctness/systolic/pe/array-1.expect +++ b/tests/correctness/systolic/pe/array-1.expect @@ -1,5 +1,5 @@ { - "cycles": 14, + "cycles": 16, "pe_00": [ 0, 120, diff --git a/tests/correctness/systolic/pe/array-1.systolic.jq b/tests/correctness/systolic/pe/array-1.systolic.jq index 8e75b4114..a61fe68a9 100644 --- a/tests/correctness/systolic/pe/array-1.systolic.jq +++ b/tests/correctness/systolic/pe/array-1.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main | ({ +.TOP.TOP.main.systolic_array | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, }) diff --git a/tests/correctness/systolic/pe/array-2.expect b/tests/correctness/systolic/pe/array-2.expect index c94727974..5bcf45bd8 100644 --- a/tests/correctness/systolic/pe/array-2.expect +++ b/tests/correctness/systolic/pe/array-2.expect @@ -1,5 +1,5 @@ { - "cycles": 16, + "cycles": 18, "pe_00": [ 0, 120, diff --git a/tests/correctness/systolic/pe/array-2.systolic.jq b/tests/correctness/systolic/pe/array-2.systolic.jq index 267a10407..0cedc930a 100644 --- a/tests/correctness/systolic/pe/array-2.systolic.jq +++ b/tests/correctness/systolic/pe/array-2.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main | ({ +.TOP.TOP.main.systolic_array | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, "pe_01": .pe_0_1.acc.out | unique, diff --git a/tests/correctness/systolic/pe/array-3.expect b/tests/correctness/systolic/pe/array-3.expect index 25ea25a92..f8afb09ec 100644 --- a/tests/correctness/systolic/pe/array-3.expect +++ b/tests/correctness/systolic/pe/array-3.expect @@ -1,5 +1,5 @@ { - "cycles": 18, + "cycles": 20, "pe_00": [ 0, 120, diff --git a/tests/correctness/systolic/pe/array-3.systolic.jq b/tests/correctness/systolic/pe/array-3.systolic.jq index e2a09856e..d79a90dc5 100644 --- a/tests/correctness/systolic/pe/array-3.systolic.jq +++ b/tests/correctness/systolic/pe/array-3.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main | ({ +.TOP.TOP.main.systolic_array | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index d1ed422c8..46f4792a3 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -27,36 +27,80 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } } } -component main() -> () { +component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 2, l0_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1) { cells { + min_depth_4 = std_reg(32); + lt_depth_4 = std_lt(32); + iter_limit = std_reg(32); + iter_limit_add = std_add(32); + depth_plus_5 = std_add(32); + depth_plus_0 = std_add(32); + depth_plus_1 = std_add(32); + min_depth_4_plus_1 = std_add(32); + depth_plus_6 = std_add(32); pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); - @external t0 = std_mem_d1(32, 3, 2); t0_idx = std_reg(2); t0_add = std_add(2); - @external l0 = std_mem_d1(32, 3, 2); l0_idx = std_reg(2); l0_add = std_add(2); - @external out_mem_0 = std_mem_d1(32, 1, 1); - idx = std_reg(4); - idx_add = std_add(4); - idx_between_8_9_reg = std_reg(1); - index_lt_9 = std_lt(4); - index_ge_8 = std_ge(4); - idx_between_8_9_comb = std_and(1); - idx_between_0_3_reg = std_reg(1); - index_lt_3 = std_lt(4); - idx_between_1_4_reg = std_reg(1); - index_lt_4 = std_lt(4); - index_ge_1 = std_ge(4); - idx_between_1_4_comb = std_and(1); - idx_between_5_8_reg = std_reg(1); - index_lt_8 = std_lt(4); - index_ge_5 = std_ge(4); - idx_between_5_8_comb = std_and(1); + idx = std_reg(32); + idx_add = std_add(32); + lt_iter_limit = std_lt(32); + cond_reg = std_reg(1); + idx_between_5_depth_plus_5_reg = std_reg(1); + index_lt_depth_plus_5 = std_lt(32); + index_ge_5 = std_ge(32); + idx_between_5_depth_plus_5_comb = std_and(1); + idx_between_0_depth_plus_0_reg = std_reg(1); + index_lt_depth_plus_0 = std_lt(32); + idx_between_1_depth_plus_1_reg = std_reg(1); + index_lt_depth_plus_1 = std_lt(32); + index_ge_1 = std_ge(32); + idx_between_1_depth_plus_1_comb = std_and(1); + idx_between_1_min_depth_4_plus_1_reg = std_reg(1); + index_lt_min_depth_4_plus_1 = std_lt(32); + idx_between_1_min_depth_4_plus_1_comb = std_and(1); + idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); + index_lt_depth_plus_6 = std_lt(32); + index_ge_depth_plus_5 = std_ge(32); + idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); } wires { + static<1> group init_min_depth { + lt_depth_4.left = depth; + lt_depth_4.right = 32'd4; + min_depth_4.in = lt_depth_4.out ? depth; + min_depth_4.in = !lt_depth_4.out ? 32'd4; + min_depth_4.write_en = 1'd1; + } + static<1> group init_iter_limit { + iter_limit_add.left = 32'd6; + iter_limit_add.right = depth; + iter_limit.in = iter_limit_add.out; + iter_limit.write_en = 1'd1; + } + static<1> group depth_plus_5_group { + depth_plus_5.left = depth; + depth_plus_5.right = 32'd5; + } + static<1> group depth_plus_0_group { + depth_plus_0.left = depth; + depth_plus_0.right = 32'd0; + } + static<1> group depth_plus_1_group { + depth_plus_1.left = depth; + depth_plus_1.right = 32'd1; + } + static<1> group min_depth_4_plus_1_group { + min_depth_4_plus_1.left = min_depth_4.out; + min_depth_4_plus_1.right = 32'd1; + } + static<1> group depth_plus_6_group { + depth_plus_6.left = depth; + depth_plus_6.right = 32'd6; + } static<1> group t0_idx_init { t0_idx.in = 2'd0; t0_idx.write_en = 1'd1; @@ -68,8 +112,8 @@ component main() -> () { t0_idx.write_en = 1'd1; } static<1> group t0_move { - t0.addr0 = t0_idx.out; - top_0_0.in = t0.read_data; + t0_addr0 = t0_idx.out; + top_0_0.in = t0_read_data; top_0_0.write_en = 1'd1; } static<1> group l0_idx_init { @@ -83,94 +127,122 @@ component main() -> () { l0_idx.write_en = 1'd1; } static<1> group l0_move { - l0.addr0 = l0_idx.out; - left_0_0.in = l0.read_data; + l0_addr0 = l0_idx.out; + left_0_0.in = l0_read_data; left_0_0.write_en = 1'd1; } static<1> group pe_0_0_out_write { - out_mem_0.addr0 = 1'd0; - out_mem_0.write_data = pe_0_0.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd0; + out_mem_0_write_data = pe_0_0.out; + out_mem_0_write_en = 1'd1; } static<1> group init_idx { - idx.in = 4'd0; + idx.in = 32'd0; idx.write_en = 1'd1; } static<1> group incr_idx { idx_add.left = idx.out; - idx_add.right = 4'd1; + idx_add.right = 32'd1; idx.in = idx_add.out; idx.write_en = 1'd1; } - static<1> group idx_between_8_9_group { - index_ge_8.left = idx_add.out; - index_ge_8.right = 4'd8; - index_lt_9.left = idx_add.out; - index_lt_9.right = 4'd9; - idx_between_8_9_comb.left = index_ge_8.out; - idx_between_8_9_comb.right = index_lt_9.out; - idx_between_8_9_reg.in = idx_between_8_9_comb.out; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_8_9 { - idx_between_8_9_reg.in = 1'd0; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group idx_between_0_3_group { - index_lt_3.left = idx_add.out; - index_lt_3.right = 4'd3; - idx_between_0_3_reg.in = index_lt_3.out; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_3 { - idx_between_0_3_reg.in = 1'd1; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group idx_between_1_4_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 4'd1; - index_lt_4.left = idx_add.out; - index_lt_4.right = 4'd4; - idx_between_1_4_comb.left = index_ge_1.out; - idx_between_1_4_comb.right = index_lt_4.out; - idx_between_1_4_reg.in = idx_between_1_4_comb.out; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_4 { - idx_between_1_4_reg.in = 1'd0; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group idx_between_5_8_group { + static<1> group lt_iter_limit_group { + lt_iter_limit.left = idx_add.out; + lt_iter_limit.right = iter_limit.out; + cond_reg.in = lt_iter_limit.out; + cond_reg.write_en = 1'd1; + } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } + static<1> group idx_between_5_depth_plus_5_group { index_ge_5.left = idx_add.out; - index_ge_5.right = 4'd5; - index_lt_8.left = idx_add.out; - index_lt_8.right = 4'd8; - idx_between_5_8_comb.left = index_ge_5.out; - idx_between_5_8_comb.right = index_lt_8.out; - idx_between_5_8_reg.in = idx_between_5_8_comb.out; - idx_between_5_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_8 { - idx_between_5_8_reg.in = 1'd0; - idx_between_5_8_reg.write_en = 1'd1; + index_ge_5.right = 32'd5; + index_lt_depth_plus_5.left = idx_add.out; + index_lt_depth_plus_5.right = depth_plus_5.out; + idx_between_5_depth_plus_5_comb.left = index_ge_5.out; + idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; + idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group init_idx_between_5_depth_plus_5 { + idx_between_5_depth_plus_5_reg.in = 1'd0; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group idx_between_0_depth_plus_0_group { + index_lt_depth_plus_0.left = idx_add.out; + index_lt_depth_plus_0.right = depth_plus_0.out; + idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group init_idx_between_0_depth_plus_0 { + idx_between_0_depth_plus_0_reg.in = 1'd1; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group idx_between_1_depth_plus_1_group { + index_ge_1.left = idx_add.out; + index_ge_1.right = 32'd1; + index_lt_depth_plus_1.left = idx_add.out; + index_lt_depth_plus_1.right = depth_plus_1.out; + idx_between_1_depth_plus_1_comb.left = index_ge_1.out; + idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; + idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_depth_plus_1 { + idx_between_1_depth_plus_1_reg.in = 1'd0; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_1_min_depth_4_plus_1_group { + index_ge_1.left = idx_add.out; + index_ge_1.right = 32'd1; + index_lt_min_depth_4_plus_1.left = idx_add.out; + index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; + idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_min_depth_4_plus_1 { + idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_5_depth_plus_6_group { + index_ge_depth_plus_5.left = idx_add.out; + index_ge_depth_plus_5.right = depth_plus_5.out; + index_lt_depth_plus_6.left = idx_add.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; + idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_5_depth_plus_6 { + idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; } } control { - static seq { + seq { static par { t0_idx_init; l0_idx_init; init_idx; - init_idx_between_8_9; - init_idx_between_0_3; - init_idx_between_1_4; - init_idx_between_5_8; + init_min_depth; + init_iter_limit; + init_cond_reg; + init_idx_between_5_depth_plus_5; + init_idx_between_0_depth_plus_0; + init_idx_between_1_depth_plus_1; + init_idx_between_1_min_depth_4_plus_1; + init_idx_between_depth_plus_5_depth_plus_6; } - static repeat 9 { + while cond_reg.out { static par { static par { static par { - static if idx_between_0_3_reg.out { + static if idx_between_0_depth_plus_0_reg.out { static par { l0_move; l0_idx_update; @@ -178,17 +250,17 @@ component main() -> () { t0_idx_update; } } - static if idx_between_1_4_reg.out { + static if idx_between_1_min_depth_4_plus_1_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); } } - static if idx_between_5_8_reg.out { + static if idx_between_5_depth_plus_5_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); } } - static if idx_between_8_9_reg.out { + static if idx_between_depth_plus_5_depth_plus_6_reg.out { static par { pe_0_0_out_write; } @@ -197,16 +269,37 @@ component main() -> () { } static par { incr_idx; - idx_between_8_9_group; - idx_between_0_3_group; - idx_between_1_4_group; - idx_between_5_8_group; + lt_iter_limit_group; + idx_between_5_depth_plus_5_group; + idx_between_0_depth_plus_0_group; + idx_between_1_depth_plus_1_group; + idx_between_1_min_depth_4_plus_1_group; + idx_between_depth_plus_5_depth_plus_6_group; + depth_plus_5_group; + depth_plus_0_group; + depth_plus_1_group; + min_depth_4_plus_1_group; + depth_plus_6_group; } } } } } } +component main() -> () { + cells { + systolic_array = systolic_array_comp(); + @external t0 = std_mem_d1(32, 3, 2); + @external l0 = std_mem_d1(32, 3, 2); + @external out_mem_0 = std_mem_d1(32, 1, 32); + } + wires { + + } + control { + invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, l0_read_data=l0.read_data)(t0_addr0=t0.addr0, l0_addr0=l0.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en); + } +} metadata #{ -0: pe_0_0 filling: [1,4) accumulating: [5 8) +0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) }# diff --git a/tests/frontend/systolic/array-2.expect b/tests/frontend/systolic/array-2.expect index 60218356a..c8ac3cdca 100644 --- a/tests/frontend/systolic/array-2.expect +++ b/tests/frontend/systolic/array-2.expect @@ -27,8 +27,23 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } } } -component main() -> () { +component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_read_data: 32, l1_read_data: 32) -> (t0_addr0: 2, t1_addr0: 2, l0_addr0: 2, l1_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1, out_mem_1_addr0: 32, out_mem_1_write_data: 32, out_mem_1_write_en: 1) { cells { + min_depth_4 = std_reg(32); + lt_depth_4 = std_lt(32); + iter_limit = std_reg(32); + iter_limit_add = std_add(32); + depth_plus_5 = std_add(32); + depth_plus_2 = std_add(32); + depth_plus_7 = std_add(32); + depth_plus_0 = std_add(32); + min_depth_4_plus_1 = std_add(32); + depth_plus_1 = std_add(32); + depth_plus_6 = std_add(32); + min_depth_4_plus_3 = std_add(32); + depth_plus_3 = std_add(32); + min_depth_4_plus_2 = std_add(32); + depth_plus_8 = std_add(32); pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); @@ -41,60 +56,122 @@ component main() -> () { pe_1_1 = mac_pe(); top_1_1 = std_reg(32); left_1_1 = std_reg(32); - @external t0 = std_mem_d1(32, 3, 2); t0_idx = std_reg(2); t0_add = std_add(2); - @external t1 = std_mem_d1(32, 3, 2); t1_idx = std_reg(2); t1_add = std_add(2); - @external l0 = std_mem_d1(32, 3, 2); l0_idx = std_reg(2); l0_add = std_add(2); - @external l1 = std_mem_d1(32, 3, 2); l1_idx = std_reg(2); l1_add = std_add(2); - @external out_mem_0 = std_mem_d1(32, 2, 2); - @external out_mem_1 = std_mem_d1(32, 2, 2); - idx = std_reg(4); - idx_add = std_add(4); - idx_between_9_10_reg = std_reg(1); - index_lt_10 = std_lt(4); - index_ge_9 = std_ge(4); - idx_between_9_10_comb = std_and(1); - idx_between_10_11_reg = std_reg(1); - index_lt_11 = std_lt(4); - index_ge_10 = std_ge(4); - idx_between_10_11_comb = std_and(1); - idx_between_5_8_reg = std_reg(1); - index_lt_8 = std_lt(4); - index_ge_5 = std_ge(4); - idx_between_5_8_comb = std_and(1); - idx_between_7_10_reg = std_reg(1); - index_ge_7 = std_ge(4); - idx_between_7_10_comb = std_and(1); - idx_between_0_3_reg = std_reg(1); - index_lt_3 = std_lt(4); - idx_between_1_4_reg = std_reg(1); - index_lt_4 = std_lt(4); - index_ge_1 = std_ge(4); - idx_between_1_4_comb = std_and(1); - idx_between_8_9_reg = std_reg(1); - index_lt_9 = std_lt(4); - index_ge_8 = std_ge(4); - idx_between_8_9_comb = std_and(1); - idx_between_3_6_reg = std_reg(1); - index_lt_6 = std_lt(4); - index_ge_3 = std_ge(4); - idx_between_3_6_comb = std_and(1); - idx_between_2_5_reg = std_reg(1); - index_lt_5 = std_lt(4); - index_ge_2 = std_ge(4); - idx_between_2_5_comb = std_and(1); - idx_between_6_9_reg = std_reg(1); - index_ge_6 = std_ge(4); - idx_between_6_9_comb = std_and(1); + idx = std_reg(32); + idx_add = std_add(32); + lt_iter_limit = std_lt(32); + cond_reg = std_reg(1); + idx_between_5_depth_plus_5_reg = std_reg(1); + index_lt_depth_plus_5 = std_lt(32); + index_ge_5 = std_ge(32); + idx_between_5_depth_plus_5_comb = std_and(1); + idx_between_2_depth_plus_2_reg = std_reg(1); + index_lt_depth_plus_2 = std_lt(32); + index_ge_2 = std_ge(32); + idx_between_2_depth_plus_2_comb = std_and(1); + idx_between_7_depth_plus_7_reg = std_reg(1); + index_lt_depth_plus_7 = std_lt(32); + index_ge_7 = std_ge(32); + idx_between_7_depth_plus_7_comb = std_and(1); + idx_between_0_depth_plus_0_reg = std_reg(1); + index_lt_depth_plus_0 = std_lt(32); + idx_between_1_min_depth_4_plus_1_reg = std_reg(1); + index_lt_min_depth_4_plus_1 = std_lt(32); + index_ge_1 = std_ge(32); + idx_between_1_min_depth_4_plus_1_comb = std_and(1); + idx_between_1_depth_plus_1_reg = std_reg(1); + index_lt_depth_plus_1 = std_lt(32); + idx_between_1_depth_plus_1_comb = std_and(1); + idx_between_depth_plus_6_depth_plus_7_reg = std_reg(1); + index_ge_depth_plus_6 = std_ge(32); + idx_between_depth_plus_6_depth_plus_7_comb = std_and(1); + idx_between_3_min_depth_4_plus_3_reg = std_reg(1); + index_lt_min_depth_4_plus_3 = std_lt(32); + index_ge_3 = std_ge(32); + idx_between_3_min_depth_4_plus_3_comb = std_and(1); + idx_between_3_depth_plus_3_reg = std_reg(1); + index_lt_depth_plus_3 = std_lt(32); + idx_between_3_depth_plus_3_comb = std_and(1); + idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); + index_lt_depth_plus_6 = std_lt(32); + index_ge_depth_plus_5 = std_ge(32); + idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); + idx_between_2_min_depth_4_plus_2_reg = std_reg(1); + index_lt_min_depth_4_plus_2 = std_lt(32); + idx_between_2_min_depth_4_plus_2_comb = std_and(1); + idx_between_6_depth_plus_6_reg = std_reg(1); + index_ge_6 = std_ge(32); + idx_between_6_depth_plus_6_comb = std_and(1); + idx_between_depth_plus_7_depth_plus_8_reg = std_reg(1); + index_lt_depth_plus_8 = std_lt(32); + index_ge_depth_plus_7 = std_ge(32); + idx_between_depth_plus_7_depth_plus_8_comb = std_and(1); } wires { + static<1> group init_min_depth { + lt_depth_4.left = depth; + lt_depth_4.right = 32'd4; + min_depth_4.in = lt_depth_4.out ? depth; + min_depth_4.in = !lt_depth_4.out ? 32'd4; + min_depth_4.write_en = 1'd1; + } + static<1> group init_iter_limit { + iter_limit_add.left = 32'd8; + iter_limit_add.right = depth; + iter_limit.in = iter_limit_add.out; + iter_limit.write_en = 1'd1; + } + static<1> group depth_plus_5_group { + depth_plus_5.left = depth; + depth_plus_5.right = 32'd5; + } + static<1> group depth_plus_2_group { + depth_plus_2.left = depth; + depth_plus_2.right = 32'd2; + } + static<1> group depth_plus_7_group { + depth_plus_7.left = depth; + depth_plus_7.right = 32'd7; + } + static<1> group depth_plus_0_group { + depth_plus_0.left = depth; + depth_plus_0.right = 32'd0; + } + static<1> group min_depth_4_plus_1_group { + min_depth_4_plus_1.left = min_depth_4.out; + min_depth_4_plus_1.right = 32'd1; + } + static<1> group depth_plus_1_group { + depth_plus_1.left = depth; + depth_plus_1.right = 32'd1; + } + static<1> group depth_plus_6_group { + depth_plus_6.left = depth; + depth_plus_6.right = 32'd6; + } + static<1> group min_depth_4_plus_3_group { + min_depth_4_plus_3.left = min_depth_4.out; + min_depth_4_plus_3.right = 32'd3; + } + static<1> group depth_plus_3_group { + depth_plus_3.left = depth; + depth_plus_3.right = 32'd3; + } + static<1> group min_depth_4_plus_2_group { + min_depth_4_plus_2.left = min_depth_4.out; + min_depth_4_plus_2.right = 32'd2; + } + static<1> group depth_plus_8_group { + depth_plus_8.left = depth; + depth_plus_8.right = 32'd8; + } static<1> group t0_idx_init { t0_idx.in = 2'd0; t0_idx.write_en = 1'd1; @@ -106,8 +183,8 @@ component main() -> () { t0_idx.write_en = 1'd1; } static<1> group t0_move { - t0.addr0 = t0_idx.out; - top_0_0.in = t0.read_data; + t0_addr0 = t0_idx.out; + top_0_0.in = t0_read_data; top_0_0.write_en = 1'd1; } static<1> group t1_idx_init { @@ -121,8 +198,8 @@ component main() -> () { t1_idx.write_en = 1'd1; } static<1> group t1_move { - t1.addr0 = t1_idx.out; - top_0_1.in = t1.read_data; + t1_addr0 = t1_idx.out; + top_0_1.in = t1_read_data; top_0_1.write_en = 1'd1; } static<1> group l0_idx_init { @@ -136,8 +213,8 @@ component main() -> () { l0_idx.write_en = 1'd1; } static<1> group l0_move { - l0.addr0 = l0_idx.out; - left_0_0.in = l0.read_data; + l0_addr0 = l0_idx.out; + left_0_0.in = l0_read_data; left_0_0.write_en = 1'd1; } static<1> group l1_idx_init { @@ -151,8 +228,8 @@ component main() -> () { l1_idx.write_en = 1'd1; } static<1> group l1_move { - l1.addr0 = l1_idx.out; - left_1_0.in = l1.read_data; + l1_addr0 = l1_idx.out; + left_1_0.in = l1_read_data; left_1_0.write_en = 1'd1; } static<1> group pe_0_0_right_move { @@ -164,204 +241,262 @@ component main() -> () { top_1_0.write_en = 1'd1; } static<1> group pe_0_0_out_write { - out_mem_0.addr0 = 2'd0; - out_mem_0.write_data = pe_0_0.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd0; + out_mem_0_write_data = pe_0_0.out; + out_mem_0_write_en = 1'd1; } static<1> group pe_0_1_down_move { top_1_1.in = top_0_1.out; top_1_1.write_en = 1'd1; } static<1> group pe_0_1_out_write { - out_mem_0.addr0 = 2'd1; - out_mem_0.write_data = pe_0_1.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd1; + out_mem_0_write_data = pe_0_1.out; + out_mem_0_write_en = 1'd1; } static<1> group pe_1_0_right_move { left_1_1.in = left_1_0.out; left_1_1.write_en = 1'd1; } static<1> group pe_1_0_out_write { - out_mem_1.addr0 = 2'd0; - out_mem_1.write_data = pe_1_0.out; - out_mem_1.write_en = 1'd1; + out_mem_1_addr0 = 32'd0; + out_mem_1_write_data = pe_1_0.out; + out_mem_1_write_en = 1'd1; } static<1> group pe_1_1_out_write { - out_mem_1.addr0 = 2'd1; - out_mem_1.write_data = pe_1_1.out; - out_mem_1.write_en = 1'd1; + out_mem_1_addr0 = 32'd1; + out_mem_1_write_data = pe_1_1.out; + out_mem_1_write_en = 1'd1; } static<1> group init_idx { - idx.in = 4'd0; + idx.in = 32'd0; idx.write_en = 1'd1; } static<1> group incr_idx { idx_add.left = idx.out; - idx_add.right = 4'd1; + idx_add.right = 32'd1; idx.in = idx_add.out; idx.write_en = 1'd1; } - static<1> group idx_between_9_10_group { - index_ge_9.left = idx_add.out; - index_ge_9.right = 4'd9; - index_lt_10.left = idx_add.out; - index_lt_10.right = 4'd10; - idx_between_9_10_comb.left = index_ge_9.out; - idx_between_9_10_comb.right = index_lt_10.out; - idx_between_9_10_reg.in = idx_between_9_10_comb.out; - idx_between_9_10_reg.write_en = 1'd1; - } - static<1> group init_idx_between_9_10 { - idx_between_9_10_reg.in = 1'd0; - idx_between_9_10_reg.write_en = 1'd1; - } - static<1> group idx_between_10_11_group { - index_ge_10.left = idx_add.out; - index_ge_10.right = 4'd10; - index_lt_11.left = idx_add.out; - index_lt_11.right = 4'd11; - idx_between_10_11_comb.left = index_ge_10.out; - idx_between_10_11_comb.right = index_lt_11.out; - idx_between_10_11_reg.in = idx_between_10_11_comb.out; - idx_between_10_11_reg.write_en = 1'd1; - } - static<1> group init_idx_between_10_11 { - idx_between_10_11_reg.in = 1'd0; - idx_between_10_11_reg.write_en = 1'd1; - } - static<1> group idx_between_5_8_group { + static<1> group lt_iter_limit_group { + lt_iter_limit.left = idx_add.out; + lt_iter_limit.right = iter_limit.out; + cond_reg.in = lt_iter_limit.out; + cond_reg.write_en = 1'd1; + } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } + static<1> group idx_between_5_depth_plus_5_group { index_ge_5.left = idx_add.out; - index_ge_5.right = 4'd5; - index_lt_8.left = idx_add.out; - index_lt_8.right = 4'd8; - idx_between_5_8_comb.left = index_ge_5.out; - idx_between_5_8_comb.right = index_lt_8.out; - idx_between_5_8_reg.in = idx_between_5_8_comb.out; - idx_between_5_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_8 { - idx_between_5_8_reg.in = 1'd0; - idx_between_5_8_reg.write_en = 1'd1; - } - static<1> group idx_between_7_10_group { + index_ge_5.right = 32'd5; + index_lt_depth_plus_5.left = idx_add.out; + index_lt_depth_plus_5.right = depth_plus_5.out; + idx_between_5_depth_plus_5_comb.left = index_ge_5.out; + idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; + idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group init_idx_between_5_depth_plus_5 { + idx_between_5_depth_plus_5_reg.in = 1'd0; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group idx_between_2_depth_plus_2_group { + index_ge_2.left = idx_add.out; + index_ge_2.right = 32'd2; + index_lt_depth_plus_2.left = idx_add.out; + index_lt_depth_plus_2.right = depth_plus_2.out; + idx_between_2_depth_plus_2_comb.left = index_ge_2.out; + idx_between_2_depth_plus_2_comb.right = index_lt_depth_plus_2.out; + idx_between_2_depth_plus_2_reg.in = idx_between_2_depth_plus_2_comb.out; + idx_between_2_depth_plus_2_reg.write_en = 1'd1; + } + static<1> group init_idx_between_2_depth_plus_2 { + idx_between_2_depth_plus_2_reg.in = 1'd0; + idx_between_2_depth_plus_2_reg.write_en = 1'd1; + } + static<1> group idx_between_7_depth_plus_7_group { index_ge_7.left = idx_add.out; - index_ge_7.right = 4'd7; - index_lt_10.left = idx_add.out; - index_lt_10.right = 4'd10; - idx_between_7_10_comb.left = index_ge_7.out; - idx_between_7_10_comb.right = index_lt_10.out; - idx_between_7_10_reg.in = idx_between_7_10_comb.out; - idx_between_7_10_reg.write_en = 1'd1; - } - static<1> group init_idx_between_7_10 { - idx_between_7_10_reg.in = 1'd0; - idx_between_7_10_reg.write_en = 1'd1; - } - static<1> group idx_between_0_3_group { - index_lt_3.left = idx_add.out; - index_lt_3.right = 4'd3; - idx_between_0_3_reg.in = index_lt_3.out; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_3 { - idx_between_0_3_reg.in = 1'd1; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group idx_between_1_4_group { + index_ge_7.right = 32'd7; + index_lt_depth_plus_7.left = idx_add.out; + index_lt_depth_plus_7.right = depth_plus_7.out; + idx_between_7_depth_plus_7_comb.left = index_ge_7.out; + idx_between_7_depth_plus_7_comb.right = index_lt_depth_plus_7.out; + idx_between_7_depth_plus_7_reg.in = idx_between_7_depth_plus_7_comb.out; + idx_between_7_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group init_idx_between_7_depth_plus_7 { + idx_between_7_depth_plus_7_reg.in = 1'd0; + idx_between_7_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group idx_between_0_depth_plus_0_group { + index_lt_depth_plus_0.left = idx_add.out; + index_lt_depth_plus_0.right = depth_plus_0.out; + idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group init_idx_between_0_depth_plus_0 { + idx_between_0_depth_plus_0_reg.in = 1'd1; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group idx_between_1_min_depth_4_plus_1_group { index_ge_1.left = idx_add.out; - index_ge_1.right = 4'd1; - index_lt_4.left = idx_add.out; - index_lt_4.right = 4'd4; - idx_between_1_4_comb.left = index_ge_1.out; - idx_between_1_4_comb.right = index_lt_4.out; - idx_between_1_4_reg.in = idx_between_1_4_comb.out; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_4 { - idx_between_1_4_reg.in = 1'd0; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group idx_between_8_9_group { - index_ge_8.left = idx_add.out; - index_ge_8.right = 4'd8; - index_lt_9.left = idx_add.out; - index_lt_9.right = 4'd9; - idx_between_8_9_comb.left = index_ge_8.out; - idx_between_8_9_comb.right = index_lt_9.out; - idx_between_8_9_reg.in = idx_between_8_9_comb.out; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_8_9 { - idx_between_8_9_reg.in = 1'd0; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group idx_between_3_6_group { + index_ge_1.right = 32'd1; + index_lt_min_depth_4_plus_1.left = idx_add.out; + index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; + idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_min_depth_4_plus_1 { + idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_1_depth_plus_1_group { + index_ge_1.left = idx_add.out; + index_ge_1.right = 32'd1; + index_lt_depth_plus_1.left = idx_add.out; + index_lt_depth_plus_1.right = depth_plus_1.out; + idx_between_1_depth_plus_1_comb.left = index_ge_1.out; + idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; + idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_depth_plus_1 { + idx_between_1_depth_plus_1_reg.in = 1'd0; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_6_depth_plus_7_group { + index_ge_depth_plus_6.left = idx_add.out; + index_ge_depth_plus_6.right = depth_plus_6.out; + index_lt_depth_plus_7.left = idx_add.out; + index_lt_depth_plus_7.right = depth_plus_7.out; + idx_between_depth_plus_6_depth_plus_7_comb.left = index_ge_depth_plus_6.out; + idx_between_depth_plus_6_depth_plus_7_comb.right = index_lt_depth_plus_7.out; + idx_between_depth_plus_6_depth_plus_7_reg.in = idx_between_depth_plus_6_depth_plus_7_comb.out; + idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_6_depth_plus_7 { + idx_between_depth_plus_6_depth_plus_7_reg.in = 1'd0; + idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group idx_between_3_min_depth_4_plus_3_group { + index_ge_3.left = idx_add.out; + index_ge_3.right = 32'd3; + index_lt_min_depth_4_plus_3.left = idx_add.out; + index_lt_min_depth_4_plus_3.right = min_depth_4_plus_3.out; + idx_between_3_min_depth_4_plus_3_comb.left = index_ge_3.out; + idx_between_3_min_depth_4_plus_3_comb.right = index_lt_min_depth_4_plus_3.out; + idx_between_3_min_depth_4_plus_3_reg.in = idx_between_3_min_depth_4_plus_3_comb.out; + idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; + } + static<1> group init_idx_between_3_min_depth_4_plus_3 { + idx_between_3_min_depth_4_plus_3_reg.in = 1'd0; + idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; + } + static<1> group idx_between_3_depth_plus_3_group { index_ge_3.left = idx_add.out; - index_ge_3.right = 4'd3; - index_lt_6.left = idx_add.out; - index_lt_6.right = 4'd6; - idx_between_3_6_comb.left = index_ge_3.out; - idx_between_3_6_comb.right = index_lt_6.out; - idx_between_3_6_reg.in = idx_between_3_6_comb.out; - idx_between_3_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_6 { - idx_between_3_6_reg.in = 1'd0; - idx_between_3_6_reg.write_en = 1'd1; - } - static<1> group idx_between_2_5_group { + index_ge_3.right = 32'd3; + index_lt_depth_plus_3.left = idx_add.out; + index_lt_depth_plus_3.right = depth_plus_3.out; + idx_between_3_depth_plus_3_comb.left = index_ge_3.out; + idx_between_3_depth_plus_3_comb.right = index_lt_depth_plus_3.out; + idx_between_3_depth_plus_3_reg.in = idx_between_3_depth_plus_3_comb.out; + idx_between_3_depth_plus_3_reg.write_en = 1'd1; + } + static<1> group init_idx_between_3_depth_plus_3 { + idx_between_3_depth_plus_3_reg.in = 1'd0; + idx_between_3_depth_plus_3_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_5_depth_plus_6_group { + index_ge_depth_plus_5.left = idx_add.out; + index_ge_depth_plus_5.right = depth_plus_5.out; + index_lt_depth_plus_6.left = idx_add.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; + idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_5_depth_plus_6 { + idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group idx_between_2_min_depth_4_plus_2_group { index_ge_2.left = idx_add.out; - index_ge_2.right = 4'd2; - index_lt_5.left = idx_add.out; - index_lt_5.right = 4'd5; - idx_between_2_5_comb.left = index_ge_2.out; - idx_between_2_5_comb.right = index_lt_5.out; - idx_between_2_5_reg.in = idx_between_2_5_comb.out; - idx_between_2_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_5 { - idx_between_2_5_reg.in = 1'd0; - idx_between_2_5_reg.write_en = 1'd1; - } - static<1> group idx_between_6_9_group { + index_ge_2.right = 32'd2; + index_lt_min_depth_4_plus_2.left = idx_add.out; + index_lt_min_depth_4_plus_2.right = min_depth_4_plus_2.out; + idx_between_2_min_depth_4_plus_2_comb.left = index_ge_2.out; + idx_between_2_min_depth_4_plus_2_comb.right = index_lt_min_depth_4_plus_2.out; + idx_between_2_min_depth_4_plus_2_reg.in = idx_between_2_min_depth_4_plus_2_comb.out; + idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; + } + static<1> group init_idx_between_2_min_depth_4_plus_2 { + idx_between_2_min_depth_4_plus_2_reg.in = 1'd0; + idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; + } + static<1> group idx_between_6_depth_plus_6_group { index_ge_6.left = idx_add.out; - index_ge_6.right = 4'd6; - index_lt_9.left = idx_add.out; - index_lt_9.right = 4'd9; - idx_between_6_9_comb.left = index_ge_6.out; - idx_between_6_9_comb.right = index_lt_9.out; - idx_between_6_9_reg.in = idx_between_6_9_comb.out; - idx_between_6_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_6_9 { - idx_between_6_9_reg.in = 1'd0; - idx_between_6_9_reg.write_en = 1'd1; + index_ge_6.right = 32'd6; + index_lt_depth_plus_6.left = idx_add.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_6_depth_plus_6_comb.left = index_ge_6.out; + idx_between_6_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_6_depth_plus_6_reg.in = idx_between_6_depth_plus_6_comb.out; + idx_between_6_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group init_idx_between_6_depth_plus_6 { + idx_between_6_depth_plus_6_reg.in = 1'd0; + idx_between_6_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_7_depth_plus_8_group { + index_ge_depth_plus_7.left = idx_add.out; + index_ge_depth_plus_7.right = depth_plus_7.out; + index_lt_depth_plus_8.left = idx_add.out; + index_lt_depth_plus_8.right = depth_plus_8.out; + idx_between_depth_plus_7_depth_plus_8_comb.left = index_ge_depth_plus_7.out; + idx_between_depth_plus_7_depth_plus_8_comb.right = index_lt_depth_plus_8.out; + idx_between_depth_plus_7_depth_plus_8_reg.in = idx_between_depth_plus_7_depth_plus_8_comb.out; + idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_7_depth_plus_8 { + idx_between_depth_plus_7_depth_plus_8_reg.in = 1'd0; + idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; } } control { - static seq { + seq { static par { t0_idx_init; t1_idx_init; l0_idx_init; l1_idx_init; init_idx; - init_idx_between_9_10; - init_idx_between_10_11; - init_idx_between_5_8; - init_idx_between_7_10; - init_idx_between_0_3; - init_idx_between_1_4; - init_idx_between_8_9; - init_idx_between_3_6; - init_idx_between_2_5; - init_idx_between_6_9; + init_min_depth; + init_iter_limit; + init_cond_reg; + init_idx_between_5_depth_plus_5; + init_idx_between_2_depth_plus_2; + init_idx_between_7_depth_plus_7; + init_idx_between_0_depth_plus_0; + init_idx_between_1_min_depth_4_plus_1; + init_idx_between_1_depth_plus_1; + init_idx_between_depth_plus_6_depth_plus_7; + init_idx_between_3_min_depth_4_plus_3; + init_idx_between_3_depth_plus_3; + init_idx_between_depth_plus_5_depth_plus_6; + init_idx_between_2_min_depth_4_plus_2; + init_idx_between_6_depth_plus_6; + init_idx_between_depth_plus_7_depth_plus_8; } - static repeat 11 { + while cond_reg.out { static par { static par { static par { - static if idx_between_0_3_reg.out { + static if idx_between_0_depth_plus_0_reg.out { static par { l0_move; l0_idx_update; @@ -369,96 +504,96 @@ component main() -> () { t0_idx_update; } } - static if idx_between_1_4_reg.out { + static if idx_between_1_min_depth_4_plus_1_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); } } - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { pe_0_0_down_move; pe_0_0_right_move; } } - static if idx_between_5_8_reg.out { + static if idx_between_5_depth_plus_5_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); } } - static if idx_between_8_9_reg.out { + static if idx_between_depth_plus_5_depth_plus_6_reg.out { static par { pe_0_0_out_write; } } } static par { - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { t1_move; t1_idx_update; } } - static if idx_between_2_5_reg.out { + static if idx_between_2_min_depth_4_plus_2_reg.out { static par { static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd0)(); } } - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { pe_0_1_down_move; } } - static if idx_between_6_9_reg.out { + static if idx_between_6_depth_plus_6_reg.out { static par { static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd1)(); } } - static if idx_between_9_10_reg.out { + static if idx_between_depth_plus_6_depth_plus_7_reg.out { static par { pe_0_1_out_write; } } } static par { - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { l1_move; l1_idx_update; } } - static if idx_between_2_5_reg.out { + static if idx_between_2_min_depth_4_plus_2_reg.out { static par { static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd0)(); } } - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { pe_1_0_right_move; } } - static if idx_between_6_9_reg.out { + static if idx_between_6_depth_plus_6_reg.out { static par { static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd1)(); } } - static if idx_between_9_10_reg.out { + static if idx_between_depth_plus_6_depth_plus_7_reg.out { static par { pe_1_0_out_write; } } } static par { - static if idx_between_3_6_reg.out { + static if idx_between_3_min_depth_4_plus_3_reg.out { static par { static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd0)(); } } - static if idx_between_7_10_reg.out { + static if idx_between_7_depth_plus_7_reg.out { static par { static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd1)(); } } - static if idx_between_10_11_reg.out { + static if idx_between_depth_plus_7_depth_plus_8_reg.out { static par { pe_1_1_out_write; } @@ -467,25 +602,57 @@ component main() -> () { } static par { incr_idx; - idx_between_9_10_group; - idx_between_10_11_group; - idx_between_5_8_group; - idx_between_7_10_group; - idx_between_0_3_group; - idx_between_1_4_group; - idx_between_8_9_group; - idx_between_3_6_group; - idx_between_2_5_group; - idx_between_6_9_group; + lt_iter_limit_group; + idx_between_5_depth_plus_5_group; + idx_between_2_depth_plus_2_group; + idx_between_7_depth_plus_7_group; + idx_between_0_depth_plus_0_group; + idx_between_1_min_depth_4_plus_1_group; + idx_between_1_depth_plus_1_group; + idx_between_depth_plus_6_depth_plus_7_group; + idx_between_3_min_depth_4_plus_3_group; + idx_between_3_depth_plus_3_group; + idx_between_depth_plus_5_depth_plus_6_group; + idx_between_2_min_depth_4_plus_2_group; + idx_between_6_depth_plus_6_group; + idx_between_depth_plus_7_depth_plus_8_group; + depth_plus_5_group; + depth_plus_2_group; + depth_plus_7_group; + depth_plus_0_group; + min_depth_4_plus_1_group; + depth_plus_1_group; + depth_plus_6_group; + min_depth_4_plus_3_group; + depth_plus_3_group; + min_depth_4_plus_2_group; + depth_plus_8_group; } } } } } } +component main() -> () { + cells { + systolic_array = systolic_array_comp(); + @external t0 = std_mem_d1(32, 3, 2); + @external t1 = std_mem_d1(32, 3, 2); + @external l0 = std_mem_d1(32, 3, 2); + @external l1 = std_mem_d1(32, 3, 2); + @external out_mem_0 = std_mem_d1(32, 2, 32); + @external out_mem_1 = std_mem_d1(32, 2, 32); + } + wires { + + } + control { + invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, t1_read_data=t1.read_data, l0_read_data=l0.read_data, l1_read_data=l1.read_data)(t0_addr0=t0.addr0, t1_addr0=t1.addr0, l0_addr0=l0.addr0, l1_addr0=l1.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en, out_mem_1_addr0=out_mem_1.addr0, out_mem_1_write_data=out_mem_1.write_data, out_mem_1_write_en=out_mem_1.write_en); + } +} metadata #{ -0: pe_0_0 filling: [1,4) accumulating: [5 8) -1: pe_0_1 filling: [2,5) accumulating: [6 9) -2: pe_1_0 filling: [2,5) accumulating: [6 9) -3: pe_1_1 filling: [3,6) accumulating: [7 10) +0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) +1: pe_0_1 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) +2: pe_1_0 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) +3: pe_1_1 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) }# diff --git a/tests/frontend/systolic/array-3.expect b/tests/frontend/systolic/array-3.expect index 8f08efe89..7d0fa872e 100644 --- a/tests/frontend/systolic/array-3.expect +++ b/tests/frontend/systolic/array-3.expect @@ -27,8 +27,28 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } } } -component main() -> () { +component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_read_data: 32, l0_read_data: 32, l1_read_data: 32, l2_read_data: 32) -> (t0_addr0: 2, t1_addr0: 2, t2_addr0: 2, l0_addr0: 2, l1_addr0: 2, l2_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1, out_mem_1_addr0: 32, out_mem_1_write_data: 32, out_mem_1_write_en: 1, out_mem_2_addr0: 32, out_mem_2_write_data: 32, out_mem_2_write_en: 1) { cells { + min_depth_4 = std_reg(32); + lt_depth_4 = std_lt(32); + iter_limit = std_reg(32); + iter_limit_add = std_add(32); + depth_plus_8 = std_add(32); + depth_plus_9 = std_add(32); + min_depth_4_plus_2 = std_add(32); + depth_plus_2 = std_add(32); + depth_plus_7 = std_add(32); + depth_plus_3 = std_add(32); + min_depth_4_plus_3 = std_add(32); + depth_plus_5 = std_add(32); + depth_plus_6 = std_add(32); + depth_plus_10 = std_add(32); + depth_plus_4 = std_add(32); + min_depth_4_plus_4 = std_add(32); + min_depth_4_plus_5 = std_add(32); + depth_plus_0 = std_add(32); + depth_plus_1 = std_add(32); + min_depth_4_plus_1 = std_add(32); pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); @@ -56,83 +76,170 @@ component main() -> () { pe_2_2 = mac_pe(); top_2_2 = std_reg(32); left_2_2 = std_reg(32); - @external t0 = std_mem_d1(32, 3, 2); t0_idx = std_reg(2); t0_add = std_add(2); - @external t1 = std_mem_d1(32, 3, 2); t1_idx = std_reg(2); t1_add = std_add(2); - @external t2 = std_mem_d1(32, 3, 2); t2_idx = std_reg(2); t2_add = std_add(2); - @external l0 = std_mem_d1(32, 3, 2); l0_idx = std_reg(2); l0_add = std_add(2); - @external l1 = std_mem_d1(32, 3, 2); l1_idx = std_reg(2); l1_add = std_add(2); - @external l2 = std_mem_d1(32, 3, 2); l2_idx = std_reg(2); l2_add = std_add(2); - @external out_mem_0 = std_mem_d1(32, 3, 2); - @external out_mem_1 = std_mem_d1(32, 3, 2); - @external out_mem_2 = std_mem_d1(32, 3, 2); - idx = std_reg(4); - idx_add = std_add(4); - idx_between_9_10_reg = std_reg(1); - index_lt_10 = std_lt(4); - index_ge_9 = std_ge(4); - idx_between_9_10_comb = std_and(1); - idx_between_10_11_reg = std_reg(1); - index_lt_11 = std_lt(4); - index_ge_10 = std_ge(4); - idx_between_10_11_comb = std_and(1); - idx_between_5_8_reg = std_reg(1); - index_lt_8 = std_lt(4); - index_ge_5 = std_ge(4); - idx_between_5_8_comb = std_and(1); - idx_between_7_10_reg = std_reg(1); - index_ge_7 = std_ge(4); - idx_between_7_10_comb = std_and(1); - idx_between_0_3_reg = std_reg(1); - index_lt_3 = std_lt(4); - idx_between_9_12_reg = std_reg(1); - index_lt_12 = std_lt(4); - idx_between_9_12_comb = std_and(1); - idx_between_12_13_reg = std_reg(1); - index_lt_13 = std_lt(4); - index_ge_12 = std_ge(4); - idx_between_12_13_comb = std_and(1); - idx_between_1_4_reg = std_reg(1); - index_lt_4 = std_lt(4); - index_ge_1 = std_ge(4); - idx_between_1_4_comb = std_and(1); - idx_between_11_12_reg = std_reg(1); - index_ge_11 = std_ge(4); - idx_between_11_12_comb = std_and(1); - idx_between_8_9_reg = std_reg(1); - index_lt_9 = std_lt(4); - index_ge_8 = std_ge(4); - idx_between_8_9_comb = std_and(1); - idx_between_3_6_reg = std_reg(1); - index_lt_6 = std_lt(4); - index_ge_3 = std_ge(4); - idx_between_3_6_comb = std_and(1); - idx_between_2_5_reg = std_reg(1); - index_lt_5 = std_lt(4); - index_ge_2 = std_ge(4); - idx_between_2_5_comb = std_and(1); - idx_between_6_9_reg = std_reg(1); - index_ge_6 = std_ge(4); - idx_between_6_9_comb = std_and(1); - idx_between_4_7_reg = std_reg(1); - index_lt_7 = std_lt(4); - index_ge_4 = std_ge(4); - idx_between_4_7_comb = std_and(1); - idx_between_8_11_reg = std_reg(1); - idx_between_8_11_comb = std_and(1); + idx = std_reg(32); + idx_add = std_add(32); + lt_iter_limit = std_lt(32); + cond_reg = std_reg(1); + idx_between_depth_plus_8_depth_plus_9_reg = std_reg(1); + index_lt_depth_plus_9 = std_lt(32); + index_ge_depth_plus_8 = std_ge(32); + idx_between_depth_plus_8_depth_plus_9_comb = std_and(1); + idx_between_2_min_depth_4_plus_2_reg = std_reg(1); + index_lt_min_depth_4_plus_2 = std_lt(32); + index_ge_2 = std_ge(32); + idx_between_2_min_depth_4_plus_2_comb = std_and(1); + idx_between_2_depth_plus_2_reg = std_reg(1); + index_lt_depth_plus_2 = std_lt(32); + idx_between_2_depth_plus_2_comb = std_and(1); + idx_between_7_depth_plus_7_reg = std_reg(1); + index_lt_depth_plus_7 = std_lt(32); + index_ge_7 = std_ge(32); + idx_between_7_depth_plus_7_comb = std_and(1); + idx_between_3_depth_plus_3_reg = std_reg(1); + index_lt_depth_plus_3 = std_lt(32); + index_ge_3 = std_ge(32); + idx_between_3_depth_plus_3_comb = std_and(1); + idx_between_3_min_depth_4_plus_3_reg = std_reg(1); + index_lt_min_depth_4_plus_3 = std_lt(32); + idx_between_3_min_depth_4_plus_3_comb = std_and(1); + idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); + index_lt_depth_plus_6 = std_lt(32); + index_ge_depth_plus_5 = std_ge(32); + idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); + idx_between_depth_plus_9_depth_plus_10_reg = std_reg(1); + index_lt_depth_plus_10 = std_lt(32); + index_ge_depth_plus_9 = std_ge(32); + idx_between_depth_plus_9_depth_plus_10_comb = std_and(1); + idx_between_8_depth_plus_8_reg = std_reg(1); + index_lt_depth_plus_8 = std_lt(32); + index_ge_8 = std_ge(32); + idx_between_8_depth_plus_8_comb = std_and(1); + idx_between_depth_plus_6_depth_plus_7_reg = std_reg(1); + index_ge_depth_plus_6 = std_ge(32); + idx_between_depth_plus_6_depth_plus_7_comb = std_and(1); + idx_between_4_depth_plus_4_reg = std_reg(1); + index_lt_depth_plus_4 = std_lt(32); + index_ge_4 = std_ge(32); + idx_between_4_depth_plus_4_comb = std_and(1); + idx_between_4_min_depth_4_plus_4_reg = std_reg(1); + index_lt_min_depth_4_plus_4 = std_lt(32); + idx_between_4_min_depth_4_plus_4_comb = std_and(1); + idx_between_5_min_depth_4_plus_5_reg = std_reg(1); + index_lt_min_depth_4_plus_5 = std_lt(32); + index_ge_5 = std_ge(32); + idx_between_5_min_depth_4_plus_5_comb = std_and(1); + idx_between_5_depth_plus_5_reg = std_reg(1); + index_lt_depth_plus_5 = std_lt(32); + idx_between_5_depth_plus_5_comb = std_and(1); + idx_between_0_depth_plus_0_reg = std_reg(1); + index_lt_depth_plus_0 = std_lt(32); + idx_between_9_depth_plus_9_reg = std_reg(1); + index_ge_9 = std_ge(32); + idx_between_9_depth_plus_9_comb = std_and(1); + idx_between_1_depth_plus_1_reg = std_reg(1); + index_lt_depth_plus_1 = std_lt(32); + index_ge_1 = std_ge(32); + idx_between_1_depth_plus_1_comb = std_and(1); + idx_between_1_min_depth_4_plus_1_reg = std_reg(1); + index_lt_min_depth_4_plus_1 = std_lt(32); + idx_between_1_min_depth_4_plus_1_comb = std_and(1); + idx_between_6_depth_plus_6_reg = std_reg(1); + index_ge_6 = std_ge(32); + idx_between_6_depth_plus_6_comb = std_and(1); + idx_between_depth_plus_7_depth_plus_8_reg = std_reg(1); + index_ge_depth_plus_7 = std_ge(32); + idx_between_depth_plus_7_depth_plus_8_comb = std_and(1); } wires { + static<1> group init_min_depth { + lt_depth_4.left = depth; + lt_depth_4.right = 32'd4; + min_depth_4.in = lt_depth_4.out ? depth; + min_depth_4.in = !lt_depth_4.out ? 32'd4; + min_depth_4.write_en = 1'd1; + } + static<1> group init_iter_limit { + iter_limit_add.left = 32'd10; + iter_limit_add.right = depth; + iter_limit.in = iter_limit_add.out; + iter_limit.write_en = 1'd1; + } + static<1> group depth_plus_8_group { + depth_plus_8.left = depth; + depth_plus_8.right = 32'd8; + } + static<1> group depth_plus_9_group { + depth_plus_9.left = depth; + depth_plus_9.right = 32'd9; + } + static<1> group min_depth_4_plus_2_group { + min_depth_4_plus_2.left = min_depth_4.out; + min_depth_4_plus_2.right = 32'd2; + } + static<1> group depth_plus_2_group { + depth_plus_2.left = depth; + depth_plus_2.right = 32'd2; + } + static<1> group depth_plus_7_group { + depth_plus_7.left = depth; + depth_plus_7.right = 32'd7; + } + static<1> group depth_plus_3_group { + depth_plus_3.left = depth; + depth_plus_3.right = 32'd3; + } + static<1> group min_depth_4_plus_3_group { + min_depth_4_plus_3.left = min_depth_4.out; + min_depth_4_plus_3.right = 32'd3; + } + static<1> group depth_plus_5_group { + depth_plus_5.left = depth; + depth_plus_5.right = 32'd5; + } + static<1> group depth_plus_6_group { + depth_plus_6.left = depth; + depth_plus_6.right = 32'd6; + } + static<1> group depth_plus_10_group { + depth_plus_10.left = depth; + depth_plus_10.right = 32'd10; + } + static<1> group depth_plus_4_group { + depth_plus_4.left = depth; + depth_plus_4.right = 32'd4; + } + static<1> group min_depth_4_plus_4_group { + min_depth_4_plus_4.left = min_depth_4.out; + min_depth_4_plus_4.right = 32'd4; + } + static<1> group min_depth_4_plus_5_group { + min_depth_4_plus_5.left = min_depth_4.out; + min_depth_4_plus_5.right = 32'd5; + } + static<1> group depth_plus_0_group { + depth_plus_0.left = depth; + depth_plus_0.right = 32'd0; + } + static<1> group depth_plus_1_group { + depth_plus_1.left = depth; + depth_plus_1.right = 32'd1; + } + static<1> group min_depth_4_plus_1_group { + min_depth_4_plus_1.left = min_depth_4.out; + min_depth_4_plus_1.right = 32'd1; + } static<1> group t0_idx_init { t0_idx.in = 2'd0; t0_idx.write_en = 1'd1; @@ -144,8 +251,8 @@ component main() -> () { t0_idx.write_en = 1'd1; } static<1> group t0_move { - t0.addr0 = t0_idx.out; - top_0_0.in = t0.read_data; + t0_addr0 = t0_idx.out; + top_0_0.in = t0_read_data; top_0_0.write_en = 1'd1; } static<1> group t1_idx_init { @@ -159,8 +266,8 @@ component main() -> () { t1_idx.write_en = 1'd1; } static<1> group t1_move { - t1.addr0 = t1_idx.out; - top_0_1.in = t1.read_data; + t1_addr0 = t1_idx.out; + top_0_1.in = t1_read_data; top_0_1.write_en = 1'd1; } static<1> group t2_idx_init { @@ -174,8 +281,8 @@ component main() -> () { t2_idx.write_en = 1'd1; } static<1> group t2_move { - t2.addr0 = t2_idx.out; - top_0_2.in = t2.read_data; + t2_addr0 = t2_idx.out; + top_0_2.in = t2_read_data; top_0_2.write_en = 1'd1; } static<1> group l0_idx_init { @@ -189,8 +296,8 @@ component main() -> () { l0_idx.write_en = 1'd1; } static<1> group l0_move { - l0.addr0 = l0_idx.out; - left_0_0.in = l0.read_data; + l0_addr0 = l0_idx.out; + left_0_0.in = l0_read_data; left_0_0.write_en = 1'd1; } static<1> group l1_idx_init { @@ -204,8 +311,8 @@ component main() -> () { l1_idx.write_en = 1'd1; } static<1> group l1_move { - l1.addr0 = l1_idx.out; - left_1_0.in = l1.read_data; + l1_addr0 = l1_idx.out; + left_1_0.in = l1_read_data; left_1_0.write_en = 1'd1; } static<1> group l2_idx_init { @@ -219,8 +326,8 @@ component main() -> () { l2_idx.write_en = 1'd1; } static<1> group l2_move { - l2.addr0 = l2_idx.out; - left_2_0.in = l2.read_data; + l2_addr0 = l2_idx.out; + left_2_0.in = l2_read_data; left_2_0.write_en = 1'd1; } static<1> group pe_0_0_right_move { @@ -232,9 +339,9 @@ component main() -> () { top_1_0.write_en = 1'd1; } static<1> group pe_0_0_out_write { - out_mem_0.addr0 = 2'd0; - out_mem_0.write_data = pe_0_0.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd0; + out_mem_0_write_data = pe_0_0.out; + out_mem_0_write_en = 1'd1; } static<1> group pe_0_1_right_move { left_0_2.in = left_0_1.out; @@ -245,18 +352,18 @@ component main() -> () { top_1_1.write_en = 1'd1; } static<1> group pe_0_1_out_write { - out_mem_0.addr0 = 2'd1; - out_mem_0.write_data = pe_0_1.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd1; + out_mem_0_write_data = pe_0_1.out; + out_mem_0_write_en = 1'd1; } static<1> group pe_0_2_down_move { top_1_2.in = top_0_2.out; top_1_2.write_en = 1'd1; } static<1> group pe_0_2_out_write { - out_mem_0.addr0 = 2'd2; - out_mem_0.write_data = pe_0_2.out; - out_mem_0.write_en = 1'd1; + out_mem_0_addr0 = 32'd2; + out_mem_0_write_data = pe_0_2.out; + out_mem_0_write_en = 1'd1; } static<1> group pe_1_0_right_move { left_1_1.in = left_1_0.out; @@ -267,9 +374,9 @@ component main() -> () { top_2_0.write_en = 1'd1; } static<1> group pe_1_0_out_write { - out_mem_1.addr0 = 2'd0; - out_mem_1.write_data = pe_1_0.out; - out_mem_1.write_en = 1'd1; + out_mem_1_addr0 = 32'd0; + out_mem_1_write_data = pe_1_0.out; + out_mem_1_write_en = 1'd1; } static<1> group pe_1_1_right_move { left_1_2.in = left_1_1.out; @@ -280,261 +387,341 @@ component main() -> () { top_2_1.write_en = 1'd1; } static<1> group pe_1_1_out_write { - out_mem_1.addr0 = 2'd1; - out_mem_1.write_data = pe_1_1.out; - out_mem_1.write_en = 1'd1; + out_mem_1_addr0 = 32'd1; + out_mem_1_write_data = pe_1_1.out; + out_mem_1_write_en = 1'd1; } static<1> group pe_1_2_down_move { top_2_2.in = top_1_2.out; top_2_2.write_en = 1'd1; } static<1> group pe_1_2_out_write { - out_mem_1.addr0 = 2'd2; - out_mem_1.write_data = pe_1_2.out; - out_mem_1.write_en = 1'd1; + out_mem_1_addr0 = 32'd2; + out_mem_1_write_data = pe_1_2.out; + out_mem_1_write_en = 1'd1; } static<1> group pe_2_0_right_move { left_2_1.in = left_2_0.out; left_2_1.write_en = 1'd1; } static<1> group pe_2_0_out_write { - out_mem_2.addr0 = 2'd0; - out_mem_2.write_data = pe_2_0.out; - out_mem_2.write_en = 1'd1; + out_mem_2_addr0 = 32'd0; + out_mem_2_write_data = pe_2_0.out; + out_mem_2_write_en = 1'd1; } static<1> group pe_2_1_right_move { left_2_2.in = left_2_1.out; left_2_2.write_en = 1'd1; } static<1> group pe_2_1_out_write { - out_mem_2.addr0 = 2'd1; - out_mem_2.write_data = pe_2_1.out; - out_mem_2.write_en = 1'd1; + out_mem_2_addr0 = 32'd1; + out_mem_2_write_data = pe_2_1.out; + out_mem_2_write_en = 1'd1; } static<1> group pe_2_2_out_write { - out_mem_2.addr0 = 2'd2; - out_mem_2.write_data = pe_2_2.out; - out_mem_2.write_en = 1'd1; + out_mem_2_addr0 = 32'd2; + out_mem_2_write_data = pe_2_2.out; + out_mem_2_write_en = 1'd1; } static<1> group init_idx { - idx.in = 4'd0; + idx.in = 32'd0; idx.write_en = 1'd1; } static<1> group incr_idx { idx_add.left = idx.out; - idx_add.right = 4'd1; + idx_add.right = 32'd1; idx.in = idx_add.out; idx.write_en = 1'd1; } - static<1> group idx_between_9_10_group { - index_ge_9.left = idx_add.out; - index_ge_9.right = 4'd9; - index_lt_10.left = idx_add.out; - index_lt_10.right = 4'd10; - idx_between_9_10_comb.left = index_ge_9.out; - idx_between_9_10_comb.right = index_lt_10.out; - idx_between_9_10_reg.in = idx_between_9_10_comb.out; - idx_between_9_10_reg.write_en = 1'd1; - } - static<1> group init_idx_between_9_10 { - idx_between_9_10_reg.in = 1'd0; - idx_between_9_10_reg.write_en = 1'd1; - } - static<1> group idx_between_10_11_group { - index_ge_10.left = idx_add.out; - index_ge_10.right = 4'd10; - index_lt_11.left = idx_add.out; - index_lt_11.right = 4'd11; - idx_between_10_11_comb.left = index_ge_10.out; - idx_between_10_11_comb.right = index_lt_11.out; - idx_between_10_11_reg.in = idx_between_10_11_comb.out; - idx_between_10_11_reg.write_en = 1'd1; - } - static<1> group init_idx_between_10_11 { - idx_between_10_11_reg.in = 1'd0; - idx_between_10_11_reg.write_en = 1'd1; - } - static<1> group idx_between_5_8_group { - index_ge_5.left = idx_add.out; - index_ge_5.right = 4'd5; - index_lt_8.left = idx_add.out; - index_lt_8.right = 4'd8; - idx_between_5_8_comb.left = index_ge_5.out; - idx_between_5_8_comb.right = index_lt_8.out; - idx_between_5_8_reg.in = idx_between_5_8_comb.out; - idx_between_5_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_8 { - idx_between_5_8_reg.in = 1'd0; - idx_between_5_8_reg.write_en = 1'd1; - } - static<1> group idx_between_7_10_group { + static<1> group lt_iter_limit_group { + lt_iter_limit.left = idx_add.out; + lt_iter_limit.right = iter_limit.out; + cond_reg.in = lt_iter_limit.out; + cond_reg.write_en = 1'd1; + } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_8_depth_plus_9_group { + index_ge_depth_plus_8.left = idx_add.out; + index_ge_depth_plus_8.right = depth_plus_8.out; + index_lt_depth_plus_9.left = idx_add.out; + index_lt_depth_plus_9.right = depth_plus_9.out; + idx_between_depth_plus_8_depth_plus_9_comb.left = index_ge_depth_plus_8.out; + idx_between_depth_plus_8_depth_plus_9_comb.right = index_lt_depth_plus_9.out; + idx_between_depth_plus_8_depth_plus_9_reg.in = idx_between_depth_plus_8_depth_plus_9_comb.out; + idx_between_depth_plus_8_depth_plus_9_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_8_depth_plus_9 { + idx_between_depth_plus_8_depth_plus_9_reg.in = 1'd0; + idx_between_depth_plus_8_depth_plus_9_reg.write_en = 1'd1; + } + static<1> group idx_between_2_min_depth_4_plus_2_group { + index_ge_2.left = idx_add.out; + index_ge_2.right = 32'd2; + index_lt_min_depth_4_plus_2.left = idx_add.out; + index_lt_min_depth_4_plus_2.right = min_depth_4_plus_2.out; + idx_between_2_min_depth_4_plus_2_comb.left = index_ge_2.out; + idx_between_2_min_depth_4_plus_2_comb.right = index_lt_min_depth_4_plus_2.out; + idx_between_2_min_depth_4_plus_2_reg.in = idx_between_2_min_depth_4_plus_2_comb.out; + idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; + } + static<1> group init_idx_between_2_min_depth_4_plus_2 { + idx_between_2_min_depth_4_plus_2_reg.in = 1'd0; + idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; + } + static<1> group idx_between_2_depth_plus_2_group { + index_ge_2.left = idx_add.out; + index_ge_2.right = 32'd2; + index_lt_depth_plus_2.left = idx_add.out; + index_lt_depth_plus_2.right = depth_plus_2.out; + idx_between_2_depth_plus_2_comb.left = index_ge_2.out; + idx_between_2_depth_plus_2_comb.right = index_lt_depth_plus_2.out; + idx_between_2_depth_plus_2_reg.in = idx_between_2_depth_plus_2_comb.out; + idx_between_2_depth_plus_2_reg.write_en = 1'd1; + } + static<1> group init_idx_between_2_depth_plus_2 { + idx_between_2_depth_plus_2_reg.in = 1'd0; + idx_between_2_depth_plus_2_reg.write_en = 1'd1; + } + static<1> group idx_between_7_depth_plus_7_group { index_ge_7.left = idx_add.out; - index_ge_7.right = 4'd7; - index_lt_10.left = idx_add.out; - index_lt_10.right = 4'd10; - idx_between_7_10_comb.left = index_ge_7.out; - idx_between_7_10_comb.right = index_lt_10.out; - idx_between_7_10_reg.in = idx_between_7_10_comb.out; - idx_between_7_10_reg.write_en = 1'd1; - } - static<1> group init_idx_between_7_10 { - idx_between_7_10_reg.in = 1'd0; - idx_between_7_10_reg.write_en = 1'd1; - } - static<1> group idx_between_0_3_group { - index_lt_3.left = idx_add.out; - index_lt_3.right = 4'd3; - idx_between_0_3_reg.in = index_lt_3.out; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_3 { - idx_between_0_3_reg.in = 1'd1; - idx_between_0_3_reg.write_en = 1'd1; - } - static<1> group idx_between_9_12_group { + index_ge_7.right = 32'd7; + index_lt_depth_plus_7.left = idx_add.out; + index_lt_depth_plus_7.right = depth_plus_7.out; + idx_between_7_depth_plus_7_comb.left = index_ge_7.out; + idx_between_7_depth_plus_7_comb.right = index_lt_depth_plus_7.out; + idx_between_7_depth_plus_7_reg.in = idx_between_7_depth_plus_7_comb.out; + idx_between_7_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group init_idx_between_7_depth_plus_7 { + idx_between_7_depth_plus_7_reg.in = 1'd0; + idx_between_7_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group idx_between_3_depth_plus_3_group { + index_ge_3.left = idx_add.out; + index_ge_3.right = 32'd3; + index_lt_depth_plus_3.left = idx_add.out; + index_lt_depth_plus_3.right = depth_plus_3.out; + idx_between_3_depth_plus_3_comb.left = index_ge_3.out; + idx_between_3_depth_plus_3_comb.right = index_lt_depth_plus_3.out; + idx_between_3_depth_plus_3_reg.in = idx_between_3_depth_plus_3_comb.out; + idx_between_3_depth_plus_3_reg.write_en = 1'd1; + } + static<1> group init_idx_between_3_depth_plus_3 { + idx_between_3_depth_plus_3_reg.in = 1'd0; + idx_between_3_depth_plus_3_reg.write_en = 1'd1; + } + static<1> group idx_between_3_min_depth_4_plus_3_group { + index_ge_3.left = idx_add.out; + index_ge_3.right = 32'd3; + index_lt_min_depth_4_plus_3.left = idx_add.out; + index_lt_min_depth_4_plus_3.right = min_depth_4_plus_3.out; + idx_between_3_min_depth_4_plus_3_comb.left = index_ge_3.out; + idx_between_3_min_depth_4_plus_3_comb.right = index_lt_min_depth_4_plus_3.out; + idx_between_3_min_depth_4_plus_3_reg.in = idx_between_3_min_depth_4_plus_3_comb.out; + idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; + } + static<1> group init_idx_between_3_min_depth_4_plus_3 { + idx_between_3_min_depth_4_plus_3_reg.in = 1'd0; + idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_5_depth_plus_6_group { + index_ge_depth_plus_5.left = idx_add.out; + index_ge_depth_plus_5.right = depth_plus_5.out; + index_lt_depth_plus_6.left = idx_add.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; + idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_5_depth_plus_6 { + idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; + idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_9_depth_plus_10_group { + index_ge_depth_plus_9.left = idx_add.out; + index_ge_depth_plus_9.right = depth_plus_9.out; + index_lt_depth_plus_10.left = idx_add.out; + index_lt_depth_plus_10.right = depth_plus_10.out; + idx_between_depth_plus_9_depth_plus_10_comb.left = index_ge_depth_plus_9.out; + idx_between_depth_plus_9_depth_plus_10_comb.right = index_lt_depth_plus_10.out; + idx_between_depth_plus_9_depth_plus_10_reg.in = idx_between_depth_plus_9_depth_plus_10_comb.out; + idx_between_depth_plus_9_depth_plus_10_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_9_depth_plus_10 { + idx_between_depth_plus_9_depth_plus_10_reg.in = 1'd0; + idx_between_depth_plus_9_depth_plus_10_reg.write_en = 1'd1; + } + static<1> group idx_between_8_depth_plus_8_group { + index_ge_8.left = idx_add.out; + index_ge_8.right = 32'd8; + index_lt_depth_plus_8.left = idx_add.out; + index_lt_depth_plus_8.right = depth_plus_8.out; + idx_between_8_depth_plus_8_comb.left = index_ge_8.out; + idx_between_8_depth_plus_8_comb.right = index_lt_depth_plus_8.out; + idx_between_8_depth_plus_8_reg.in = idx_between_8_depth_plus_8_comb.out; + idx_between_8_depth_plus_8_reg.write_en = 1'd1; + } + static<1> group init_idx_between_8_depth_plus_8 { + idx_between_8_depth_plus_8_reg.in = 1'd0; + idx_between_8_depth_plus_8_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_6_depth_plus_7_group { + index_ge_depth_plus_6.left = idx_add.out; + index_ge_depth_plus_6.right = depth_plus_6.out; + index_lt_depth_plus_7.left = idx_add.out; + index_lt_depth_plus_7.right = depth_plus_7.out; + idx_between_depth_plus_6_depth_plus_7_comb.left = index_ge_depth_plus_6.out; + idx_between_depth_plus_6_depth_plus_7_comb.right = index_lt_depth_plus_7.out; + idx_between_depth_plus_6_depth_plus_7_reg.in = idx_between_depth_plus_6_depth_plus_7_comb.out; + idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_6_depth_plus_7 { + idx_between_depth_plus_6_depth_plus_7_reg.in = 1'd0; + idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; + } + static<1> group idx_between_4_depth_plus_4_group { + index_ge_4.left = idx_add.out; + index_ge_4.right = 32'd4; + index_lt_depth_plus_4.left = idx_add.out; + index_lt_depth_plus_4.right = depth_plus_4.out; + idx_between_4_depth_plus_4_comb.left = index_ge_4.out; + idx_between_4_depth_plus_4_comb.right = index_lt_depth_plus_4.out; + idx_between_4_depth_plus_4_reg.in = idx_between_4_depth_plus_4_comb.out; + idx_between_4_depth_plus_4_reg.write_en = 1'd1; + } + static<1> group init_idx_between_4_depth_plus_4 { + idx_between_4_depth_plus_4_reg.in = 1'd0; + idx_between_4_depth_plus_4_reg.write_en = 1'd1; + } + static<1> group idx_between_4_min_depth_4_plus_4_group { + index_ge_4.left = idx_add.out; + index_ge_4.right = 32'd4; + index_lt_min_depth_4_plus_4.left = idx_add.out; + index_lt_min_depth_4_plus_4.right = min_depth_4_plus_4.out; + idx_between_4_min_depth_4_plus_4_comb.left = index_ge_4.out; + idx_between_4_min_depth_4_plus_4_comb.right = index_lt_min_depth_4_plus_4.out; + idx_between_4_min_depth_4_plus_4_reg.in = idx_between_4_min_depth_4_plus_4_comb.out; + idx_between_4_min_depth_4_plus_4_reg.write_en = 1'd1; + } + static<1> group init_idx_between_4_min_depth_4_plus_4 { + idx_between_4_min_depth_4_plus_4_reg.in = 1'd0; + idx_between_4_min_depth_4_plus_4_reg.write_en = 1'd1; + } + static<1> group idx_between_5_min_depth_4_plus_5_group { + index_ge_5.left = idx_add.out; + index_ge_5.right = 32'd5; + index_lt_min_depth_4_plus_5.left = idx_add.out; + index_lt_min_depth_4_plus_5.right = min_depth_4_plus_5.out; + idx_between_5_min_depth_4_plus_5_comb.left = index_ge_5.out; + idx_between_5_min_depth_4_plus_5_comb.right = index_lt_min_depth_4_plus_5.out; + idx_between_5_min_depth_4_plus_5_reg.in = idx_between_5_min_depth_4_plus_5_comb.out; + idx_between_5_min_depth_4_plus_5_reg.write_en = 1'd1; + } + static<1> group init_idx_between_5_min_depth_4_plus_5 { + idx_between_5_min_depth_4_plus_5_reg.in = 1'd0; + idx_between_5_min_depth_4_plus_5_reg.write_en = 1'd1; + } + static<1> group idx_between_5_depth_plus_5_group { + index_ge_5.left = idx_add.out; + index_ge_5.right = 32'd5; + index_lt_depth_plus_5.left = idx_add.out; + index_lt_depth_plus_5.right = depth_plus_5.out; + idx_between_5_depth_plus_5_comb.left = index_ge_5.out; + idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; + idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group init_idx_between_5_depth_plus_5 { + idx_between_5_depth_plus_5_reg.in = 1'd0; + idx_between_5_depth_plus_5_reg.write_en = 1'd1; + } + static<1> group idx_between_0_depth_plus_0_group { + index_lt_depth_plus_0.left = idx_add.out; + index_lt_depth_plus_0.right = depth_plus_0.out; + idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group init_idx_between_0_depth_plus_0 { + idx_between_0_depth_plus_0_reg.in = 1'd1; + idx_between_0_depth_plus_0_reg.write_en = 1'd1; + } + static<1> group idx_between_9_depth_plus_9_group { index_ge_9.left = idx_add.out; - index_ge_9.right = 4'd9; - index_lt_12.left = idx_add.out; - index_lt_12.right = 4'd12; - idx_between_9_12_comb.left = index_ge_9.out; - idx_between_9_12_comb.right = index_lt_12.out; - idx_between_9_12_reg.in = idx_between_9_12_comb.out; - idx_between_9_12_reg.write_en = 1'd1; - } - static<1> group init_idx_between_9_12 { - idx_between_9_12_reg.in = 1'd0; - idx_between_9_12_reg.write_en = 1'd1; - } - static<1> group idx_between_12_13_group { - index_ge_12.left = idx_add.out; - index_ge_12.right = 4'd12; - index_lt_13.left = idx_add.out; - index_lt_13.right = 4'd13; - idx_between_12_13_comb.left = index_ge_12.out; - idx_between_12_13_comb.right = index_lt_13.out; - idx_between_12_13_reg.in = idx_between_12_13_comb.out; - idx_between_12_13_reg.write_en = 1'd1; - } - static<1> group init_idx_between_12_13 { - idx_between_12_13_reg.in = 1'd0; - idx_between_12_13_reg.write_en = 1'd1; - } - static<1> group idx_between_1_4_group { + index_ge_9.right = 32'd9; + index_lt_depth_plus_9.left = idx_add.out; + index_lt_depth_plus_9.right = depth_plus_9.out; + idx_between_9_depth_plus_9_comb.left = index_ge_9.out; + idx_between_9_depth_plus_9_comb.right = index_lt_depth_plus_9.out; + idx_between_9_depth_plus_9_reg.in = idx_between_9_depth_plus_9_comb.out; + idx_between_9_depth_plus_9_reg.write_en = 1'd1; + } + static<1> group init_idx_between_9_depth_plus_9 { + idx_between_9_depth_plus_9_reg.in = 1'd0; + idx_between_9_depth_plus_9_reg.write_en = 1'd1; + } + static<1> group idx_between_1_depth_plus_1_group { index_ge_1.left = idx_add.out; - index_ge_1.right = 4'd1; - index_lt_4.left = idx_add.out; - index_lt_4.right = 4'd4; - idx_between_1_4_comb.left = index_ge_1.out; - idx_between_1_4_comb.right = index_lt_4.out; - idx_between_1_4_reg.in = idx_between_1_4_comb.out; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_4 { - idx_between_1_4_reg.in = 1'd0; - idx_between_1_4_reg.write_en = 1'd1; - } - static<1> group idx_between_11_12_group { - index_ge_11.left = idx_add.out; - index_ge_11.right = 4'd11; - index_lt_12.left = idx_add.out; - index_lt_12.right = 4'd12; - idx_between_11_12_comb.left = index_ge_11.out; - idx_between_11_12_comb.right = index_lt_12.out; - idx_between_11_12_reg.in = idx_between_11_12_comb.out; - idx_between_11_12_reg.write_en = 1'd1; - } - static<1> group init_idx_between_11_12 { - idx_between_11_12_reg.in = 1'd0; - idx_between_11_12_reg.write_en = 1'd1; - } - static<1> group idx_between_8_9_group { - index_ge_8.left = idx_add.out; - index_ge_8.right = 4'd8; - index_lt_9.left = idx_add.out; - index_lt_9.right = 4'd9; - idx_between_8_9_comb.left = index_ge_8.out; - idx_between_8_9_comb.right = index_lt_9.out; - idx_between_8_9_reg.in = idx_between_8_9_comb.out; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_8_9 { - idx_between_8_9_reg.in = 1'd0; - idx_between_8_9_reg.write_en = 1'd1; - } - static<1> group idx_between_3_6_group { - index_ge_3.left = idx_add.out; - index_ge_3.right = 4'd3; - index_lt_6.left = idx_add.out; - index_lt_6.right = 4'd6; - idx_between_3_6_comb.left = index_ge_3.out; - idx_between_3_6_comb.right = index_lt_6.out; - idx_between_3_6_reg.in = idx_between_3_6_comb.out; - idx_between_3_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_6 { - idx_between_3_6_reg.in = 1'd0; - idx_between_3_6_reg.write_en = 1'd1; - } - static<1> group idx_between_2_5_group { - index_ge_2.left = idx_add.out; - index_ge_2.right = 4'd2; - index_lt_5.left = idx_add.out; - index_lt_5.right = 4'd5; - idx_between_2_5_comb.left = index_ge_2.out; - idx_between_2_5_comb.right = index_lt_5.out; - idx_between_2_5_reg.in = idx_between_2_5_comb.out; - idx_between_2_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_5 { - idx_between_2_5_reg.in = 1'd0; - idx_between_2_5_reg.write_en = 1'd1; - } - static<1> group idx_between_6_9_group { + index_ge_1.right = 32'd1; + index_lt_depth_plus_1.left = idx_add.out; + index_lt_depth_plus_1.right = depth_plus_1.out; + idx_between_1_depth_plus_1_comb.left = index_ge_1.out; + idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; + idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_depth_plus_1 { + idx_between_1_depth_plus_1_reg.in = 1'd0; + idx_between_1_depth_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_1_min_depth_4_plus_1_group { + index_ge_1.left = idx_add.out; + index_ge_1.right = 32'd1; + index_lt_min_depth_4_plus_1.left = idx_add.out; + index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; + idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; + idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group init_idx_between_1_min_depth_4_plus_1 { + idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; + idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; + } + static<1> group idx_between_6_depth_plus_6_group { index_ge_6.left = idx_add.out; - index_ge_6.right = 4'd6; - index_lt_9.left = idx_add.out; - index_lt_9.right = 4'd9; - idx_between_6_9_comb.left = index_ge_6.out; - idx_between_6_9_comb.right = index_lt_9.out; - idx_between_6_9_reg.in = idx_between_6_9_comb.out; - idx_between_6_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_6_9 { - idx_between_6_9_reg.in = 1'd0; - idx_between_6_9_reg.write_en = 1'd1; - } - static<1> group idx_between_4_7_group { - index_ge_4.left = idx_add.out; - index_ge_4.right = 4'd4; - index_lt_7.left = idx_add.out; - index_lt_7.right = 4'd7; - idx_between_4_7_comb.left = index_ge_4.out; - idx_between_4_7_comb.right = index_lt_7.out; - idx_between_4_7_reg.in = idx_between_4_7_comb.out; - idx_between_4_7_reg.write_en = 1'd1; - } - static<1> group init_idx_between_4_7 { - idx_between_4_7_reg.in = 1'd0; - idx_between_4_7_reg.write_en = 1'd1; - } - static<1> group idx_between_8_11_group { - index_ge_8.left = idx_add.out; - index_ge_8.right = 4'd8; - index_lt_11.left = idx_add.out; - index_lt_11.right = 4'd11; - idx_between_8_11_comb.left = index_ge_8.out; - idx_between_8_11_comb.right = index_lt_11.out; - idx_between_8_11_reg.in = idx_between_8_11_comb.out; - idx_between_8_11_reg.write_en = 1'd1; - } - static<1> group init_idx_between_8_11 { - idx_between_8_11_reg.in = 1'd0; - idx_between_8_11_reg.write_en = 1'd1; + index_ge_6.right = 32'd6; + index_lt_depth_plus_6.left = idx_add.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_6_depth_plus_6_comb.left = index_ge_6.out; + idx_between_6_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_6_depth_plus_6_reg.in = idx_between_6_depth_plus_6_comb.out; + idx_between_6_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group init_idx_between_6_depth_plus_6 { + idx_between_6_depth_plus_6_reg.in = 1'd0; + idx_between_6_depth_plus_6_reg.write_en = 1'd1; + } + static<1> group idx_between_depth_plus_7_depth_plus_8_group { + index_ge_depth_plus_7.left = idx_add.out; + index_ge_depth_plus_7.right = depth_plus_7.out; + index_lt_depth_plus_8.left = idx_add.out; + index_lt_depth_plus_8.right = depth_plus_8.out; + idx_between_depth_plus_7_depth_plus_8_comb.left = index_ge_depth_plus_7.out; + idx_between_depth_plus_7_depth_plus_8_comb.right = index_lt_depth_plus_8.out; + idx_between_depth_plus_7_depth_plus_8_reg.in = idx_between_depth_plus_7_depth_plus_8_comb.out; + idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; + } + static<1> group init_idx_between_depth_plus_7_depth_plus_8 { + idx_between_depth_plus_7_depth_plus_8_reg.in = 1'd0; + idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; } } control { - static seq { + seq { static par { t0_idx_init; t1_idx_init; @@ -543,27 +730,35 @@ component main() -> () { l1_idx_init; l2_idx_init; init_idx; - init_idx_between_9_10; - init_idx_between_10_11; - init_idx_between_5_8; - init_idx_between_7_10; - init_idx_between_0_3; - init_idx_between_9_12; - init_idx_between_12_13; - init_idx_between_1_4; - init_idx_between_11_12; - init_idx_between_8_9; - init_idx_between_3_6; - init_idx_between_2_5; - init_idx_between_6_9; - init_idx_between_4_7; - init_idx_between_8_11; + init_min_depth; + init_iter_limit; + init_cond_reg; + init_idx_between_depth_plus_8_depth_plus_9; + init_idx_between_2_min_depth_4_plus_2; + init_idx_between_2_depth_plus_2; + init_idx_between_7_depth_plus_7; + init_idx_between_3_depth_plus_3; + init_idx_between_3_min_depth_4_plus_3; + init_idx_between_depth_plus_5_depth_plus_6; + init_idx_between_depth_plus_9_depth_plus_10; + init_idx_between_8_depth_plus_8; + init_idx_between_depth_plus_6_depth_plus_7; + init_idx_between_4_depth_plus_4; + init_idx_between_4_min_depth_4_plus_4; + init_idx_between_5_min_depth_4_plus_5; + init_idx_between_5_depth_plus_5; + init_idx_between_0_depth_plus_0; + init_idx_between_9_depth_plus_9; + init_idx_between_1_depth_plus_1; + init_idx_between_1_min_depth_4_plus_1; + init_idx_between_6_depth_plus_6; + init_idx_between_depth_plus_7_depth_plus_8; } - static repeat 13 { + while cond_reg.out { static par { static par { static par { - static if idx_between_0_3_reg.out { + static if idx_between_0_depth_plus_0_reg.out { static par { l0_move; l0_idx_update; @@ -571,221 +766,221 @@ component main() -> () { t0_idx_update; } } - static if idx_between_1_4_reg.out { + static if idx_between_1_min_depth_4_plus_1_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); } } - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { pe_0_0_down_move; pe_0_0_right_move; } } - static if idx_between_5_8_reg.out { + static if idx_between_5_depth_plus_5_reg.out { static par { static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); } } - static if idx_between_8_9_reg.out { + static if idx_between_depth_plus_5_depth_plus_6_reg.out { static par { pe_0_0_out_write; } } } static par { - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { t1_move; t1_idx_update; } } - static if idx_between_2_5_reg.out { + static if idx_between_2_min_depth_4_plus_2_reg.out { static par { static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd0)(); } } - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { pe_0_1_down_move; pe_0_1_right_move; } } - static if idx_between_6_9_reg.out { + static if idx_between_6_depth_plus_6_reg.out { static par { static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd1)(); } } - static if idx_between_9_10_reg.out { + static if idx_between_depth_plus_6_depth_plus_7_reg.out { static par { pe_0_1_out_write; } } } static par { - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { t2_move; t2_idx_update; } } - static if idx_between_3_6_reg.out { + static if idx_between_3_min_depth_4_plus_3_reg.out { static par { static invoke pe_0_2(top=top_0_2.out, left=left_0_2.out, mul_ready=1'd0)(); } } - static if idx_between_3_6_reg.out { + static if idx_between_3_depth_plus_3_reg.out { static par { pe_0_2_down_move; } } - static if idx_between_7_10_reg.out { + static if idx_between_7_depth_plus_7_reg.out { static par { static invoke pe_0_2(top=top_0_2.out, left=left_0_2.out, mul_ready=1'd1)(); } } - static if idx_between_10_11_reg.out { + static if idx_between_depth_plus_7_depth_plus_8_reg.out { static par { pe_0_2_out_write; } } } static par { - static if idx_between_1_4_reg.out { + static if idx_between_1_depth_plus_1_reg.out { static par { l1_move; l1_idx_update; } } - static if idx_between_2_5_reg.out { + static if idx_between_2_min_depth_4_plus_2_reg.out { static par { static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd0)(); } } - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { pe_1_0_down_move; pe_1_0_right_move; } } - static if idx_between_6_9_reg.out { + static if idx_between_6_depth_plus_6_reg.out { static par { static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd1)(); } } - static if idx_between_9_10_reg.out { + static if idx_between_depth_plus_6_depth_plus_7_reg.out { static par { pe_1_0_out_write; } } } static par { - static if idx_between_3_6_reg.out { + static if idx_between_3_min_depth_4_plus_3_reg.out { static par { static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd0)(); } } - static if idx_between_3_6_reg.out { + static if idx_between_3_depth_plus_3_reg.out { static par { pe_1_1_down_move; pe_1_1_right_move; } } - static if idx_between_7_10_reg.out { + static if idx_between_7_depth_plus_7_reg.out { static par { static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd1)(); } } - static if idx_between_10_11_reg.out { + static if idx_between_depth_plus_7_depth_plus_8_reg.out { static par { pe_1_1_out_write; } } } static par { - static if idx_between_4_7_reg.out { + static if idx_between_4_min_depth_4_plus_4_reg.out { static par { static invoke pe_1_2(top=top_1_2.out, left=left_1_2.out, mul_ready=1'd0)(); } } - static if idx_between_4_7_reg.out { + static if idx_between_4_depth_plus_4_reg.out { static par { pe_1_2_down_move; } } - static if idx_between_8_11_reg.out { + static if idx_between_8_depth_plus_8_reg.out { static par { static invoke pe_1_2(top=top_1_2.out, left=left_1_2.out, mul_ready=1'd1)(); } } - static if idx_between_11_12_reg.out { + static if idx_between_depth_plus_8_depth_plus_9_reg.out { static par { pe_1_2_out_write; } } } static par { - static if idx_between_2_5_reg.out { + static if idx_between_2_depth_plus_2_reg.out { static par { l2_move; l2_idx_update; } } - static if idx_between_3_6_reg.out { + static if idx_between_3_min_depth_4_plus_3_reg.out { static par { static invoke pe_2_0(top=top_2_0.out, left=left_2_0.out, mul_ready=1'd0)(); } } - static if idx_between_3_6_reg.out { + static if idx_between_3_depth_plus_3_reg.out { static par { pe_2_0_right_move; } } - static if idx_between_7_10_reg.out { + static if idx_between_7_depth_plus_7_reg.out { static par { static invoke pe_2_0(top=top_2_0.out, left=left_2_0.out, mul_ready=1'd1)(); } } - static if idx_between_10_11_reg.out { + static if idx_between_depth_plus_7_depth_plus_8_reg.out { static par { pe_2_0_out_write; } } } static par { - static if idx_between_4_7_reg.out { + static if idx_between_4_min_depth_4_plus_4_reg.out { static par { static invoke pe_2_1(top=top_2_1.out, left=left_2_1.out, mul_ready=1'd0)(); } } - static if idx_between_4_7_reg.out { + static if idx_between_4_depth_plus_4_reg.out { static par { pe_2_1_right_move; } } - static if idx_between_8_11_reg.out { + static if idx_between_8_depth_plus_8_reg.out { static par { static invoke pe_2_1(top=top_2_1.out, left=left_2_1.out, mul_ready=1'd1)(); } } - static if idx_between_11_12_reg.out { + static if idx_between_depth_plus_8_depth_plus_9_reg.out { static par { pe_2_1_out_write; } } } static par { - static if idx_between_5_8_reg.out { + static if idx_between_5_min_depth_4_plus_5_reg.out { static par { static invoke pe_2_2(top=top_2_2.out, left=left_2_2.out, mul_ready=1'd0)(); } } - static if idx_between_9_12_reg.out { + static if idx_between_9_depth_plus_9_reg.out { static par { static invoke pe_2_2(top=top_2_2.out, left=left_2_2.out, mul_ready=1'd1)(); } } - static if idx_between_12_13_reg.out { + static if idx_between_depth_plus_9_depth_plus_10_reg.out { static par { pe_2_2_out_write; } @@ -794,35 +989,77 @@ component main() -> () { } static par { incr_idx; - idx_between_9_10_group; - idx_between_10_11_group; - idx_between_5_8_group; - idx_between_7_10_group; - idx_between_0_3_group; - idx_between_9_12_group; - idx_between_12_13_group; - idx_between_1_4_group; - idx_between_11_12_group; - idx_between_8_9_group; - idx_between_3_6_group; - idx_between_2_5_group; - idx_between_6_9_group; - idx_between_4_7_group; - idx_between_8_11_group; + lt_iter_limit_group; + idx_between_depth_plus_8_depth_plus_9_group; + idx_between_2_min_depth_4_plus_2_group; + idx_between_2_depth_plus_2_group; + idx_between_7_depth_plus_7_group; + idx_between_3_depth_plus_3_group; + idx_between_3_min_depth_4_plus_3_group; + idx_between_depth_plus_5_depth_plus_6_group; + idx_between_depth_plus_9_depth_plus_10_group; + idx_between_8_depth_plus_8_group; + idx_between_depth_plus_6_depth_plus_7_group; + idx_between_4_depth_plus_4_group; + idx_between_4_min_depth_4_plus_4_group; + idx_between_5_min_depth_4_plus_5_group; + idx_between_5_depth_plus_5_group; + idx_between_0_depth_plus_0_group; + idx_between_9_depth_plus_9_group; + idx_between_1_depth_plus_1_group; + idx_between_1_min_depth_4_plus_1_group; + idx_between_6_depth_plus_6_group; + idx_between_depth_plus_7_depth_plus_8_group; + depth_plus_8_group; + depth_plus_9_group; + min_depth_4_plus_2_group; + depth_plus_2_group; + depth_plus_7_group; + depth_plus_3_group; + min_depth_4_plus_3_group; + depth_plus_5_group; + depth_plus_6_group; + depth_plus_10_group; + depth_plus_4_group; + min_depth_4_plus_4_group; + min_depth_4_plus_5_group; + depth_plus_0_group; + depth_plus_1_group; + min_depth_4_plus_1_group; } } } } } } +component main() -> () { + cells { + systolic_array = systolic_array_comp(); + @external t0 = std_mem_d1(32, 3, 2); + @external t1 = std_mem_d1(32, 3, 2); + @external t2 = std_mem_d1(32, 3, 2); + @external l0 = std_mem_d1(32, 3, 2); + @external l1 = std_mem_d1(32, 3, 2); + @external l2 = std_mem_d1(32, 3, 2); + @external out_mem_0 = std_mem_d1(32, 3, 32); + @external out_mem_1 = std_mem_d1(32, 3, 32); + @external out_mem_2 = std_mem_d1(32, 3, 32); + } + wires { + + } + control { + invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, t1_read_data=t1.read_data, t2_read_data=t2.read_data, l0_read_data=l0.read_data, l1_read_data=l1.read_data, l2_read_data=l2.read_data)(t0_addr0=t0.addr0, t1_addr0=t1.addr0, t2_addr0=t2.addr0, l0_addr0=l0.addr0, l1_addr0=l1.addr0, l2_addr0=l2.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en, out_mem_1_addr0=out_mem_1.addr0, out_mem_1_write_data=out_mem_1.write_data, out_mem_1_write_en=out_mem_1.write_en, out_mem_2_addr0=out_mem_2.addr0, out_mem_2_write_data=out_mem_2.write_data, out_mem_2_write_en=out_mem_2.write_en); + } +} metadata #{ -0: pe_0_0 filling: [1,4) accumulating: [5 8) -1: pe_0_1 filling: [2,5) accumulating: [6 9) -2: pe_0_2 filling: [3,6) accumulating: [7 10) -3: pe_1_0 filling: [2,5) accumulating: [6 9) -4: pe_1_1 filling: [3,6) accumulating: [7 10) -5: pe_1_2 filling: [4,7) accumulating: [8 11) -6: pe_2_0 filling: [3,6) accumulating: [7 10) -7: pe_2_1 filling: [4,7) accumulating: [8 11) -8: pe_2_2 filling: [5,8) accumulating: [9 12) +0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) +1: pe_0_1 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) +2: pe_0_2 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) +3: pe_1_0 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) +4: pe_1_1 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) +5: pe_1_2 filling: [4,min_depth_4_plus_4) accumulating: [8 depth_plus_8) +6: pe_2_0 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) +7: pe_2_1 filling: [4,min_depth_4_plus_4) accumulating: [8 depth_plus_8) +8: pe_2_2 filling: [5,min_depth_4_plus_5) accumulating: [9 depth_plus_9) }# From 938f782cfa311ee4c65028b5f8f0b1775602413d Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 31 Jul 2023 17:27:03 -0400 Subject: [PATCH 010/189] Reduce Register Usage for Separate Static Islands (#1632) * first draft of single fsm compilation * it works * fixed nested repeat bug * added documentation * added test cases * removed unnecessary doc * bug fix (needed more conflicts) * small documentation changes * fixed test and removed debug stmt * modified test case to catch bug * removed unnecessary files * code cleaning * renamed function --- calyx-ir/src/component.rs | 13 + calyx-opt/src/analysis/graph_coloring.rs | 10 +- calyx-opt/src/default_passes.rs | 1 + calyx-opt/src/passes/cell_share.rs | 8 +- calyx-opt/src/passes/compile_static.rs | 405 ++++++++++++++++-- examples/futil/dot-product.expect | 111 +++-- examples/futil/simple.expect | 30 +- examples/futil/vectorized-add.expect | 101 +++-- runt.toml | 4 +- .../static-islands/par-static-islands.expect | 5 + .../static-islands/par-static-islands.futil | 47 ++ .../par-static-islands.futil.data | 12 + .../seq-mem-dot-product.expect | 0 .../seq-mem-dot-product.futil | 0 .../seq-mem-dot-product.futil.data | 0 ...roup_go.expect => rewrite-group-go.expect} | 2 +- ..._group_go.futil => rewrite-group-go.futil} | 0 .../rewrite-static-while-nested.expect | 58 ++- .../rewrite-static-while.expect | 54 ++- .../compile-static/separate-fsms.expect | 113 +++++ .../passes/compile-static/separate-fsms.futil | 45 ++ 21 files changed, 802 insertions(+), 217 deletions(-) create mode 100644 tests/correctness/static-islands/par-static-islands.expect create mode 100644 tests/correctness/static-islands/par-static-islands.futil create mode 100644 tests/correctness/static-islands/par-static-islands.futil.data rename tests/correctness/{repeat => static-islands}/seq-mem-dot-product.expect (100%) rename tests/correctness/{repeat => static-islands}/seq-mem-dot-product.futil (100%) rename tests/correctness/{repeat => static-islands}/seq-mem-dot-product.futil.data (100%) rename tests/passes/compile-static/{rewrite_group_go.expect => rewrite-group-go.expect} (100%) rename tests/passes/compile-static/{rewrite_group_go.futil => rewrite-group-go.futil} (100%) create mode 100644 tests/passes/compile-static/separate-fsms.expect create mode 100644 tests/passes/compile-static/separate-fsms.futil diff --git a/calyx-ir/src/component.rs b/calyx-ir/src/component.rs index d14d60988..165489cbb 100644 --- a/calyx-ir/src/component.rs +++ b/calyx-ir/src/component.rs @@ -207,6 +207,19 @@ impl Component { self.cells.find(name) } + /// Return a reference to the cell with `name` if present. + pub fn find_guaranteed_cell(&self, name: S) -> RRC + where + S: Into + std::fmt::Debug + Copy, + { + self.cells.find(name).unwrap_or_else(|| { + unreachable!( + "called find_certain_cell on {:?} but it wasn't found", + name + ) + }) + } + /// Construct a non-conflicting name using the Component's namegenerator. pub fn generate_name(&mut self, prefix: S) -> Id where diff --git a/calyx-opt/src/analysis/graph_coloring.rs b/calyx-opt/src/analysis/graph_coloring.rs index 58842dbe2..dcea4f6f2 100644 --- a/calyx-opt/src/analysis/graph_coloring.rs +++ b/calyx-opt/src/analysis/graph_coloring.rs @@ -74,7 +74,13 @@ where /// Given an `ordering` of `T`s, find a mapping from nodes to `T`s such /// that no node has a neighbor with the same `T`. - pub fn color_greedy(&mut self, bound: Option) -> HashMap { + /// `keep_self_color` indicates whether to keep the mapping of the node to + /// itself in the returned HashMap (since nodes are "colors") + pub fn color_greedy( + &mut self, + bound: Option, + keep_self_color: bool, + ) -> HashMap { let mut all_colors: BTreeMap = BTreeMap::new(); let mut coloring: HashMap = HashMap::new(); let always_share = bound.is_none(); @@ -159,7 +165,7 @@ where coloring .into_iter() .map(|(n1, n2)| (rev_map[&n1].clone(), rev_map[&n2].clone())) - .filter(|(a, b)| a != b) + .filter(|(a, b)| (a != b) || keep_self_color) .collect() } diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 59e19d1c2..0190e9f83 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -106,6 +106,7 @@ impl PassManager { [ StaticInliner, MergeAssign, // Static inliner generates lots of assigns + DeadGroupRemoval, // Static inliner generates lots of dead groups SimplifyStaticGuards, CompileStatic, TopDownStaticTiming, diff --git a/calyx-opt/src/passes/cell_share.rs b/calyx-opt/src/passes/cell_share.rs index d5e5ae496..46ac420f4 100644 --- a/calyx-opt/src/passes/cell_share.rs +++ b/calyx-opt/src/passes/cell_share.rs @@ -442,9 +442,9 @@ impl Visitor for CellShare { let parent_b = par_thread_map.get(live_b).unwrap(); if live_a != live_b && parent_a == parent_b { - // we have to check par_timing_map - // to see whether liveness overlaps - // for dynamic pars, liveness_overlaps() returns + // We have to check par_timing_map + // to see whether liveness overlaps. + // For dynamic pars, liveness_overlaps() returns // true no matter what. if self.par_timing_map.liveness_overlaps( parent_a, live_a, live_b, a, b, @@ -497,7 +497,7 @@ impl Visitor for CellShare { if graph.has_nodes() { coloring.extend( graph - .color_greedy(*bound) + .color_greedy(*bound, false) .iter() .map(|(a, b)| (*a, comp.find_cell(*b).unwrap())), ); diff --git a/calyx-opt/src/passes/compile_static.rs b/calyx-opt/src/passes/compile_static.rs index 0cd873530..a103c6d39 100644 --- a/calyx-opt/src/passes/compile_static.rs +++ b/calyx-opt/src/passes/compile_static.rs @@ -1,11 +1,12 @@ use super::math_utilities::get_bit_width_from; +use crate::analysis::GraphColoring; use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir as ir; use calyx_ir::{guard, structure, GetAttributes}; use calyx_utils::Error; use ir::{build_assignments, Nothing, StaticTiming, RRC}; use itertools::Itertools; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::ops::Not; use std::rc::Rc; @@ -16,6 +17,8 @@ pub struct CompileStatic { reset_early_map: HashMap, /// maps group that has an FSM that resets early to its dynamic "wrapper" group name. wrapper_map: HashMap, + /// maps fsm names to their corresponding signal_reg + signal_reg_map: HashMap, /// maps reset_early_group names to (fsm name, fsm_width) fsm_info_map: HashMap, /// rewrites `static_group[go]` to `dynamic_group[go]` @@ -103,6 +106,39 @@ fn make_assign_dyn( } } +// Given a list of `static_groups`, find the group named `name`. +// If there is no such group, then there is an unreachable! error. +fn find_static_group( + name: &ir::Id, + static_groups: &[ir::RRC], +) -> ir::RRC { + Rc::clone( + static_groups + .iter() + .find(|static_group| static_group.borrow().name() == name) + .unwrap_or_else(|| { + unreachable!("couldn't find static group {name}") + }), + ) +} + +// Given an input static_group `sgroup`, finds the names of all of the groups +// that it triggers through their go hole. +// E.g., if `sgroup` has assignments that write to `sgroup1[go]` and `sgroup2[go]` +// then return `{sgroup1, sgroup2}` +// NOTE: assumes that static groups will only write the go holes of other static +// groups, and never dynamic groups +fn get_go_writes(sgroup: &ir::RRC) -> HashSet { + let mut uses = HashSet::new(); + for asgn in &sgroup.borrow().assignments { + let dst = asgn.dst.borrow(); + if dst.is_hole() && dst.name == "go" { + uses.insert(dst.get_parent_name()); + } + } + uses +} + impl CompileStatic { // returns an "early reset" group based on the information given // in the arguments. @@ -115,12 +151,17 @@ impl CompileStatic { sgroup_name: ir::Id, latency: u64, attributes: ir::Attributes, + fsm: ir::RRC, builder: &mut ir::Builder, ) -> ir::RRC { - let fsm_size = - get_bit_width_from(latency + 1 /* represent 0..latency */); + let fsm_name = fsm.borrow().name(); + let fsm_size = fsm + .borrow() + .find("out") + .unwrap_or_else(|| unreachable!("no `out` port on {fsm_name}")) + .borrow() + .width; structure!( builder; - let fsm = prim std_reg(fsm_size); // done hole will be undefined bc of early reset let ud = prim undef(1); let signal_on = constant(1,1); @@ -172,7 +213,9 @@ impl CompileStatic { fsm_name: &ir::Id, fsm_width: u64, group_name: &ir::Id, + signal_reg: ir::RRC, builder: &mut ir::Builder, + add_continuous_assigns: bool, ) -> ir::RRC { // get the groups/fsm necessary to build the wrapper group let early_reset_group = builder @@ -194,7 +237,6 @@ impl CompileStatic { }); structure!( builder; - let signal_reg = prim std_reg(1); let state_zero = constant(0, fsm_width); let signal_on = constant(1, 1); let signal_off = constant(0, 1); @@ -226,15 +268,17 @@ impl CompileStatic { // group[done] = fsm.out == 0 & signal_reg.out ? 1'd1 g["done"] = first_state_and_signal ? signal_on["out"]; ); - // continuous assignments to reset signal_reg back to 0 when the wrapper is done - let continuous_assigns = build_assignments!( - builder; - // when (fsm == 0 & signal_reg is high), which is the done condition of the wrapper, - // reset the signal_reg back to low - signal_reg["write_en"] = first_state_and_signal ? signal_on["out"]; - signal_reg["in"] = first_state_and_signal ? signal_off["out"]; - ); - builder.add_continuous_assignments(continuous_assigns.to_vec()); + if add_continuous_assigns { + // continuous assignments to reset signal_reg back to 0 when the wrapper is done + let continuous_assigns = build_assignments!( + builder; + // when (fsm == 0 & signal_reg is high), which is the done condition of the wrapper, + // reset the signal_reg back to low + signal_reg["write_en"] = first_state_and_signal ? signal_on["out"]; + signal_reg["in"] = first_state_and_signal ? signal_off["out"]; + ); + builder.add_continuous_assignments(continuous_assigns.to_vec()); + } g.borrow_mut().assignments = group_assigns.to_vec(); g.borrow_mut().attributes = early_reset_group.borrow().attributes.clone(); @@ -321,6 +365,257 @@ impl CompileStatic { wrapper_group.borrow_mut().assignments.extend(assignments); wrapper_group } + + // Gets all of the triggered static groups within `c`, and adds it to `cur_names`. + // Relies on sgroup_uses_map to take into account groups that are triggered through + // their `go` hole. + fn get_used_sgroups( + c: &ir::Control, + cur_names: &mut HashSet, + sgroup_uses_map: &HashMap>, + ) { + match c { + ir::Control::Empty(_) + | ir::Control::Enable(_) + | ir::Control::Invoke(_) => (), + ir::Control::Static(sc) => { + let ir::StaticControl::Enable(s) = sc else { + unreachable!("Non-Enable Static Control should have been compiled away. Run {} to do this", crate::passes::StaticInliner::name()); + }; + let group_name = s.group.borrow().name(); + if let Some(sgroup_uses) = sgroup_uses_map.get(&group_name) { + cur_names.extend(sgroup_uses); + } + cur_names.insert(group_name); + } + ir::Control::Par(ir::Par { stmts, .. }) + | ir::Control::Seq(ir::Seq { stmts, .. }) => { + for stmt in stmts { + Self::get_used_sgroups(stmt, cur_names, sgroup_uses_map); + } + } + ir::Control::Repeat(ir::Repeat { body, .. }) + | ir::Control::While(ir::While { body, .. }) => { + Self::get_used_sgroups(body, cur_names, sgroup_uses_map); + } + ir::Control::If(if_stmt) => { + Self::get_used_sgroups( + &if_stmt.tbranch, + cur_names, + sgroup_uses_map, + ); + Self::get_used_sgroups( + &if_stmt.fbranch, + cur_names, + sgroup_uses_map, + ); + } + } + } + + /// Given control `c`, adds conflicts to `conflict_graph` between all + /// static groups that are executed in separate threads of the same par block. + /// `sgroup_uses_map` maps: + /// static group names -> all of the static groups that it triggers the go ports + /// of (even recursively). + /// Example: group A {B[go] = 1;} group B {C[go] = 1} group C{} + /// Would map: A -> {B,C} and B -> {C} + fn add_par_conflicts( + c: &ir::Control, + sgroup_uses_map: &HashMap>, + conflict_graph: &mut GraphColoring, + ) { + match c { + ir::Control::Empty(_) + | ir::Control::Enable(_) + | ir::Control::Invoke(_) + | ir::Control::Static(_) => (), + ir::Control::Seq(seq) => { + for stmt in &seq.stmts { + Self::add_par_conflicts( + stmt, + sgroup_uses_map, + conflict_graph, + ); + } + } + ir::Control::Repeat(ir::Repeat { body, .. }) + | ir::Control::While(ir::While { body, .. }) => { + Self::add_par_conflicts(body, sgroup_uses_map, conflict_graph) + } + ir::Control::If(if_stmt) => { + Self::add_par_conflicts( + &if_stmt.tbranch, + sgroup_uses_map, + conflict_graph, + ); + Self::add_par_conflicts( + &if_stmt.fbranch, + sgroup_uses_map, + conflict_graph, + ); + } + ir::Control::Par(par) => { + // sgroup_conflict_vec is a vec of HashSets. + // Each entry of the vec corresponds to a par thread, and holds + // all of the groups executed in that thread. + let mut sgroup_conflict_vec = Vec::new(); + for stmt in &par.stmts { + let mut used_sgroups = HashSet::new(); + Self::get_used_sgroups( + stmt, + &mut used_sgroups, + sgroup_uses_map, + ); + sgroup_conflict_vec.push(used_sgroups); + } + for (thread1_sgroups, thread2_sgroups) in + sgroup_conflict_vec.iter().tuple_combinations() + { + for sgroup1 in thread1_sgroups { + for sgroup2 in thread2_sgroups { + conflict_graph.insert_conflict(sgroup1, sgroup2); + } + } + } + // Necessary to add conflicts between nested pars + for stmt in &par.stmts { + Self::add_par_conflicts( + stmt, + sgroup_uses_map, + conflict_graph, + ); + } + } + } + } + + /// Given an `sgroup_uses_map`, which maps: + /// static group names -> all of the static groups that it triggers the go ports + /// of (even recursively). + /// Example: group A {B[go] = 1;} group B {C[go] = 1} group C{} + /// Would map: A -> {B,C} and B -> {C} + /// Adds conflicts between any groups triggered at the same time based on + /// `go` port triggering. + fn add_go_port_conflicts( + sgroup_uses_map: &HashMap>, + conflict_graph: &mut GraphColoring, + ) { + for (sgroup, sgroup_uses) in sgroup_uses_map { + for sgroup_use in sgroup_uses { + conflict_graph.insert_conflict(sgroup_use, sgroup); + } + // If multiple groups are triggered by the same group, then + // we conservatively add a conflict between such groups + for (sgroup_use1, sgroup_use2) in + sgroup_uses.iter().tuple_combinations() + { + conflict_graph.insert_conflict(sgroup_use1, sgroup_use2); + } + } + } + + // Given a "coloring" of static group names -> their "colors", + // instantiate one fsm per color and return a hashmap that maps + // fsm names -> groups that it handles + fn build_fsm_mapping( + coloring: HashMap, + static_groups: &[ir::RRC], + builder: &mut ir::Builder, + ) -> HashMap> { + // "reverse" the coloring to map colors -> static group_names + let mut color_to_groups: HashMap> = + HashMap::new(); + for (group, color) in coloring { + color_to_groups.entry(color).or_default().insert(group); + } + // Need deterministic ordering for testing. + let mut vec_color_to_groups: Vec<(ir::Id, HashSet)> = + color_to_groups.into_iter().collect(); + vec_color_to_groups + .sort_by(|(color1, _), (color2, _)| color1.cmp(color2)); + vec_color_to_groups.into_iter().map(|(color, group_names)| { + // For each color, build an FSM that has the number of bits required + // for the largest latency in `group_names` + let max_latency = group_names + .iter() + .map(|g| { + find_static_group(g, static_groups).borrow() + .latency + }) + .max().unwrap_or_else(|| unreachable!("group {color} had no corresponding groups in its coloring map") + ); + let fsm_size = get_bit_width_from( + max_latency + 1, /* represent 0..latency */ + ); + structure!( builder; + let fsm = prim std_reg(fsm_size); + ); + let fsm_name = fsm.borrow().name(); + (fsm_name, group_names) + }).collect() + } + + // helper to `build_sgroup_uses_map` + // `parent_group` is the group that we are "currently" analyzing + // `full_group_ancestry` is the "ancestry of the group we are analyzing" + // Example: group A {B[go] = 1;} group B {C[go] = 1} group C{}, and `parent_group` + // is B, then ancestry would be B and A. + // `cur_mapping` is the current_mapping for `sgroup_uses_map` + // `group_names` is a vec of group_names. Once we analyze a group, we should + // remove it from group_names + // `sgroups` is a vec of static groups. + fn update_sgroup_uses_map( + parent_group: &ir::Id, + full_group_ancestry: &mut HashSet, + cur_mapping: &mut HashMap>, + group_names: &mut HashSet, + sgroups: &Vec>, + ) { + let group_uses = + get_go_writes(&find_static_group(parent_group, sgroups)); + for group_use in group_uses { + for ancestor in full_group_ancestry.iter() { + cur_mapping.entry(*ancestor).or_default().insert(group_use); + } + full_group_ancestry.insert(group_use); + Self::update_sgroup_uses_map( + &group_use, + full_group_ancestry, + cur_mapping, + group_names, + sgroups, + ); + full_group_ancestry.remove(&group_use); + } + group_names.remove(parent_group); + } + + /// Builds an `sgroup_uses_map`, which maps: + /// static group names -> all of the static groups that it triggers the go ports + /// of (even recursively). + /// Example: group A {B[go] = 1;} group B {C[go] = 1} group C{} + /// Would map: A -> {B,C} and B -> {C} + fn build_sgroup_uses_map( + sgroups: &Vec>, + ) -> HashMap> { + let mut names: HashSet = sgroups + .iter() + .map(|sgroup| sgroup.borrow().name()) + .collect(); + let mut cur_mapping = HashMap::new(); + while !names.is_empty() { + let random_group = *names.iter().next().unwrap(); + Self::update_sgroup_uses_map( + &random_group, + &mut HashSet::from([random_group]), + &mut cur_mapping, + &mut names, + sgroups, + ) + } + cur_mapping + } } impl Visitor for CompileStatic { @@ -332,7 +627,32 @@ impl Visitor for CompileStatic { ) -> VisResult { let sgroups: Vec> = comp.get_static_groups_mut().drain().collect(); + // `sgroup_uses_map` builds a mapping of static groups -> groups that + // it (even indirectly) triggers the `go` port of. + let sgroup_uses_map = Self::build_sgroup_uses_map(&sgroups); + // Build conflict graph and get coloring. + let mut conflict_graph: GraphColoring = + GraphColoring::from(sgroups.iter().map(|g| g.borrow().name())); + Self::add_par_conflicts( + &comp.control.borrow(), + &sgroup_uses_map, + &mut conflict_graph, + ); + Self::add_go_port_conflicts(&sgroup_uses_map, &mut conflict_graph); + let coloring = conflict_graph.color_greedy(None, true); let mut builder = ir::Builder::new(comp, sigs); + // build Mappings of fsm names -> set of groups that it can handle. + let fsm_mappings = + Self::build_fsm_mapping(coloring, &sgroups, &mut builder); + let mut groups_to_fsms = HashMap::new(); + // "Reverses" fsm_mappings to map group names -> fsm cells + for (fsm_name, group_names) in fsm_mappings { + let fsm = builder.component.find_guaranteed_cell(fsm_name); + for group_name in group_names { + groups_to_fsms.insert(group_name, Rc::clone(&fsm)); + } + } + // create "early reset" dynamic groups that never reach set their done hole for sgroup in sgroups.iter() { let mut sgroup_ref = sgroup.borrow_mut(); @@ -345,6 +665,9 @@ impl Visitor for CompileStatic { sgroup_name, sgroup_latency, sgroup_attributes, + Rc::clone(groups_to_fsms.get(&sgroup_name).unwrap_or_else( + || unreachable!("{sgroup_name} has no corresponding fsm"), + )), &mut builder, ); // map the static group name -> early reset group name @@ -362,7 +685,7 @@ impl Visitor for CompileStatic { } // rewrite static_group[go] to early_reset_group[go] - // don't have to worrry about writing static_group[done] b/c static + // don't have to worry about writing static_group[done] b/c static // groups don't have done holes. comp.for_each_assignment(|assign| { assign.for_each_port(|port| { @@ -398,7 +721,7 @@ impl Visitor for CompileStatic { let early_reset_name = self.reset_early_map.get(&sgroup_name).unwrap_or_else(|| { unreachable!( - "group {} early reset wrapper has not been created", + "group {} early reset has not been created", sgroup_name ) }); @@ -409,12 +732,47 @@ impl Visitor for CompileStatic { // create the builder/cells that we need to create wrapper group let mut builder = ir::Builder::new(comp, sigs); let (fsm_name, fsm_width )= self.fsm_info_map.get(early_reset_name).unwrap_or_else(|| unreachable!("group {} has no correspondoing fsm in self.fsm_map", early_reset_name)); - let wrapper = Self::build_wrapper_group( - fsm_name, - *fsm_width, - early_reset_name, - &mut builder, - ); + // If we've already made a wrapper for a group that uses the same + // FSM, we can reuse the signal_reg. Otherwise, we must + // instantiate a new signal_reg. + let wrapper = match self.signal_reg_map.get(fsm_name) { + None => { + // Need to build the signal_reg and the continuous + // assignment that resets the signal_reg + structure!( builder; + let signal_reg = prim std_reg(1); + ); + self.signal_reg_map + .insert(*fsm_name, signal_reg.borrow().name()); + Self::build_wrapper_group( + fsm_name, + *fsm_width, + early_reset_name, + signal_reg, + &mut builder, + true, + ) + } + Some(reg_name) => { + // Already_built the signal_reg. + // We don't need to add continuous assignments + // that resets signal_reg. + let signal_reg = builder + .component + .find_cell(*reg_name) + .unwrap_or_else(|| { + unreachable!("signal reg {reg_name} found") + }); + Self::build_wrapper_group( + fsm_name, + *fsm_width, + early_reset_name, + signal_reg, + &mut builder, + false, + ) + } + }; self.wrapper_map .insert(*early_reset_name, wrapper.borrow().name()); wrapper @@ -444,7 +802,6 @@ impl Visitor for CompileStatic { /// } /// ... /// } - /// control { /// while l.out { /// A; @@ -479,7 +836,7 @@ impl Visitor for CompileStatic { let mut builder = ir::Builder::new(comp, sigs); let reset_group_name = self.get_reset_group_name(sc); - // get fsm for reset_group + // Get fsm for reset_group let (fsm, fsm_width) = self.fsm_info_map.get(reset_group_name).unwrap_or_else(|| unreachable!("group {} has no correspondoing fsm in self.fsm_map", reset_group_name)); let wrapper_group = self.build_wrapper_group_while( fsm, diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index e3cd96fdb..b90294a1e 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -17,14 +17,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @data mult_pipe0 = std_mult_pipe(32); @external @data v0 = std_mem_d1(32, 1, 1); @generated comb_reg = std_reg(1); - @generated fsm = std_reg(1); + @generated fsm = std_reg(4); @generated ud = undef(1); - @generated adder = std_add(1); - @generated fsm7 = std_reg(4); - @generated ud7 = undef(1); - @generated adder7 = std_add(4); + @generated adder = std_add(4); + @generated ud0 = undef(1); + @generated adder0 = std_add(4); @generated signal_reg = std_reg(1); - @generated fsm9 = std_reg(2); + @generated fsm0 = std_reg(2); @generated invoke0_go = std_wire(1); @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @@ -39,86 +38,82 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm7.out == 4'd7 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm7.out == 4'd7 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 4'd7 & early_reset_static_seq_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm7.out == 4'd7 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm7.out == 4'd7 & early_reset_static_seq_go.out ? const3.out; + add1.left = fsm.out == 4'd7 & early_reset_static_seq_go.out ? i0.out; + add1.right = fsm.out == 4'd7 & early_reset_static_seq_go.out ? const3.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; - fsm.in = fsm.out != 1'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out == 1'd0 & early_reset_cond00_go.out ? 1'd0; + fsm.in = fsm.out != 4'd0 & early_reset_cond00_go.out ? adder.out; + fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 4'd0; + fsm.in = fsm.out != 4'd8 & early_reset_static_seq_go.out ? adder0.out; adder.left = early_reset_cond00_go.out ? fsm.out; - adder.right = early_reset_cond00_go.out ? 1'd1; - add0.left = fsm7.out == 4'd6 & early_reset_static_seq_go.out ? v0.read_data; - add0.right = fsm7.out == 4'd6 & early_reset_static_seq_go.out ? B_read0_0.out; - v0.write_en = fsm7.out == 4'd6 & early_reset_static_seq_go.out ? 1'd1; + adder.right = early_reset_cond00_go.out ? 4'd1; + add0.left = fsm.out == 4'd6 & early_reset_static_seq_go.out ? v0.read_data; + add0.right = fsm.out == 4'd6 & early_reset_static_seq_go.out ? B_read0_0.out; + v0.write_en = fsm.out == 4'd6 & early_reset_static_seq_go.out ? 1'd1; v0.clk = clk; - v0.addr0 = fsm7.out == 4'd6 & early_reset_static_seq_go.out ? const2.out; + v0.addr0 = fsm.out == 4'd6 & early_reset_static_seq_go.out ? const2.out; v0.reset = reset; - v0.write_data = fsm7.out == 4'd6 & early_reset_static_seq_go.out ? add0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm7.out == 4'd8 & early_reset_static_seq_go.out ? 1'd1; + v0.write_data = fsm.out == 4'd6 & early_reset_static_seq_go.out ? add0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm7.out == 4'd8 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - fsm9.write_en = fsm9.out == 2'd3 | fsm9.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm9.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm9.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; - fsm9.clk = clk; - fsm9.reset = reset; - fsm9.in = fsm9.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; - fsm9.in = fsm9.out == 2'd3 ? 2'd0; - fsm9.in = fsm9.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; - fsm9.in = fsm9.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm9.out == 2'd2 & tdcc_go.out ? 1'd1; - fsm7.write_en = early_reset_static_seq_go.out ? 1'd1; - fsm7.clk = clk; - fsm7.reset = reset; - fsm7.in = fsm7.out == 4'd8 & early_reset_static_seq_go.out ? 4'd0; - fsm7.in = fsm7.out != 4'd8 & early_reset_static_seq_go.out ? adder7.out; - invoke0_go.in = !invoke0_done.out & fsm9.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm7.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; A0.reset = reset; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + fsm0.clk = clk; + fsm0.reset = reset; + fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; + fsm0.in = fsm0.out == 2'd3 ? 2'd0; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; mult_pipe0.clk = clk; - mult_pipe0.left = fsm7.out >= 4'd1 & fsm7.out < 4'd4 & early_reset_static_seq_go.out ? A_read0_0.out; - mult_pipe0.go = fsm7.out >= 4'd1 & fsm7.out < 4'd4 & early_reset_static_seq_go.out ? 1'd1; + mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? A_read0_0.out; + mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? 1'd1; mult_pipe0.reset = reset; - mult_pipe0.right = fsm7.out >= 4'd1 & fsm7.out < 4'd4 & early_reset_static_seq_go.out ? B_read0_0.out; + mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? B_read0_0.out; + adder0.left = early_reset_static_seq_go.out ? fsm.out; + adder0.right = early_reset_static_seq_go.out ? 4'd1; invoke0_done.in = i0.done; early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm7.out == 4'd8 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm7.out == 4'd8 & early_reset_static_seq_go.out ? const1.out; - signal_reg.write_en = fsm.out == 1'd0 & signal_reg.out | fsm.out == 1'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; + le0.left = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? const1.out; + signal_reg.write_en = fsm.out == 4'd0 & signal_reg.out | fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm.out == 1'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; - signal_reg.in = fsm.out == 1'd0 & signal_reg.out ? 1'd0; + signal_reg.in = fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; + signal_reg.in = fsm.out == 4'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm7.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = (fsm7.out == 4'd0 | fsm7.out == 4'd5) & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5) & early_reset_static_seq_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm7.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; - B_read0_0.in = fsm7.out == 4'd5 & early_reset_static_seq_go.out ? A_read0_0.out; - wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm9.out == 2'd1 & tdcc_go.out ? 1'd1; - wrapper_early_reset_cond00_done.in = fsm.out == 1'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud7.out; - tdcc_done.in = fsm9.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm7.out == 4'd0 ? 1'd1; - A_read0_0.write_en = (fsm7.out == 4'd0 | fsm7.out == 4'd4) & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 4'd5 & early_reset_static_seq_go.out ? A_read0_0.out; + wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; + wrapper_early_reset_cond00_done.in = fsm.out == 4'd0 & signal_reg.out ? 1'd1; + early_reset_static_seq_done.in = ud0.out; + tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; + while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; + A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4) & early_reset_static_seq_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm7.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; - A_read0_0.in = fsm7.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; - adder7.left = early_reset_static_seq_go.out ? fsm7.out; - adder7.right = early_reset_static_seq_go.out ? 4'd1; + A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; } control {} } diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 316dd1b3f..4f61bc431 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -2,9 +2,9 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @generated fsm2 = std_reg(3); - @generated ud2 = undef(1); - @generated adder2 = std_add(3); + @generated fsm = std_reg(3); + @generated ud = undef(1); + @generated adder = std_add(3); @generated signal_reg = std_reg(1); @generated early_reset_static_seq_go = std_wire(1); @generated early_reset_static_seq_done = std_wire(1); @@ -13,21 +13,21 @@ static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } wires { done = wrapper_early_reset_static_seq_done.out ? 1'd1; - fsm2.write_en = early_reset_static_seq_go.out ? 1'd1; - fsm2.clk = clk; - fsm2.reset = reset; - fsm2.in = fsm2.out != 3'd4 & early_reset_static_seq_go.out ? adder2.out; - fsm2.in = fsm2.out == 3'd4 & early_reset_static_seq_go.out ? 3'd0; - adder2.left = early_reset_static_seq_go.out ? fsm2.out; - adder2.right = early_reset_static_seq_go.out ? 3'd1; - wrapper_early_reset_static_seq_done.in = fsm2.out == 3'd0 & signal_reg.out ? 1'd1; + fsm.write_en = early_reset_static_seq_go.out ? 1'd1; + fsm.clk = clk; + fsm.reset = reset; + fsm.in = fsm.out != 3'd4 & early_reset_static_seq_go.out ? adder.out; + fsm.in = fsm.out == 3'd4 & early_reset_static_seq_go.out ? 3'd0; + adder.left = early_reset_static_seq_go.out ? fsm.out; + adder.right = early_reset_static_seq_go.out ? 3'd1; + wrapper_early_reset_static_seq_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; early_reset_static_seq_go.in = wrapper_early_reset_static_seq_go.out ? 1'd1; - signal_reg.write_en = fsm2.out == 3'd0 & signal_reg.out | fsm2.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm2.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; - signal_reg.in = fsm2.out == 3'd0 & signal_reg.out ? 1'd0; - early_reset_static_seq_done.in = ud2.out; + signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; + early_reset_static_seq_done.in = ud.out; wrapper_early_reset_static_seq_go.in = go; } control {} diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index b18b1ed14..005c8bc0f 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -14,14 +14,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @data i0 = std_reg(4); @control le0 = std_le(4); @generated comb_reg = std_reg(1); - @generated fsm = std_reg(1); + @generated fsm = std_reg(3); @generated ud = undef(1); - @generated adder = std_add(1); - @generated fsm4 = std_reg(3); - @generated ud4 = undef(1); - @generated adder4 = std_add(3); + @generated adder = std_add(3); + @generated ud0 = undef(1); + @generated adder0 = std_add(3); @generated signal_reg = std_reg(1); - @generated fsm6 = std_reg(2); + @generated fsm0 = std_reg(2); @generated invoke0_go = std_wire(1); @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @@ -36,79 +35,75 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm4.out == 3'd2 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_seq_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm4.out == 3'd2 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 3'd2 & early_reset_static_seq_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm4.out == 3'd2 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm4.out == 3'd2 & early_reset_static_seq_go.out ? const2.out; + add1.left = fsm.out == 3'd2 & early_reset_static_seq_go.out ? i0.out; + add1.right = fsm.out == 3'd2 & early_reset_static_seq_go.out ? const2.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; - fsm.in = fsm.out != 1'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out == 1'd0 & early_reset_cond00_go.out ? 1'd0; + fsm.in = fsm.out != 3'd0 & early_reset_cond00_go.out ? adder.out; + fsm.in = fsm.out != 3'd3 & early_reset_static_seq_go.out ? adder0.out; + fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 3'd0; adder.left = early_reset_cond00_go.out ? fsm.out; - adder.right = early_reset_cond00_go.out ? 1'd1; - fsm6.write_en = fsm6.out == 2'd3 | fsm6.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm6.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm6.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; - fsm6.clk = clk; - fsm6.reset = reset; - fsm6.in = fsm6.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; - fsm6.in = fsm6.out == 2'd3 ? 2'd0; - fsm6.in = fsm6.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; - fsm6.in = fsm6.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; - add0.left = fsm4.out == 3'd1 & early_reset_static_seq_go.out ? A_read0_0.out; - add0.right = fsm4.out == 3'd1 & early_reset_static_seq_go.out ? B_read0_0.out; - adder4.left = early_reset_static_seq_go.out ? fsm4.out; - adder4.right = early_reset_static_seq_go.out ? 3'd1; - comb_reg.write_en = early_reset_cond00_go.out | fsm4.out == 3'd3 & early_reset_static_seq_go.out ? 1'd1; + adder.right = early_reset_cond00_go.out ? 3'd1; + add0.left = fsm.out == 3'd1 & early_reset_static_seq_go.out ? A_read0_0.out; + add0.right = fsm.out == 3'd1 & early_reset_static_seq_go.out ? B_read0_0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm4.out == 3'd3 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - fsm4.write_en = early_reset_static_seq_go.out ? 1'd1; - fsm4.clk = clk; - fsm4.reset = reset; - fsm4.in = fsm4.out != 3'd3 & early_reset_static_seq_go.out ? adder4.out; - fsm4.in = fsm4.out == 3'd3 & early_reset_static_seq_go.out ? 3'd0; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm6.out == 2'd2 & tdcc_go.out ? 1'd1; - invoke0_go.in = !invoke0_done.out & fsm6.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; A0.reset = reset; - Sum0.write_en = fsm4.out == 3'd1 & early_reset_static_seq_go.out ? 1'd1; + Sum0.write_en = fsm.out == 3'd1 & early_reset_static_seq_go.out ? 1'd1; Sum0.clk = clk; - Sum0.addr0 = fsm4.out == 3'd1 & early_reset_static_seq_go.out ? i0.out; + Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_seq_go.out ? i0.out; Sum0.reset = reset; - Sum0.write_data = fsm4.out == 3'd1 & early_reset_static_seq_go.out ? add0.out; + Sum0.write_data = fsm.out == 3'd1 & early_reset_static_seq_go.out ? add0.out; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + fsm0.clk = clk; + fsm0.reset = reset; + fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; + fsm0.in = fsm0.out == 2'd3 ? 2'd0; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; + adder0.left = early_reset_static_seq_go.out ? fsm.out; + adder0.right = early_reset_static_seq_go.out ? 3'd1; invoke0_done.in = i0.done; early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm4.out == 3'd3 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm4.out == 3'd3 & early_reset_static_seq_go.out ? const1.out; - signal_reg.write_en = fsm.out == 1'd0 & signal_reg.out | fsm.out == 1'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; + le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? const1.out; + signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm.out == 1'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; - signal_reg.in = fsm.out == 1'd0 & signal_reg.out ? 1'd0; + signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; + signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? B0.read_data; - wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm6.out == 2'd1 & tdcc_go.out ? 1'd1; - wrapper_early_reset_cond00_done.in = fsm.out == 1'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud4.out; - tdcc_done.in = fsm6.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm4.out == 3'd0 ? 1'd1; - A_read0_0.write_en = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? B0.read_data; + wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; + wrapper_early_reset_cond00_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; + early_reset_static_seq_done.in = ud0.out; + tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; + while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; + A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm4.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; } control {} } diff --git a/runt.toml b/runt.toml index aebc5191b..063b399a4 100644 --- a/runt.toml +++ b/runt.toml @@ -233,9 +233,9 @@ fud exec --from calyx --to jq \ """ [[tests]] -name = "dynamic repeat correctness test" +name = "correctness test of static islands without static promotion" paths = [ - "tests/correctness/repeat/*.futil", + "tests/correctness/static-islands/*.futil", ] cmd = """ fud exec --from calyx --to jq \ diff --git a/tests/correctness/static-islands/par-static-islands.expect b/tests/correctness/static-islands/par-static-islands.expect new file mode 100644 index 000000000..5c36f52b9 --- /dev/null +++ b/tests/correctness/static-islands/par-static-islands.expect @@ -0,0 +1,5 @@ +{ + "m": [ + 150 + ] +} diff --git a/tests/correctness/static-islands/par-static-islands.futil b/tests/correctness/static-islands/par-static-islands.futil new file mode 100644 index 000000000..90d5bdba4 --- /dev/null +++ b/tests/correctness/static-islands/par-static-islands.futil @@ -0,0 +1,47 @@ +import "primitives/core.futil"; + +component main() -> () { + cells { + @external m = std_mem_d1(32, 1, 1); + r1 = std_reg(32); + r2 = std_reg(32); + add1 = std_add(32); + add2 = std_add(32); + add = std_add(32); + } + wires { + static<1> group add_five_r1 { + add1.left = r1.out; + add1.right = 32'd5; + r1.in = add1.out; + r1.write_en = 1'd1; + } + static<1> group add_five_r2 { + add2.left = r2.out; + add2.right = 32'd5; + r2.in = add2.out; + r2.write_en = 1'd1; + } + group write_mem { + m.addr0 = 1'd0; + add.left = r1.out; + add.right = r2.out; + m.write_data = add.out; + m.write_en = 1'd1; + write_mem[done] = m.done; + } + } + control { + seq { + par { + static repeat 15 { + add_five_r1; + } + static repeat 15 { + add_five_r2; + } + } + write_mem; + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-islands/par-static-islands.futil.data b/tests/correctness/static-islands/par-static-islands.futil.data new file mode 100644 index 000000000..e2e250183 --- /dev/null +++ b/tests/correctness/static-islands/par-static-islands.futil.data @@ -0,0 +1,12 @@ +{ + "m": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/repeat/seq-mem-dot-product.expect b/tests/correctness/static-islands/seq-mem-dot-product.expect similarity index 100% rename from tests/correctness/repeat/seq-mem-dot-product.expect rename to tests/correctness/static-islands/seq-mem-dot-product.expect diff --git a/tests/correctness/repeat/seq-mem-dot-product.futil b/tests/correctness/static-islands/seq-mem-dot-product.futil similarity index 100% rename from tests/correctness/repeat/seq-mem-dot-product.futil rename to tests/correctness/static-islands/seq-mem-dot-product.futil diff --git a/tests/correctness/repeat/seq-mem-dot-product.futil.data b/tests/correctness/static-islands/seq-mem-dot-product.futil.data similarity index 100% rename from tests/correctness/repeat/seq-mem-dot-product.futil.data rename to tests/correctness/static-islands/seq-mem-dot-product.futil.data diff --git a/tests/passes/compile-static/rewrite_group_go.expect b/tests/passes/compile-static/rewrite-group-go.expect similarity index 100% rename from tests/passes/compile-static/rewrite_group_go.expect rename to tests/passes/compile-static/rewrite-group-go.expect index 7ed7158d9..5b44b35b5 100644 --- a/tests/passes/compile-static/rewrite_group_go.expect +++ b/tests/passes/compile-static/rewrite-group-go.expect @@ -6,9 +6,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { b = std_reg(2); c = std_reg(2); @generated fsm = std_reg(2); + @generated fsm0 = std_reg(3); @generated ud = undef(1); @generated adder = std_add(2); - @generated fsm0 = std_reg(3); @generated ud0 = undef(1); @generated adder0 = std_add(3); @generated signal_reg = std_reg(1); diff --git a/tests/passes/compile-static/rewrite_group_go.futil b/tests/passes/compile-static/rewrite-group-go.futil similarity index 100% rename from tests/passes/compile-static/rewrite_group_go.futil rename to tests/passes/compile-static/rewrite-group-go.futil diff --git a/tests/passes/compile-static/rewrite-static-while-nested.expect b/tests/passes/compile-static/rewrite-static-while-nested.expect index 409fa6735..8e8a8d83f 100644 --- a/tests/passes/compile-static/rewrite-static-while-nested.expect +++ b/tests/passes/compile-static/rewrite-static-while-nested.expect @@ -8,13 +8,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r = std_reg(3); l2 = std_lt(3); r_cond = std_reg(1); - @generated fsm = std_reg(1); + @generated fsm = std_reg(2); @generated ud = undef(1); - @generated adder = std_add(1); - @generated fsm0 = std_reg(1); + @generated adder = std_add(2); @generated ud0 = undef(1); - @generated adder0 = std_add(1); - @generated fsm1 = std_reg(2); + @generated adder0 = std_add(2); @generated ud1 = undef(1); @generated adder1 = std_add(2); @generated signal_reg = std_reg(1); @@ -39,47 +37,47 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r_cond.in = l.out; r_cond.write_en = 1'd1; p.addr0 = 1'd0; - adder0.left = fsm0.out; - adder0.right = 1'd1; - fsm0.write_en = 1'd1; - fsm0.in = fsm0.out != 1'd0 ? adder0.out; - fsm0.in = fsm0.out == 1'd0 ? 1'd0; + adder0.left = fsm.out; + adder0.right = 2'd1; + fsm.write_en = 1'd1; + fsm.in = fsm.out != 2'd0 ? adder0.out; + fsm.in = fsm.out == 2'd0 ? 2'd0; early_reset_A2[done] = ud0.out; } group early_reset_static_seq { - incr.left = fsm1.out == 2'd0 ? p.read_data; - incr.right = fsm1.out == 2'd0 ? 3'd1; - p.write_data = fsm1.out == 2'd0 ? incr.out; - p.write_en = fsm1.out == 2'd0 ? 1'd1; - p.addr0 = fsm1.out == 2'd0 ? 1'd0; - l.left = fsm1.out == 2'd1 ? p.read_data; - l.right = fsm1.out == 2'd1 ? 3'd6; - r_cond.in = fsm1.out == 2'd1 ? l.out; - r_cond.write_en = fsm1.out == 2'd1 ? 1'd1; - p.addr0 = fsm1.out == 2'd1 ? 1'd0; - adder1.left = fsm1.out; + incr.left = fsm.out == 2'd0 ? p.read_data; + incr.right = fsm.out == 2'd0 ? 3'd1; + p.write_data = fsm.out == 2'd0 ? incr.out; + p.write_en = fsm.out == 2'd0 ? 1'd1; + p.addr0 = fsm.out == 2'd0 ? 1'd0; + l.left = fsm.out == 2'd1 ? p.read_data; + l.right = fsm.out == 2'd1 ? 3'd6; + r_cond.in = fsm.out == 2'd1 ? l.out; + r_cond.write_en = fsm.out == 2'd1 ? 1'd1; + p.addr0 = fsm.out == 2'd1 ? 1'd0; + adder1.left = fsm.out; adder1.right = 2'd1; - fsm1.write_en = 1'd1; - fsm1.in = fsm1.out != 2'd1 ? adder1.out; - fsm1.in = fsm1.out == 2'd1 ? 2'd0; + fsm.write_en = 1'd1; + fsm.in = fsm.out != 2'd1 ? adder1.out; + fsm.in = fsm.out == 2'd1 ? 2'd0; early_reset_static_seq[done] = ud1.out; } group wrapper_early_reset_A2 { early_reset_A2[go] = 1'd1; - signal_reg.write_en = fsm0.out == 1'd0 & !signal_reg.out ? 1'd1; - signal_reg.in = fsm0.out == 1'd0 & !signal_reg.out ? 1'd1; - wrapper_early_reset_A2[done] = fsm0.out == 1'd0 & signal_reg.out ? 1'd1; + signal_reg.write_en = fsm.out == 2'd0 & !signal_reg.out ? 1'd1; + signal_reg.in = fsm.out == 2'd0 & !signal_reg.out ? 1'd1; + wrapper_early_reset_A2[done] = fsm.out == 2'd0 & signal_reg.out ? 1'd1; } group while_wrapper_early_reset_static_seq { early_reset_static_seq[go] = 1'd1; - while_wrapper_early_reset_static_seq[done] = !r_cond.out & fsm1.out == 2'd0 ? 1'd1; + while_wrapper_early_reset_static_seq[done] = !r_cond.out & fsm.out == 2'd0 ? 1'd1; } comb group comp { l2.left = r.out; l2.right = 3'd3; } - signal_reg.write_en = fsm0.out == 1'd0 & signal_reg.out ? 1'd1; - signal_reg.in = fsm0.out == 1'd0 & signal_reg.out ? 1'd0; + signal_reg.write_en = fsm.out == 2'd0 & signal_reg.out ? 1'd1; + signal_reg.in = fsm.out == 2'd0 & signal_reg.out ? 1'd0; } control { while l2.out with comp { diff --git a/tests/passes/compile-static/rewrite-static-while.expect b/tests/passes/compile-static/rewrite-static-while.expect index 9ddba91f2..00656c54e 100644 --- a/tests/passes/compile-static/rewrite-static-while.expect +++ b/tests/passes/compile-static/rewrite-static-while.expect @@ -6,13 +6,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { incr = std_add(3); l = std_lt(3); r = std_reg(1); - @generated fsm = std_reg(1); + @generated fsm = std_reg(2); @generated ud = undef(1); - @generated adder = std_add(1); - @generated fsm0 = std_reg(1); + @generated adder = std_add(2); @generated ud0 = undef(1); - @generated adder0 = std_add(1); - @generated fsm1 = std_reg(2); + @generated adder0 = std_add(2); @generated ud1 = undef(1); @generated adder1 = std_add(2); @generated signal_reg = std_reg(1); @@ -23,41 +21,41 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { l.right = 3'd6; r.in = l.out; r.write_en = 1'd1; - adder0.left = fsm0.out; - adder0.right = 1'd1; - fsm0.write_en = 1'd1; - fsm0.in = fsm0.out != 1'd0 ? adder0.out; - fsm0.in = fsm0.out == 1'd0 ? 1'd0; + adder0.left = fsm.out; + adder0.right = 2'd1; + fsm.write_en = 1'd1; + fsm.in = fsm.out != 2'd0 ? adder0.out; + fsm.in = fsm.out == 2'd0 ? 2'd0; early_reset_B[done] = ud0.out; } group early_reset_static_seq { - incr.left = fsm1.out == 2'd0 ? p.out; - incr.right = fsm1.out == 2'd0 ? 3'd1; - p.in = fsm1.out == 2'd0 ? incr.out; - p.write_en = fsm1.out == 2'd0 ? 1'd1; - l.left = fsm1.out == 2'd1 ? p.out; - l.right = fsm1.out == 2'd1 ? 3'd6; - r.in = fsm1.out == 2'd1 ? l.out; - r.write_en = fsm1.out == 2'd1 ? 1'd1; - adder1.left = fsm1.out; + incr.left = fsm.out == 2'd0 ? p.out; + incr.right = fsm.out == 2'd0 ? 3'd1; + p.in = fsm.out == 2'd0 ? incr.out; + p.write_en = fsm.out == 2'd0 ? 1'd1; + l.left = fsm.out == 2'd1 ? p.out; + l.right = fsm.out == 2'd1 ? 3'd6; + r.in = fsm.out == 2'd1 ? l.out; + r.write_en = fsm.out == 2'd1 ? 1'd1; + adder1.left = fsm.out; adder1.right = 2'd1; - fsm1.write_en = 1'd1; - fsm1.in = fsm1.out != 2'd1 ? adder1.out; - fsm1.in = fsm1.out == 2'd1 ? 2'd0; + fsm.write_en = 1'd1; + fsm.in = fsm.out != 2'd1 ? adder1.out; + fsm.in = fsm.out == 2'd1 ? 2'd0; early_reset_static_seq[done] = ud1.out; } group wrapper_early_reset_B { early_reset_B[go] = 1'd1; - signal_reg.write_en = fsm0.out == 1'd0 & !signal_reg.out ? 1'd1; - signal_reg.in = fsm0.out == 1'd0 & !signal_reg.out ? 1'd1; - wrapper_early_reset_B[done] = fsm0.out == 1'd0 & signal_reg.out ? 1'd1; + signal_reg.write_en = fsm.out == 2'd0 & !signal_reg.out ? 1'd1; + signal_reg.in = fsm.out == 2'd0 & !signal_reg.out ? 1'd1; + wrapper_early_reset_B[done] = fsm.out == 2'd0 & signal_reg.out ? 1'd1; } group while_wrapper_early_reset_static_seq { early_reset_static_seq[go] = 1'd1; - while_wrapper_early_reset_static_seq[done] = !r.out & fsm1.out == 2'd0 ? 1'd1; + while_wrapper_early_reset_static_seq[done] = !r.out & fsm.out == 2'd0 ? 1'd1; } - signal_reg.write_en = fsm0.out == 1'd0 & signal_reg.out ? 1'd1; - signal_reg.in = fsm0.out == 1'd0 & signal_reg.out ? 1'd0; + signal_reg.write_en = fsm.out == 2'd0 & signal_reg.out ? 1'd1; + signal_reg.in = fsm.out == 2'd0 & signal_reg.out ? 1'd0; } control { seq { diff --git a/tests/passes/compile-static/separate-fsms.expect b/tests/passes/compile-static/separate-fsms.expect new file mode 100644 index 000000000..fed018914 --- /dev/null +++ b/tests/passes/compile-static/separate-fsms.expect @@ -0,0 +1,113 @@ +import "primitives/core.futil"; +import "primitives/pipelined.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + d = std_reg(2); + @generated fsm = std_reg(1); + @generated fsm0 = std_reg(1); + @generated fsm1 = std_reg(1); + @generated fsm2 = std_reg(1); + @generated fsm3 = std_reg(3); + @generated ud = undef(1); + @generated adder = std_add(1); + @generated ud0 = undef(1); + @generated adder0 = std_add(1); + @generated ud1 = undef(1); + @generated adder1 = std_add(1); + @generated ud2 = undef(1); + @generated adder2 = std_add(1); + @generated ud3 = undef(1); + @generated adder3 = std_add(3); + @generated signal_reg = std_reg(1); + @generated signal_reg0 = std_reg(1); + @generated signal_reg1 = std_reg(1); + } + wires { + group early_reset_B { + b.in = 2'd0; + b.write_en = fsm2.out == 1'd0 ? 1'd1; + adder.left = fsm2.out; + adder.right = 1'd1; + fsm2.write_en = 1'd1; + fsm2.in = fsm2.out != 1'd0 ? adder.out; + fsm2.in = fsm2.out == 1'd0 ? 1'd0; + early_reset_B[done] = ud.out; + } + group early_reset_C { + c.in = 2'd0; + c.write_en = fsm0.out == 1'd0 ? 1'd1; + adder0.left = fsm0.out; + adder0.right = 1'd1; + fsm0.write_en = 1'd1; + fsm0.in = fsm0.out != 1'd0 ? adder0.out; + fsm0.in = fsm0.out == 1'd0 ? 1'd0; + early_reset_C[done] = ud0.out; + } + group early_reset_A { + a.in = 2'd0; + a.write_en = fsm.out == 1'd0 ? 1'd1; + adder1.left = fsm.out; + adder1.right = 1'd1; + fsm.write_en = 1'd1; + fsm.in = fsm.out != 1'd0 ? adder1.out; + fsm.in = fsm.out == 1'd0 ? 1'd0; + early_reset_A[done] = ud1.out; + } + group early_reset_D { + d.in = 2'd0; + d.write_en = fsm1.out == 1'd0 ? 1'd1; + adder2.left = fsm1.out; + adder2.right = 1'd1; + fsm1.write_en = 1'd1; + fsm1.in = fsm1.out != 1'd0 ? adder2.out; + fsm1.in = fsm1.out == 1'd0 ? 1'd0; + early_reset_D[done] = ud2.out; + } + group early_reset_run_A_and_D { + early_reset_A[go] = fsm3.out < 3'd4 ? 1'd1; + early_reset_D[go] = fsm3.out >= 3'd4 & fsm3.out < 3'd6 ? 1'd1; + adder3.left = fsm3.out; + adder3.right = 3'd1; + fsm3.write_en = 1'd1; + fsm3.in = fsm3.out != 3'd5 ? adder3.out; + fsm3.in = fsm3.out == 3'd5 ? 3'd0; + early_reset_run_A_and_D[done] = ud3.out; + } + group wrapper_early_reset_run_A_and_D { + early_reset_run_A_and_D[go] = 1'd1; + signal_reg.write_en = fsm3.out == 3'd0 & !signal_reg.out ? 1'd1; + signal_reg.in = fsm3.out == 3'd0 & !signal_reg.out ? 1'd1; + wrapper_early_reset_run_A_and_D[done] = fsm3.out == 3'd0 & signal_reg.out ? 1'd1; + } + group wrapper_early_reset_B { + early_reset_B[go] = 1'd1; + signal_reg0.write_en = fsm2.out == 1'd0 & !signal_reg0.out ? 1'd1; + signal_reg0.in = fsm2.out == 1'd0 & !signal_reg0.out ? 1'd1; + wrapper_early_reset_B[done] = fsm2.out == 1'd0 & signal_reg0.out ? 1'd1; + } + group wrapper_early_reset_C { + early_reset_C[go] = 1'd1; + signal_reg1.write_en = fsm0.out == 1'd0 & !signal_reg1.out ? 1'd1; + signal_reg1.in = fsm0.out == 1'd0 & !signal_reg1.out ? 1'd1; + wrapper_early_reset_C[done] = fsm0.out == 1'd0 & signal_reg1.out ? 1'd1; + } + signal_reg.write_en = fsm3.out == 3'd0 & signal_reg.out ? 1'd1; + signal_reg.in = fsm3.out == 3'd0 & signal_reg.out ? 1'd0; + signal_reg0.write_en = fsm2.out == 1'd0 & signal_reg0.out ? 1'd1; + signal_reg0.in = fsm2.out == 1'd0 & signal_reg0.out ? 1'd0; + signal_reg1.write_en = fsm0.out == 1'd0 & signal_reg1.out ? 1'd1; + signal_reg1.in = fsm0.out == 1'd0 & signal_reg1.out ? 1'd0; + } + control { + par { + par { + wrapper_early_reset_run_A_and_D; + wrapper_early_reset_B; + } + wrapper_early_reset_C; + } + } +} diff --git a/tests/passes/compile-static/separate-fsms.futil b/tests/passes/compile-static/separate-fsms.futil new file mode 100644 index 000000000..9a7dc0f00 --- /dev/null +++ b/tests/passes/compile-static/separate-fsms.futil @@ -0,0 +1,45 @@ +// -p well-formed -p compile-static -p dead-group-removal -p remove-ids + +// Test that we need separate FSMS: a) across par blocks and b) when a group +// triggers the "go" hole of another group +import "primitives/core.futil"; +import "primitives/pipelined.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + d = std_reg(2); + } + + wires { + static<1> group B{ + b.in = 2'd0; + b.write_en = %0 ? 1'd1; + } + static<1> group C{ + c.in = 2'd0; + c.write_en = %0 ? 1'd1; + } + static<1> group A{ + a.in = 2'd0; + a.write_en = %0 ? 1'd1; + } + static<1> group D{ + d.in = 2'd0; + d.write_en = %0 ? 1'd1; + } + static<6> group run_A_and_D{ + A[go] = %[0:4] ? 1'd1; + D[go] = %[4:6] ? 1'd1; + } + } + + control { + par { + par {run_A_and_D; B;} + C; + } + } +} \ No newline at end of file From 898e2279c46d42c018b06ab89f3ae1660a66422d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 31 Jul 2023 18:39:50 -0400 Subject: [PATCH 011/189] locked build for playground --- .github/workflows/playground.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 48a2a5cfc..b073f786d 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -29,7 +29,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: install - args: --version 0.2.80 -f wasm-bindgen-cli + args: --version 0.2.80 -f wasm-bindgen-cli --locked - run: yarn working-directory: ./web - run: yarn build From 643f468b570cc4ad2cd049a3822025aeb57eac5a Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 31 Jul 2023 18:56:45 -0400 Subject: [PATCH 012/189] locked build for playground --- .github/workflows/playground.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index b073f786d..f5505d191 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -23,7 +23,7 @@ jobs: - name: Install wasm-pack uses: actions-rs/cargo@v1 with: - command: install + command: install --locked args: wasm-pack - name: Install wasm-bindgen-cli uses: actions-rs/cargo@v1 From 748474caa4de5f9336d05085a9e4e48dc46c321d Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 31 Jul 2023 18:58:41 -0400 Subject: [PATCH 013/189] locked build for playground --- .github/workflows/playground.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index f5505d191..5f2a26b2a 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -23,8 +23,8 @@ jobs: - name: Install wasm-pack uses: actions-rs/cargo@v1 with: - command: install --locked - args: wasm-pack + command: install + args: wasm-pack --locked - name: Install wasm-bindgen-cli uses: actions-rs/cargo@v1 with: From 4e8751d306268c8a8211ca3fa100e9d4be3f424e Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:38:09 -0400 Subject: [PATCH 014/189] FIFO: catch up to new interface, and expose command `peek` (#1643) --- calyx-py/calyx/builder_util.py | 126 +++++++++- calyx-py/test/correctness/fifo.py | 380 ++++++++++++------------------ 2 files changed, 275 insertions(+), 231 deletions(-) diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py index 927c49b73..14c961a06 100644 --- a/calyx-py/calyx/builder_util.py +++ b/calyx-py/calyx/builder_util.py @@ -29,6 +29,22 @@ def insert_eq(comp: cb.ComponentBuilder, left, right, cellname, width): return insert_comb_group(comp, left, right, eq_cell, f"{cellname}_group") +def insert_neq(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to check if {left} != {right}. + + = std_neq(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + neq_cell = comp.neq(cellname, width) + return insert_comb_group(comp, left, right, neq_cell, f"{cellname}_group") + + def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): """Inserts wiring into component {comp} to check if {left} < {right}. @@ -45,6 +61,22 @@ def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): return insert_comb_group(comp, left, right, lt_cell, f"{cellname}_group") +def insert_gt(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to check if {left} > {right}. + + = std_gt(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + gt_cell = comp.gt(cellname, width) + return insert_comb_group(comp, left, right, gt_cell, f"{cellname}_group") + + def insert_add(comp: cb.ComponentBuilder, left, right, cellname, width): """Inserts wiring into component {comp} to compute {left} + {right}. @@ -113,19 +145,109 @@ def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): return decr_group +def mem_load(comp: cb.ComponentBuilder, mem, i, reg, group): + """Loads a value from one memory into a register. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from memory {mem} at address {i}. + 3. Writes the value into register {reg}. + 4. Returns the group that does this. + """ + with comp.group(group) as load_grp: + mem.addr0 = i + reg.write_en = 1 + reg.in_ = mem.read_data + load_grp.done = reg.done + return load_grp + + +def mem_store(comp: cb.ComponentBuilder, mem, i, val, group): + """Stores a value from one memory into another. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from {val}. + 3. Writes the value into memory {mem} at address i. + 4. Returns the group that does this. + """ + with comp.group(group) as store_grp: + mem.addr0 = i + mem.write_en = 1 + mem.write_data = val + store_grp.done = mem.done + return store_grp + + def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): """Stores a value in a register. 1. Within component {comp}, creates a group called {group}. 2. Within {group}, sets the register {reg} to {val}. 3. Returns the group that does this. """ - with comp.group(group) as store_grp: + with comp.group(group) as reg_grp: reg.in_ = val reg.write_en = 1 - store_grp.done = reg.done + reg_grp.done = reg.done + return reg_grp + + +def mem_read_seqd1(comp: cb.ComponentBuilder, mem, i, group): + """Given a seq_mem_d1, reads from memory at address i. + Note that this does not write the value anywhere. + """ + assert mem.is_seq_mem_d1 + with comp.group(group) as read_grp: + mem.addr0 = i + mem.read_en = 1 + read_grp.done = mem.read_done + return read_grp + + +def mem_write_seqd1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): + """Given a seq_mem_d1 that is already assumed to have a latched value, + reads the latched value and writes it to a register. + """ + assert mem.is_seq_mem_d1 + with comp.group(group) as write_grp: + reg.write_en = 1 + reg.in_ = mem.read_data + write_grp.done = reg.done + return write_grp + + +def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): + """Stores a value from one memory into another. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from {val}. + 3. Writes the value into memory {mem} at address i. + 4. Returns the group that does this. + """ + assert mem.is_seq_mem_d1 + with comp.group(group) as store_grp: + mem.addr0 = i + mem.write_en = 1 + mem.write_data = val + store_grp.done = mem.write_done return store_grp +def reg_swap(comp: cb.ComponentBuilder, a, b, group): + """Swaps the values of two registers. + 1. Within component {comp}, creates a group called {group}. + 2. Reads the value of {a} into a temporary register. + 3. Writes the value of {b} into {a}. + 4. Writes the value of the temporary register into {b}. + 5. Returns the group that does this. + """ + with comp.group(group) as swap_grp: + tmp = comp.reg("tmp", 1) + tmp.write_en = 1 + tmp.in_ = a.out + a.write_en = 1 + a.in_ = b.out + b.write_en = 1 + b.in_ = tmp.out + swap_grp.done = b.done + return swap_grp + + def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): """Loads a value from one std_mem_d1 memory into another. 1. Within component {comp}, creates a group called {group}. diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index 6be12caca..fd01e5049 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -1,108 +1,6 @@ # pylint: disable=import-error import calyx.builder as cb - - -def insert_eq(comp: cb.ComponentBuilder, a, b, cell, width): - """Inserts wiring into component {comp} to check if {a} == {b}. - 1. Within {comp}, creates a combinational group called {cell}_group. - 2. Within the group, creates a {cell} that checks equalities of {width}. - 3. Puts the values {a} and {b} into {cell}. - 4. Returns the equality-checking cell and the overall group. - """ - eq_cell = comp.eq(cell, width) - with comp.comb_group(f"{cell}_group") as eq_group: - eq_cell.left = a - eq_cell.right = b - return eq_cell, eq_group - - -def insert_incr(comp: cb.ComponentBuilder, reg, cell, group): - """Inserts wiring into component {comp} to increment {reg} by 1. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, adds a cell {cell} that computes sums. - 3. Puts the values of {port} and 1 into {cell}. - 4. Then puts the answer of the computation back into {port}. - 4. Returns the group that does this. - """ - incr_cell = comp.add(cell, 32) - with comp.group(group) as incr_group: - incr_cell.left = reg.out - incr_cell.right = 1 - reg.write_en = 1 - reg.in_ = incr_cell.out - incr_group.done = reg.done - return incr_group - - -def insert_decr(comp: cb.ComponentBuilder, reg, cell, group): - """Inserts wiring into component {comp} to decrement {reg} by 1. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, adds a cell {cell} that computes differences. - 3. Puts the values of {port} and 1 into {cell}. - 4. Then puts the answer of the computation back into {port}. - 4. Returns the group that does this. - """ - decr_cell = comp.sub(cell, 32) - with comp.group(group) as decr_group: - decr_cell.left = reg.out - decr_cell.right = cb.const(32, 1) - reg.write_en = 1 - reg.in_ = decr_cell.out - decr_group.done = reg.done - return decr_group - - -def mem_read_seqd1(comp: cb.ComponentBuilder, mem, i, group): - """Given a seq_mem_d1, reads from memory at address i. - Note that this does not write the value anywhere. - """ - assert mem.is_seq_mem_d1 - with comp.group(group) as read_grp: - mem.addr0 = i - mem.read_en = 1 - read_grp.done = mem.read_done - return read_grp - - -def mem_write_seqd1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): - """Given a seq_mem_d1 that is already assumed to have a latched value, - reads the latched value and writes it to a register. - """ - assert mem.is_seq_mem_d1 - with comp.group(group) as write_grp: - reg.write_en = 1 - reg.in_ = mem.read_data - write_grp.done = reg.done - return write_grp - - -def mem_store(comp: cb.ComponentBuilder, mem, i, val, group): - """Stores a value from one memory into another. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from {val}. - 3. Writes the value into memory {mem} at address i. - 4. Returns the group that does this. - """ - assert mem.is_seq_mem_d1 - with comp.group(group) as store_grp: - mem.addr0 = i - mem.write_en = 1 - mem.write_data = val - store_grp.done = mem.write_done - return store_grp - - -def reg_store(comp: cb.ComponentBuilder, reg, val, group): - """Stores a value in a register. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, sets the register {reg} to {val}. - 3. Returns the group that does this. - """ - with comp.group(group) as reg_grp: - reg.in_ = val - reg.write_en = 1 - reg_grp.done = reg.done - return reg_grp +import calyx.builder_util as util def insert_raise_err_if_i_eq_15(prog): @@ -118,8 +16,8 @@ def insert_raise_err_if_i_eq_15(prog): i = raise_err_if_i_eq_15.input("i", 32) err = raise_err_if_i_eq_15.reg("err", 1, is_ref=True) - i_eq_15 = insert_eq(raise_err_if_i_eq_15, i, 15, "i_eq_15", 32) - raise_err = reg_store(raise_err_if_i_eq_15, err, 1, "raise_err") + i_eq_15 = util.insert_eq(raise_err_if_i_eq_15, i, 15, "i_eq_15", 32) + raise_err = util.insert_reg_store(raise_err_if_i_eq_15, err, 1, "raise_err") raise_err_if_i_eq_15.control += [ cb.if_( @@ -132,20 +30,19 @@ def insert_raise_err_if_i_eq_15(prog): return raise_err_if_i_eq_15 -def insert_fifo(prog): +def insert_fifo(prog, name): """Inserts the component `fifo` into the program. It has: - - three inputs, `pop`, `push`, and `payload`. + - one input, `cmd`. - one memory, `mem`, of size 10. - two registers, `next_write` and `next_read`. - three ref registers, `ans`, `err`, and `len`. """ - fifo: cb.ComponentBuilder = prog.component("fifo") - pop = fifo.input("pop", 1) - push = fifo.input("push", 1) - payload = fifo.input("payload", 32) + fifo: cb.ComponentBuilder = prog.component(name) + cmd = fifo.input("cmd", 32) + # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. mem = fifo.seq_mem_d1("mem", 32, 10, 32) @@ -168,116 +65,136 @@ def insert_fifo(prog): len = fifo.reg("len", 32, is_ref=True) # The length of the queue # Cells and groups to compute equality - pop_eq_push = insert_eq(fifo, pop, push, "pop_eq_push", 1) # `pop` == `push` - pop_eq_1 = insert_eq(fifo, pop, 1, "pop_eq_1", 1) # `pop` == 1 - push_eq_1 = insert_eq(fifo, push, 1, "push_eq_1", 1) # `push` == 1 - write_eq_10 = insert_eq(fifo, write.out, 10, "write_eq_10", 32) # `write` == 10 - read_eq_10 = insert_eq(fifo, read.out, 10, "read_eq_10", 32) # `read` == 10 - len_eq_0 = insert_eq(fifo, len.out, 0, "len_eq_0", 32) # `len` == 0 - len_eq_10 = insert_eq(fifo, len.out, 10, "len_eq_10", 32) # `len` == 10 + cmd_eq_0 = util.insert_eq(fifo, cmd, 0, "cmd_eq_0", 32) # `cmd` == 0 + cmd_eq_1 = util.insert_eq(fifo, cmd, 1, "cmd_eq_1", 32) # `cmd` == 1 + cmd_gt_1 = util.insert_gt(fifo, cmd, 1, "cmd_gt_1", 32) # `cmd` > 1 + + write_eq_10 = util.insert_eq( + fifo, write.out, 10, "write_eq_10", 32 + ) # `write` == 10 + read_eq_10 = util.insert_eq(fifo, read.out, 10, "read_eq_10", 32) # `read` == 10 + len_eq_0 = util.insert_eq(fifo, len.out, 0, "len_eq_0", 32) # `len` == 0 + len_eq_10 = util.insert_eq(fifo, len.out, 10, "len_eq_10", 32) # `len` == 10 # Cells and groups to increment read and write registers - write_incr = insert_incr(fifo, write, "add1", "write_incr") # write++ - read_incr = insert_incr(fifo, read, "add2", "read_incr") # read++ - len_incr = insert_incr(fifo, len, "add5", "len_incr") # len++ - len_decr = insert_decr(fifo, len, "add6", "len_decr") # len-- + write_incr = util.insert_incr(fifo, write, "write_incr") # write++ + read_incr = util.insert_incr(fifo, read, "read_incr") # read++ + len_incr = util.insert_incr(fifo, len, "len_incr") # len++ + len_decr = util.insert_decr(fifo, len, "len_decr") # len-- # Cells and groups to modify flags, which are registers - write_wrap = reg_store(fifo, write, 0, "write_wraparound") # zero out `write` - read_wrap = reg_store(fifo, read, 0, "read_wraparound") # zero out `read` - raise_err = reg_store(fifo, err, 1, "raise_err") # set `err` to 1 - zero_out_ans = reg_store(fifo, ans, 0, "zero_out_ans") # zero out `ans` + write_wrap = util.insert_reg_store( + fifo, write, 0, "write_wraparound" + ) # zero out `write` + read_wrap = util.insert_reg_store( + fifo, read, 0, "read_wraparound" + ) # zero out `read` + raise_err = util.insert_reg_store(fifo, err, 1, "raise_err") # set `err` to 1 + zero_out_ans = util.insert_reg_store(fifo, ans, 0, "zero_out_ans") # zero out `ans` # Load and store into an arbitary slot in memory - write_to_mem = mem_store(fifo, mem, write.out, payload, "write_payload_to_mem") - # read_from_mem = mem_load(fifo, mem, read.out, ans, "read_payload_from_mem") - - read_from_mem = mem_read_seqd1(fifo, mem, read.out, "read_payload_from_mem_phase1") - write_to_ans = mem_write_seqd1_to_reg( + write_to_mem = util.mem_store_seq_d1( + fifo, mem, write.out, cmd, "write_payload_to_mem" + ) + read_from_mem = util.mem_read_seqd1( + fifo, mem, read.out, "read_payload_from_mem_phase1" + ) + write_to_ans = util.mem_write_seqd1_to_reg( fifo, mem, ans, "read_payload_from_mem_phase2" ) fifo.control += [ - cb.if_( - pop_eq_push[0].out, - pop_eq_push[1], - # Checking if the user called pop and push at the same time, - # or issued no command. - [ - raise_err, # If so, we're done. - zero_out_ans, # We zero out the answer register. - ], - cb.par( # If not, we continue. + cb.par( + cb.if_( + # Did the user call pop? + cmd_eq_0[0].out, + cmd_eq_0[1], cb.if_( - # Did the user call pop? - pop_eq_1[0].out, - pop_eq_1[1], - cb.if_( - # Yes, the user called pop. But is the queue empty? - len_eq_0[0].out, - len_eq_0[1], - [raise_err, zero_out_ans], # The queue is empty: underflow. - [ # The queue is not empty. Proceed. - read_from_mem, # Read from the queue. - write_to_ans, # Write the answer to the answer register. - read_incr, # Increment the read pointer. - cb.if_( - # Wrap around if necessary. - read_eq_10[0].out, - read_eq_10[1], - read_wrap, - ), - len_decr, # Decrement the length. - ], - ), + # Yes, the user called pop. But is the queue empty? + len_eq_0[0].out, + len_eq_0[1], + [raise_err, zero_out_ans], # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + read_from_mem, # Read from the queue. + write_to_ans, # Write the answer to the answer register. + read_incr, # Increment the read pointer. + cb.if_( + # Wrap around if necessary. + read_eq_10[0].out, + read_eq_10[1], + read_wrap, + ), + len_decr, # Decrement the length. + ], + ), + ), + cb.if_( + # Did the user call peek? + cmd_eq_1[0].out, + cmd_eq_1[1], + cb.if_( # Yes, the user called peek. But is the queue empty? + len_eq_0[0].out, + len_eq_0[1], + [raise_err, zero_out_ans], # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + read_from_mem, # Read from the queue. + write_to_ans, # Write the answer to the answer register. + # But don't increment the read pointer or change the length. + ], ), + ), + cb.if_( + # Did the user call push? + cmd_gt_1[0].out, + cmd_gt_1[1], cb.if_( - # Did the user call push? - push_eq_1[0].out, - push_eq_1[1], - cb.if_( - # Yes, the user called push. But is the queue full? - len_eq_10[0].out, - len_eq_10[1], - [raise_err, zero_out_ans], # The queue is full: overflow. - [ # The queue is not full. Proceed. - write_to_mem, # Write to the queue. - write_incr, # Increment the write pointer. - cb.if_( - # Wrap around if necessary. - write_eq_10[0].out, - write_eq_10[1], - write_wrap, - ), - len_incr, # Increment the length. - ], - ), + # Yes, the user called push. But is the queue full? + len_eq_10[0].out, + len_eq_10[1], + [raise_err, zero_out_ans], # The queue is full: overflow. + [ # The queue is not full. Proceed. + write_to_mem, # Write to the queue. + write_incr, # Increment the write pointer. + cb.if_( + # Wrap around if necessary. + write_eq_10[0].out, + write_eq_10[1], + write_wrap, + ), + len_incr, # Increment the length. + ], ), ), - ) + ), ] return fifo -def insert_main(prog, fifo, raise_err_if_i_eq_15): +def insert_main(prog): """Inserts the component `main` into the program. This will be used to `invoke` the component `fifo`. """ main: cb.ComponentBuilder = prog.component("main") - # The user-facing interface is: + # The user-facing interface of the `main` component is: # - a list of commands (the input) # where each command is a 32-bit unsigned integer, with the following format: # `0`: pop - # any other value: push that value + # `1`: peek + # any value greater than 1: push that value # - a list of answers (the output). commands = main.seq_mem_d1("commands", 32, 15, 32, is_external=True) ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) + # The two components we'll use: + fifo = main.cell("myfifo", insert_fifo(prog, "fifo")) + raise_err_if_i_eq_15 = main.cell( + "raise_err_if_i_eq_15", insert_raise_err_if_i_eq_15(prog) + ) + # We will use the `invoke` method to call the `fifo` component. - fifo = main.cell("myfifo", fifo) - # The fifo component takes two `ref` inputs: + # The fifo component takes three `ref` inputs: err = main.reg("err", 1) # A flag to indicate an error ans = main.reg("ans", 32) # A memory to hold the answer of a pop len = main.reg("len", 32) # A register to hold the len of the queue @@ -285,59 +202,66 @@ def insert_main(prog, fifo, raise_err_if_i_eq_15): # We will set up a while loop that runs over the command list, relaying # the commands to the `fifo` component. # It will run until the `err` flag is raised by the `fifo` component. - raise_err_if_i_eq_15 = main.cell("raise_err_if_i_eq_15", raise_err_if_i_eq_15) i = main.reg("i", 32) # The index of the command we're currently processing j = main.reg("j", 32) # The index on the answer-list we'll write to - command = main.reg("command", 32) # The command we're currently processing - - zero_i = reg_store(main, i, 0, "zero_i") # zero out `i` - zero_j = reg_store(main, j, 0, "zero_j") # zero out `j` - incr_i = insert_incr(main, i, "add3", "incr_i") # i = i + 1 - incr_j = insert_incr(main, j, "add4", "incr_j") # j = j + 1 - err_eq_zero = insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? - read_command = mem_read_seqd1(main, commands, i.out, "read_command_phase1") - write_command_to_reg = mem_write_seqd1_to_reg( - main, commands, command, "write_command_phase2" + cmd = main.reg("command", 32) # The command we're currently processing + + zero_i = util.insert_reg_store(main, i, 0, "zero_i") # zero out `i` + zero_j = util.insert_reg_store(main, j, 0, "zero_j") # zero out `j` + incr_i = util.insert_incr(main, i, "incr_i") # i = i + 1 + incr_j = util.insert_incr(main, j, "incr_j") # j = j + 1 + err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? + cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0 + cmd_neq_0 = util.insert_neq( + main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32 + ) # cmd != 0 + + read_cmd = util.mem_read_seqd1(main, commands, i.out, "read_cmd_phase1") + write_cmd_to_reg = util.mem_write_seqd1_to_reg( + main, commands, cmd, "write_cmd_phase2" ) - command_eq_zero = insert_eq(main, command.out, 0, "command_eq_zero", 32) - write_ans = mem_store(main, ans_mem, j.out, ans.out, "write_ans") + + write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans") main.control += [ zero_i, zero_j, cb.while_( - err_eq_zero[0].out, - err_eq_zero[1], # Run while the `err` flag is down + err_eq_0[0].out, + err_eq_0[1], # Run while the `err` flag is down [ - read_command, # Read the command at `i` - write_command_to_reg, # Write the command to `command` - cb.if_( - # Is this a pop or a push? - command_eq_zero[0].out, - command_eq_zero[1], - [ # A pop - cb.invoke( # First we call pop + read_cmd, # Read `commands[i]` + write_cmd_to_reg, # Write it to `cmd` + cb.par( + cb.if_( + # Is this a pop? + cmd_eq_0[0].out, + cmd_eq_0[1], + [ # A pop + cb.invoke( # First we call pop + fifo, + in_cmd=cmd.out, + ref_ans=ans, + ref_err=err, + ref_len=len, + ), + # AM: if err flag comes back raised, + # do not perform this write or this incr + write_ans, + incr_j, + ], + ), + cb.if_( # Is this a push? + cmd_neq_0[0].out, + cmd_neq_0[1], + cb.invoke( # A push fifo, - in_pop=cb.const(1, 1), - in_push=cb.const(1, 0), + in_cmd=cmd.out, ref_ans=ans, ref_err=err, ref_len=len, ), - # AM: if err flag comes back raised, - # do not perform this write or this incr - write_ans, - incr_j, - ], - cb.invoke( # A push - fifo, - in_pop=cb.const(1, 0), - in_push=cb.const(1, 1), - in_payload=command.out, - ref_ans=ans, - ref_err=err, - ref_len=len, ), ), incr_i, # Increment the command index @@ -352,9 +276,7 @@ def insert_main(prog, fifo, raise_err_if_i_eq_15): def build(): """Top-level function to build the program.""" prog = cb.Builder() - fifo = insert_fifo(prog) - raise_err_if_i_eq_15 = insert_raise_err_if_i_eq_15(prog) - insert_main(prog, fifo, raise_err_if_i_eq_15) + insert_main(prog) return prog.program From 591876937d65ce5f9fba1f81b436877d8d706355 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Wed, 9 Aug 2023 06:56:06 -0400 Subject: [PATCH 015/189] Leaky Relu Post Op to Systolic Array (#1644) * reference files * everything compiled but somethings probably wrong * modified data_gen tool * leaky relu working * cleaned code * finishing touches * frontend test * frontend .expect * rewrite frontend test * newline * doc changes --- calyx-py/calyx/builder.py | 58 ++- calyx-py/calyx/py_ast.py | 8 + frontends/systolic-lang/check-output.py | 39 +- frontends/systolic-lang/gen-systolic.py | 410 ++++++++++++++--- primitives/pipelined.futil | 12 + primitives/pipelined.sv | 42 ++ runt.toml | 2 +- .../systolic/leaky-relu/array-2-3-4.expect | 47 ++ .../systolic/leaky-relu/array-2-3-4.systolic | 7 + .../leaky-relu/array-2-3-4.systolic.data | 108 +++++ .../systolic/leaky-relu/array-8.expect | 245 ++++++++++ .../systolic/leaky-relu/array-8.systolic | 7 + .../systolic/leaky-relu/array-8.systolic.data | 434 ++++++++++++++++++ tests/frontend/systolic/array-1.expect | 12 +- tests/frontend/systolic/array-2.expect | 12 +- tests/frontend/systolic/array-3.expect | 12 +- tools/data_gen/src/main.rs | 3 +- 17 files changed, 1352 insertions(+), 106 deletions(-) create mode 100644 tests/correctness/systolic/leaky-relu/array-2-3-4.expect create mode 100644 tests/correctness/systolic/leaky-relu/array-2-3-4.systolic create mode 100644 tests/correctness/systolic/leaky-relu/array-2-3-4.systolic.data create mode 100644 tests/correctness/systolic/leaky-relu/array-8.expect create mode 100644 tests/correctness/systolic/leaky-relu/array-8.systolic create mode 100644 tests/correctness/systolic/leaky-relu/array-8.systolic.data diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 7ee0f55ed..acd3adb8e 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -227,6 +227,10 @@ def reg(self, name: str, size: int, is_ref=False) -> CellBuilder: """Generate a StdReg cell.""" return self.cell(name, ast.Stdlib.register(size), False, is_ref) + def wire(self, name: str, size: int, is_ref=False) -> CellBuilder: + """Generate a StdReg cell.""" + return self.cell(name, ast.Stdlib.wire(size), False, is_ref) + def slice(self, name: str, in_width: int, out_width, is_ref=False) -> CellBuilder: """Generate a StdReg cell.""" return self.cell(name, ast.Stdlib.slice(in_width, out_width), False, is_ref) @@ -320,6 +324,45 @@ def pipelined_mult(self, name: str) -> CellBuilder: self.prog.import_("primitives/pipelined.futil") return self.cell(name, ast.Stdlib.pipelined_mult()) + def pipelined_fp_smult( + self, name: str, width, int_width, frac_width + ) -> CellBuilder: + """Generate a pipelined fixed point signed multiplier.""" + self.prog.import_("primitives/pipelined.futil") + return self.cell( + name, ast.Stdlib.pipelined_fp_smult(width, int_width, frac_width) + ) + + def fp_op( + self, + cell_name: str, + op_name, + width: int, + int_width: int, + frac_width: int, + ) -> CellBuilder: + """Generate an UNSIGNED fixed point op.""" + self.prog.import_("primitives/binary_operators.futil") + return self.cell( + cell_name, + ast.Stdlib.fixed_point_op(op_name, width, int_width, frac_width, False), + ) + + def fp_sop( + self, + cell_name: str, + op_name, + width: int, + int_width: int, + frac_width: int, + ) -> CellBuilder: + """Generate a SIGNED fixed point op.""" + self.prog.import_("primitives/binary_operators.futil") + return self.cell( + cell_name, + ast.Stdlib.fixed_point_op(op_name, width, int_width, frac_width, True), + ) + def as_control(obj): """Convert a Python object into a control statement. @@ -746,7 +789,19 @@ def infer_width(expr): return inst.args[0] elif port_name == "write_en": return 1 - elif prim in ("std_add", "std_lt", "std_le", "std_ge", "std_gt", "std_eq"): + # XXX(Caleb): add all the primitive names instead of adding whenever I need one + elif prim in ( + "std_add", + "std_lt", + "std_le", + "std_ge", + "std_gt", + "std_eq", + "std_sgt", + "std_slt", + "std_fp_sgt", + "std_fp_slt", + ): if port_name == "left" or port_name == "right": return inst.args[0] elif prim == "std_mem_d1" or prim == "seq_mem_d1": @@ -766,6 +821,7 @@ def infer_width(expr): "std_smod_pipe", "std_div_pipe", "std_sdiv_pipe", + "std_fp_smult_pipe", ): if port_name == "left" or port_name == "right": return inst.args[0] diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index f274482ac..d1eedcb2e 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -501,6 +501,10 @@ class Stdlib: def register(bitwidth: int): return CompInst("std_reg", [bitwidth]) + @staticmethod + def wire(bitwidth: int): + return CompInst("std_wire", [bitwidth]) + @staticmethod def constant(bitwidth: int, value: int): return CompInst("std_const", [bitwidth, value]) @@ -631,3 +635,7 @@ def fixed_point_op( @staticmethod def pipelined_mult(): return CompInst(f"pipelined_mult", []) + + @staticmethod + def pipelined_fp_smult(width: int, int_width: int, frac_width: int): + return CompInst(f"pipelined_fp_smult", [width, int_width, frac_width]) diff --git a/frontends/systolic-lang/check-output.py b/frontends/systolic-lang/check-output.py index b88efaa4f..677c46a8f 100644 --- a/frontends/systolic-lang/check-output.py +++ b/frontends/systolic-lang/check-output.py @@ -22,6 +22,7 @@ parser.add_argument("-td", "--top-depth", type=int) parser.add_argument("-ll", "--left-length", type=int) parser.add_argument("-ld", "--left-depth", type=int) + parser.add_argument("-r", "--leaky-relu", action="store_true") parser.add_argument("-j", "--json-file", type=str) args = parser.parse_args() @@ -30,12 +31,17 @@ td = args.top_depth ll = args.left_length ld = args.left_depth + relu = args.leaky_relu json_file = args.json_file assert td == ld, f"Cannot multiply matrices: " f"{tl}x{td} and {ld}x{ll}" - left = np.zeros((ll, ld), dtype="i") - top = np.zeros((td, tl), dtype="i") + if relu: + dtype = "f" + else: + dtype = "i" + left = np.zeros((ll, ld), dtype) + top = np.zeros((td, tl), dtype) json_data = json.load(open(json_file))["memories"] for r in range(ll): @@ -47,16 +53,31 @@ top[r][c] = json_data[f"t{c}"][r] matmul_result = np.matmul(left, top) + if relu: + matmul_result = np.where(matmul_result > 0, matmul_result, matmul_result * 0.01) res = [] for r in range(ll): - res.append(json_data[f"out_mem_{r}"]) + if relu: + res.append(list(map(float, json_data[f"out_mem_{r}"]))) + else: + res.append(json_data[f"out_mem_{r}"]) + json_result = np.array(res) - if np.array_equal(json_result, matmul_result): - print("Correct") + if relu: + if np.isclose(matmul_result, json_result, atol=1e-3).all(): + print("Correct") + else: + print("Incorrect\n. Should have been:\n") + print(matmul_result) + print("\nBut got:\n") + print(json_result) else: - print("Incorrect\n. Should have been:\n") - print(matmul_result) - print("\nBut got:\n") - print(json_result) + if np.equal(json_result, matmul_result): + print("Correct") + else: + print("Incorrect\n. Should have been:\n") + print(matmul_result) + print("\nBut got:\n") + print(json_result) diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 19abcba3d..6bcac49ec 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -4,9 +4,13 @@ import calyx.builder as cb from calyx import py_ast from calyx.utils import bits_needed +from fud.stages.verilator import numeric_types +from calyx.utils import float_to_fixed_point # Global constant for the current bitwidth. BITWIDTH = 32 +INTWIDTH = 16 +FRACWIDTH = 16 # Name of the ouput array OUT_MEM = "out_mem" PE_NAME = "mac_pe" @@ -48,16 +52,22 @@ def __str__(self): ) -def pe(prog: cb.Builder): +def pe(prog: cb.Builder, leaky_relu): comp = prog.component(name=PE_NAME, latency=1) comp.input("top", BITWIDTH) comp.input("left", BITWIDTH) comp.input("mul_ready", 1) comp.output("out", BITWIDTH) acc = comp.reg("acc", BITWIDTH) - add = comp.add("add", BITWIDTH) - # XXX: pipelined mult assumes 32 bit multiplication - mul = comp.pipelined_mult("mul") + # Leaky relu means 32 bit signed fixed point operations. + if leaky_relu: + add = comp.fp_sop("adder", "add", BITWIDTH, INTWIDTH, FRACWIDTH) + mul = comp.pipelined_fp_smult("mul", BITWIDTH, INTWIDTH, FRACWIDTH) + # No leaky relu means integer operations + else: + add = comp.add("add", BITWIDTH) + # XXX: pipelined mult assumes 32 bit multiplication + mul = comp.pipelined_mult("mul") this = comp.this() with comp.static_group("do_add", 1): @@ -129,7 +139,7 @@ def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuil def add_read_mem_argument(comp: cb.ComponentBuilder, name, addr_width): """ - Add arguments to component `comp` if we want to read from a mem named `name` wth + Add arguments to component `comp` if we want to read from a mem named `name` with width of `addr_width` """ comp.input(f"{name}_read_data", BITWIDTH) @@ -138,8 +148,8 @@ def add_read_mem_argument(comp: cb.ComponentBuilder, name, addr_width): def add_write_mem_argument(comp: cb.ComponentBuilder, name, addr_width): """ - Add arguments to component `comp` if we want to write to a mem named `name` wth - width of `addr_width` + Add arguments to component `comp` if we want to write to a mem named `name` with + width of `addr_width` inside `comp.` """ comp.output(f"{name}_addr0", addr_width) comp.output(f"{name}_write_data", BITWIDTH) @@ -234,8 +244,37 @@ def instantiate_output_move(comp: cb.ComponentBuilder, row, col, cols): g.asgn(write_en_port, 1) +def instantiate_relu_cond_reg( + comp: cb.ComponentBuilder, + num_rows, +): + """ + Writes into `cond_reg`, the condition register for the while loop. + `cond_reg` basically checks whether the relu operation has finished yet + for all rows of the array. If so, it sets `cond_reg` to lo. Otherwise it + sets it to high. + """ + cond_reg = comp.get_cell("cond_reg") + cond_wire = comp.wire("cond_wire", 1) + for r in range(num_rows): + if r == 0: + guard = comp.get_cell(f"relu_finished_reg_r{r}").port("out") + else: + guard = guard & comp.get_cell(f"relu_finished_reg_r{r}").port("out") + with comp.static_group("write_cond_reg", 1): + cond_wire.in_ = guard @ 1 + cond_reg.in_ = ~cond_wire.out @ 1 + cond_reg.in_ = cond_wire.out @ 0 + cond_reg.write_en = 1 + + def gen_schedules( - top_length, top_depth, left_length, left_depth, comp: cb.ComponentBuilder + top_length, + top_depth, + left_length, + left_depth, + leaky_relu, + comp: cb.ComponentBuilder, ): """ Generates 5 arrays that are the same size as the output (systolic) array @@ -250,6 +289,8 @@ def gen_schedules( `pe_move_sched` contains when to "move" the PE (i.e., pass data) `pe_write_sched` contains when to "write" the PE value into memory (i.e., when the PE is "finished") + `relu_sched` replaces `pe_write_sched` for Leaky Relu, and contains when to + start the relu operation for a given row. """ depth_port = comp.this().depth min_depth_4_port = comp.get_cell("min_depth_4").port("out") @@ -258,8 +299,14 @@ def gen_schedules( pe_fill_sched = np.zeros((left_length, top_length), dtype=object) pe_accum_sched = np.zeros((left_length, top_length), dtype=object) pe_move_sched = np.zeros((left_length, top_length), dtype=object) + # will only actually use one of the following two schedules pe_write_sched = np.zeros((left_length, top_length), dtype=object) + relu_sched = np.zeros((left_length), dtype=object) for row in range(0, left_length): + relu_sched[row] = ( + CalyxAdd(depth_port, row + 5), + None, + ) for col in range(0, top_length): pos = row + col update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) @@ -274,7 +321,11 @@ def gen_schedules( schedules["fill_sched"] = pe_fill_sched schedules["accum_sched"] = pe_accum_sched schedules["move_sched"] = pe_move_sched - schedules["write_sched"] = pe_write_sched + # Only need one of relu_sched and write_sched + if leaky_relu: + schedules["relu_sched"] = relu_sched + else: + schedules["write_sched"] = pe_write_sched return schedules @@ -285,17 +336,23 @@ def accum_nec_ranges(nec_ranges, schedule): the schedule nec_ranges is a set of tuples. - schedule is a 2d array with tuple (start,end) entries. + schedule is either a 2d array or 1d array with tuple (start,end) entries. Adds all intervals (start,end) in schedule to nec_ranges if the it's - not already in nec_ranges + not already in nec_ranges. """ - for r in schedule: - for c in r: - nec_ranges.add(c) + if schedule.ndim == 1: + for r in schedule: + nec_ranges.add(r) + elif schedule.ndim == 2: + for r in schedule: + for c in r: + nec_ranges.add(c) + else: + raise Exception("accum_nec_ranges expects only 1d or 2d arrays") return nec_ranges -def build_calyx_add(comp, obj): +def try_build_calyx_add(comp, obj): """ Attempts to build an adder for obj, with name str(obj) and group name str(obj) + "_group" that adds obj.port and obj.const @@ -319,14 +376,14 @@ def instantiate_calyx_adds(comp, nec_ranges): """ depth_adders = [] for lo, hi in nec_ranges: - if build_calyx_add(comp, lo): + if try_build_calyx_add(comp, lo): depth_adders.append(str(lo) + "_group") - if build_calyx_add(comp, hi): + if try_build_calyx_add(comp, hi): depth_adders.append(str(hi) + "_group") return depth_adders -def instantiate_idx_cond_groups(comp: cb.ComponentBuilder): +def instantiate_idx_cond_groups(comp: cb.ComponentBuilder, leaky_relu): """ Builds groups that instantiate idx to 0 and increment idx Also builds groups that set cond_reg to 1 (runs before the while loop) @@ -334,8 +391,6 @@ def instantiate_idx_cond_groups(comp: cb.ComponentBuilder): """ idx = comp.reg("idx", BITWIDTH) add = comp.add("idx_add", BITWIDTH) - iter_limit = comp.get_cell("iter_limit") - lt_iter_limit = comp.lt("lt_iter_limit", BITWIDTH) cond_reg = comp.reg("cond_reg", 1) with comp.static_group("init_idx", 1): idx.in_ = 0 @@ -345,37 +400,45 @@ def instantiate_idx_cond_groups(comp: cb.ComponentBuilder): add.right = 1 idx.in_ = add.out idx.write_en = 1 - with comp.static_group("lt_iter_limit_group", 1): - lt_iter_limit.left = add.out - lt_iter_limit.right = iter_limit.out - cond_reg.in_ = lt_iter_limit.out - cond_reg.write_en = 1 with comp.static_group("init_cond_reg", 1): cond_reg.in_ = 1 cond_reg.write_en = 1 - - -def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit): + # Only check iter_limit if not leaky_relu. + # For leaky_relu we don't check iterations, we check if the relu + # operations are finished yet + if not leaky_relu: + iter_limit = comp.get_cell("iter_limit") + lt_iter_limit = comp.lt("lt_iter_limit", BITWIDTH) + with comp.static_group("lt_iter_limit_group", 1): + lt_iter_limit.left = add.out + lt_iter_limit.right = iter_limit.out + cond_reg.in_ = lt_iter_limit.out + cond_reg.write_en = 1 + + +def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit, leaky_relu): """ Builds group that instantiates the dynamic/runtime values for the systolic array: its depth and iteration limit/count (since its iteration limit depends on its depth). + If leaky_relu, we do not need to check iteration limit. """ min_depth_4 = comp.reg("min_depth_4", BITWIDTH) lt_depth_4 = comp.lt("lt_depth_4", BITWIDTH) - iter_limit = comp.reg("iter_limit", BITWIDTH) - iter_limit_add = comp.add("iter_limit_add", BITWIDTH) with comp.static_group("init_min_depth", 1): lt_depth_4.left = depth_port lt_depth_4.right = 4 min_depth_4.in_ = lt_depth_4.out @ depth_port min_depth_4.in_ = ~lt_depth_4.out @ 4 min_depth_4.write_en = 1 - with comp.static_group("init_iter_limit", 1): - iter_limit_add.left = rem_iter_limit - iter_limit_add.right = depth_port - iter_limit.in_ = iter_limit_add.out - iter_limit.write_en = 1 + if not leaky_relu: + iter_limit = comp.reg("iter_limit", BITWIDTH) + iter_limit_add = comp.add("iter_limit_add", BITWIDTH) + with comp.static_group("init_iter_limit", 1): + iter_limit_add.left = rem_iter_limit + iter_limit_add.right = depth_port + iter_limit.in_ = iter_limit_add.out + iter_limit.write_en = 1 def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: @@ -400,36 +463,50 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: group_str = f"idx_between_{lo}_{hi}_group" index_lt = f"index_lt_{str(hi)}" index_ge = f"index_ge_{str(lo)}" - reg = comp.reg(reg_str, 1) - lt = ( - comp.get_cell(index_lt) - if comp.try_get_cell(index_lt) is not None - else comp.lt(index_lt, BITWIDTH) - ) - # if lo == 0, then only need to check if reg < hi - if type(lo) == int and lo == 0: - with comp.static_group(group_str, 1): - lt.left = idx_add.out - lt.right = hi_value - reg.in_ = lt.out - reg.write_en = 1 - # need to check if reg >= lo and reg < hi - else: + assert ( + not type(lo) is None + ), "None Type Lower Bound not supported in instantiate_idx_between" + # If no upper bound, then only need to check reg >= lo + if hi is None: ge = ( comp.get_cell(index_ge) if comp.try_get_cell(index_ge) is not None else comp.ge(index_ge, BITWIDTH) ) - and_ = comp.and_(comb_str, 1) with comp.static_group(group_str, 1): ge.left = idx_add.out ge.right = lo_value - lt.left = idx_add.out - lt.right = hi_value - and_.left = ge.out - and_.right = lt.out - reg.in_ = and_.out - reg.write_en = 1 + else: + reg = comp.reg(reg_str, 1) + lt = ( + comp.get_cell(index_lt) + if comp.try_get_cell(index_lt) is not None + else comp.lt(index_lt, BITWIDTH) + ) + # if lo == 0, then only need to check if reg < hi + if type(lo) == int and lo == 0: + with comp.static_group(group_str, 1): + lt.left = idx_add.out + lt.right = hi_value + reg.in_ = lt.out + reg.write_en = 1 + # need to check if reg >= lo and reg < hi + else: + ge = ( + comp.get_cell(index_ge) + if comp.try_get_cell(index_ge) is not None + else comp.ge(index_ge, BITWIDTH) + ) + and_ = comp.and_(comb_str, 1) + with comp.static_group(group_str, 1): + ge.left = idx_add.out + ge.right = lo_value + lt.left = idx_add.out + lt.right = hi_value + and_.left = ge.out + and_.right = lt.out + reg.in_ = and_.out + reg.write_en = 1 def instantiate_init_group(comp: cb.ComponentBuilder, lo, hi): @@ -439,12 +516,119 @@ def instantiate_init_group(comp: cb.ComponentBuilder, lo, hi): # if lo == 0, then the idx will initially be in between the interval, so # need to set idx_between to high start_hi = 1 if lo == 0 else 0 + # XXX(Caleb): assumed hi=None is used for a Relu computation, and therefore + # idx_between_reg is not necessary. + if hi is None: + return idx_between = comp.get_cell(f"idx_between_{lo}_{hi}_reg") with comp.static_group(f"init_idx_between_{lo}_{hi}", 1): idx_between.in_ = start_hi idx_between.write_en = 1 +def instantiate_relu_groups(comp: cb.ComponentBuilder, row, top_length): + """ + Instantiates leaky relu groups that performs leaky relu on `row`. + """ + + # Helper function adds assignment wire.in = reg.out == col ? pe_{row}_{col}_out. + def build_assignment( + comp: cb.ComponentBuilder, group: cb.GroupBuilder, wire, register, row, col + ): + wire_in = wire.port("in") + reg_out = register.port("out") + pe_out = comp.get_cell(f"pe_{row}_{col}").port("out") + group.asgn( + wire_in, + pe_out, + reg_out == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, col)), + ) + + # Current value we are performing relu on. + cur_val = comp.wire(f"relu_r{row}_cur_val", BITWIDTH) + # Current idx within the row for the value we are performing relu on. + idx_reg = comp.reg(f"relu_r{row}_cur_idx", BITWIDTH) + group_assigns = [] + group = comp.static_group(f"relu_r{row}_helper", 1) + # assigning cur_val = value of PE at (row,idx_reg). + for col in range(top_length): + group_assigns.append(build_assignment(comp, group, cur_val, idx_reg, row, col)) + + # Wire that tells us we are finished with relu operation for this row. + relu_finished_wire = comp.wire(f"relu_finished_wire_r{row}", 1) + # Register that holds the value of relu_finished_wire for later cycles. + relu_finished_reg = comp.reg(f"relu_finished_reg_r{row}", 1) + # Checks whether cur_val is > 0. + cur_gt = comp.fp_sop(f"relu_r{row}_val_gt", "gt", BITWIDTH, INTWIDTH, FRACWIDTH) + # Checks whether we should go onto the next entry in the row. This occurs + # either when a) value is positive or b) multiply operation has finished. + go_next = comp.wire(f"relu_r{row}_go_next", BITWIDTH) + # Increments idx_reg. + incr = comp.add(f"relu_r{row}_incr", BITWIDTH) + # Performs multiplication for leaky relu. + fp_mult = comp.fp_sop( + f"relu_r{row}_val_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH + ) + this = comp.this() + mem_name = OUT_MEM + f"_{row}" + addr0_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_addr0")) + write_data_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_data")) + write_en_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_en")) + with comp.static_group(f"execute_relu_r{row}", 1) as g: + # Check if the current value is positive or negative. + cur_gt.left = cur_val.out + cur_gt.right = 0 + + # Handle incrementing the idx_reg. + # Increment either when a) multiplication is done or b) cur value is positive + incr.left = idx_reg.out + incr.right = 1 + go_next.in_ = (fp_mult.done | cur_gt.out) @ 1 + idx_reg.in_ = go_next.out @ incr.out + idx_reg.write_en = go_next.out @ 1 + + # Perform the multiplication. + # Get FP approximation of 0.01. + fp_mult.left = numeric_types.FixedPoint( + str(float_to_fixed_point(0.01, FRACWIDTH)), BITWIDTH, INTWIDTH, True + ).unsigned_integer() + fp_mult.right = cur_val.out + fp_mult.go = ~go_next.out @ 1 + + # Write to mem based on whether cur_valu >= 0 + g.asgn(write_en_port, 1, go_next.out) + g.asgn(addr0_port, idx_reg.out) + g.asgn(write_data_port, cur_val.out, cur_gt.out) + g.asgn(write_data_port, fp_mult.out, ~cur_gt.out) + + # While loop logic. relu_finished when idx_reg == top_length - 1 & go_next, + # i.e., when we're at the last index and about to "go to the next value". + relu_finished_wire.in_ = ( + go_next.out + & ( + idx_reg.out + == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, top_length - 1)) + ) + ) @ 1 + relu_finished_reg.in_ = relu_finished_wire.out @ 1 + relu_finished_reg.write_en_ = relu_finished_wire.out @ 1 + + # Start relu when idx_ge row + depth + 5, i.e., when first value in row + # is ready to be computed. + relu_start_port = comp.get_cell(f"index_ge_depth_plus_{5 + row}").port("out") + # relu_cond_wire coordinates when relu_cond_reg should be hi/lo + relu_cond_wire = comp.wire(f"relu_cond_wire_r{row}", 1) + # relu_cond_reg guards when we should perform the relu execution group defined + # above. + relu_cond_reg = comp.reg(f"relu_cond_reg_r{row}", 1) + guard = relu_start_port & (~relu_finished_wire.out) + with comp.static_group(f"check_relu_cond_r{row}", 1): + relu_cond_wire.in_ = guard @ 1 + relu_cond_reg.in_ = relu_cond_wire.out @ 1 + relu_cond_reg.in_ = ~relu_cond_wire.out @ 0 + relu_cond_reg.write_en = ~relu_finished_reg.out @ 1 + + def get_memory_updates(row, col): """ Gets the memory moves and memory idx updates for (row,col) @@ -514,6 +698,22 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): ] +def execute_if_register(comp: cb.ComponentBuilder, register, body): + """ + body is a list of control stmts + if body is empty, return an empty list + otherwise, builds an if stmt that executes body in parallel reg.out is high + """ + if not body: + return [] + return [ + cb.static_if( + register.out, + py_ast.StaticParComp(body), + ) + ] + + def generate_control( comp: cb.ComponentBuilder, top_length, @@ -523,6 +723,7 @@ def generate_control( schedules, depth_adders, nec_ranges, + leaky_relu, ): """ Logically, control performs the following actions: @@ -551,11 +752,16 @@ def generate_control( + [ py_ast.Enable("init_idx"), py_ast.Enable("init_min_depth"), - py_ast.Enable("init_iter_limit"), py_ast.Enable("init_cond_reg"), ] - + [py_ast.Enable(f"init_idx_between_{lo}_{hi}") for (lo, hi) in (nec_ranges)] + + [ + py_ast.Enable(f"init_idx_between_{lo}_{hi}") + for (lo, hi) in filter(lambda x: x[1] is not None, nec_ranges) + ] ) + if not leaky_relu: + init_indices.append(py_ast.Enable("init_iter_limit")) + control.append(py_ast.StaticParComp(init_indices)) # source_pos metadata init @@ -571,7 +777,9 @@ def counter(): # end source pos init control_stmts = [] - incr_stmts = [py_ast.Enable("incr_idx"), py_ast.Enable("lt_iter_limit_group")] + incr_stmts = [py_ast.Enable("incr_idx")] + if not leaky_relu: + incr_stmts.append(py_ast.Enable("lt_iter_limit_group")) for r in range(left_length): for c in range(top_length): # build 4 if stmts for the 4 schedules that we need to account for @@ -599,12 +807,19 @@ def counter(): schedules["accum_sched"][r][c][1], [get_pe_invoke(r, c, top_length, left_length, 1)], ) - pe_writes = execute_if_between( - comp, - schedules["write_sched"][r][c][0], - schedules["write_sched"][r][c][1], - [py_ast.Enable(NAME_SCHEME["out mem move"].format(pe=f"pe_{r}_{c}"))], - ) + if leaky_relu: + pe_writes = [] + else: + pe_writes = execute_if_between( + comp, + schedules["write_sched"][r][c][0], + schedules["write_sched"][r][c][1], + [ + py_ast.Enable( + NAME_SCHEME["out mem move"].format(pe=f"pe_{r}_{c}") + ) + ], + ) pe_control = input_mem_updates + pe_fills + pe_moves + pe_accums + pe_writes control_stmts.append(py_ast.StaticParComp(pe_control)) # providing metadata @@ -614,6 +829,20 @@ def counter(): ] = f"pe_{r}_{c} filling: [{schedules['fill_sched'][r][c][0]},\ {schedules['fill_sched'][r][c][1]}) accumulating: [{schedules['accum_sched'][r][c][0]} \ {schedules['accum_sched'][r][c][1]})" + + if leaky_relu: + relu_execution = [py_ast.Enable("write_cond_reg")] + for r in range(left_length): + relu_execution += execute_if_register( + comp, + comp.get_cell(f"relu_cond_reg_r{r}"), + [ + py_ast.Enable(f"execute_relu_r{r}"), + py_ast.Enable(f"relu_r{r}_helper"), + ], + ) + relu_execution.append(py_ast.Enable(f"check_relu_cond_r{r}")) + for start, end in nec_ranges: # build the control stmts that assign correct values to # idx_between_{start}_{end}_reg, which is what the if stmts above^ rely on @@ -621,9 +850,10 @@ def counter(): for depth_adder_group in depth_adders: incr_stmts.append(py_ast.Enable(depth_adder_group)) - while_body = py_ast.StaticParComp( - [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] - ) + while_ctrl = [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] + if leaky_relu: + while_ctrl.append(py_ast.StaticParComp(relu_execution)) + while_body = py_ast.StaticParComp(while_ctrl) # build the while loop with condition cond_reg. # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 @@ -636,7 +866,12 @@ def counter(): def create_systolic_array( - prog: cb.Builder, top_length, top_depth, left_length, left_depth + prog: cb.Builder, + top_length, + top_depth, + left_length, + left_depth, + leaky_relu, ): """ top_length: Number of PEs in each row. @@ -652,10 +887,12 @@ def create_systolic_array( computational_unit = prog.component("systolic_array_comp") depth_port = computational_unit.input("depth", BITWIDTH) - init_dyn_vals(computational_unit, depth_port, top_length + left_length + 4) + init_dyn_vals( + computational_unit, depth_port, top_length + left_length + 4, leaky_relu + ) schedules = gen_schedules( - top_length, top_depth, left_length, left_depth, computational_unit + top_length, top_depth, left_length, left_depth, leaky_relu, computational_unit ) nec_ranges = set() for sched in schedules.values(): @@ -692,15 +929,24 @@ def create_systolic_array( ) # Instantiate output movement structure - instantiate_output_move(computational_unit, row, col, top_length) + # Leaky relu will write into memories using different groups + if not leaky_relu: + instantiate_output_move(computational_unit, row, col, top_length) # instantiate groups that handle cond_reg and idx variables - instantiate_idx_cond_groups(computational_unit) + instantiate_idx_cond_groups(computational_unit, leaky_relu) for start, end in nec_ranges: # create the groups that create for idx_in_between registers instantiate_idx_between(computational_unit, start, end) instantiate_init_group(computational_unit, start, end) + if leaky_relu: + # Instantiate groups to compute Relu. + for row in range(left_length): + instantiate_relu_groups(computational_unit, row, top_length) + # Write into the cond reg of the while loop. + instantiate_relu_cond_reg(computational_unit, left_length) + # Generate the control and set the source map control, source_map = generate_control( computational_unit, @@ -711,6 +957,7 @@ def create_systolic_array( schedules, depth_adders, nec_ranges, + leaky_relu, ) computational_unit.control = control prog.program.meta = source_map @@ -774,10 +1021,17 @@ def create_systolic_array( parser.add_argument("-td", "--top-depth", type=int) parser.add_argument("-ll", "--left-length", type=int) parser.add_argument("-ld", "--left-depth", type=int) + parser.add_argument("-r", "--leaky-relu", action="store_true") args = parser.parse_args() - top_length, top_depth, left_length, left_depth = None, None, None, None + top_length, top_depth, left_length, left_depth, leaky_relu = ( + None, + None, + None, + None, + False, + ) fields = [args.top_length, args.top_depth, args.left_length, args.left_depth] if all(map(lambda x: x is not None, fields)): @@ -785,6 +1039,7 @@ def create_systolic_array( top_depth = args.top_depth left_length = args.left_length left_depth = args.left_depth + leaky_relu = args.leaky_relu elif args.file is not None: with open(args.file, "r") as f: spec = json.load(f) @@ -792,6 +1047,8 @@ def create_systolic_array( top_depth = spec["top_depth"] left_length = spec["left_length"] left_depth = spec["left_depth"] + # default to not perform leaky_relu + leaky_relu = spec.get("leaky_relu", False) else: parser.error( "Need to pass either `FILE` or all of `" @@ -799,13 +1056,14 @@ def create_systolic_array( ) prog = cb.Builder() - pe(prog) + pe(prog, leaky_relu) create_systolic_array( prog, top_length=top_length, top_depth=top_depth, left_length=left_length, left_depth=left_depth, + leaky_relu=leaky_relu, ) prog.program.emit() diff --git a/primitives/pipelined.futil b/primitives/pipelined.futil index 280a0676e..b3436d613 100644 --- a/primitives/pipelined.futil +++ b/primitives/pipelined.futil @@ -8,4 +8,16 @@ extern "pipelined.sv" { ) -> ( out: 32 ); + + // A latency-sensitive multiplier that takes 4 cycles to compute its result. + static<4> primitive pipelined_fp_smult [ + WIDTH, INT_WIDTH, FRAC_WIDTH + ] ( + @clk clk: 1, + @reset reset: 1, + left: WIDTH, + right: WIDTH + ) -> ( + out: WIDTH + ); } \ No newline at end of file diff --git a/primitives/pipelined.sv b/primitives/pipelined.sv index edc486597..086bcaeea 100644 --- a/primitives/pipelined.sv +++ b/primitives/pipelined.sv @@ -32,4 +32,46 @@ always_ff @(posedge clk) begin end end +endmodule + +/// +module pipelined_fp_smult #( + parameter WIDTH = 32, + parameter INT_WIDTH = 16, + parameter FRAC_WIDTH = 16 +)( + input wire clk, + input wire reset, + // inputs + input wire [WIDTH-1:0] left, + input wire [WIDTH-1:0] right, + // The input has been committed + output wire [WIDTH-1:0] out +); + +logic [WIDTH-1:0] lt, rt, buff0, buff1, buff2; +logic [(WIDTH << 1) - 1:0] tmp_prod; + +assign out = buff2; +assign tmp_prod = $signed( + { {WIDTH{lt[WIDTH-1]}}, lt} * + { {WIDTH{rt[WIDTH-1]}}, rt} + ); + +always_ff @(posedge clk) begin + if (reset) begin + lt <= 0; + rt <= 0; + buff0 <= 0; + buff1 <= 0; + buff2 <= 0; + end else begin + lt <= $signed(left); + rt <= $signed(right); + buff0 <= tmp_prod[(WIDTH << 1) - INT_WIDTH - 1 : WIDTH - INT_WIDTH]; + buff1 <= buff0; + buff2 <= buff1; + end +end + endmodule diff --git a/runt.toml b/runt.toml index 063b399a4..247947a14 100644 --- a/runt.toml +++ b/runt.toml @@ -276,7 +276,7 @@ fud e --from systolic --to jq \ [[tests]] name = "[frontend] systolic array output correctness" -paths = [ "tests/correctness/systolic/output/*.systolic" ] +paths = [ "tests/correctness/systolic/output/*.systolic", "tests/correctness/systolic/leaky-relu/*.systolic" ] cmd = """ fud e --from systolic --to dat \ --through verilog \ diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.expect b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect new file mode 100644 index 000000000..f5097415d --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect @@ -0,0 +1,47 @@ +{ + "cycles": 20, + "memories": { + "l0": [ + "-1.7772064208984375", + "4.447052001953125", + "-2.3607330322265625" + ], + "l1": [ + "2.4268341064453125", + "1.2045745849609375", + "-3.9895172119140625" + ], + "out_mem_0": [ + "4.8839263916015625", + "-0.013458251953125", + "-0.1131134033203125", + "29.574005126953125" + ], + "out_mem_1": [ + "-0.0778045654296875", + "6.2762298583984375", + "20.638031005859375", + "7.0403594970703125" + ], + "t0": [ + "-1.6006317138671875", + "1.1641387939453125", + "1.3291168212890625" + ], + "t1": [ + "0.63531494140625", + "-0.80828857421875", + "-1.4307708740234375" + ], + "t2": [ + "2.711456298828125", + "-3.96783447265625", + "-4.721710205078125" + ], + "t3": [ + "-4.130462646484375", + "3.249847412109375", + "-3.296051025390625" + ] + } +} diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic new file mode 100644 index 000000000..4394a5bd2 --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 4, + "top_depth": 3, + "left_length": 2, + "left_depth": 3, + "leaky_relu": true +} \ No newline at end of file diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic.data b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic.data new file mode 100644 index 000000000..485424069 --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic.data @@ -0,0 +1,108 @@ +{ + "l0": { + "data": [ + -1.777205467224121, + 4.447059631347656, + -2.3607325553894043 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + 2.4268269538879395, + 1.2045726776123047, + -3.9895176887512207 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + -1.600632667541504, + 1.1641407012939453, + 1.329122543334961 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + 0.63531494140625, + -0.8082904815673828, + -1.4307689666748047 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + 2.711460590362549, + -3.967834711074829, + -4.721712112426758 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + -4.130462646484375, + 3.2498397827148438, + -3.2960569858551025 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/systolic/leaky-relu/array-8.expect b/tests/correctness/systolic/leaky-relu/array-8.expect new file mode 100644 index 000000000..7628c9b73 --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-8.expect @@ -0,0 +1,245 @@ +{ + "cycles": 41, + "memories": { + "l0": [ + "3.5089263916015625", + "-2.4468841552734375", + "2.8453826904296875", + "-3.62884521484375", + "0.58929443359375", + "-0.500091552734375", + "-2.9769134521484375", + "-0.0243682861328125" + ], + "l1": [ + "3.923828125", + "1.53765869140625", + "-0.33563232421875", + "2.169586181640625", + "1.622589111328125", + "1.8556365966796875", + "-4.4359283447265625", + "0.8365020751953125" + ], + "l2": [ + "-4.1279296875", + "2.71234130859375", + "-3.32666015625", + "2.5266571044921875", + "-3.276275634765625", + "-2.7594757080078125", + "3.641357421875", + "-3.8071136474609375" + ], + "l3": [ + "-3.6282806396484375", + "-1.774749755859375", + "-0.194580078125", + "-2.395263671875", + "-0.26727294921875", + "1.663665771484375", + "2.736114501953125", + "-2.902496337890625" + ], + "l4": [ + "-4.1309814453125", + "2.616790771484375", + "-3.8528289794921875", + "-0.85223388671875", + "-0.6961212158203125", + "0.49066162109375", + "-4.21832275390625", + "-0.55133056640625" + ], + "l5": [ + "-0.21466064453125", + "3.553741455078125", + "-3.767547607421875", + "4.906829833984375", + "-3.7222137451171875", + "-1.092559814453125", + "3.1661376953125", + "0.950347900390625" + ], + "l6": [ + "4.27069091796875", + "-0.9052276611328125", + "-3.8193206787109375", + "-4.525848388671875", + "-0.305908203125", + "-2.857208251953125", + "0.2507171630859375", + "2.9556732177734375" + ], + "l7": [ + "-3.020721435546875", + "0.41107177734375", + "1.85107421875", + "2.9339599609375", + "-3.6439971923828125", + "-3.2292327880859375", + "-0.4127197265625", + "3.55841064453125" + ], + "out_mem_0": [ + "-0.06610107421875", + "-0.18218994140625", + "12.004302978515625", + "-0.5319366455078125", + "12.8704833984375", + "7.0037384033203125", + "-0.488494873046875", + "22.9842681884765625" + ], + "out_mem_1": [ + "-0.137969970703125", + "-0.0732269287109375", + "37.6787109375", + "-0.1321563720703125", + "32.53472900390625", + "5.47552490234375", + "-0.168182373046875", + "-0.114013671875" + ], + "out_mem_2": [ + "5.7530670166015625", + "27.1723785400390625", + "-0.3221893310546875", + "45.33734130859375", + "-0.102874755859375", + "2.21435546875", + "71.3912811279296875", + "-0.21209716796875" + ], + "out_mem_3": [ + "4.902496337890625", + "-0.0472869873046875", + "-0.0914154052734375", + "-0.1087646484375", + "-0.199798583984375", + "16.94140625", + "-0.040191650390625", + "36.811798095703125" + ], + "out_mem_4": [ + "-0.3016815185546875", + "-0.1766510009765625", + "0.7630462646484375", + "11.793975830078125", + "-0.2859954833984375", + "24.3327789306640625", + "20.1204833984375", + "-0.110809326171875" + ], + "out_mem_5": [ + "11.931121826171875", + "43.5961456298828125", + "-0.128692626953125", + "68.196075439453125", + "0.246734619140625", + "-0.240966796875", + "65.08526611328125", + "-0.42913818359375" + ], + "out_mem_6": [ + "-0.0768280029296875", + "24.37506103515625", + "-0.042816162109375", + "-0.090606689453125", + "-0.324188232421875", + "8.8478240966796875", + "-0.266998291015625", + "9.9342803955078125" + ], + "out_mem_7": [ + "6.928497314453125", + "3.4259490966796875", + "-0.3175811767578125", + "45.2135467529296875", + "-0.12518310546875", + "-0.4728240966796875", + "43.8671875", + "-0.5387725830078125" + ], + "t0": [ + "0.8427734375", + "-0.3623809814453125", + "2.189697265625", + "1.1002044677734375", + "-0.9313812255859375", + "0.3701934814453125", + "4.0137481689453125", + "0.5058746337890625" + ], + "t1": [ + "2.8635101318359375", + "-1.757843017578125", + "-4.0618743896484375", + "2.4990386962890625", + "-2.5228424072265625", + "-1.2569122314453125", + "3.7235260009765625", + "0.35687255859375" + ], + "t2": [ + "3.27734375", + "-2.5147247314453125", + "-1.9622344970703125", + "2.0919189453125", + "1.2744293212890625", + "4.7816619873046875", + "-3.068603515625", + "-1.27239990234375" + ], + "t3": [ + "-3.059967041015625", + "4.7850341796875", + "-1.820220947265625", + "3.753173828125", + "-2.1552734375", + "-0.821502685546875", + "3.695068359375", + "4.884033203125" + ], + "t4": [ + "4.87396240234375", + "1.7840423583984375", + "4.3836517333984375", + "4.1121826171875", + "0.0283660888671875", + "1.183441162109375", + "-1.02581787109375", + "-4.27496337890625" + ], + "t5": [ + "0.055145263671875", + "1.250579833984375", + "-3.052520751953125", + "-3.5447235107421875", + "3.4227142333984375", + "1.121307373046875", + "-1.3860931396484375", + "-4.5196685791015625" + ], + "t6": [ + "-3.4802398681640625", + "4.9503326416015625", + "-0.89923095703125", + "4.38916015625", + "-3.4346160888671875", + "-3.2621917724609375", + "1.91033935546875", + "-0.605682373046875" + ], + "t7": [ + "1.1960906982421875", + "-4.0765838623046875", + "-0.900054931640625", + "-4.7776336669921875", + "1.2126007080078125", + "4.4374542236328125", + "1.529144287109375", + "-3.8090057373046875" + ] + } +} diff --git a/tests/correctness/systolic/leaky-relu/array-8.systolic b/tests/correctness/systolic/leaky-relu/array-8.systolic new file mode 100644 index 000000000..b92e26302 --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-8.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 8, + "top_depth": 8, + "left_length": 8, + "left_depth": 8, + "leaky_relu": true +} \ No newline at end of file diff --git a/tests/correctness/systolic/leaky-relu/array-8.systolic.data b/tests/correctness/systolic/leaky-relu/array-8.systolic.data new file mode 100644 index 000000000..3a2167eb7 --- /dev/null +++ b/tests/correctness/systolic/leaky-relu/array-8.systolic.data @@ -0,0 +1,434 @@ +{ + "l0": { + "data": [ + 3.5089216232299805, + -2.446882724761963, + 2.8453850746154785, + -3.62884521484375, + 0.5892906188964844, + -0.5000886917114258, + -2.976912260055542, + -0.024374961853027344 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + 3.9238243103027344, + 1.5376663208007812, + -0.3356289863586426, + 2.169581413269043, + 1.6225967407226562, + 1.8556394577026367, + -4.435929298400879, + 0.8365049362182617 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l2": { + "data": [ + -4.127925872802734, + 2.712334632873535, + -3.326665163040161, + 2.526651382446289, + -3.276275396347046, + -2.7594733238220215, + 3.6413497924804688, + -3.8071072101593018 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l3": { + "data": [ + -3.628286123275757, + -1.7747509479522705, + -0.19457578659057617, + -2.395268678665161, + -0.2672767639160156, + 1.6636600494384766, + 2.7361106872558594, + -2.902493476867676 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l4": { + "data": [ + -4.130977630615234, + 2.616786003112793, + -3.852827548980713, + -0.8522329330444336, + -0.6961202621459961, + 0.49065589904785156, + -4.21832799911499, + -0.5513343811035156 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l5": { + "data": [ + -0.21466827392578125, + 3.5537376403808594, + -3.7675487995147705, + 4.906822204589844, + -3.722212314605713, + -1.0925579071044922, + 3.1661453247070312, + 0.9503436088562012 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l6": { + "data": [ + 4.270698547363281, + -0.9052324295043945, + -3.8193154335021973, + -4.525848388671875, + -0.30591487884521484, + -2.857205867767334, + 0.25072336196899414, + 2.9556703567504883 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l7": { + "data": [ + -3.0207204818725586, + 0.41107892990112305, + 1.8510746955871582, + 2.933957576751709, + -3.64399790763855, + -3.2292330265045166, + -0.4127206802368164, + 3.5584144592285156 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + -3.4809136390686035, + 2.264728546142578, + -4.266811370849609, + -1.241927146911621, + -0.6377410888671875, + -3.5931968688964844, + -0.15332460403442383, + 4.545896530151367 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + -1.7033541202545166, + 0.3431119918823242, + 0.9715232849121094, + -3.105705976486206, + 3.492002487182617, + 3.131464958190918, + -2.9434382915496826, + 4.742429733276367 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_2": { + "data": [ + -2.962273359298706, + 3.9950218200683594, + 1.6904220581054688, + 4.854471206665039, + 4.110817909240723, + -0.9114718437194824, + 1.317741870880127, + -4.7364091873168945 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_3": { + "data": [ + 4.841580390930176, + 3.4891843795776367, + -4.655121803283691, + -1.4582061767578125, + 3.0532665252685547, + 0.668736457824707, + -0.7960214614868164, + 0.8393869400024414 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_4": { + "data": [ + -1.8250370025634766, + -3.8680505752563477, + 3.660983085632324, + -0.20006895065307617, + -0.8848738670349121, + 3.7470951080322266, + -3.8722217082977295, + -0.14223480224609375 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_5": { + "data": [ + -4.142299652099609, + 4.823736190795898, + 4.255157470703125, + -3.674696683883667, + 0.696253776550293, + 3.6422557830810547, + -0.20247936248779297, + 4.1369829177856445 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_6": { + "data": [ + -2.0664501190185547, + -0.10728597640991211, + -3.3495473861694336, + -1.4406120777130127, + 0.7708454132080078, + -4.890356063842773, + 1.7780232429504395, + 4.020656585693359 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_7": { + "data": [ + -0.47556638717651367, + 1.7370271682739258, + -2.5221478939056396, + -3.3124852180480957, + 2.141094207763672, + -3.798264265060425, + -3.913508653640747, + 1.0798931121826172 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + 0.8427715301513672, + -0.3623795509338379, + 2.189702033996582, + 1.1002016067504883, + -0.9313831329345703, + 0.37019968032836914, + 4.0137434005737305, + 0.5058774948120117 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + 2.863511085510254, + -1.7578387260437012, + -4.061868190765381, + 2.4990406036376953, + -2.5228404998779297, + -1.2569129467010498, + 3.723520278930664, + 0.3568706512451172 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + 3.277338981628418, + -2.514725923538208, + -1.9622313976287842, + 2.0919203758239746, + 1.274425983428955, + 4.781658172607422, + -3.068598508834839, + -1.2724018096923828 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + -3.0599617958068848, + 4.785041809082031, + -1.820225715637207, + 3.7531795501708984, + -2.155280113220215, + -0.8215103149414062, + 3.6950721740722656, + 4.884031295776367 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t4": { + "data": [ + 4.873963356018066, + 1.7840375900268555, + 4.383649826049805, + 4.112177848815918, + 0.028369426727294922, + 1.1834344863891602, + -1.0258245468139648, + -4.274955749511719 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t5": { + "data": [ + 0.05514240264892578, + 1.2505817413330078, + -3.052520751953125, + -3.544718027114868, + 3.4227123260498047, + 1.1213006973266602, + -1.3860869407653809, + -4.5196638107299805 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t6": { + "data": [ + -3.4802377223968506, + 4.9503326416015625, + -0.8992242813110352, + 4.389162063598633, + -3.434615135192871, + -3.2621967792510986, + 1.9103469848632812, + -0.605682373046875 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t7": { + "data": [ + 1.1960840225219727, + -4.076590538024902, + -0.9000587463378906, + -4.77763557434082, + 1.2126026153564453, + 4.437448501586914, + 1.5291452407836914, + -3.80900502204895 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 46f4792a3..62729030f 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -47,8 +47,8 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> l0_add = std_add(2); idx = std_reg(32); idx_add = std_add(32); - lt_iter_limit = std_lt(32); cond_reg = std_reg(1); + lt_iter_limit = std_lt(32); idx_between_5_depth_plus_5_reg = std_reg(1); index_lt_depth_plus_5 = std_lt(32); index_ge_5 = std_ge(32); @@ -146,16 +146,16 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> idx.in = idx_add.out; idx.write_en = 1'd1; } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } static<1> group lt_iter_limit_group { lt_iter_limit.left = idx_add.out; lt_iter_limit.right = iter_limit.out; cond_reg.in = lt_iter_limit.out; cond_reg.write_en = 1'd1; } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } static<1> group idx_between_5_depth_plus_5_group { index_ge_5.left = idx_add.out; index_ge_5.right = 32'd5; @@ -230,13 +230,13 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> l0_idx_init; init_idx; init_min_depth; - init_iter_limit; init_cond_reg; init_idx_between_5_depth_plus_5; init_idx_between_0_depth_plus_0; init_idx_between_1_depth_plus_1; init_idx_between_1_min_depth_4_plus_1; init_idx_between_depth_plus_5_depth_plus_6; + init_iter_limit; } while cond_reg.out { static par { diff --git a/tests/frontend/systolic/array-2.expect b/tests/frontend/systolic/array-2.expect index c8ac3cdca..e0682f062 100644 --- a/tests/frontend/systolic/array-2.expect +++ b/tests/frontend/systolic/array-2.expect @@ -66,8 +66,8 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_ l1_add = std_add(2); idx = std_reg(32); idx_add = std_add(32); - lt_iter_limit = std_lt(32); cond_reg = std_reg(1); + lt_iter_limit = std_lt(32); idx_between_5_depth_plus_5_reg = std_reg(1); index_lt_depth_plus_5 = std_lt(32); index_ge_5 = std_ge(32); @@ -278,16 +278,16 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_ idx.in = idx_add.out; idx.write_en = 1'd1; } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } static<1> group lt_iter_limit_group { lt_iter_limit.left = idx_add.out; lt_iter_limit.right = iter_limit.out; cond_reg.in = lt_iter_limit.out; cond_reg.write_en = 1'd1; } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } static<1> group idx_between_5_depth_plus_5_group { index_ge_5.left = idx_add.out; index_ge_5.right = 32'd5; @@ -476,7 +476,6 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_ l1_idx_init; init_idx; init_min_depth; - init_iter_limit; init_cond_reg; init_idx_between_5_depth_plus_5; init_idx_between_2_depth_plus_2; @@ -491,6 +490,7 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_ init_idx_between_2_min_depth_4_plus_2; init_idx_between_6_depth_plus_6; init_idx_between_depth_plus_7_depth_plus_8; + init_iter_limit; } while cond_reg.out { static par { diff --git a/tests/frontend/systolic/array-3.expect b/tests/frontend/systolic/array-3.expect index 7d0fa872e..580d914d0 100644 --- a/tests/frontend/systolic/array-3.expect +++ b/tests/frontend/systolic/array-3.expect @@ -90,8 +90,8 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_ l2_add = std_add(2); idx = std_reg(32); idx_add = std_add(32); - lt_iter_limit = std_lt(32); cond_reg = std_reg(1); + lt_iter_limit = std_lt(32); idx_between_depth_plus_8_depth_plus_9_reg = std_reg(1); index_lt_depth_plus_9 = std_lt(32); index_ge_depth_plus_8 = std_ge(32); @@ -433,16 +433,16 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_ idx.in = idx_add.out; idx.write_en = 1'd1; } + static<1> group init_cond_reg { + cond_reg.in = 1'd1; + cond_reg.write_en = 1'd1; + } static<1> group lt_iter_limit_group { lt_iter_limit.left = idx_add.out; lt_iter_limit.right = iter_limit.out; cond_reg.in = lt_iter_limit.out; cond_reg.write_en = 1'd1; } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } static<1> group idx_between_depth_plus_8_depth_plus_9_group { index_ge_depth_plus_8.left = idx_add.out; index_ge_depth_plus_8.right = depth_plus_8.out; @@ -731,7 +731,6 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_ l2_idx_init; init_idx; init_min_depth; - init_iter_limit; init_cond_reg; init_idx_between_depth_plus_8_depth_plus_9; init_idx_between_2_min_depth_4_plus_2; @@ -753,6 +752,7 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_ init_idx_between_1_min_depth_4_plus_1; init_idx_between_6_depth_plus_6; init_idx_between_depth_plus_7_depth_plus_8; + init_iter_limit; } while cond_reg.out { static par { diff --git a/tools/data_gen/src/main.rs b/tools/data_gen/src/main.rs index b4c7e23ff..cbcbdba15 100644 --- a/tools/data_gen/src/main.rs +++ b/tools/data_gen/src/main.rs @@ -11,6 +11,7 @@ use std::path::{Path, PathBuf}; // run: cargo run -p data_gen -- to generate data w/ all 0s and // type int // add -f true if you want random values of type fix<32,16> +// add -r true if you want randomized values lazy_static::lazy_static! { static ref SIZEMAP: HashMap<&'static str, Vec<&'static str>> = { @@ -136,7 +137,7 @@ fn gen_random_4d_int( // generates random of size usize fn gen_random_vec(d0: usize) -> Vec { let mut rng = rand::thread_rng(); - (0..d0).map(|_| rng.gen_range(0.0..1.0)).collect() + (0..d0).map(|_| rng.gen_range(-5.0..5.0)).collect() } // generates random 2d vec of size usize From 3ea001438fb5c8e363b8d042d95b1b6d4113505b Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 10 Aug 2023 15:21:06 +0530 Subject: [PATCH 016/189] `dead-assign-removal` considers continuous assignments (#1652) --- calyx-ir/src/structure.rs | 2 + .../src/passes/dead_assignment_removal.rs | 95 ++++++++++++------- .../simple.expect} | 0 .../simple.futil} | 0 .../dead-assign-removal/unused-cont.expect | 20 ++++ .../dead-assign-removal/unused-cont.futil | 24 +++++ .../dead-assign-removal/used-cont.expect | 22 +++++ .../dead-assign-removal/used-cont.futil | 24 +++++ 8 files changed, 153 insertions(+), 34 deletions(-) rename tests/passes/{dead-assign-removal.expect => dead-assign-removal/simple.expect} (100%) rename tests/passes/{dead-assign-removal.futil => dead-assign-removal/simple.futil} (100%) create mode 100644 tests/passes/dead-assign-removal/unused-cont.expect create mode 100644 tests/passes/dead-assign-removal/unused-cont.futil create mode 100644 tests/passes/dead-assign-removal/used-cont.expect create mode 100644 tests/passes/dead-assign-removal/used-cont.futil diff --git a/calyx-ir/src/structure.rs b/calyx-ir/src/structure.rs index 178ce5a3a..fa1867fec 100644 --- a/calyx-ir/src/structure.rs +++ b/calyx-ir/src/structure.rs @@ -441,6 +441,8 @@ impl Cell { // returns true if cell is comb, false otherwise // note that this component/component cannot be combinational + // XXX(rachit): Combinational components are now supported so this function returns + // the wrong answer when the parent is a combinational component pub fn is_comb_cell(&self) -> bool { match self.prototype { CellType::Primitive { is_comb, .. } => is_comb, diff --git a/calyx-opt/src/passes/dead_assignment_removal.rs b/calyx-opt/src/passes/dead_assignment_removal.rs index 1c89690fd..a28fa71d5 100644 --- a/calyx-opt/src/passes/dead_assignment_removal.rs +++ b/calyx-opt/src/passes/dead_assignment_removal.rs @@ -2,8 +2,8 @@ use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir::{self as ir}; use std::collections::{HashMap, HashSet}; -// maps combinational combinational components to set of all combinational components that it reads from -// so the entries are (comb comp, ) +// Construct map from combinational instances to all the combinational instances that write to them. +// So the entries are (comb comp, ) fn get_comb_dependence_map( assigns: &Vec>, ) -> HashMap> { @@ -74,45 +74,72 @@ impl Named for DeadAssignmentRemoval { } } +/// Saturate the combinational dependence map by repeatedly adding used cells till we reach a fixed point. +fn saturate_dep_maps( + mut comb_dep_map: HashMap>, + mut non_comb_writes: Vec, +) -> HashSet { + // To be a used_comb, must + // a) be a non_comb_write + // b) writes to a used_comb + let mut used_combs = HashSet::new(); + // while loop is bound by size of comb_dependence_map, which is bound + // in size by number of ports in the group's assignments + while !(non_comb_writes.is_empty()) { + let used = non_comb_writes.pop().unwrap(); + // add all writes to used to non_comb_writes + if let Some(write_to_used) = comb_dep_map.remove(&used) { + for write in write_to_used { + non_comb_writes.push(write); + } + } + // add used to used_combs + used_combs.insert(used); + } + + used_combs +} + impl Visitor for DeadAssignmentRemoval { - fn enable( + fn start( &mut self, - s: &mut ir::Enable, - _comp: &mut ir::Component, + comp: &mut ir::Component, _sigs: &ir::LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - let mut comb_dependence_map: HashMap> = - get_comb_dependence_map(&s.group.borrow().assignments); - let mut non_comb_writes: Vec = - get_non_comb_writes(&s.group.borrow().assignments); - // To be a used_comb, must - // a) be a non_comb_write - // b) writes to a used_comb - let mut used_combs: HashSet = HashSet::new(); - // while loop is bound by size of comb_dependence_map, which is bound - // in size by number of ports in the group's assignments - while !(non_comb_writes.is_empty()) { - let used = non_comb_writes.pop().unwrap(); - // add all writes to used to non_comb_writes - if let Some(write_to_used) = comb_dependence_map.remove(&used) { - for write in write_to_used { - non_comb_writes.push(write); + let cont_comb_dep_map = + get_comb_dependence_map(&comp.continuous_assignments); + let cont_non_comb_writes = + get_non_comb_writes(&comp.continuous_assignments); + + for gr in comp.groups.iter() { + let group = gr.borrow(); + + // Construct the dependence maps from the group assignments and extend using the continuous assignments + let mut comb_dependence_map = + get_comb_dependence_map(&group.assignments); + comb_dependence_map.extend(cont_comb_dep_map.clone()); + + let mut non_comb_writes = get_non_comb_writes(&group.assignments); + non_comb_writes.extend(cont_non_comb_writes.clone()); + + let used_combs = + saturate_dep_maps(comb_dependence_map, non_comb_writes); + + // Explicit drop so we don't get already borrowed error from mutable borrow. + drop(group); + + gr.borrow_mut().assignments.retain(|assign| { + let dst = assign.dst.borrow(); + // if dst is a combinational component, must be used + if dst.parent_is_comb() { + return used_combs.contains(&dst.get_parent_name()); } - } - // add used to used_combs - used_combs.insert(used); + // Make sure that the assignment's guard it not false + !assign.guard.is_false() + }); } - s.group.borrow_mut().assignments.retain(|assign| { - let dst = assign.dst.borrow(); - // if dst is a combinational component, must be used - if dst.parent_is_comb() { - return used_combs.contains(&dst.get_parent_name()); - } - // Make sure that the assignment's guard it not false - !assign.guard.is_false() - }); - Ok(Action::Continue) + Ok(Action::Stop) } } diff --git a/tests/passes/dead-assign-removal.expect b/tests/passes/dead-assign-removal/simple.expect similarity index 100% rename from tests/passes/dead-assign-removal.expect rename to tests/passes/dead-assign-removal/simple.expect diff --git a/tests/passes/dead-assign-removal.futil b/tests/passes/dead-assign-removal/simple.futil similarity index 100% rename from tests/passes/dead-assign-removal.futil rename to tests/passes/dead-assign-removal/simple.futil diff --git a/tests/passes/dead-assign-removal/unused-cont.expect b/tests/passes/dead-assign-removal/unused-cont.expect new file mode 100644 index 000000000..adee51f21 --- /dev/null +++ b/tests/passes/dead-assign-removal/unused-cont.expect @@ -0,0 +1,20 @@ +import "primitives/core.futil"; +component main(x: 16, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { + cells { + r = std_reg(8); + rsh = std_rsh(16); + slice = std_slice(16, 8); + } + wires { + group write { + r.write_en = 1'd1; + r.in = 8'd10; + write[done] = r.done; + } + out = r.out; + slice.in = rsh.out; + } + control { + write; + } +} diff --git a/tests/passes/dead-assign-removal/unused-cont.futil b/tests/passes/dead-assign-removal/unused-cont.futil new file mode 100644 index 000000000..9821828b9 --- /dev/null +++ b/tests/passes/dead-assign-removal/unused-cont.futil @@ -0,0 +1,24 @@ +// -p validate -p dead-assign-removal +import "primitives/core.futil"; + +component main(x: 16) -> (out: 8) { + cells { + r = std_reg(8); + rsh = std_rsh(16); + slice = std_slice(16, 8); + } + wires { + group write { + rsh.left = x; + rsh.right = 16'd8; + r.in = 8'd10; + r.write_en = 1'd1; + write[done] = r.done; + } + slice.in = rsh.out; + out = r.out; + } + control { + write; + } +} \ No newline at end of file diff --git a/tests/passes/dead-assign-removal/used-cont.expect b/tests/passes/dead-assign-removal/used-cont.expect new file mode 100644 index 000000000..ba00db327 --- /dev/null +++ b/tests/passes/dead-assign-removal/used-cont.expect @@ -0,0 +1,22 @@ +import "primitives/core.futil"; +component main(x: 16, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { + cells { + r = std_reg(8); + rsh = std_rsh(16); + slice = std_slice(16, 8); + } + wires { + group write { + r.write_en = 1'd1; + r.in = slice.out; + rsh.right = 16'd8; + rsh.left = x; + write[done] = r.done; + } + out = r.out; + slice.in = rsh.out; + } + control { + write; + } +} diff --git a/tests/passes/dead-assign-removal/used-cont.futil b/tests/passes/dead-assign-removal/used-cont.futil new file mode 100644 index 000000000..371a37d4a --- /dev/null +++ b/tests/passes/dead-assign-removal/used-cont.futil @@ -0,0 +1,24 @@ +// -p validate -p dead-assign-removal +import "primitives/core.futil"; + +component main(x: 16) -> (out: 8) { + cells { + r = std_reg(8); + rsh = std_rsh(16); + slice = std_slice(16, 8); + } + wires { + group write { + rsh.left = x; + rsh.right = 16'd8; + r.in = slice.out; + r.write_en = 1'd1; + write[done] = r.done; + } + slice.in = rsh.out; + out = r.out; + } + control { + write; + } +} \ No newline at end of file From e25dc21a5a6fdc8c338208f4d2a7e6d3354e3e1f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 10 Aug 2023 15:36:41 +0530 Subject: [PATCH 017/189] Support inlining `ref` cells (#1651) * controlport analysis gets ref cells from invokes * support ref cell inlining * add test for inlining and fix broken test --- CHANGELOG.md | 1 + calyx-opt/src/analysis/control_ports.rs | 37 ++++++--- calyx-opt/src/default_passes.rs | 4 +- calyx-opt/src/passes/component_iniliner.rs | 91 ++++++++++++++-------- calyx-opt/src/passes/data_path_infer.rs | 4 +- tests/passes/inliner/inline-ref.expect | 41 ++++++++++ tests/passes/inliner/inline-ref.futil | 32 ++++++++ 7 files changed, 164 insertions(+), 46 deletions(-) create mode 100644 tests/passes/inliner/inline-ref.expect create mode 100644 tests/passes/inliner/inline-ref.futil diff --git a/CHANGELOG.md b/CHANGELOG.md index ddb240cbb..6517d71f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Unreleased - Don't require `@clk` and `@reset` ports in `comb` components +- `inline` pass supports inlining `ref` cells ## 0.4.0 diff --git a/calyx-opt/src/analysis/control_ports.rs b/calyx-opt/src/analysis/control_ports.rs index 486854a1f..2ca1c46d7 100644 --- a/calyx-opt/src/analysis/control_ports.rs +++ b/calyx-opt/src/analysis/control_ports.rs @@ -6,7 +6,7 @@ use std::{ }; type PortMap = HashMap>>; -type Binding = Vec<(ir::Id, RRC)>; +type Binding = (Vec<(ir::Id, RRC)>, Vec<(ir::Id, RRC)>); type InvokeMap = HashMap>; /// Contains a mapping from name of [ir::CombGroup] to the ports read by the control program @@ -15,7 +15,7 @@ type InvokeMap = HashMap>; pub struct ControlPorts { // Map name of combinational group to the ports read by the control program. cg_to_port: PortMap, - // Mapping from name of invoke instance to the port bindings. + // Mapping from name of invoke instance to the ref cells and port bindings. invoke_map: InvokeMap, } @@ -61,6 +61,7 @@ impl ControlPorts { &mut self, inputs: &[(ir::Id, ir::RRC)], outputs: &[(ir::Id, ir::RRC)], + ref_cells: &[(ir::Id, ir::RRC)], comp: &ir::RRC, comb_group: &Option>, ) { @@ -86,7 +87,10 @@ impl ControlPorts { let name = comp.borrow().name(); let bindings = inputs.iter().chain(outputs.iter()).cloned().collect_vec(); - self.invoke_map.entry(name).or_default().push(bindings); + self.invoke_map + .entry(name) + .or_default() + .push((ref_cells.to_vec(), bindings)); } } @@ -113,9 +117,10 @@ impl ControlPorts { comp, inputs, outputs, + ref_cells, .. }) => { - self.handle_invoke(inputs, outputs, comp, &None); + self.handle_invoke(inputs, outputs, ref_cells, comp, &None); } } } @@ -128,9 +133,12 @@ impl ControlPorts { comb_group, inputs, outputs, + ref_cells, .. }) => { - self.handle_invoke(inputs, outputs, comp, comb_group); + self.handle_invoke( + inputs, outputs, ref_cells, comp, comb_group, + ); } ir::Control::If(ir::If { cond, @@ -193,12 +201,19 @@ impl From<&ir::Control> for ControlPorts { cp.invoke_map.values_mut().for_each(|v| { *v = v .drain(..) - .unique_by(|binding| { - binding - .clone() - .into_iter() - .map(|(p, v)| (p, v.borrow().canonical())) - .collect_vec() + .unique_by(|(cells, ports)| { + ( + cells + .clone() + .into_iter() + .map(|(c, cell)| (c, cell.borrow().name())) + .collect_vec(), + ports + .clone() + .into_iter() + .map(|(p, v)| (p, v.borrow().canonical())) + .collect_vec(), + ) }) .collect() }); diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 0190e9f83..9455f95b7 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -87,10 +87,10 @@ impl PassManager { DeadAssignmentRemoval, GroupToInvoke, // Creates Dead Groups potentially InferShare, - CompileRef, //Must run before cell-share, and before component-inliner ComponentInliner, CombProp, - CellShare, // LiveRangeAnalaysis should handle comb groups + CompileRef, //Must run before cell-share, and before component-inliner + CellShare, // LiveRangeAnalaysis should handle comb groups SimplifyWithControl, // Must run before infer-static-timing CompileInvoke, // creates dead comb groups AttributePromotion, diff --git a/calyx-opt/src/passes/component_iniliner.rs b/calyx-opt/src/passes/component_iniliner.rs index 18a4390ce..1c925c372 100644 --- a/calyx-opt/src/passes/component_iniliner.rs +++ b/calyx-opt/src/passes/component_iniliner.rs @@ -271,6 +271,7 @@ impl ComponentInliner { /// of interface ports of the component being inlined. fn inline_component( builder: &mut ir::Builder, + mut cell_map: rewriter::RewriteMap, comp: &ir::Component, name: ir::Id, ) -> ( @@ -279,11 +280,14 @@ impl ComponentInliner { ) { // For each cell in the component, create a new cell in the parent // of the same type and build a rewrite map using it. - let cell_map: rewriter::RewriteMap = comp - .cells - .iter() - .map(|cell_ref| Self::inline_cell(builder, cell_ref)) - .collect(); + cell_map.extend(comp.cells.iter().filter_map(|cell_ref| { + if !cell_ref.borrow().is_reference() { + Some(Self::inline_cell(builder, cell_ref)) + } else { + None + } + })); + // Rewrites to inline the interface. let interface_map = Self::inline_interface(builder, comp, name); let rewrite = ir::Rewriter::new(&cell_map, &interface_map); @@ -372,6 +376,30 @@ impl Visitor for ComponentInliner { return Ok(Action::Stop); } + // Use analysis to get all bindings for invokes and filter out bindings + // for inlined cells. + let invoke_bindings: HashMap = + analysis::ControlPorts::::from(&*comp.control.borrow()) + .get_all_bindings() + .into_iter() + .filter(|(instance, _)| { + inline_cells.iter().any(|c| c.borrow().name() == instance) + }) + .collect(); + + // If any invoke has more than one binding, error out: + for (instance, bindings) in &invoke_bindings { + if bindings.len() > 1 { + return Err( + Error::pass_assumption( + Self::name(), + format!( + "Instance `{}.{}` invoked with multiple parameters (currently unsupported)", + comp.name, + instance))); + } + } + // Mapping from component name to component definition let comp_map = comps .iter() @@ -385,17 +413,8 @@ impl Visitor for ComponentInliner { let mut builder = ir::Builder::new(comp, sigs); for cell_ref in &inline_cells { let cell = cell_ref.borrow(); - if cell.is_component() { - let comp_name = cell.type_name().unwrap(); - let (control, rewrites) = Self::inline_component( - &mut builder, - comp_map[&comp_name], - cell.name(), - ); - interface_rewrites.extend(rewrites); - self.control_map.insert(cell.name(), control); - inlined_cells.insert(cell.name()); - } else { + // Error if the cell is not a component + if !cell.is_component() { let msg = format!( "Cannot inline `{}`. It is a instance of primitive: `{}`", cell.name(), @@ -406,6 +425,28 @@ impl Visitor for ComponentInliner { return Err(Error::pass_assumption(Self::name(), msg) .with_pos(&cell.attributes)); } + + let comp_name = cell.type_name().unwrap(); + let cell_map = + if let Some(binding) = &invoke_bindings.get(&cell.name()) { + let (cell_binds, _) = &binding[0]; + cell_binds.iter().map(|(k, v)| (*k, v.clone())).collect() + } else { + log::info!( + "no binding for `{}` which means instance is unused", + cell.name() + ); + HashMap::new() + }; + let (control, rewrites) = Self::inline_component( + &mut builder, + cell_map, + comp_map[&comp_name], + cell.name(), + ); + interface_rewrites.extend(rewrites); + self.control_map.insert(cell.name(), control); + inlined_cells.insert(cell.name()); } // XXX: This is unneccessarily iterate over the newly inlined groups. @@ -440,15 +481,6 @@ impl Visitor for ComponentInliner { }); }); - // Use analysis to get all bindings for invokes and filter out bindings - // for inlined cells. - let invoke_bindings = analysis::ControlPorts::::from( - &*builder.component.control.borrow(), - ) - .get_all_bindings() - .into_iter() - .filter(|(instance, _)| inlined_cells.contains(instance)); - // Ensure that all invokes use the same parameters and inline the parameter assignments. for (instance, mut bindings) in invoke_bindings { if bindings.len() > 1 { @@ -460,8 +492,9 @@ impl Visitor for ComponentInliner { comp.name, instance))); } - let binding = - bindings.pop().expect("Instance binding cannot be empty"); + let Some((_, binding)) = bindings.pop() else { + unreachable!("Instance binding is empty"); + }; let mut assigns = binding .into_iter() .map(|(name, param)| { @@ -540,10 +573,6 @@ impl Visitor for ComponentInliner { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - // Invokes with ref cells are not supported - if !s.ref_cells.is_empty() { - return Err(Error::pass_assumption(Self::name(), format!("invoke with ref cell is not supported. Run {} before this pass", super::CompileRef::name()))); - } // Regardless of whether the associated instance has been inlined, // we still may need to rewrite the input/output ports self.rewrite_invoke_ports(s); diff --git a/calyx-opt/src/passes/data_path_infer.rs b/calyx-opt/src/passes/data_path_infer.rs index fc705994a..934fbce0d 100644 --- a/calyx-opt/src/passes/data_path_infer.rs +++ b/calyx-opt/src/passes/data_path_infer.rs @@ -37,10 +37,10 @@ impl DataPathInfer { /// Mark the cell associated with the port as a part of the control path. fn mark_port_control(&mut self, port: &ir::Port) { if Self::always_safe_src(port) || port.is_hole() { - log::info!("`{}': safe port", port.canonical()); + log::debug!("`{}': safe port", port.canonical()); return; } - log::info!("`{}': control port", port.canonical()); + log::debug!("`{}': control port", port.canonical()); self.control_cells.insert(port.get_parent_name()); } diff --git a/tests/passes/inliner/inline-ref.expect b/tests/passes/inliner/inline-ref.expect new file mode 100644 index 000000000..293b14e00 --- /dev/null +++ b/tests/passes/inliner/inline-ref.expect @@ -0,0 +1,41 @@ +import "primitives/compile.futil"; +component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + ref r = std_reg(32); + add = std_add(32); + } + wires { + group incr { + add.right = 32'd1; + add.left = r.out; + r.write_en = 1'd1; + r.in = add.out; + incr[done] = r.done; + } + } + control { + incr; + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + @generated add = std_add(32); + @generated f_go = std_wire(1); + @generated f_clk = std_wire(1); + @generated f_reset = std_wire(1); + @generated f_done = std_wire(1); + } + wires { + group incr { + add.right = 32'd1; + add.left = r0.out; + r0.write_en = 1'd1; + r0.in = add.out; + incr[done] = r0.done; + } + } + control { + incr; + } +} diff --git a/tests/passes/inliner/inline-ref.futil b/tests/passes/inliner/inline-ref.futil new file mode 100644 index 000000000..a889e01c4 --- /dev/null +++ b/tests/passes/inliner/inline-ref.futil @@ -0,0 +1,32 @@ +// -p validate -p inline +import "primitives/compile.futil"; + +component foo() -> () { + cells { + ref r = std_reg(32); + add = std_add(32); + } + wires { + group incr { + r.in = add.out; + r.write_en = 1'd1; + add.left = r.out; + add.right = 32'd1; + incr[done] = r.done; + } + } + control { + incr; + } +} + +component main () -> () { + cells { + @inline f = foo(); + r0 = std_reg(32); + } + wires {} + control { + invoke f[r=r0]()(); + } +} \ No newline at end of file From a7adeeea3dd4b9925c82f87f2ce3f97c62a60c60 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 10 Aug 2023 16:04:22 +0530 Subject: [PATCH 018/189] Inling does not generate assignments for clk and reset ports (#1654) --- calyx-opt/src/passes/component_iniliner.rs | 41 ++++++++++++++++------ 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/calyx-opt/src/passes/component_iniliner.rs b/calyx-opt/src/passes/component_iniliner.rs index 1c925c372..f2736ae9b 100644 --- a/calyx-opt/src/passes/component_iniliner.rs +++ b/calyx-opt/src/passes/component_iniliner.rs @@ -390,13 +390,35 @@ impl Visitor for ComponentInliner { // If any invoke has more than one binding, error out: for (instance, bindings) in &invoke_bindings { if bindings.len() > 1 { + let bindings_str = bindings + .iter() + .map(|(cells, ports)| { + format!( + "[{}]({})", + cells + .iter() + .map(|(c, cell)| format!( + "{c}={}", + cell.borrow().name() + )) + .join(", "), + ports + .iter() + .map(|(p, port)| format!( + "{p}={}", + port.borrow().canonical() + )) + .join(", ") + ) + }) + .join("\n"); return Err( Error::pass_assumption( Self::name(), format!( - "Instance `{}.{}` invoked with multiple parameters (currently unsupported)", + "Instance `{}.{instance}` invoked with multiple parameters (currently unsupported):\n{bindings_str}", comp.name, - instance))); + ))); } } @@ -483,20 +505,17 @@ impl Visitor for ComponentInliner { // Ensure that all invokes use the same parameters and inline the parameter assignments. for (instance, mut bindings) in invoke_bindings { - if bindings.len() > 1 { - return Err( - Error::pass_assumption( - Self::name(), - format!( - "Instance `{}.{}` invoked with multiple parameters (currently unsupported)", - comp.name, - instance))); - } let Some((_, binding)) = bindings.pop() else { unreachable!("Instance binding is empty"); }; let mut assigns = binding .into_iter() + .filter(|(_, pr)| { + let port = pr.borrow(); + // Skip clk and reset ports + !port.attributes.has(ir::BoolAttr::Clk) + && !port.attributes.has(ir::BoolAttr::Reset) + }) .map(|(name, param)| { let port = Rc::clone( &interface_rewrites[&ir::Canonical(instance, name)], From 7b9316748e05b49a3ed329579d208fcaf3d6973e Mon Sep 17 00:00:00 2001 From: Basant Khalil Date: Thu, 10 Aug 2023 11:09:43 -0400 Subject: [PATCH 019/189] Get the file path and respond to initialization requests (#1647) * trying to use dap-rs intially for server0 * creating TCP connection for the server to attach * connecting to server and client in dap.rs; not fully successfull yet * can print result now * working for second request. still need cleanup. * got the second request to work? -_- * pretty printing * remove the loopfor server.run and clean up * clean up a bit; remove unused variables * launch the extension * convert the adapter to use stdin/stdout * revert launch.json * Make adapter agnostic to read/write operations * adding optional path argument * switch to either run with stdin/stdout or tcp * switch based on the flag to either use stdin/stdout or rather switch to tcp * add the needed dependencies for argh * remove unused imports * proper error handling * run cargo clippy and fix the linting * delete symlink committed by mistake * implement better error handling * add docs for error variants * add commands in the extension.js for printing logging messages to track the status of the extension attaching * can print as well as invoke the adpater, need to figure outpassing file as an argument * get file name from user * can successfully take file as input from the user * log when extension activates * change it so that it does not ask for file name twice * try it with multi-session * it can attach to vscode currently in multi session * work on getting file path and intialization. * changes to PR for better readability * change the release for dap-rs * Create README.md * Update README.md * Update README.md * clippy --- .vscode/launch.json | 13 +++ Cargo.lock | 146 +++++++++++++++++++----------- cider-dap/Cargo.toml | 9 +- cider-dap/README.md | 105 +++++++++++++++++++++ cider-dap/calyxDebug/extension.js | 142 +++++++++++++++++++++++++++++ cider-dap/src/error.rs | 16 +++- cider-dap/src/main.rs | 107 +++++++++++++++++++--- 7 files changed, 467 insertions(+), 71 deletions(-) create mode 100644 cider-dap/README.md create mode 100644 cider-dap/calyxDebug/extension.js diff --git a/.vscode/launch.json b/.vscode/launch.json index 116775c4d..9e20f454f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,19 @@ { "version": "0.2.0", "configurations": [ + { + "type": "cider-dap", + "request": "launch", + "name": "Launch Program (Multi Session)", + "program": "${file}", + "stopOnEntry": true, + }, + { + "type": "cider-dap", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceFolder}/Program" + }, { "name": "Python: Current File", "type": "python", diff --git a/Cargo.lock b/Cargo.lock index 035757aff..e2b818658 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,8 +486,8 @@ dependencies = [ [[package]] name = "dap" -version = "0.2.0-alpha1" -source = "git+https://github.com/sztomi/dap-rs?rev=7be5376#7be5376b84fbf1a3fbbc1953153e0130cbc7bfb6" +version = "0.3.1-alpha1" +source = "git+https://github.com/sztomi/dap-rs?tag=v0.3.1-alpha1#0a989dcd8bdd45233dca4af728120fa19566c416" dependencies = [ "serde", "serde_json", @@ -539,7 +539,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] @@ -561,7 +561,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] @@ -666,9 +666,12 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] name = "fd-lock" @@ -677,7 +680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix", + "rustix 0.38.3", "windows-sys", ] @@ -836,6 +839,15 @@ dependencies = [ "serde", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "interp" version = "0.1.1" @@ -870,6 +882,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys", +] + [[package]] name = "itertools" version = "0.9.0" @@ -890,9 +913,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "js-sys" @@ -927,6 +950,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.3" @@ -1103,9 +1132,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "pest" -version = "2.7.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" +checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" dependencies = [ "thiserror", "ucd-trie", @@ -1135,9 +1164,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" +checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" dependencies = [ "pest", "pest_generator", @@ -1145,22 +1174,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" +checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] name = "pest_meta" -version = "2.7.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" +checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", @@ -1225,9 +1254,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -1270,9 +1299,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.31" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -1397,9 +1426,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" dependencies = [ "aho-corasick", "memchr", @@ -1420,22 +1449,36 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "rustix" -version = "0.38.4" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" dependencies = [ "bitflags 2.3.3", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.3", "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "rusty-fork" @@ -1474,9 +1517,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -1495,9 +1538,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.174" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] @@ -1514,20 +1557,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.174" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ "itoa", "ryu", @@ -1591,7 +1634,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] @@ -1717,9 +1760,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -1740,14 +1783,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.7.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.23", "windows-sys", ] @@ -1782,22 +1826,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.25", ] [[package]] @@ -1875,9 +1919,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-segmentation" diff --git a/cider-dap/Cargo.toml b/cider-dap/Cargo.toml index 2e69afbd1..0510e6924 100644 --- a/cider-dap/Cargo.toml +++ b/cider-dap/Cargo.toml @@ -6,20 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] - -dap = { git = "https://github.com/sztomi/dap-rs", rev = "7be5376" } +dap = { git = "https://github.com/sztomi/dap-rs", tag = "v0.3.1-alpha1" } thiserror = "1.*" serde_json = "1.0" serde.workspace= true owo-colors = "^3.5" argh = "0.1" - -[[bin]] -name = "demo_client" -path = "src/demo_client.rs" - [[bin]] name = "cider-dap" path = "src/main.rs" - diff --git a/cider-dap/README.md b/cider-dap/README.md new file mode 100644 index 000000000..7e0d6c1af --- /dev/null +++ b/cider-dap/README.md @@ -0,0 +1,105 @@ +## About the Name? +Inspired by the comforting essence of apple cider, our sub-crate tries to bring some of that warmth to debugging. Now, onto what this project is and what's been brewing! + +cider-dap is a sub-crate created for facilitating debugging processes. The name is inspired by the core name "Cider", and "dap" stands for Debug Adapter Protocol! +### Project Overview: +Cider-dap is a debug adapter protocol implementation using Rust, which aids in debugging processes. It interfaces with IDEs or other tools using the Debug Adapter Protocol. +This project primarily leverages the Debug Adapter Protocol (DAP) for its functionality. The structure is organized into different directories and files which encapsulate the functionalities: +
+
+1.``` cider-dap ``` directory: The main directory which contains the following sub-directories and files: +
+        ```calyxDebug```: Contains the file responsible for debugging extensions and related utilities. So it is a dedicated directory for VSCode debugging extensions. It establishes the bridge between your Rust codebase and the VSCode debugging environment.
+        ```src```: Houses the Rust source files for the project. It contains the project's core functionalities, logic, and structures.
+        ```cargo.lock``` & ```cargo.toml```: Standard Rust project files detailing dependencies and project metadata.
+3. ```src``` directory:
+        ```adapter.rs```: Defines the primary adapter structure for the project and its associated functionalities. Not just any adapter, this file structures the fundamental protocols, handling the translation of high-level debugging commands into actionable, low-level instructions.
+        ```error.rs```: Contains custom error definitions and types for better error handling.
+        ```main.rs```: The entry point for the project, it integrates functionalities from the other source files and provides the main execution logic.
+4. ```calyxDebug``` directory:
+        ```extension.js```: JavaScript file for VSCode extension integration. It provides functions to interface between the VSCode environment and the Rust backend.
+ +### About main.rs: the Main File +In ``` main.rs ```, our program is set up to accommodate both single and multi-session debugging. It defines the entry point of our application and orchestrates how the server is run based on user-provided arguments. + +#### Initialization: +At the start of the ```main()``` function: + +- The Opts struct captures command-line arguments. This struct contains an optional file path, a switch to determine if the application runs in multi-session mode, and a port number (with a default of 8080). +- ```argh::from_env()``` processes the command-line arguments based on the defined struct. The use of argh simplifies command-line parsing, allowing you to focus on the main logic without getting bogged down in argument processing. + +#### Single vs. Multi-Session Decision: +Depending on whether the ```is_multi_session flag``` is set: + +##### Multi-Session: +-         A TCP listener is set up, which will listen for incoming debugger connections. +-         On accepting a connection, the streams are buffered for efficient I/O operations. +-         The multi_session_init function gets the adapter configured for the session, handling initial handshakes like the Initialize and Launch commands. +-         The run_server function then takes over, orchestrating the actual debugging session with the given adapter. +##### Single-Session: +-         Directly reads from standard input and writes to standard output. +-         Instead of expecting and processing initial handshakes, the function simply sets up the adapter with the provided file and begins the server loop. + +This dual mode is valuable: the single-session approach allows for streamlined debugging in local environments or for simpler setups, while the multi-session setup allows for more advanced scenarios, perhaps remote debugging or handling multiple debugger sessions. + +#### ```multi_session_init``` +This function sets up an adapter for a multi-session environment. Here's a step-by-step breakdown: +##### 1. Initial Handshake: +- It first waits for and processes an Initialize request. This is fundamental in the DAP as it establishes the initial connection between the debugger client and server. +- After successfully processing this request, it sends an Initialized event to notify the client that the server is ready for subsequent commands. + +##### 2. Setup: +- The next expected command is a Launch command. This command contains additional information (like the path to the program being debugged). This path is extracted and checked for validity. +- The program is then opened and used to construct the MyAdapter instance. +The purpose of this function is to perform the initial setup necessary to start a debugging session. By separating it from the run_server function, the code remains modular, allowing for easier debugging, testing, and modification. + +#### run_server : +The heart of the debugger's runtime: + +##### Core Loop : + +The function continuously polls for requests from the client. +- Upon receiving a Launch command, it sends a successful response back to the client. This indicates that the server is ready to begin debugging. +- The loop can be expanded to handle other DAP commands as needed. For example, handling a Disconnect command could cleanly terminate the loop and close the server. + +##### Command Processing: +- The only command being actively handled right now is the Launch command. Upon receiving this command, the server simply responds with a success message, indicating that it's ready to commence debugging. +- The loop is designed with extensibility in mind. Comments suggest places where commands like Disconnect can be incorporated to handle disconnection events, allowing the server to terminate gracefully. + +##### Error Handling : +- If an unknown command is received, it's printed to the error output and the server terminates with an UnhandledCommandError. +- This is a robust approach, ensuring that only expected commands are processed and any anomalies are immediately flagged. + +### Dependencies +The following dependencies have been added to the project as specified in the cargo.toml: +
+- ```dap```: Rust DAP implementation. At its core, this Rust DAP implementation is what powers cider-dap. It's the backbone that ensures all debugging actions are in line with the protocol's standards.
+- ```thiserror```: Used for ergonomic error handling. Enhancing error handling by providing more contextual feedback and streamlined debugging.
+- ```serde_json``` & ```serde```: Serialization and deserialization of data. Essential for data communication. They ensure that data structures are efficiently serialized and deserialized between different parts of the system.
+- ```owo-colors```: For colored console output. So it elevates user experience by introducing color-coded outputs, making console interactions more intuitive.
+- ```argh```: For command line argument parsing. It simplifies command line interactions, ensuring that user inputs are effectively parsed and processed.
+ +### Running the Project +1. Ensure you have the necessary dependencies installed. If not, you can install them using cargo: + ```cargo install ``` +3. To run the main project: +```cargo run ``` + +### Next Steps + +1. Advanced Error Handling: Utilize the structures in error.rs to provide detailed insights, potentially integrating with external error databases or logs. +2. Command Enhancements: Augment the DAP commands and responses in main.rs, exploring beyond traditional debugging actions. +3. There are changes needed to be done inside run_server: +### Additional Command Handling: +- Incorporate command handlers for other DAP commands: +- ```Disconnect ```: Handle disconnect commands gracefully, ensuring any necessary cleanup is done before closing the server. +- ```Breakpoint ```: Implement functionality to pause execution at specific points. +- ```StepOver ```, ```StepInto ```, ```StepOut ```: Allow fine-grained control over the debugging process, allowing users to inspect code step-by-step. +- ```Evaluate ```: Handle evaluation requests from the debugger, returning values as needed. +### Refined Error Handling: +- Instead of immediate termination on an unknown command, consider logging these events or sending specific error messages back to the client. This provides a more user-friendly debugging experience. +### Enhanced Logging: +- Implement more detailed logging to provide insights into server operations. This would be especially useful in identifying issues or understanding the flow of commands and responses. +### Asynchronous Processing: +- Consider incorporating asynchronous command processing. This would allow the server to handle multiple requests concurrently, offering faster response times and smoother user experiences, especially in complex debugging scenarios. + diff --git a/cider-dap/calyxDebug/extension.js b/cider-dap/calyxDebug/extension.js new file mode 100644 index 000000000..65af7769c --- /dev/null +++ b/cider-dap/calyxDebug/extension.js @@ -0,0 +1,142 @@ +const vscode = require('vscode'); +const cp = require('child_process'); +const net = require('net'); + +// Hold the debug adapter instance +let debugAdapter = null; +let programName = null; // Store the program name +// Create output channel +let outputChannel = vscode.window.createOutputChannel("cider dap"); + +function logToPanel(message) { + console.log("inside logPanel"); + outputChannel.appendLine(message); +} + +// Function to get the program name from the user +async function getProgramName() { + const fileName = await vscode.window.showInputBox({ + placeHolder: 'Please enter the name of a futil file in the workspace folder', + value: 'default.futil' + }); + + if (fileName) { + if (!fileName.startsWith('/')) { + const path = require('path'); + return path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, fileName); + } + return fileName; + } else { + return null; + } +} + +class CiderDebugAdapterDescriptorFactory { + constructor(adapterPath, workspace, outputChannel) { + logToPanel("inside constructor"); + this.adapter = new CiderDebugAdapter(adapterPath, workspace, outputChannel); + this.adapterPath = adapterPath; + this.workspace = workspace; + this.outputChannel = outputChannel; + } + + createDebugAdapterDescriptor(session) { + // Return a new debug adapter descriptor + logToPanel("creating adapter descriptor"); + return new vscode.DebugAdapterServer(this._startDebugServer(session)); + } + + _startDebugServer(session) { + logToPanel("start of startDebugServer"); + const port = 8888; // This is the default value + + if (!this.adapter.isServerRunning()) { + logToPanel("server is not running"); + this.adapter.start(port); + logToPanel("started dap-server"); + } + + logToPanel("exiting startDebugging"); + return port; + } +} +class CiderDebugAdapter { + constructor(adapterPath, cwd, outputChannel) { + logToPanel("inside CiderDebugAdapter"); + this.adapterPath = adapterPath; + this.cwd = cwd; + this.outputChannel = outputChannel; + this.adapterProcess = null; + logToPanel("at the end of ciderDebugAdapter"); + } + isServerRunning() { + logToPanel("checking if server is running"); + return this.adapterProcess != null && this.adapterProcess.exitCode == null; + } + // Start the debug adapter process + start(port) { + logToPanel('begining of start'); + + // Spawn a new child process for the debug adapter + // Include the port as a command line argument + this.adapterProcess = cp.spawn(this.adapterPath, [programName, '--port', port, "--tcp"], { cwd: this.cwd }); + + // Attach event listener to capture standard output of the adapter process and log it to the output channel + this.adapterProcess.stdout.on('data', (data) => { + logToPanel(data.toString()); + }); + + // Attach event listener to capture standard error of the adapter process and log it to the output channel + this.adapterProcess.stderr.on('data', (data) => { + logToPanel(data.toString()); + }); + + logToPanel('Debugger started on port ' + port + '!'); + } + + stop() { + if (this.adapterProcess) { + this.adapterProcess.kill(); + this.adapterProcess = null; + this.isRunning = false; + logToPanel('Debugger stopped.'); + } else { + logToPanel('No running debug adapter to stop.'); + } + } +} + +function activate(context) { + logToPanel('Extension activated!'); + + // Start the debug server explicitly + const factory = new CiderDebugAdapterDescriptorFactory('/home/basantkhalil/calyx2/target/debug/cider-dap', vscode.workspace.rootPath, outputChannel); + context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('cider-dap', factory)); + logToPanel("after start server"); + + // Update the adapter path with the serverPort and use it for starting the debug adapter + const adapterPath = '/home/basantkhalil/calyx2/target/debug/cider-dap'; + const cwd = vscode.workspace.rootPath; + logToPanel("before startDebugging"); + /* context.subscriptions.push(vscode.commands.registerCommand('cider.startDebugging', startDebugging)); + context.subscriptions.push(vscode.commands.registerCommand('cider.stopDebugging', stopDebugging)); + */ + logToPanel('Hello, your extension is now activated!'); +} + +function stopDebugging() { + if (debugAdapter) { + debugAdapter.stop(); + } else { + logToPanel('No running debug adapter to stop.'); + } +} + +function deactivate() { + logToPanel("deactivate"); +} + +module.exports = { + activate, + deactivate +}; \ No newline at end of file diff --git a/cider-dap/src/error.rs b/cider-dap/src/error.rs index d80865385..70bc5e439 100644 --- a/cider-dap/src/error.rs +++ b/cider-dap/src/error.rs @@ -1,4 +1,6 @@ -#[allow(dead_code)] //remove this later +use dap::errors::ServerError; + +#[allow(dead_code)] // remove this later #[derive(thiserror::Error, Debug)] pub enum MyAdapterError { /// Represents an unhandled command error. @@ -17,9 +19,21 @@ pub enum MyAdapterError { #[error("IO error: {0}")] IO(#[from] std::io::Error), + /// Represents an error for an invalid path. + #[error("Invalid path provided")] + InvalidPathError, + /// Represents an error when a command is missing. #[error("Missing command")] MissingCommandError, + + /// Represents a missing request. + #[error("Missing request")] + MissingRequest, + + /// Represents a server error. + #[error(transparent)] + ServerError(#[from] ServerError), } /// A type alias for the result returned by the adapter functions. diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index f5ba5e999..3bb2b1657 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -30,31 +30,116 @@ fn read_path(path: &str) -> Result { fn main() -> Result<(), MyAdapterError> { let opts: Opts = argh::from_env(); - let path = opts.file.ok_or(MyAdapterError::MissingFile)?; - let file = File::open(path)?; - let adapter = MyAdapter::new(file); if opts.is_multi_session { + eprintln!("running multi-session"); let listener = TcpListener::bind(("127.0.0.1", opts.port))?; + eprintln!("bound on port: {} ", opts.port); let (stream, addr) = listener.accept()?; - println!("Accepted client on: {}", addr); + eprintln!("Accepted client on: {}", addr); // changed to eprintln! let read_stream = BufReader::new(stream.try_clone()?); let write_stream = BufWriter::new(stream); - let server = Server::new(read_stream, write_stream); - run_server(server, adapter)?; + let mut server = Server::new(read_stream, write_stream); + + // Get the adapter from the init function + let adapter = multi_session_init(&mut server)?; + + // Run the server using the adapter + run_server(&mut server, adapter)?; } else { + let path = opts.file.ok_or(MyAdapterError::MissingFile)?; + let file = File::open(path)?; + let adapter = MyAdapter::new(file); + eprintln!("running single-session"); let write = BufWriter::new(stdout()); let read = BufReader::new(stdin()); - let server = Server::new(read, write); - run_server(server, adapter)?; + let mut server = Server::new(read, write); + run_server(&mut server, adapter)?; } - + eprintln!("exited run_Server"); Ok(()) } +fn multi_session_init( + server: &mut Server, +) -> AdapterResult +where + R: Read, + W: Write, +{ + // handle the first request (Initialize) + let req = match server.poll_request()? { + Some(req) => req, + None => return Err(MyAdapterError::MissingCommandError), + }; + match &req.command { + Command::Initialize(_) => { + let rsp = + req.success(ResponseBody::Initialize(types::Capabilities { + ..Default::default() + })); + server.respond(rsp)?; + server.send_event(Event::Initialized)?; + } + _ => return Err(MyAdapterError::UnhandledCommandError), + } + + // handle the second request (Launch) + let req = match server.poll_request()? { + Some(req) => req, + None => return Err(MyAdapterError::MissingCommandError), + }; + + let program_path = if let Command::Launch(params) = &req.command { + if let Some(data) = ¶ms.additional_data { + if let Some(program_path) = data.get("program") { + eprintln!("Program path: {}", program_path); + program_path + .as_str() + .ok_or(MyAdapterError::InvalidPathError)? + } else { + return Err(MyAdapterError::MissingFile); + } + } else { + return Err(MyAdapterError::MissingFile); + } + } else { + panic!("second request was not a launch"); + }; + + // Open file using the extracted program path + let file = File::open(program_path)?; + + // Construct the adapter + let adapter = MyAdapter::new(file); + + // Return the adapter instead of running the server + Ok(adapter) +} + fn run_server( - _server: Server, + server: &mut Server, _adapter: MyAdapter, ) -> AdapterResult<()> { - todo!() + loop { + // Start looping here + let req = match server.poll_request()? { + Some(req) => req, + None => return Err(MyAdapterError::MissingCommandError), + }; + match &req.command { + Command::Launch(_) => { + let rsp = req.success(ResponseBody::Launch); + server.respond(rsp)?; + } + // Here, can add a match pattern for a disconnect or exit command + // to break out of the loop and close the server. + // Command::Disconnect(_) => break, + // ... + unknown_command => { + eprintln!("Unknown_command: {:?}", unknown_command); + return Err(MyAdapterError::UnhandledCommandError); + } + } + } } From 1c221c0d15566b9f1f21deb7fe8fe6e03f771c42 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 10 Aug 2023 23:54:45 +0530 Subject: [PATCH 020/189] Attempt to fix `compile-ref` bug (#1650) * attempt to fix the compile refs bug * works --- calyx-ir/src/common.rs | 23 +++- calyx-ir/src/rewriter.rs | 37 ++++++ calyx-opt/src/passes/compile_ref.rs | 148 ++++++++++++++++------ calyx-opt/src/passes/dump_ports.rs | 43 ++++--- calyx-opt/src/passes/externalize.rs | 23 +++- tests/passes/compile-ref/ref-chain.expect | 55 ++++++++ tests/passes/compile-ref/ref-chain.futil | 50 ++++++++ 7 files changed, 314 insertions(+), 65 deletions(-) create mode 100644 tests/passes/compile-ref/ref-chain.expect create mode 100644 tests/passes/compile-ref/ref-chain.futil diff --git a/calyx-ir/src/common.rs b/calyx-ir/src/common.rs index 546071689..2c74148f0 100644 --- a/calyx-ir/src/common.rs +++ b/calyx-ir/src/common.rs @@ -1,3 +1,4 @@ +use calyx_utils::{GetName, Id}; use std::cell::RefCell; use std::rc::{Rc, Weak}; @@ -9,34 +10,42 @@ pub type RRC = Rc>; /// Used by parent pointers in the internal representation. #[allow(clippy::upper_case_acronyms)] #[derive(Debug)] -pub struct WRC { +pub struct WRC +where + T: GetName, +{ pub(super) internal: Weak>, + debug_name: Id, } -impl WRC { +impl WRC { /// Convinience method to upgrade and extract the underlying internal weak /// pointer. pub fn upgrade(&self) -> RRC { - self.internal - .upgrade() - .expect("Weak reference points to nothing") + let Some(r) = self.internal.upgrade() else { + unreachable!("weak reference points to a dropped. Original object's name: `{}'", self.debug_name) + }; + r } } /// From implementation with the same signature as `Rc::downgrade`. -impl From<&RRC> for WRC { +impl From<&RRC> for WRC { fn from(internal: &RRC) -> Self { + let debug_name = internal.borrow().name(); Self { internal: Rc::downgrade(internal), + debug_name, } } } /// Clone the Weak reference inside the WRC. -impl Clone for WRC { +impl Clone for WRC { fn clone(&self) -> Self { Self { internal: Weak::clone(&self.internal), + debug_name: self.debug_name, } } } diff --git a/calyx-ir/src/rewriter.rs b/calyx-ir/src/rewriter.rs index 4afc228ac..297d4ebfa 100644 --- a/calyx-ir/src/rewriter.rs +++ b/calyx-ir/src/rewriter.rs @@ -1,5 +1,6 @@ use crate::control::StaticInvoke; use crate::{self as ir, RRC}; +use std::borrow::BorrowMut; use std::collections::HashMap; use std::rc::Rc; @@ -84,6 +85,42 @@ impl<'a> Rewriter<'a> { .or_else(|| self.get_cell_port_rewrite(port_ref)) } + /// Rewrite assignments in a guard + pub fn rewrite_guard(&self, guard: &mut ir::Guard) { + match guard { + ir::Guard::And(l, r) | ir::Guard::Or(l, r) => { + self.rewrite_guard(l.borrow_mut()); + self.rewrite_guard(r.borrow_mut()) + } + ir::Guard::Not(g) => self.rewrite_guard(g.borrow_mut()), + ir::Guard::CompOp(_, l, r) => { + if let Some(nl) = self.get(l) { + *l = nl; + } + if let Some(nr) = self.get(r) { + *r = nr; + } + } + ir::Guard::Port(p) => { + if let Some(np) = self.get(p) { + *p = np; + } + } + ir::Guard::Info(_) | ir::Guard::True => (), + } + } + + /// Rewrite an assignment + pub fn rewrite_assign(&self, assign: &mut ir::Assignment) { + if let Some(dst) = self.get(&assign.dst) { + assign.dst = dst; + } + if let Some(src) = self.get(&assign.src) { + assign.src = src; + } + self.rewrite_guard(&mut assign.guard); + } + // =========== Control Rewriting Methods ============= /// Rewrite a `invoke` node using a [RewriteMap] and a [RewriteMap] pub fn rewrite_invoke( diff --git a/calyx-opt/src/passes/compile_ref.rs b/calyx-opt/src/passes/compile_ref.rs index 46fef7c58..6f4293e66 100644 --- a/calyx-opt/src/passes/compile_ref.rs +++ b/calyx-opt/src/passes/compile_ref.rs @@ -2,24 +2,18 @@ use super::dump_ports; use crate::traversal::{ Action, ConstructVisitor, Named, Order, VisResult, Visitor, }; -use calyx_ir::WRC; -use calyx_ir::{self as ir, LibrarySignatures, RRC}; -use calyx_ir::{Attributes, Canonical}; +use calyx_ir::{self as ir, Attributes, LibrarySignatures, RRC, WRC}; use calyx_utils::CalyxResult; +use itertools::Itertools; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; type PortMap = Vec<(ir::Id, ir::RRC)>; -/// 1. Remove all the cells marked with the 'ref' keyword -/// 2. Inline all the ports of the ref cells to the component signature -/// 3. Remove all the ref cell mappings from the invoke statement -/// 4. Inline all the mappings of ports to the invoke signature - /// Map for storing added ports for each ref cell /// level of Hashmap represents: -/// HashMap<-component name-, Hashmap<(-cell name-,-port name-), port>>; +/// HashMap<-component name-, Hashmap<(-ref cell name-,-port name-), port>>; pub(super) type RefPortMap = HashMap>>; @@ -40,8 +34,19 @@ impl GetPorts for RefPortMap { } } } + +/// Pass to eliminate `ref` cells from the program. +/// 1. Remove all the cells marked with the 'ref' keyword +/// 2. Inline all the ports of the ref cells to the component signature +/// 3. Remove all the ref cell mappings from the invoke statement +/// 4. Inline all the mappings of ports to the invoke signature pub struct CompileRef { port_names: RefPortMap, + /// Mapping from the ports of cells that were removed to the new port on the + /// component signature. + removed: HashMap>, + /// Ref cells in the component. We hold onto these so that our references don't get invalidated + ref_cells: Vec>, } impl ConstructVisitor for CompileRef { @@ -49,14 +54,16 @@ impl ConstructVisitor for CompileRef { where Self: Sized, { - let compile_external = CompileRef { + Ok(CompileRef { port_names: HashMap::new(), - }; - Ok(compile_external) + removed: HashMap::new(), + ref_cells: Vec::new(), + }) } fn clear_data(&mut self) { - // data is shared between components + self.removed.clear(); + self.ref_cells.clear() } } @@ -75,37 +82,67 @@ impl Named for CompileRef { } impl CompileRef { - // given `ref_cells` of an invoke, reuturns `(inputs, outputs)` where - // inputs are the corresponding inputs to the `invoke` and - // outputs are the corresponding outputs to the `invoke` + /// Given `ref_cells` of an invoke, returns `(inputs, outputs)` where + /// inputs are the corresponding inputs to the `invoke` and + /// outputs are the corresponding outputs to the `invoke`. + /// + /// Since this pass eliminates all ref cells in post order, we expect that + /// invoked component already had all of its ref cells removed. fn ref_cells_to_ports( &mut self, - comp_name: ir::Id, - ref_cells: &mut Vec<(ir::Id, ir::RRC)>, + inv_comp: ir::Id, + ref_cells: Vec<(ir::Id, ir::RRC)>, ) -> (PortMap, PortMap) { let mut inputs = Vec::new(); let mut outputs = Vec::new(); - for (in_cell, cell) in ref_cells.drain(..) { - for port in cell.borrow().ports.iter() { - if port.borrow().attributes.get(ir::BoolAttr::Clk).is_none() - && port - .borrow() - .attributes - .get(ir::BoolAttr::Reset) - .is_none() + for (ref_cell_name, cell) in ref_cells { + log::debug!( + "Removing ref cell `{}` with {} ports", + ref_cell_name, + cell.borrow().ports.len() + ); + let Some(comp_ports) = self.port_names.get(&inv_comp) else { + unreachable!("component `{}` invoked but not already visited by the pass", inv_comp) + }; + // The type of the cell is the same as the ref cell so we can + // iterate over its ports and generate bindings for the ref cell. + for pr in &cell.borrow().ports { + let port = pr.borrow(); + if !port.attributes.has(ir::BoolAttr::Clk) + && !port.attributes.has(ir::BoolAttr::Reset) { - let canon = Canonical(in_cell, port.borrow().name); - let port_name = - self.port_names[&comp_name][&canon].borrow().name; - match port.borrow().direction { + log::debug!("Adding port `{}`", port.name); + let canon = ir::Canonical(ref_cell_name, port.name); + let Some(ref_port) = comp_ports.get(&canon) else { + unreachable!("port `{}` not found. Known ports are: {}", + canon, + comp_ports.keys().map(|c| c.1.as_ref()).collect_vec().join(", ") + ) + }; + let port_name = ref_port.borrow().name; + let old_port = pr.borrow().canonical(); + // If the port has been removed already, get the new port from the component's signature + let port_bind = + if let Some(sig_pr) = self.removed.get(&old_port) { + log::debug!( + "Port `{}` has been removed. Using `{}`", + old_port, + sig_pr.borrow().name + ); + (port_name, Rc::clone(sig_pr)) + } else { + (port_name, Rc::clone(pr)) + }; + + match port.direction { ir::Direction::Input => { - outputs.push((port_name, Rc::clone(port))); + outputs.push(port_bind); } ir::Direction::Output => { - inputs.push((port_name, Rc::clone(port))); + inputs.push(port_bind); } _ => { - unreachable!("Internal Error: This state should not be reachable."); + unreachable!("Cell should have inout ports"); } } } @@ -126,17 +163,26 @@ impl Visitor for CompileRef { _ctx: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - dump_ports::dump_ports_to_signature( + log::debug!("compile-ref: {}", comp.name); + self.ref_cells = dump_ports::dump_ports_to_signature( comp, is_external_cell, true, &mut self.port_names, + &mut self.removed, ); + // For all subcomponents that had a `ref` cell in them, we need to + // update their cell to have the new ports added from inlining the + // signatures of all the ref cells. for cell in comp.cells.iter() { let mut new_ports: Vec> = Vec::new(); - if let Some(ref name) = cell.borrow().type_name() { - if let Some(vec) = self.port_names.get_ports(name) { + if let Some(name) = cell.borrow().type_name() { + if let Some(vec) = self.port_names.get_ports(&name) { + log::debug!( + "Updating ports of cell `{}' (type `{name}')", + cell.borrow().name() + ); for p in vec.iter() { let new_port = Rc::new(RefCell::new(ir::Port { name: p.borrow().name, @@ -162,8 +208,9 @@ impl Visitor for CompileRef { _comps: &[ir::Component], ) -> VisResult { let comp_name = s.comp.borrow().type_name().unwrap(); + let ref_cells = std::mem::take(&mut s.ref_cells); let (mut inputs, mut outputs) = - self.ref_cells_to_ports(comp_name, &mut s.ref_cells); + self.ref_cells_to_ports(comp_name, ref_cells); s.inputs.append(&mut inputs); s.outputs.append(&mut outputs); Ok(Action::Continue) @@ -176,10 +223,35 @@ impl Visitor for CompileRef { _comps: &[ir::Component], ) -> VisResult { let comp_name = s.comp.borrow().type_name().unwrap(); + let ref_cells = std::mem::take(&mut s.ref_cells); let (mut inputs, mut outputs) = - self.ref_cells_to_ports(comp_name, &mut s.ref_cells); + self.ref_cells_to_ports(comp_name, ref_cells); s.inputs.append(&mut inputs); s.outputs.append(&mut outputs); Ok(Action::Continue) } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + // Rewrite all of the ref cell ports + let empty = HashMap::new(); + let rw = ir::Rewriter::new(&empty, &self.removed); + comp.for_each_assignment(|assign| { + rw.rewrite_assign(assign); + }); + comp.for_each_static_assignment(|assign| { + rw.rewrite_assign(assign); + }); + rw.rewrite_control( + &mut comp.control.borrow_mut(), + &HashMap::new(), + &HashMap::new(), + &HashMap::new(), + ); + Ok(Action::Continue) + } } diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index 8086b3b10..d9f0fa49b 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -1,7 +1,7 @@ use crate::passes::compile_ref::RefPortMap; use calyx_ir::{self as ir, RRC, WRC}; use itertools::Itertools; -use std::rc::Rc; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; /// Formats name of a port given the id of the cell and the port pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id { @@ -18,53 +18,60 @@ pub(super) fn dump_ports_to_signature( cell_filter: fn(&RRC) -> bool, remove_signals: bool, port_names: &mut RefPortMap, -) { + removed: &mut HashMap>, +) -> Vec> { let comp_name = component.name; let (ext_cells, cells): (Vec<_>, Vec<_>) = component.cells.drain().partition(cell_filter); component.cells.append(cells.into_iter()); - for cell_ref in ext_cells { - let mut cell = cell_ref.borrow_mut(); + for cell_ref in &ext_cells { + let cell = cell_ref.borrow(); + log::debug!("`{}' is matches predictate", cell.name()); // If we do not eliminate the @clk and @reset ports, we may // get signals conflicting the original @clk and @reset signals of // the component, see https://github.com/cucapra/calyx/issues/1034 let ports_inline = cell .ports - .drain(..) + .iter() .filter(|pr| { let p = pr.borrow(); if remove_signals { - p.attributes.get(ir::BoolAttr::Clk).is_none() - && p.attributes.get(ir::BoolAttr::Reset).is_none() + !p.attributes.has(ir::BoolAttr::Clk) + && !p.attributes.has(ir::BoolAttr::Reset) } else { true } }) + .map(Rc::clone) .collect_vec(); - // Explicitly drop `cell` otherwise call to `canonical` will panic - drop(cell); for port_ref in ports_inline { let canon = port_ref.borrow().canonical(); - let port = &mut port_ref.borrow_mut(); - // Change the name and the parent of this port. - port.name = component.generate_name(format_port_name(&canon)); - // Point to the signature cell as its parent - port.parent = ir::PortParent::Cell(WRC::from(&component.signature)); - // Remove any attributes from this cell port. - port.attributes = ir::Attributes::default(); + let port = port_ref.borrow(); + let new_port = Rc::new(RefCell::new(ir::Port { + name: component.generate_name(format_port_name(&canon)), + width: port.width, + direction: port.direction.clone(), + parent: ir::PortParent::Cell(WRC::from(&component.signature)), + attributes: ir::Attributes::default(), + })); component .signature .borrow_mut() .ports - .push(Rc::clone(&port_ref)); + .push(Rc::clone(&new_port)); + + // Record the port as removed + removed.insert(canon.clone(), Rc::clone(&new_port)); + // Record the port to add to cells port_names .entry(comp_name) .or_default() - .insert(canon, Rc::clone(&port_ref)); + .insert(canon, Rc::clone(&new_port)); } } + ext_cells } diff --git a/calyx-opt/src/passes/externalize.rs b/calyx-opt/src/passes/externalize.rs index a2dbd17d3..0a8d7002c 100644 --- a/calyx-opt/src/passes/externalize.rs +++ b/calyx-opt/src/passes/externalize.rs @@ -76,13 +76,32 @@ impl Visitor for Externalize { _comps: &[ir::Component], ) -> VisResult { let mut port_names = HashMap::new(); - dump_ports::dump_ports_to_signature( + let mut renamed = HashMap::new(); + let cells = dump_ports::dump_ports_to_signature( comp, has_external_attribute, false, &mut port_names, + &mut renamed, ); - Ok(Action::Continue) + let cell_map = HashMap::default(); + let rw = ir::Rewriter::new(&cell_map, &renamed); + comp.for_each_assignment(|assign| { + rw.rewrite_assign(assign); + }); + comp.for_each_static_assignment(|assign| { + rw.rewrite_assign(assign); + }); + rw.rewrite_control( + &mut comp.control.borrow_mut(), + &HashMap::new(), + &HashMap::new(), + &HashMap::new(), + ); + // Don't allow cells to be dropped before this because otherwise rewriting will fail + drop(cells); + + Ok(Action::Stop) } } diff --git a/tests/passes/compile-ref/ref-chain.expect b/tests/passes/compile-ref/ref-chain.expect new file mode 100644 index 000000000..7c7e28dea --- /dev/null +++ b/tests/passes/compile-ref/ref-chain.expect @@ -0,0 +1,55 @@ +import "primitives/compile.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + i = incr(); + value = std_reg(32); + } + wires {} + control { + seq { + invoke i( + value_out = value.out, + value_done = value.done + )( + value_in = value.in, + value_write_en = value.write_en + ); + } + } +} +component incr(@go go: 1, @clk clk: 1, @reset reset: 1, value_out: 32, value_done: 1) -> (@done done: 1, value_in: 32, value_write_en: 1) { + cells { + ih = incr_helper(); + } + wires {} + control { + seq { + invoke ih( + value_out = value_out, + value_done = value_done + )( + value_in = value_in, + value_write_en = value_write_en + ); + } + } +} +component incr_helper(@go go: 1, @clk clk: 1, @reset reset: 1, value_out: 32, value_done: 1) -> (@done done: 1, value_in: 32, value_write_en: 1) { + cells { + incr_value = std_add(32); + } + wires { + group incr_value_group { + value_write_en = 1'd1; + incr_value.right = 32'd1; + incr_value.left = value_out; + value_in = incr_value.out; + incr_value_group[done] = value_done; + } + } + control { + seq { + incr_value_group; + } + } +} diff --git a/tests/passes/compile-ref/ref-chain.futil b/tests/passes/compile-ref/ref-chain.futil new file mode 100644 index 000000000..a1281b943 --- /dev/null +++ b/tests/passes/compile-ref/ref-chain.futil @@ -0,0 +1,50 @@ +// -p validate -p compile-ref +import "primitives/compile.futil"; +component main() -> () { + cells { + i = incr(); + value = std_reg(32); + } + wires { + + } + control { + seq { + invoke i[value=value]()(); + } + } +} +component incr() -> () { + cells { + ref value = std_reg(32); + ih = incr_helper(); + } + wires { + + } + control { + seq { + invoke ih[value=value]()(); + } + } +} +component incr_helper() -> () { + cells { + ref value = std_reg(32); + incr_value = std_add(32); + } + wires { + group incr_value_group { + incr_value.left = value.out; + incr_value.right = 32'd1; + value.write_en = 1'd1; + value.in = incr_value.out; + incr_value_group[done] = value.done; + } + } + control { + seq { + incr_value_group; + } + } +} \ No newline at end of file From 597aadc5c2ff5536545d58ac27fdad0a0dde59e3 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 11 Aug 2023 13:44:35 +0530 Subject: [PATCH 021/189] `comb-prop`: Disable rewrites when wire output is used (#1656) --- CHANGELOG.md | 1 + calyx-ir/src/structure.rs | 20 ++ calyx-opt/src/passes/comb_prop.rs | 228 ++++++++++++++------ tests/passes/comb-prop/wire-dst-read.expect | 18 ++ tests/passes/comb-prop/wire-dst-read.futil | 22 ++ 5 files changed, 228 insertions(+), 61 deletions(-) create mode 100644 tests/passes/comb-prop/wire-dst-read.expect create mode 100644 tests/passes/comb-prop/wire-dst-read.futil diff --git a/CHANGELOG.md b/CHANGELOG.md index 6517d71f4..b3989a023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Unreleased - Don't require `@clk` and `@reset` ports in `comb` components - `inline` pass supports inlining `ref` cells +- `comb-prop`: disable rewrite from `wire.in = port` when the output of a wire is read. ## 0.4.0 diff --git a/calyx-ir/src/structure.rs b/calyx-ir/src/structure.rs index fa1867fec..0a08ce8ed 100644 --- a/calyx-ir/src/structure.rs +++ b/calyx-ir/src/structure.rs @@ -469,6 +469,26 @@ pub struct Assignment { } impl Assignment { + /// Build a new unguarded assignment + pub fn new(dst: RRC, src: RRC) -> Self { + assert!( + dst.borrow().direction == Direction::Input, + "{} is not in input port", + dst.borrow().canonical() + ); + assert!( + src.borrow().direction == Direction::Output, + "{} is not in output port", + src.borrow().canonical() + ); + Self { + dst, + src, + guard: Box::new(Guard::True), + attributes: Attributes::default(), + } + } + /// Apply function `f` to each port contained within the assignment and /// replace the port with the generated value if not None. pub fn for_each_port(&mut self, mut f: F) diff --git a/calyx-opt/src/passes/comb_prop.rs b/calyx-opt/src/passes/comb_prop.rs index bd4116ae1..9ea00ee09 100644 --- a/calyx-opt/src/passes/comb_prop.rs +++ b/calyx-opt/src/passes/comb_prop.rs @@ -12,19 +12,87 @@ struct WireRewriter { } impl WireRewriter { - /// Insert into rewrite map. If `v` is in current `rewrites`, then insert `k` -> `rewrites[v]`. - /// Panics if there is already a mapping for `k`. - pub fn insert( + // If the destination is a wire, then we have something like: + // ``` + // wire.in = c.out; + // ``` + // Which means all instances of `wire.out` can be replaced with `c.out` because the + // wire is being used to forward values from `c.out`. + pub fn insert_src_rewrite( + &mut self, + wire: RRC, + src: RRC, + ) { + let wire_out = wire.borrow().get("out"); + log::debug!( + "src rewrite: {} -> {}", + wire_out.borrow().canonical(), + src.borrow().canonical(), + ); + let old = self.insert(wire_out, Rc::clone(&src)); + assert!( + old.is_none(), + "Attempting to add multiple sources to a wire" + ); + } + + // If the source is a wire, we have something like: + // ``` + // c.in = wire.out; + // ``` + // Which means all instances of `wire.in` can be replaced with `c.in` because the wire + // is being used to unconditionally forward values. + pub fn insert_dst_rewrite( + &mut self, + wire: RRC, + dst: RRC, + ) { + let wire_in = wire.borrow().get("in"); + log::debug!( + "dst rewrite: {} -> {}", + wire_in.borrow().canonical(), + dst.borrow().canonical(), + ); + let old_v = self.insert(Rc::clone(&wire_in), dst); + + // If the insertion process found an old key, we have something like: + // ``` + // x.in = wire.out; + // y.in = wire.out; + // ``` + // This means that `wire` is being used to forward values to many components and a + // simple inlining will not work. + if old_v.is_some() { + self.remove(wire_in); + } + + // No forwading generated because the wire is used in dst position + } + + /// Insert into rewrite map. If `v` is in current `rewrites`, then insert `k` -> `rewrites[v]` + /// and returns the previous rewrite if any. + fn insert( &mut self, from: RRC, to: RRC, ) -> Option> { let from_idx = from.borrow().canonical(); - self.rewrites.insert(from_idx, to) + let old = self.rewrites.insert(from_idx, to); + if log::log_enabled!(log::Level::Debug) { + if let Some(ref old) = old { + log::debug!( + "Previous rewrite: {} -> {}", + from.borrow().canonical(), + old.borrow().canonical() + ); + } + } + old } // Removes the mapping associated with the key. pub fn remove(&mut self, from: RRC) { + log::debug!("Removing rewrite for `{}'", from.borrow().canonical()); let from_idx = from.borrow().canonical(); self.rewrites.remove(&from_idx); } @@ -123,7 +191,7 @@ pub struct CombProp { /// Disable automatic removal of some dead assignments needed for correctness and instead mark /// them with @dead. /// NOTE: if this is enabled, the pass will not remove obviously conflicting assignments. - do_not_eliminate: bool, + no_eliminate: bool, } impl ConstructVisitor for CombProp { @@ -133,7 +201,7 @@ impl ConstructVisitor for CombProp { { let opts = Self::get_opts(ctx); Ok(CombProp { - do_not_eliminate: opts[0], + no_eliminate: opts[0], }) } @@ -160,26 +228,82 @@ impl Named for CombProp { } impl CombProp { + /// Predicate for removing an assignment + #[inline] + fn remove_predicate( + rewritten: &[RRC], + assign: &ir::Assignment, + ) -> bool + where + T: Clone + Eq + ToString, + { + let out = rewritten.iter().any(|v| Rc::ptr_eq(v, &assign.dst)); + if log::log_enabled!(log::Level::Debug) && out { + log::debug!("Removing: {}", ir::Printer::assignment_to_str(assign)); + } + out + } + /// Mark assignments for removal fn remove_rewritten( &self, - rewritten: Vec<&RRC>, + rewritten: &[RRC], comp: &mut ir::Component, ) { + log::debug!( + "Rewritten: {}", + rewritten + .iter() + .map(|p| format!("{}", p.borrow().canonical())) + .collect::>() + .join(", ") + ); // Remove writes to all the ports that show up in write position - if self.do_not_eliminate { + if self.no_eliminate { // If elimination is disabled, mark the assignments with the @dead attribute. for assign in &mut comp.continuous_assignments { - if rewritten.iter().any(|v| Rc::ptr_eq(v, &assign.dst)) { + if Self::remove_predicate(rewritten, assign) { assign.attributes.insert(ir::InternalAttr::DEAD, 1) } } } else { comp.continuous_assignments.retain_mut(|assign| { - !rewritten.iter().any(|v| Rc::ptr_eq(v, &assign.dst)) + !Self::remove_predicate(rewritten, assign) }); } } + + fn parent_is_wire(parent: &ir::PortParent) -> bool { + match parent { + ir::PortParent::Cell(cell_wref) => { + let cr = cell_wref.upgrade(); + let cell = cr.borrow(); + cell.is_primitive(Some("std_wire")) + } + ir::PortParent::Group(_) => false, + ir::PortParent::StaticGroup(_) => false, + } + } + + fn disable_rewrite( + assign: &mut ir::Assignment, + rewrites: &mut WireRewriter, + ) { + if assign.guard.is_true() { + return; + } + assign.for_each_port(|pr| { + let p = pr.borrow(); + if p.direction == ir::Direction::Output + && Self::parent_is_wire(&p.parent) + { + let cell = p.cell_parent(); + rewrites.remove(cell.borrow().get("in")); + } + // Never change the port + None + }); + } } impl Visitor for CombProp { @@ -191,76 +315,58 @@ impl Visitor for CombProp { ) -> VisResult { let mut rewrites = WireRewriter::default(); - let parent_is_wire = |parent: &ir::PortParent| -> bool { - match parent { - ir::PortParent::Cell(cell_wref) => { - let cr = cell_wref.upgrade(); - let cell = cr.borrow(); - cell.is_primitive(Some("std_wire")) - } - ir::PortParent::Group(_) => false, - ir::PortParent::StaticGroup(_) => false, - } - }; - for assign in &mut comp.continuous_assignments { - // Skip conditional continuous assignments + // Cannot add rewrites for conditional statements if !assign.guard.is_true() { continue; } - // If the destination is a wire, then we have something like: - // ``` - // wire.in = c.out; - // ``` - // Which means all instances of `wire.out` can be replaced with `c.out` because the - // wire is being used to forward values from `c.out`. + let dst = assign.dst.borrow(); - if parent_is_wire(&dst.parent) { - rewrites.insert( - dst.cell_parent().borrow().get("out"), + if Self::parent_is_wire(&dst.parent) { + rewrites.insert_src_rewrite( + dst.cell_parent(), Rc::clone(&assign.src), ); } - // If the source is a wire, we have something like: - // ``` - // c.in = wire.out; - // ``` - // Which means all instances of `wire.in` can be replaced with `c.in` because the wire - // is being used to unconditionally forward values. let src = assign.src.borrow(); - if parent_is_wire(&src.parent) { - let port = src.cell_parent().borrow().get("in"); - let old_v = - rewrites.insert(Rc::clone(&port), Rc::clone(&assign.dst)); - - // If the insertion process found an old key, we have something like: - // ``` - // x.in = wire.out; - // y.in = wire.out; - // ``` - // This means that `wire` is being used to forward values to many components and a - // simple inlining will not work. - if old_v.is_some() { - rewrites.remove(port); - } + if Self::parent_is_wire(&src.parent) { + rewrites.insert_dst_rewrite( + src.cell_parent(), + Rc::clone(&assign.dst), + ); } } + // Disable all rewrites: + // If the statement uses a wire output (w.out) as a source, we + // cannot rewrite the wire's input (w.in) uses + comp.for_each_assignment(|assign| { + Self::disable_rewrite(assign, &mut rewrites) + }); + comp.for_each_static_assignment(|assign| { + Self::disable_rewrite(assign, &mut rewrites) + }); + // Rewrite assignments + // Make the set of rewrites consistent and transform into map let rewrites: ir::rewriter::PortRewriteMap = rewrites.into(); - let rewritten = rewrites.values().collect_vec(); - self.remove_rewritten(rewritten, comp); + let rewritten = rewrites.values().cloned().collect_vec(); + self.remove_rewritten(&rewritten, comp); comp.for_each_assignment(|assign| { - assign.for_each_port(|port| { - rewrites.get(&port.borrow().canonical()).cloned() - }) + if !assign.attributes.has(ir::InternalAttr::DEAD) { + assign.for_each_port(|port| { + rewrites.get(&port.borrow().canonical()).cloned() + }) + } }); comp.for_each_static_assignment(|assign| { - assign.for_each_port(|port| { - rewrites.get(&port.borrow().canonical()).cloned() - }) + if !assign.attributes.has(ir::InternalAttr::DEAD) { + assign.for_each_port(|port| { + rewrites.get(&port.borrow().canonical()).cloned() + }) + } }); let cell_rewrites = HashMap::new(); diff --git a/tests/passes/comb-prop/wire-dst-read.expect b/tests/passes/comb-prop/wire-dst-read.expect new file mode 100644 index 000000000..539480b77 --- /dev/null +++ b/tests/passes/comb-prop/wire-dst-read.expect @@ -0,0 +1,18 @@ +import "primitives/compile.futil"; +component main<"toplevel"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + opt = std_wire(32); + r = std_reg(32); + r0 = std_reg(1); + r1 = std_reg(1); + r2 = std_reg(1); + } + wires { + r.in = opt.out; + r.write_en = 1'd1; + opt.in = r0.out ? 32'd10; + opt.in = r1.out ? 32'd20; + out = r2.out ? opt.out; + } + control {} +} diff --git a/tests/passes/comb-prop/wire-dst-read.futil b/tests/passes/comb-prop/wire-dst-read.futil new file mode 100644 index 000000000..377092bc8 --- /dev/null +++ b/tests/passes/comb-prop/wire-dst-read.futil @@ -0,0 +1,22 @@ +// -p well-formed -p comb-prop +import "primitives/compile.futil"; +component main<"toplevel"=1>() -> (out: 32) { + cells { + opt = std_wire(32); + r = std_reg(32); + // Stable conditions + r0 = std_reg(1); + r1 = std_reg(1); + r2 = std_reg(1); + } + wires { + r.in = opt.out; + r.write_en = 1'd1; + + opt.in = r0.out ? 32'd10; + opt.in = r1.out ? 32'd20; + + out = r2.out ? opt.out; + } + control {} +} \ No newline at end of file From e07d145342af17267d60a5f96cc31f4571055bf1 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:42:35 -0400 Subject: [PATCH 022/189] PIFO in Calyx (#1625) --- calyx-py/calyx/builder.py | 25 ++- calyx-py/calyx/builder_util.py | 95 +++++----- calyx-py/calyx/queue_call.py | 141 ++++++++++++++ calyx-py/test/correctness/fifo.py | 150 +-------------- calyx-py/test/correctness/pifo.data | 45 +++++ calyx-py/test/correctness/pifo.expect | 31 ++++ calyx-py/test/correctness/pifo.py | 255 ++++++++++++++++++++++++++ 7 files changed, 547 insertions(+), 195 deletions(-) create mode 100644 calyx-py/calyx/queue_call.py create mode 100644 calyx-py/test/correctness/pifo.data create mode 100644 calyx-py/test/correctness/pifo.expect create mode 100644 calyx-py/test/correctness/pifo.py diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index acd3adb8e..3bbf0d867 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -268,13 +268,6 @@ def seq_mem_d1( name, ast.Stdlib.seq_mem_d1(bitwidth, len, idx_size), is_external, is_ref ) - def is_seq_mem_d1(self, cell: CellBuilder) -> bool: - """Check if the cell is a SeqMemD1 cell.""" - return ( - isinstance(cell._cell.comp, ast.CompInst) - and cell._cell.comp.name == "seq_mem_d1" - ) - def add(self, name: str, size: int, signed=False) -> CellBuilder: """Generate a StdAdd cell.""" self.prog.import_("primitives/binary_operators.futil") @@ -319,6 +312,10 @@ def and_(self, name: str, size: int) -> CellBuilder: """Generate a StdAnd cell.""" return self.cell(name, ast.Stdlib.op("and", size, False)) + def not_(self, name: str, size: int) -> CellBuilder: + """Generate a StdNot cell.""" + return self.cell(name, ast.Stdlib.op("not", size, False)) + def pipelined_mult(self, name: str) -> CellBuilder: """Generate a pipelined multiplier.""" self.prog.import_("primitives/pipelined.futil") @@ -620,13 +617,21 @@ def port(self, name: str) -> ExprBuilder: """Build a port access expression.""" return ExprBuilder(ast.Atom(ast.CompPort(self._cell.id, name))) - def is_mem_d1(self) -> bool: - """Check if the cell is a StdMemD1 cell.""" + def is_primitive(self, prim_name) -> bool: + """Check if the cell is an instance of the primitive {prim_name}.""" return ( isinstance(self._cell.comp, ast.CompInst) - and self._cell.comp.id == "std_mem_d1" + and self._cell.comp.id == prim_name ) + def is_std_mem_d1(self) -> bool: + """Check if the cell is a StdMemD1 cell.""" + return self.is_primitive("std_mem_d1") + + def is_seq_mem_d1(self) -> bool: + """Check if the cell is a SeqMemD1 cell.""" + return self.is_primitive("seq_mem_d1") + @classmethod def unwrap_id(cls, obj): if isinstance(obj, cls): diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py index 14c961a06..1848ae344 100644 --- a/calyx-py/calyx/builder_util.py +++ b/calyx-py/calyx/builder_util.py @@ -109,6 +109,20 @@ def insert_sub(comp: cb.ComponentBuilder, left, right, cellname, width): return insert_comb_group(comp, left, right, sub_cell, f"{cellname}_group") +def insert_bitwise_flip_reg(comp: cb.ComponentBuilder, reg, cellname, width): + """Inserts wiring into component {comp} to bitwise-flip the contents of {reg}. + + Returns a handle to the group that does this. + """ + not_cell = comp.not_(cellname, width) + with comp.group(f"{cellname}_group") as not_group: + not_cell.in_ = reg.out + reg.write_en = 1 + reg.in_ = not_cell.out + not_group.done = reg.done + return not_group + + def insert_incr(comp: cb.ComponentBuilder, reg, cellname, val=1): """Inserts wiring into component {comp} to increment register {reg} by {val}. 1. Within component {comp}, creates a group called {cellname}_group. @@ -145,13 +159,27 @@ def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): return decr_group -def mem_load(comp: cb.ComponentBuilder, mem, i, reg, group): - """Loads a value from one memory into a register. +def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): + """Stores a value in a register. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, sets the register {reg} to {val}. + 3. Returns the group that does this. + """ + with comp.group(group) as reg_grp: + reg.in_ = val + reg.write_en = 1 + reg_grp.done = reg.done + return reg_grp + + +def mem_load_std_d1(comp: cb.ComponentBuilder, mem, i, reg, group): + """Loads a value from one memory (std_d1) into a register. 1. Within component {comp}, creates a group called {group}. 2. Within {group}, reads from memory {mem} at address {i}. 3. Writes the value into register {reg}. 4. Returns the group that does this. """ + assert mem.is_std_mem_d1() with comp.group(group) as load_grp: mem.addr0 = i reg.write_en = 1 @@ -160,13 +188,14 @@ def mem_load(comp: cb.ComponentBuilder, mem, i, reg, group): return load_grp -def mem_store(comp: cb.ComponentBuilder, mem, i, val, group): - """Stores a value from one memory into another. +def mem_store_std_d1(comp: cb.ComponentBuilder, mem, i, val, group): + """Stores a value into a (std_d1) memory. 1. Within component {comp}, creates a group called {group}. 2. Within {group}, reads from {val}. 3. Writes the value into memory {mem} at address i. 4. Returns the group that does this. """ + assert mem.is_std_mem_d1() with comp.group(group) as store_grp: mem.addr0 = i mem.write_en = 1 @@ -175,24 +204,16 @@ def mem_store(comp: cb.ComponentBuilder, mem, i, val, group): return store_grp -def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): - """Stores a value in a register. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, sets the register {reg} to {val}. - 3. Returns the group that does this. - """ - with comp.group(group) as reg_grp: - reg.in_ = val - reg.write_en = 1 - reg_grp.done = reg.done - return reg_grp - - -def mem_read_seqd1(comp: cb.ComponentBuilder, mem, i, group): +def mem_read_seq_d1(comp: cb.ComponentBuilder, mem, i, group): """Given a seq_mem_d1, reads from memory at address i. Note that this does not write the value anywhere. + + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from memory {mem} at address {i}, + thereby "latching" the value. + 3. Returns the group that does this. """ - assert mem.is_seq_mem_d1 + assert mem.is_seq_mem_d1() with comp.group(group) as read_grp: mem.addr0 = i mem.read_en = 1 @@ -200,11 +221,16 @@ def mem_read_seqd1(comp: cb.ComponentBuilder, mem, i, group): return read_grp -def mem_write_seqd1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): +def mem_write_seq_d1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): """Given a seq_mem_d1 that is already assumed to have a latched value, reads the latched value and writes it to a register. + + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, reads from memory {mem}. + 3. Writes the value into register {reg}. + 4. Returns the group that does this. """ - assert mem.is_seq_mem_d1 + assert mem.is_seq_mem_d1() with comp.group(group) as write_grp: reg.write_en = 1 reg.in_ = mem.read_data @@ -213,13 +239,14 @@ def mem_write_seqd1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): - """Stores a value from one memory into another. + """Given a seq_mem_d1, stores a value into memory at address i. + 1. Within component {comp}, creates a group called {group}. 2. Within {group}, reads from {val}. 3. Writes the value into memory {mem} at address i. 4. Returns the group that does this. """ - assert mem.is_seq_mem_d1 + assert mem.is_seq_mem_d1() with comp.group(group) as store_grp: mem.addr0 = i mem.write_en = 1 @@ -228,26 +255,6 @@ def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): return store_grp -def reg_swap(comp: cb.ComponentBuilder, a, b, group): - """Swaps the values of two registers. - 1. Within component {comp}, creates a group called {group}. - 2. Reads the value of {a} into a temporary register. - 3. Writes the value of {b} into {a}. - 4. Writes the value of the temporary register into {b}. - 5. Returns the group that does this. - """ - with comp.group(group) as swap_grp: - tmp = comp.reg("tmp", 1) - tmp.write_en = 1 - tmp.in_ = a.out - a.write_en = 1 - a.in_ = b.out - b.write_en = 1 - b.in_ = tmp.out - swap_grp.done = b.done - return swap_grp - - def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): """Loads a value from one std_mem_d1 memory into another. 1. Within component {comp}, creates a group called {group}. @@ -255,7 +262,7 @@ def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): 3. Writes the value into memory {ans} at address {j}. 4. Returns the group that does this. """ - assert mem.is_mem_d1() and ans.is_mem_d1() + assert mem.is_std_mem_d1() and ans.is_std_mem_d1() with comp.group(group) as load_grp: mem.addr0 = i ans.write_en = 1 diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py new file mode 100644 index 000000000..bf2079912 --- /dev/null +++ b/calyx-py/calyx/queue_call.py @@ -0,0 +1,141 @@ +# pylint: disable=import-error +import calyx.builder as cb +import calyx.builder_util as util + +MAX_CMDS = 15 + + +def insert_raise_err_if_i_eq_max_cmds(prog): + """Inserts a the component `raise_err_if_i_eq_MAX_CMDS` into the program. + + It has: + - one input, `i`. + - one ref register, `err`. + + If `i` equals MAX_CMDS, it raises the `err` flag. + """ + raise_err_if_i_eq_max_cmds: cb.ComponentBuilder = prog.component( + "raise_err_if_i_eq_MAX_CMDS" + ) + i = raise_err_if_i_eq_max_cmds.input("i", 32) + err = raise_err_if_i_eq_max_cmds.reg("err", 1, is_ref=True) + + i_eq_max_cmds = util.insert_eq( + raise_err_if_i_eq_max_cmds, i, MAX_CMDS, "i_eq_MAX_CMDS", 32 + ) + raise_err = util.insert_reg_store(raise_err_if_i_eq_max_cmds, err, 1, "raise_err") + + raise_err_if_i_eq_max_cmds.control += [ + cb.if_( + i_eq_max_cmds[0].out, + i_eq_max_cmds[1], + raise_err, + ) + ] + + return raise_err_if_i_eq_max_cmds + + +def insert_main(prog, queue): + """Inserts the component `main` into the program. + This will be used to `invoke` the component `queue` and feed it a list of commands. + """ + main: cb.ComponentBuilder = prog.component("main") + + # The user-facing interface of the `main` component is: + # - a list of commands (the input) + # where each command is a 32-bit unsigned integer, with the following format: + # `0`: pop + # any other value: push that value + # - a list of answers (the output). + # + # The user-facing interface of the `queue` component is: + # - one input, `cmd`. + # where each command is a 32-bit unsigned integer, with the following format: + # `0`: pop + # any other value: push that value + # - one ref register, `ans`, into which the result of a pop is written. + # - one ref register, `err`, which is raised if an error occurs. + + commands = main.seq_mem_d1("commands", 32, MAX_CMDS, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) + + # The two components we'll use: + queue = main.cell("myqueue", queue) + raise_err_if_i_eq_max_cmds = main.cell( + "raise_err_if_i_eq_MAX_CMDS", insert_raise_err_if_i_eq_max_cmds(prog) + ) + + # We will use the `invoke` method to call the `queue` component. + # The queue component takes two inputs by reference and one input directly. + # The two `ref` inputs: + err = main.reg("err", 1) # A flag to indicate an error + ans = main.reg("ans", 32) # A memory to hold the answer of a pop + + # We will set up a while loop that runs over the command list, relaying + # the commands to the `queue` component. + # It will run until the `err` flag is raised by the `queue` component. + + i = main.reg("i", 32) # The index of the command we're currently processing + j = main.reg("j", 32) # The index on the answer-list we'll write to + cmd = main.reg("command", 32) # The command we're currently processing + + incr_i = util.insert_incr(main, i, "incr_i") # i++ + incr_j = util.insert_incr(main, j, "incr_j") # j++ + err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? + cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0 + cmd_neq_0 = util.insert_neq( + main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32 + ) # cmd != 0 + + read_cmd = util.mem_read_seq_d1(main, commands, i.out, "read_cmd_phase1") + write_cmd_to_reg = util.mem_write_seq_d1_to_reg( + main, commands, cmd, "write_cmd_phase2" + ) + + write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans") + + main.control += [ + cb.while_( + err_eq_0[0].out, + err_eq_0[1], # Run while the `err` flag is down + [ + read_cmd, # Read `commands[i]` + write_cmd_to_reg, # Write it to `cmd` + cb.par( # Now, in parallel, act based on the value of `cmd` + cb.if_( + # Is this a pop? + cmd_eq_0[0].out, + cmd_eq_0[1], + [ # A pop + cb.invoke( # First we call pop + queue, + in_cmd=cmd.out, + ref_ans=ans, + ref_err=err, + ), + # AM: my goal is that, + # if err flag comes back raised, + # we do not perform this write or this incr_j + write_ans, + incr_j, + ], + ), + cb.if_( # Is this a push? + cmd_neq_0[0].out, + cmd_neq_0[1], + cb.invoke( # A push + queue, + in_cmd=cmd.out, + ref_ans=ans, + ref_err=err, + ), + ), + ), + incr_i, # Increment the command index + cb.invoke( # If i = MAX_CMDS, raise error flag + raise_err_if_i_eq_max_cmds, in_i=i.out, ref_err=err + ), # AM: hella hacky + ], + ), + ] diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index fd01e5049..4789f4033 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -1,33 +1,7 @@ # pylint: disable=import-error import calyx.builder as cb import calyx.builder_util as util - - -def insert_raise_err_if_i_eq_15(prog): - """Inserts a the component `raise_err_if_i_eq_15` into the program. - - It has: - - one input, `i`. - - one ref register, `err`. - - If `i` equals 15, it raises the `err` flag. - """ - raise_err_if_i_eq_15: cb.ComponentBuilder = prog.component("raise_err_if_i_eq_15") - i = raise_err_if_i_eq_15.input("i", 32) - err = raise_err_if_i_eq_15.reg("err", 1, is_ref=True) - - i_eq_15 = util.insert_eq(raise_err_if_i_eq_15, i, 15, "i_eq_15", 32) - raise_err = util.insert_reg_store(raise_err_if_i_eq_15, err, 1, "raise_err") - - raise_err_if_i_eq_15.control += [ - cb.if_( - i_eq_15[0].out, - i_eq_15[1], - raise_err, - ) - ] - - return raise_err_if_i_eq_15 +import calyx.queue_call as qc def insert_fifo(prog, name): @@ -37,7 +11,7 @@ def insert_fifo(prog, name): - one input, `cmd`. - one memory, `mem`, of size 10. - two registers, `next_write` and `next_read`. - - three ref registers, `ans`, `err`, and `len`. + - two ref registers, `ans` and `err`. """ fifo: cb.ComponentBuilder = prog.component(name) @@ -45,10 +19,8 @@ def insert_fifo(prog, name): # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. mem = fifo.seq_mem_d1("mem", 32, 10, 32) - write = fifo.reg("next_write", 32) # The next address to write to read = fifo.reg("next_read", 32) # The next address to read from - # We will orchestrate `mem`, along with the two pointers above, to # simulate a circular queue of size 10. @@ -56,13 +28,9 @@ def insert_fifo(prog, name): # If the user wants to pop, we will write the popped value to `ans` err = fifo.reg("err", 1, is_ref=True) - # We'll raise this as a general error flag: - # overflow, - # underflow, - # if the user calls pop and push at the same time, - # or if the user issues no command. + # We'll raise this as a general error flag for overflow and underflow - len = fifo.reg("len", 32, is_ref=True) # The length of the queue + len = fifo.reg("len", 32) # The length of the FIFO # Cells and groups to compute equality cmd_eq_0 = util.insert_eq(fifo, cmd, 0, "cmd_eq_0", 32) # `cmd` == 0 @@ -96,15 +64,16 @@ def insert_fifo(prog, name): write_to_mem = util.mem_store_seq_d1( fifo, mem, write.out, cmd, "write_payload_to_mem" ) - read_from_mem = util.mem_read_seqd1( + read_from_mem = util.mem_read_seq_d1( fifo, mem, read.out, "read_payload_from_mem_phase1" ) - write_to_ans = util.mem_write_seqd1_to_reg( + write_to_ans = util.mem_write_seq_d1_to_reg( fifo, mem, ans, "read_payload_from_mem_phase2" ) fifo.control += [ cb.par( + # Was it a pop or a push? We can do both cases in parallel. cb.if_( # Did the user call pop? cmd_eq_0[0].out, @@ -171,112 +140,11 @@ def insert_fifo(prog, name): return fifo -def insert_main(prog): - """Inserts the component `main` into the program. - This will be used to `invoke` the component `fifo`. - """ - main: cb.ComponentBuilder = prog.component("main") - - # The user-facing interface of the `main` component is: - # - a list of commands (the input) - # where each command is a 32-bit unsigned integer, with the following format: - # `0`: pop - # `1`: peek - # any value greater than 1: push that value - # - a list of answers (the output). - commands = main.seq_mem_d1("commands", 32, 15, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) - - # The two components we'll use: - fifo = main.cell("myfifo", insert_fifo(prog, "fifo")) - raise_err_if_i_eq_15 = main.cell( - "raise_err_if_i_eq_15", insert_raise_err_if_i_eq_15(prog) - ) - - # We will use the `invoke` method to call the `fifo` component. - # The fifo component takes three `ref` inputs: - err = main.reg("err", 1) # A flag to indicate an error - ans = main.reg("ans", 32) # A memory to hold the answer of a pop - len = main.reg("len", 32) # A register to hold the len of the queue - - # We will set up a while loop that runs over the command list, relaying - # the commands to the `fifo` component. - # It will run until the `err` flag is raised by the `fifo` component. - - i = main.reg("i", 32) # The index of the command we're currently processing - j = main.reg("j", 32) # The index on the answer-list we'll write to - cmd = main.reg("command", 32) # The command we're currently processing - - zero_i = util.insert_reg_store(main, i, 0, "zero_i") # zero out `i` - zero_j = util.insert_reg_store(main, j, 0, "zero_j") # zero out `j` - incr_i = util.insert_incr(main, i, "incr_i") # i = i + 1 - incr_j = util.insert_incr(main, j, "incr_j") # j = j + 1 - err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? - cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0 - cmd_neq_0 = util.insert_neq( - main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32 - ) # cmd != 0 - - read_cmd = util.mem_read_seqd1(main, commands, i.out, "read_cmd_phase1") - write_cmd_to_reg = util.mem_write_seqd1_to_reg( - main, commands, cmd, "write_cmd_phase2" - ) - - write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans") - - main.control += [ - zero_i, - zero_j, - cb.while_( - err_eq_0[0].out, - err_eq_0[1], # Run while the `err` flag is down - [ - read_cmd, # Read `commands[i]` - write_cmd_to_reg, # Write it to `cmd` - cb.par( - cb.if_( - # Is this a pop? - cmd_eq_0[0].out, - cmd_eq_0[1], - [ # A pop - cb.invoke( # First we call pop - fifo, - in_cmd=cmd.out, - ref_ans=ans, - ref_err=err, - ref_len=len, - ), - # AM: if err flag comes back raised, - # do not perform this write or this incr - write_ans, - incr_j, - ], - ), - cb.if_( # Is this a push? - cmd_neq_0[0].out, - cmd_neq_0[1], - cb.invoke( # A push - fifo, - in_cmd=cmd.out, - ref_ans=ans, - ref_err=err, - ref_len=len, - ), - ), - ), - incr_i, # Increment the command index - cb.invoke( # If i = 15, raise error flag - raise_err_if_i_eq_15, in_i=i.out, ref_err=err - ), # AM: hella hacky - ], - ), - ] - - def build(): """Top-level function to build the program.""" prog = cb.Builder() - insert_main(prog) + fifo = insert_fifo(prog, "fifo") + qc.insert_main(prog, fifo) return prog.program diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data new file mode 100644 index 000000000..303b30a41 --- /dev/null +++ b/calyx-py/test/correctness/pifo.data @@ -0,0 +1,45 @@ +{ + "commands": { + "data": [ + 101, + 102, + 0, + 0, + 103, + 104, + 201, + 202, + 0, + 0, + 0, + 0, + 105, + 106, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect new file mode 100644 index 000000000..307166fe2 --- /dev/null +++ b/calyx-py/test/correctness/pifo.expect @@ -0,0 +1,31 @@ +{ + "ans_mem": [ + 101, + 102, + 201, + 103, + 202, + 104, + 105, + 0, + 0, + 0 + ], + "commands": [ + 101, + 102, + 0, + 0, + 103, + 104, + 201, + 202, + 0, + 0, + 0, + 0, + 105, + 106, + 0 + ] +} diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py new file mode 100644 index 000000000..9d416dfc5 --- /dev/null +++ b/calyx-py/test/correctness/pifo.py @@ -0,0 +1,255 @@ +# pylint: disable=import-error +import fifo +import calyx.builder as cb +import calyx.builder_util as util +import calyx.queue_call as qc + + +def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, group): + """The flow is needed when the command is a push. + If the value to be pushed is less than 200, we push to flow 0. + Otherwise, we push to flow 1. + This method adds a group to the component {comp} that does this. + 1. Within component {comp}, creates a group called {group}. + 2. Within {group}, creates a cell {cell} that checks for less-than. + 3. Puts the values of 199 and {cmd} into {cell}. + 4. Then puts the answer of the computation into {flow}. + 5. Returns the group that does this. + """ + cell = comp.lt("flow_inf", 32) + with comp.group(group) as infer_flow_grp: + cell.left = 199 + cell.right = cmd + flow.write_en = 1 + flow.in_ = cell.out + infer_flow_grp.done = flow.done + return infer_flow_grp + + +def invoke_fifo(fifo_cell, cmd, ans, err) -> cb.invoke: + """Invokes the cell {fifo_cell} with: + {cmd} passed by value + {ans} passed by reference + {err} passed by reference + """ + return cb.invoke( + fifo_cell, + in_cmd=cmd, + ref_ans=ans, + ref_err=err, + ) + + +def insert_pifo(prog, name): + """Inserts the component `pifo` into the program. + + The PIFO achieves a 50/50 split between two "flows" or "kinds". + That is, up to the availability of values, this PIFO seeks to alternate + between values of the two flows. + + We say "up to availability" because, if one flow is silent and the other + is active, the active ones gets to emit consecutive values (in temporary + violation of the 50/50 rule) until the silent flow starts transmitting again. + At that point we go back to 50/50. + + The PIFO's maximum capacity is 10. Create two FIFOs, each of capacity 10. + Let's say the two flow are called `0` and `1`, and our FIFOs are called + `fifo_0` and `fifo_1`. + Maintain additionally a register that points to which of these FIFOs is "hot". + Start off with `hot` pointing to `fifo_0` (arbitrarily). + + - `push(v, PIFO)`: + + If len(PIFO) = 10, raise an "overflow" err and exit. + + Otherwise, the charge is to enqueue value `v`. + Find out which flow `f` the value `v` should go to; + `f` better be either `0` or `1`. + Enqueue `v` into `fifo_f`. + Note that the FIFO's enqueue method is itself partial: it may raise + "overflow", in which case we propagate the overflow flag. + - `pop(PIFO)`: + + If `len(PIFO)` = 0, raise an "underflow" flag and exit. + + Try `pop(FIFO_{hot})`. + * If it succeeds it will return a value `v`; just propagate `v`. + Also flip `hot` so it points to the other FIFO. + * If it fails because of underflow, return `pop(FIFO_{not-hot})`. + If the _second_ pop also fails, propagate the error. + Leave `hot` as it was. + """ + + pifo: cb.ComponentBuilder = prog.component(name) + cmd = pifo.input("cmd", 32) + # If this is 0, we pop. Otherwise, we push the value. + + # Create the two FIFOs and ready them for invocation. + fifo_0 = pifo.cell("myfifo_0", fifo.insert_fifo(prog, "fifo_0")) + fifo_1 = pifo.cell("myfifo_1", fifo.insert_fifo(prog, "fifo_1")) + + flow = pifo.reg("flow", 1) # The flow to push to: 0 or 1. + # We will infer this using a separate component; + # it is a function of the value being pushed. + infer_flow = insert_flow_inference(pifo, cmd, flow, "infer_flow") + + ans = pifo.reg("ans", 32, is_ref=True) + # If the user wants to pop, we will write the popped value to `ans`. + + err = pifo.reg("err", 1, is_ref=True) + # We'll raise this as a general error flag for overflow and underflow. + + len = pifo.reg("len", 32) # The length of the PIFO. + + # Two registers that mark the next FIFO to `pop` from. + hot = pifo.reg("hot", 1) + + # Some equality checks. + hot_eq_0 = util.insert_eq(pifo, hot.out, 0, "hot_eq_0", 1) + hot_eq_1 = util.insert_eq(pifo, hot.out, 1, "hot_eq_1", 1) + flow_eq_0 = util.insert_eq(pifo, flow.out, 0, "flow_eq_0", 1) + flow_eq_1 = util.insert_eq(pifo, flow.out, 1, "flow_eq_1", 1) + len_eq_0 = util.insert_eq(pifo, len.out, 0, "len_eq_0", 32) + len_eq_10 = util.insert_eq(pifo, len.out, 10, "len_eq_10", 32) + cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 32) + cmd_neq_0 = util.insert_neq(pifo, cmd, cb.const(32, 0), "cmd_neq_0", 32) + err_eq_0 = util.insert_eq(pifo, err.out, 0, "err_eq_0", 1) + err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), "err_neq_0", 1) + + flip_hot = util.insert_bitwise_flip_reg(pifo, hot, "flip_hot", 1) + raise_err = util.insert_reg_store(pifo, err, 1, "raise_err") # set `err` to 1 + lower_err = util.insert_reg_store(pifo, err, 0, "lower_err") # set `err` to 0 + zero_out_ans = util.insert_reg_store(pifo, ans, 0, "zero_out_ans") + + len_incr = util.insert_incr(pifo, len, "len_incr") # len++ + len_decr = util.insert_decr(pifo, len, "len_decr") # len-- + + # The main logic. + pifo.control += [ + cb.par( + # Was it a pop or a push? We can do both cases in parallel. + cb.if_( + # Did the user call pop? + cmd_eq_0[0].out, + cmd_eq_0[1], + cb.if_( + # Yes, the user called pop. But is the queue empty? + len_eq_0[0].out, + len_eq_0[1], + [raise_err, zero_out_ans], # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + # We must check if `hot` is 0 or 1. + lower_err, + cb.par( # We'll check both cases in parallel. + cb.if_( + # Check if `hot` is 0. + hot_eq_0[0].out, + hot_eq_0[1], + [ # `hot` is 0. We'll invoke `pop` on `fifo_0`. + invoke_fifo(fifo_0, cmd, ans, err), + # Our next step depends on whether `fifo_0` + # raised the error flag. + # We can check these cases in parallel. + cb.par( + cb.if_( + err_neq_0[0].out, + err_neq_0[1], + [ # `fifo_0` raised an error. + # We'll try to pop from `fifo_1`. + # We'll pass it a lowered err + lower_err, + invoke_fifo(fifo_1, cmd, ans, err), + ], + ), + cb.if_( + err_eq_0[0].out, + err_eq_0[1], + [ # `fifo_0` succeeded. + # Its answer is our answer. + flip_hot + # We'll just make `hot` point + # to the other FIFO. + ], + ), + ), + ], + ), + # If `hot` is 1, we proceed symmetrically. + cb.if_( + hot_eq_1[0].out, + hot_eq_1[1], + [ + invoke_fifo(fifo_1, cmd, ans, err), + cb.par( + cb.if_( + err_neq_0[0].out, + err_neq_0[1], + [ + lower_err, + invoke_fifo(fifo_0, cmd, ans, err), + ], + ), + cb.if_( + err_eq_0[0].out, + err_eq_0[1], + [flip_hot], + ), + ), + ], + ), + ), + len_decr, # Decrement the length. + # It is possible that an irrecoverable error was raised above, + # in which case the length should _not_ in fact be decremented. + # However, in that case the PIFO's `err` flag would also + # have been raised, and no one will check this length anyway. + ], + ), + ), + cb.if_( + # Did the user call push? + cmd_neq_0[0].out, + cmd_neq_0[1], + cb.if_( + # Yes, the user called push. But is the queue full? + len_eq_10[0].out, + len_eq_10[1], + [raise_err, zero_out_ans], # The queue is full: overflow. + [ # The queue is not full. Proceed. + lower_err, + # We need to check which flow this value should be pushed to. + infer_flow, # Infer the flow and write it to `fifo_{flow}`. + cb.par( + cb.if_( + flow_eq_0[0].out, + flow_eq_0[1], + # This value should be pushed to flow 0. + invoke_fifo(fifo_0, cmd, ans, err), + ), + cb.if_( + flow_eq_1[0].out, + flow_eq_1[1], + # This value should be pushed to flow 1. + invoke_fifo(fifo_1, cmd, ans, err), + ), + ), + len_incr, # Increment the length. + # It is possible that an irrecoverable error was raised above, + # in which case the length should _not_ in fact be incremented. + # However, in that case the PIFO's `err` flag would also + # have been raised, and no one will check this length anyway. + ], + ), + ), + ), + ] + + return pifo + + +def build(): + """Top-level function to build the program.""" + prog = cb.Builder() + pifo = insert_pifo(prog, "pifo") + qc.insert_main(prog, pifo) + return prog.program + + +if __name__ == "__main__": + build().emit() From ab41bc5cd0399d91ec5a29bb74d34ea1c915466a Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:13:08 -0400 Subject: [PATCH 023/189] PIFO, FIFO: command `peek` (#1657) --- calyx-py/calyx/builder_util.py | 16 +++++ calyx-py/calyx/queue_call.py | 51 +++++---------- calyx-py/test/correctness/fifo.data | 2 +- calyx-py/test/correctness/fifo.expect | 4 +- calyx-py/test/correctness/pifo.data | 2 +- calyx-py/test/correctness/pifo.expect | 4 +- calyx-py/test/correctness/pifo.py | 89 +++++++++++++++++++++++++-- 7 files changed, 123 insertions(+), 45 deletions(-) diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py index 1848ae344..e9b1a740d 100644 --- a/calyx-py/calyx/builder_util.py +++ b/calyx-py/calyx/builder_util.py @@ -61,6 +61,22 @@ def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): return insert_comb_group(comp, left, right, lt_cell, f"{cellname}_group") +def insert_le(comp: cb.ComponentBuilder, left, right, cellname, width): + """Inserts wiring into component {comp} to check if {left} <= {right}. + + = std_le(); + ... + comb group _group { + .left = ; + .right = ; + } + + Returns handles to the cell and the combinational group. + """ + le_cell = comp.le(cellname, width) + return insert_comb_group(comp, left, right, le_cell, f"{cellname}_group") + + def insert_gt(comp: cb.ComponentBuilder, left, right, cellname, width): """Inserts wiring into component {comp} to check if {left} > {right}. diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index bf2079912..b58768e35 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -83,10 +83,7 @@ def insert_main(prog, queue): incr_i = util.insert_incr(main, i, "incr_i") # i++ incr_j = util.insert_incr(main, j, "incr_j") # j++ err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? - cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0 - cmd_neq_0 = util.insert_neq( - main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32 - ) # cmd != 0 + cmd_le_1 = util.insert_le(main, cmd.out, 1, "cmd_le_1", 32) # cmd <= 1 read_cmd = util.mem_read_seq_d1(main, commands, i.out, "read_cmd_phase1") write_cmd_to_reg = util.mem_write_seq_d1_to_reg( @@ -102,38 +99,24 @@ def insert_main(prog, queue): [ read_cmd, # Read `commands[i]` write_cmd_to_reg, # Write it to `cmd` - cb.par( # Now, in parallel, act based on the value of `cmd` - cb.if_( - # Is this a pop? - cmd_eq_0[0].out, - cmd_eq_0[1], - [ # A pop - cb.invoke( # First we call pop - queue, - in_cmd=cmd.out, - ref_ans=ans, - ref_err=err, - ), - # AM: my goal is that, - # if err flag comes back raised, - # we do not perform this write or this incr_j - write_ans, - incr_j, - ], - ), - cb.if_( # Is this a push? - cmd_neq_0[0].out, - cmd_neq_0[1], - cb.invoke( # A push - queue, - in_cmd=cmd.out, - ref_ans=ans, - ref_err=err, - ), - ), + cb.invoke( # Call the queue with `cmd` + queue, + in_cmd=cmd.out, + ref_ans=ans, + ref_err=err, + ), + cb.if_( # If it was a pop or a peek, write ans to the answer list + cmd_le_1[0].out, + cmd_le_1[1], + [ # AM: I'd like to have an additional check hereL + # if err flag comes back raised, + # we do not perform this write_ans or this incr_j + write_ans, + incr_j, + ], ), incr_i, # Increment the command index - cb.invoke( # If i = MAX_CMDS, raise error flag + cb.invoke( # If i = 15, raise error flag raise_err_if_i_eq_max_cmds, in_i=i.out, ref_err=err ), # AM: hella hacky ], diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 4bb645702..92ca60a44 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -2,7 +2,7 @@ "commands": { "data": [ 100, - 0, + 1, 101, 102, 0, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index 17d861b58..c4f8d2cd6 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,11 +1,11 @@ { "ans_mem": [ + 100, 100, 101, 102, 103, 104, - 105, 0, 0, 0, @@ -13,7 +13,7 @@ ], "commands": [ 100, - 0, + 1, 101, 102, 0, diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index 303b30a41..954df2114 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -9,12 +9,12 @@ 104, 201, 202, + 1, 0, 0, 0, 0, 105, - 106, 0 ], "format": { diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index 307166fe2..3e76673b6 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -3,12 +3,12 @@ 101, 102, 201, + 201, 103, 202, 104, 105, 0, - 0, 0 ], "commands": [ @@ -20,12 +20,12 @@ 104, 201, 202, + 1, 0, 0, 0, 0, 105, - 106, 0 ] } diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index 9d416dfc5..ceaa38fee 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -78,7 +78,7 @@ def insert_pifo(prog, name): pifo: cb.ComponentBuilder = prog.component(name) cmd = pifo.input("cmd", 32) - # If this is 0, we pop. Otherwise, we push the value. + # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. # Create the two FIFOs and ready them for invocation. fifo_0 = pifo.cell("myfifo_0", fifo.insert_fifo(prog, "fifo_0")) @@ -108,7 +108,8 @@ def insert_pifo(prog, name): len_eq_0 = util.insert_eq(pifo, len.out, 0, "len_eq_0", 32) len_eq_10 = util.insert_eq(pifo, len.out, 10, "len_eq_10", 32) cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 32) - cmd_neq_0 = util.insert_neq(pifo, cmd, cb.const(32, 0), "cmd_neq_0", 32) + cmd_eq_1 = util.insert_eq(pifo, cmd, 1, "cmd_eq_1", 32) + cmd_gt_1 = util.insert_gt(pifo, cmd, 1, "cmd_gt_1", 32) err_eq_0 = util.insert_eq(pifo, err.out, 0, "err_eq_0", 1) err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), "err_neq_0", 1) @@ -123,7 +124,7 @@ def insert_pifo(prog, name): # The main logic. pifo.control += [ cb.par( - # Was it a pop or a push? We can do both cases in parallel. + # Was it a pop, peek, or a push? We can do all cases in parallel. cb.if_( # Did the user call pop? cmd_eq_0[0].out, @@ -202,10 +203,88 @@ def insert_pifo(prog, name): ], ), ), + cb.if_( + # Did the user call peek? + cmd_eq_1[0].out, + cmd_eq_1[1], + cb.if_( + # Yes, the user called peek. But is the queue empty? + len_eq_0[0].out, + len_eq_0[1], + [raise_err, zero_out_ans], # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + # We must check if `hot` is 0 or 1. + lower_err, + cb.par( # We'll check both cases in parallel. + cb.if_( + # Check if `hot` is 0. + hot_eq_0[0].out, + hot_eq_0[1], + [ # `hot` is 0. We'll invoke `peek` on `fifo_0`. + cb.invoke( # First we call peek + fifo_0, + in_cmd=cb.const(32, 1), + ref_ans=ans, # Its answer is our answer. + ref_err=err, + ), + # Our next step depends on whether `fifo_0` + # raised the error flag. + cb.if_( + err_neq_0[0].out, + err_neq_0[1], + [ # `fifo_0` raised an error. + # We'll try to peek from `fifo_1`. + # We'll pass it a lowered `err`. + lower_err, + cb.invoke( + fifo_1, + in_cmd=cb.const(32, 1), + ref_ans=ans, + # Its answer is our answer. + ref_err=err, + # Its error is our error, + # whether it raised one or not. + ), + ], + ), + # Peeking does not affect `hot`. + # Peeking does not affect the length. + ], + ), + # If `hot` is 1, we proceed symmetrically. + cb.if_( + hot_eq_1[0].out, + hot_eq_1[1], + [ + cb.invoke( + fifo_1, + in_cmd=cb.const(32, 1), + ref_ans=ans, + ref_err=err, + ), + cb.if_( + err_neq_0[0].out, + err_neq_0[1], + [ + lower_err, + cb.invoke( + fifo_0, + in_cmd=cb.const(32, 1), + ref_ans=ans, + ref_err=err, + ), + ], + ), + ], + ), + ), + ], + ), + ), cb.if_( # Did the user call push? - cmd_neq_0[0].out, - cmd_neq_0[1], + cmd_gt_1[0].out, + cmd_gt_1[1], cb.if_( # Yes, the user called push. But is the queue full? len_eq_10[0].out, From d6b2bf8825a1abf388c1d011a07ce6065f0dc834 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:40:10 -0400 Subject: [PATCH 024/189] PIFO: modularize eDSL code (#1658) --- calyx-py/test/correctness/pifo.py | 122 +++++++++++++----------------- 1 file changed, 52 insertions(+), 70 deletions(-) diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index ceaa38fee..c9d36626e 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -5,20 +5,21 @@ import calyx.queue_call as qc -def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, group): +def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, boundary, group): """The flow is needed when the command is a push. - If the value to be pushed is less than 200, we push to flow 0. - Otherwise, we push to flow 1. + If the value to be pushed is less than or equal to {boundary}, + the value belongs to flow 0. + Otherwise, the value belongs to flow 1. This method adds a group to the component {comp} that does this. 1. Within component {comp}, creates a group called {group}. 2. Within {group}, creates a cell {cell} that checks for less-than. - 3. Puts the values of 199 and {cmd} into {cell}. + 3. Puts the values {boundary} and {cmd} into the left and right ports of {cell}. 4. Then puts the answer of the computation into {flow}. 5. Returns the group that does this. """ cell = comp.lt("flow_inf", 32) with comp.group(group) as infer_flow_grp: - cell.left = 199 + cell.left = boundary cell.right = cmd flow.write_en = 1 flow.in_ = cell.out @@ -26,21 +27,21 @@ def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, group): return infer_flow_grp -def invoke_fifo(fifo_cell, cmd, ans, err) -> cb.invoke: - """Invokes the cell {fifo_cell} with: +def invoke_subqueue(queue_cell, cmd, ans, err) -> cb.invoke: + """Invokes the cell {queue_cell} with: {cmd} passed by value {ans} passed by reference {err} passed by reference """ return cb.invoke( - fifo_cell, + queue_cell, in_cmd=cmd, ref_ans=ans, ref_err=err, ) -def insert_pifo(prog, name): +def insert_pifo(prog, name, queue_l, queue_r, boundary): """Inserts the component `pifo` into the program. The PIFO achieves a 50/50 split between two "flows" or "kinds". @@ -52,26 +53,28 @@ def insert_pifo(prog, name): violation of the 50/50 rule) until the silent flow starts transmitting again. At that point we go back to 50/50. - The PIFO's maximum capacity is 10. Create two FIFOs, each of capacity 10. - Let's say the two flow are called `0` and `1`, and our FIFOs are called - `fifo_0` and `fifo_1`. - Maintain additionally a register that points to which of these FIFOs is "hot". - Start off with `hot` pointing to `fifo_0` (arbitrarily). + The PIFO's maximum capacity is 10. + Let's say the two flows are called `0` and `1`. + We orchestrate two sub-queues, `queue_l` and `queue_r`, each of capacity 10. + We maintain a register that points to which of these sub-queues is "hot". + Start off with `hot` pointing to `queue_l` (arbitrarily). - `push(v, PIFO)`: + If len(PIFO) = 10, raise an "overflow" err and exit. + Otherwise, the charge is to enqueue value `v`. Find out which flow `f` the value `v` should go to; `f` better be either `0` or `1`. - Enqueue `v` into `fifo_f`. - Note that the FIFO's enqueue method is itself partial: it may raise + Enqueue `v` into `queue_l` if `f` = `0`, and into `queue_r` if `f` = `1`. + Note that the sub-queue's enqueue method is itself partial: it may raise "overflow", in which case we propagate the overflow flag. - `pop(PIFO)`: + If `len(PIFO)` = 0, raise an "underflow" flag and exit. - + Try `pop(FIFO_{hot})`. + + Try `pop(queue_{hot})`, where we use the value of `hot` to determine + which sub-queue to pop from: + `queue_l` if `hot` = 0, and `queue_r` if `hot` = 1. * If it succeeds it will return a value `v`; just propagate `v`. - Also flip `hot` so it points to the other FIFO. - * If it fails because of underflow, return `pop(FIFO_{not-hot})`. + Also flip `hot` so it points to the other sub-queue. + * If it fails because of underflow, return `pop(queue_{not-hot})`. If the _second_ pop also fails, propagate the error. Leave `hot` as it was. """ @@ -80,14 +83,14 @@ def insert_pifo(prog, name): cmd = pifo.input("cmd", 32) # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. - # Create the two FIFOs and ready them for invocation. - fifo_0 = pifo.cell("myfifo_0", fifo.insert_fifo(prog, "fifo_0")) - fifo_1 = pifo.cell("myfifo_1", fifo.insert_fifo(prog, "fifo_1")) + # Declare the two sub-queues as cells of this component. + queue_l = pifo.cell("queue_l", queue_l) + queue_r = pifo.cell("queue_r", queue_r) flow = pifo.reg("flow", 1) # The flow to push to: 0 or 1. # We will infer this using a separate component; # it is a function of the value being pushed. - infer_flow = insert_flow_inference(pifo, cmd, flow, "infer_flow") + infer_flow = insert_flow_inference(pifo, cmd, flow, boundary, "infer_flow") ans = pifo.reg("ans", 32, is_ref=True) # If the user wants to pop, we will write the popped value to `ans`. @@ -97,7 +100,7 @@ def insert_pifo(prog, name): len = pifo.reg("len", 32) # The length of the PIFO. - # Two registers that mark the next FIFO to `pop` from. + # A register that marks the next sub-queue to `pop` from. hot = pifo.reg("hot", 1) # Some equality checks. @@ -142,30 +145,30 @@ def insert_pifo(prog, name): # Check if `hot` is 0. hot_eq_0[0].out, hot_eq_0[1], - [ # `hot` is 0. We'll invoke `pop` on `fifo_0`. - invoke_fifo(fifo_0, cmd, ans, err), - # Our next step depends on whether `fifo_0` + [ # `hot` is 0. We'll invoke `pop` on `queue_l`. + invoke_subqueue(queue_l, cmd, ans, err), + # Our next step depends on whether `queue_l` # raised the error flag. # We can check these cases in parallel. cb.par( cb.if_( err_neq_0[0].out, err_neq_0[1], - [ # `fifo_0` raised an error. - # We'll try to pop from `fifo_1`. + [ # `queue_l` raised an error. + # We'll try to pop from `queue_r`. # We'll pass it a lowered err lower_err, - invoke_fifo(fifo_1, cmd, ans, err), + invoke_subqueue(queue_r, cmd, ans, err), ], ), cb.if_( err_eq_0[0].out, err_eq_0[1], - [ # `fifo_0` succeeded. + [ # `queue_l` succeeded. # Its answer is our answer. flip_hot # We'll just make `hot` point - # to the other FIFO. + # to the other sub-queue. ], ), ), @@ -176,14 +179,14 @@ def insert_pifo(prog, name): hot_eq_1[0].out, hot_eq_1[1], [ - invoke_fifo(fifo_1, cmd, ans, err), + invoke_subqueue(queue_r, cmd, ans, err), cb.par( cb.if_( err_neq_0[0].out, err_neq_0[1], [ lower_err, - invoke_fifo(fifo_0, cmd, ans, err), + invoke_subqueue(queue_l, cmd, ans, err), ], ), cb.if_( @@ -220,31 +223,18 @@ def insert_pifo(prog, name): # Check if `hot` is 0. hot_eq_0[0].out, hot_eq_0[1], - [ # `hot` is 0. We'll invoke `peek` on `fifo_0`. - cb.invoke( # First we call peek - fifo_0, - in_cmd=cb.const(32, 1), - ref_ans=ans, # Its answer is our answer. - ref_err=err, - ), - # Our next step depends on whether `fifo_0` + [ # `hot` is 0. We'll invoke `peek` on `queue_l`. + invoke_subqueue(queue_l, cmd, ans, err), + # Our next step depends on whether `queue_l` # raised the error flag. cb.if_( err_neq_0[0].out, err_neq_0[1], - [ # `fifo_0` raised an error. - # We'll try to peek from `fifo_1`. + [ # `queue_l` raised an error. + # We'll try to peek from `queue_r`. # We'll pass it a lowered `err`. lower_err, - cb.invoke( - fifo_1, - in_cmd=cb.const(32, 1), - ref_ans=ans, - # Its answer is our answer. - ref_err=err, - # Its error is our error, - # whether it raised one or not. - ), + invoke_subqueue(queue_r, cmd, ans, err), ], ), # Peeking does not affect `hot`. @@ -256,23 +246,13 @@ def insert_pifo(prog, name): hot_eq_1[0].out, hot_eq_1[1], [ - cb.invoke( - fifo_1, - in_cmd=cb.const(32, 1), - ref_ans=ans, - ref_err=err, - ), + invoke_subqueue(queue_r, cmd, ans, err), cb.if_( err_neq_0[0].out, err_neq_0[1], [ lower_err, - cb.invoke( - fifo_0, - in_cmd=cb.const(32, 1), - ref_ans=ans, - ref_err=err, - ), + invoke_subqueue(queue_l, cmd, ans, err), ], ), ], @@ -298,14 +278,14 @@ def insert_pifo(prog, name): cb.if_( flow_eq_0[0].out, flow_eq_0[1], - # This value should be pushed to flow 0. - invoke_fifo(fifo_0, cmd, ans, err), + # This value should be pushed to queue_l. + invoke_subqueue(queue_l, cmd, ans, err), ), cb.if_( flow_eq_1[0].out, flow_eq_1[1], - # This value should be pushed to flow 1. - invoke_fifo(fifo_1, cmd, ans, err), + # This value should be pushed to queue_r. + invoke_subqueue(queue_r, cmd, ans, err), ), ), len_incr, # Increment the length. @@ -325,7 +305,9 @@ def insert_pifo(prog, name): def build(): """Top-level function to build the program.""" prog = cb.Builder() - pifo = insert_pifo(prog, "pifo") + fifo_l = fifo.insert_fifo(prog, "fifo_l") + fifo_r = fifo.insert_fifo(prog, "fifo_r") + pifo = insert_pifo(prog, "pifo", fifo_l, fifo_r, 200) qc.insert_main(prog, pifo) return prog.program From 2e11cb60ce5cc93ac6dbb5e5e05ff76aa5dde59f Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:41:04 -0400 Subject: [PATCH 025/189] PIFO Tree in Calyx (#1659) --- calyx-py/test/correctness/pifo_tree.data | 45 +++++++++++++++++++ calyx-py/test/correctness/pifo_tree.expect | 31 +++++++++++++ calyx-py/test/correctness/pifo_tree.py | 21 +++++++++ .../correctness/pifo_tree_pre_tangerine.data | 45 +++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 calyx-py/test/correctness/pifo_tree.data create mode 100644 calyx-py/test/correctness/pifo_tree.expect create mode 100644 calyx-py/test/correctness/pifo_tree.py create mode 100644 calyx-py/test/correctness/pifo_tree_pre_tangerine.data diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data new file mode 100644 index 000000000..ca4781021 --- /dev/null +++ b/calyx-py/test/correctness/pifo_tree.data @@ -0,0 +1,45 @@ +{ + "commands": { + "data": [ + 11, + 12, + 201, + 202, + 203, + 101, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} \ No newline at end of file diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect new file mode 100644 index 000000000..f2b418074 --- /dev/null +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -0,0 +1,31 @@ +{ + "ans_mem": [ + 11, + 201, + 101, + 202, + 12, + 203, + 0, + 0, + 0, + 0 + ], + "commands": [ + 11, + 12, + 201, + 202, + 203, + 101, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} diff --git a/calyx-py/test/correctness/pifo_tree.py b/calyx-py/test/correctness/pifo_tree.py new file mode 100644 index 000000000..53267a068 --- /dev/null +++ b/calyx-py/test/correctness/pifo_tree.py @@ -0,0 +1,21 @@ +# pylint: disable=import-error +import fifo +import pifo +import calyx.builder as cb +import calyx.queue_call as qc + + +def build(): + """Top-level function to build the program.""" + prog = cb.Builder() + fifo_purple = fifo.insert_fifo(prog, "fifo_purple") + fifo_tangerine = fifo.insert_fifo(prog, "fifo_tangerine") + pifo_red = pifo.insert_pifo(prog, "pifo_red", fifo_purple, fifo_tangerine, 100) + fifo_blue = fifo.insert_fifo(prog, "fifo_blue") + pifo_root = pifo.insert_pifo(prog, "pifo_root", pifo_red, fifo_blue, 200) + qc.insert_main(prog, pifo_root) + return prog.program + + +if __name__ == "__main__": + build().emit() diff --git a/calyx-py/test/correctness/pifo_tree_pre_tangerine.data b/calyx-py/test/correctness/pifo_tree_pre_tangerine.data new file mode 100644 index 000000000..32f99ddc4 --- /dev/null +++ b/calyx-py/test/correctness/pifo_tree_pre_tangerine.data @@ -0,0 +1,45 @@ +{ + "commands": { + "data": [ + 11, + 12, + 201, + 202, + 203, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} \ No newline at end of file From ef33b4b12ac6d4603c8a08b300e0b0a15271f702 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Wed, 16 Aug 2023 08:26:06 -0400 Subject: [PATCH 026/189] Clarify that 10 is magic number (#1663) --- calyx-py/calyx/queue_call.py | 3 ++- calyx-py/test/correctness/fifo.py | 34 ++++++++++++++++++------------- calyx-py/test/correctness/pifo.py | 17 ++++++++++------ 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index b58768e35..b722d6c6d 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -3,6 +3,7 @@ import calyx.builder_util as util MAX_CMDS = 15 +ANS_MEM_LEN = 10 def insert_raise_err_if_i_eq_max_cmds(prog): @@ -58,7 +59,7 @@ def insert_main(prog, queue): # - one ref register, `err`, which is raised if an error occurs. commands = main.seq_mem_d1("commands", 32, MAX_CMDS, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, ANS_MEM_LEN, 32, is_external=True) # The two components we'll use: queue = main.cell("myqueue", queue) diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index 4789f4033..17ca08520 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -3,13 +3,15 @@ import calyx.builder_util as util import calyx.queue_call as qc +MAX_QUEUE_LEN = 10 + def insert_fifo(prog, name): """Inserts the component `fifo` into the program. It has: - one input, `cmd`. - - one memory, `mem`, of size 10. + - one memory, `mem`, of size MAX_QUEUE_LEN. - two registers, `next_write` and `next_read`. - two ref registers, `ans` and `err`. """ @@ -18,11 +20,11 @@ def insert_fifo(prog, name): cmd = fifo.input("cmd", 32) # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. - mem = fifo.seq_mem_d1("mem", 32, 10, 32) + mem = fifo.seq_mem_d1("mem", 32, MAX_QUEUE_LEN, 32) write = fifo.reg("next_write", 32) # The next address to write to read = fifo.reg("next_read", 32) # The next address to read from # We will orchestrate `mem`, along with the two pointers above, to - # simulate a circular queue of size 10. + # simulate a circular queue of size MAX_QUEUE_LEN. ans = fifo.reg("ans", 32, is_ref=True) # If the user wants to pop, we will write the popped value to `ans` @@ -37,12 +39,16 @@ def insert_fifo(prog, name): cmd_eq_1 = util.insert_eq(fifo, cmd, 1, "cmd_eq_1", 32) # `cmd` == 1 cmd_gt_1 = util.insert_gt(fifo, cmd, 1, "cmd_gt_1", 32) # `cmd` > 1 - write_eq_10 = util.insert_eq( - fifo, write.out, 10, "write_eq_10", 32 - ) # `write` == 10 - read_eq_10 = util.insert_eq(fifo, read.out, 10, "read_eq_10", 32) # `read` == 10 + write_eq_max_queue_len = util.insert_eq( + fifo, write.out, MAX_QUEUE_LEN, "write_eq_MAX_QUEUE_LEN", 32 + ) # `write` == MAX_QUEUE_LEN + read_eq_max_queue_len = util.insert_eq( + fifo, read.out, MAX_QUEUE_LEN, "read_eq_MAX_QUEUE_LEN", 32 + ) # `read` == MAX_QUEUE_LEN len_eq_0 = util.insert_eq(fifo, len.out, 0, "len_eq_0", 32) # `len` == 0 - len_eq_10 = util.insert_eq(fifo, len.out, 10, "len_eq_10", 32) # `len` == 10 + len_eq_max_queue_len = util.insert_eq( + fifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 + ) # `len` == MAX_QUEUE_LEN # Cells and groups to increment read and write registers write_incr = util.insert_incr(fifo, write, "write_incr") # write++ @@ -89,8 +95,8 @@ def insert_fifo(prog, name): read_incr, # Increment the read pointer. cb.if_( # Wrap around if necessary. - read_eq_10[0].out, - read_eq_10[1], + read_eq_max_queue_len[0].out, + read_eq_max_queue_len[1], read_wrap, ), len_decr, # Decrement the length. @@ -118,16 +124,16 @@ def insert_fifo(prog, name): cmd_gt_1[1], cb.if_( # Yes, the user called push. But is the queue full? - len_eq_10[0].out, - len_eq_10[1], + len_eq_max_queue_len[0].out, + len_eq_max_queue_len[1], [raise_err, zero_out_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. write_to_mem, # Write to the queue. write_incr, # Increment the write pointer. cb.if_( # Wrap around if necessary. - write_eq_10[0].out, - write_eq_10[1], + write_eq_max_queue_len[0].out, + write_eq_max_queue_len[1], write_wrap, ), len_incr, # Increment the length. diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index c9d36626e..d260eae5e 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -4,6 +4,8 @@ import calyx.builder_util as util import calyx.queue_call as qc +MAX_QUEUE_LEN = 10 + def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, boundary, group): """The flow is needed when the command is a push. @@ -53,14 +55,15 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): violation of the 50/50 rule) until the silent flow starts transmitting again. At that point we go back to 50/50. - The PIFO's maximum capacity is 10. + The PIFO's maximum capacity is MAX_QUEUE_LEN. Let's say the two flows are called `0` and `1`. - We orchestrate two sub-queues, `queue_l` and `queue_r`, each of capacity 10. + We orchestrate two sub-queues, `queue_l` and `queue_r`, + each of capacity MAX_QUEUE_LEN. We maintain a register that points to which of these sub-queues is "hot". Start off with `hot` pointing to `queue_l` (arbitrarily). - `push(v, PIFO)`: - + If len(PIFO) = 10, raise an "overflow" err and exit. + + If len(PIFO) = MAX_QUEUE_LEN, raise an "overflow" err and exit. + Otherwise, the charge is to enqueue value `v`. Find out which flow `f` the value `v` should go to; `f` better be either `0` or `1`. @@ -109,7 +112,9 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): flow_eq_0 = util.insert_eq(pifo, flow.out, 0, "flow_eq_0", 1) flow_eq_1 = util.insert_eq(pifo, flow.out, 1, "flow_eq_1", 1) len_eq_0 = util.insert_eq(pifo, len.out, 0, "len_eq_0", 32) - len_eq_10 = util.insert_eq(pifo, len.out, 10, "len_eq_10", 32) + len_eq_max_queue_len = util.insert_eq( + pifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 + ) cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 32) cmd_eq_1 = util.insert_eq(pifo, cmd, 1, "cmd_eq_1", 32) cmd_gt_1 = util.insert_gt(pifo, cmd, 1, "cmd_gt_1", 32) @@ -267,8 +272,8 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): cmd_gt_1[1], cb.if_( # Yes, the user called push. But is the queue full? - len_eq_10[0].out, - len_eq_10[1], + len_eq_max_queue_len[0].out, + len_eq_max_queue_len[1], [raise_err, zero_out_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. lower_err, From ca0e2062f61c28c06be9f3e42a8decc02dd8561b Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 17 Aug 2023 11:08:13 -0400 Subject: [PATCH 027/189] Update MrXL one-pager (#1669) --- docs/frontends/mrxl.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/frontends/mrxl.md b/docs/frontends/mrxl.md index 4091dabf2..e16f5854f 100644 --- a/docs/frontends/mrxl.md +++ b/docs/frontends/mrxl.md @@ -2,7 +2,7 @@ MrXL is an example DSL developed for the [frontend tutorial][fronttut]. MrXL programs consist of `map` and `reduce` operations on arrays. -For example, here is a dot-product implementation: +For example, here is an implementation of dot-products: input avec: int[1024] input bvec: int[1024] @@ -10,16 +10,16 @@ For example, here is a dot-product implementation: prodvec := map 16 (a <- avec, b <- bvec) { a * b } dot := reduce 4 (a, b <- prodvec) 0 { a + b } -The numbers that come right after `map` and `reduce` (16 and 4 respectively) are "parallelism factors" that guide the generation of hardware. - +The numbers that come right after `map` and `reduce` (`16` and `4` respectively) are "parallelism factors" that guide the generation of hardware. +The explanation on this page is relatively brief; see the [frontend tutorial][fronttut] for a more detailed explanation of the language. In particular, the [sum of squares][fronttut-sumsq] example is a good place to start. Install ------- -Install the [calyx-py](../calyx-py.md) library. +First, install the [calyx-py](../calyx-py.md) library. The MrXL implementation is in Python and uses [Flit][]. -First, [install flit][flit] (`pip install flit` or similar), and then type the +Install Flit (`pip install flit` or similar), and then type the following after changing your directory to `frontend/mrxl`: flit install --symlink @@ -43,24 +43,26 @@ To run the program through the MrXL interpreter, execute: mrxl .mrxl --data .mrxl.data --interpret -where `.mrxl` is a file containing MrXL source code and `.mrxl.data` is a file containing values for all the variables declared as `input`s in the MrXL program. The interpreter dumps the `output` variables, in JSON, to stdout. +where `.mrxl` is a file containing MrXL source code and `.mrxl.data` is a file containing values for all the variables declared as `input`s in the MrXL program. The interpreter dumps the `output` variables, in JSON format, to stdout. You could try, for example: mrxl test/dot.mrxl --data test/dot.mrxl.data --interpret This is just a baby version of the dot-product implementation we showed at the very top; we have just shortened the input array so you can easily see it in full. -We also provide `add.mrxl` and `sum.mrxl`, along with sample `.mrxl.data` files, under `test/`. Try playing with the inputs and the operations! +Similarly, we also provide `add.mrxl` and `sum.mrxl`, along with accompanying `.mrxl.data` files, under `test/`. Try playing with the inputs and the operations! Compiling to Calyx ------------------ +> The dot-product example above shows off features of MrXL that are not yet supported by the compiler. In particular, the compiler does not yet support `reduce` with a parallelism factor other than `1`. This is because MrXL is mostly a pedagogical device, and we want new users of Calyx to try implementing this feature themselves. To learn more about this and other extensions to MrXL, consider working through the [frontend tutorial][fronttut]. + To run the compiler and see the Calyx code your MrXL program generates, just drop the `--data` and `--interpret` flags. For instance: mrxl test/dot.mrxl -In order to run the compiler through `fud`, pass the `--from mrxl` and `--to futil` flags: +In order to run the compiler through `fud`, pass the `--from mrxl` and `--to calyx` flags: fud e --from mrxl --to calyx @@ -85,5 +87,5 @@ The changes it makes are: [flit]: https://flit.readthedocs.io/en/latest/index.html -[fronttut]: ../tutorial/frontend-tut.md - +[fronttut]: ../tutorial/frontend-tut.html +[fronttut-sumsq]: ../tutorial/frontend-tut.html#example-sum-of-squares From 96243ca02e668e2703d442bafcd3d8f70c584b48 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 17 Aug 2023 12:25:30 -0400 Subject: [PATCH 028/189] Queues: more expressive common interface (#1662) --- calyx-py/calyx/queue_call.py | 53 ++++++++++----- calyx-py/test/correctness/fifo.data | 26 ++++++- calyx-py/test/correctness/fifo.expect | 19 +++++- calyx-py/test/correctness/fifo.py | 68 +++++++++---------- calyx-py/test/correctness/pifo.data | 26 ++++++- calyx-py/test/correctness/pifo.expect | 19 +++++- calyx-py/test/correctness/pifo.py | 50 ++++++++------ calyx-py/test/correctness/pifo_tree.data | 24 +++++++ calyx-py/test/correctness/pifo_tree.expect | 17 +++++ .../correctness/pifo_tree_pre_tangerine.data | 24 +++++++ 10 files changed, 251 insertions(+), 75 deletions(-) diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index b722d6c6d..5714e0227 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -44,22 +44,30 @@ def insert_main(prog, queue): main: cb.ComponentBuilder = prog.component("main") # The user-facing interface of the `main` component is: - # - a list of commands (the input) - # where each command is a 32-bit unsigned integer, with the following format: + # - input 1: a list of commands + # where each command is a 2-bit unsigned integer, with the following format: # `0`: pop - # any other value: push that value - # - a list of answers (the output). + # `1`: peek + # `2`: push + # - input 2: a list of values to push + # where each value is a 32-bit unsigned integer + # the value at `i` is pushed if the command at `i` is `2`. + # - output: a list of answers, reflecting any pops or peeks from the queue. # # The user-facing interface of the `queue` component is: - # - one input, `cmd`. - # where each command is a 32-bit unsigned integer, with the following format: + # - input `cmd` + # where each command is a 2-bit unsigned integer, with the following format: # `0`: pop - # any other value: push that value - # - one ref register, `ans`, into which the result of a pop is written. + # `1`: peek + # `2`: push + # - input `value` + # which is a 32-bit unsigned integer. If `cmd` is `2`, push this value. + # - one ref register, `ans`, into which the result of a pop or peek is written. # - one ref register, `err`, which is raised if an error occurs. - commands = main.seq_mem_d1("commands", 32, MAX_CMDS, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, ANS_MEM_LEN, 32, is_external=True) + commands = main.seq_mem_d1("commands", 2, MAX_CMDS, 32, is_external=True) + values = main.seq_mem_d1("values", 32, MAX_CMDS, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) # The two components we'll use: queue = main.cell("myqueue", queue) @@ -79,18 +87,24 @@ def insert_main(prog, queue): i = main.reg("i", 32) # The index of the command we're currently processing j = main.reg("j", 32) # The index on the answer-list we'll write to - cmd = main.reg("command", 32) # The command we're currently processing + cmd = main.reg("command", 2) # The command we're currently processing + value = main.reg("value", 32) # The value we're currently processing incr_i = util.insert_incr(main, i, "incr_i") # i++ incr_j = util.insert_incr(main, j, "incr_j") # j++ err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? - cmd_le_1 = util.insert_le(main, cmd.out, 1, "cmd_le_1", 32) # cmd <= 1 + cmd_le_1 = util.insert_le(main, cmd.out, 1, "cmd_le_1", 2) # cmd <= 1 read_cmd = util.mem_read_seq_d1(main, commands, i.out, "read_cmd_phase1") write_cmd_to_reg = util.mem_write_seq_d1_to_reg( main, commands, cmd, "write_cmd_phase2" ) + read_value = util.mem_read_seq_d1(main, values, i.out, "read_value") + write_value_to_reg = util.mem_write_seq_d1_to_reg( + main, values, value, "write_value_to_reg" + ) + write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans") main.control += [ @@ -98,18 +112,23 @@ def insert_main(prog, queue): err_eq_0[0].out, err_eq_0[1], # Run while the `err` flag is down [ - read_cmd, # Read `commands[i]` - write_cmd_to_reg, # Write it to `cmd` - cb.invoke( # Call the queue with `cmd` + read_cmd, + write_cmd_to_reg, + # `cmd := commands[i]` + read_value, + write_value_to_reg, + # `value := values[i]` + cb.invoke( # Invoke the queue. queue, in_cmd=cmd.out, + in_value=value.out, ref_ans=ans, ref_err=err, ), cb.if_( # If it was a pop or a peek, write ans to the answer list cmd_le_1[0].out, cmd_le_1[1], - [ # AM: I'd like to have an additional check hereL + [ # AM: I'd like to have an additional check here: # if err flag comes back raised, # we do not perform this write_ans or this incr_j write_ans, @@ -117,7 +136,7 @@ def insert_main(prog, queue): ], ), incr_i, # Increment the command index - cb.invoke( # If i = 15, raise error flag + cb.invoke( # If i = MAX_CMDS, raise error flag raise_err_if_i_eq_max_cmds, in_i=i.out, ref_err=err ), # AM: hella hacky ], diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 92ca60a44..f0c8359a9 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -1,8 +1,32 @@ { "commands": { "data": [ - 100, + 2, 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { + "data": [ + 100, + 0, 101, 102, 0, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index c4f8d2cd6..72d5cf8bd 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -12,8 +12,25 @@ 0 ], "commands": [ - 100, + 2, 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0 + ], + "values": [ + 100, + 0, 101, 102, 0, diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index 17ca08520..c83e8345b 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -10,15 +10,17 @@ def insert_fifo(prog, name): """Inserts the component `fifo` into the program. It has: - - one input, `cmd`. - - one memory, `mem`, of size MAX_QUEUE_LEN. + - two inputs, `cmd` and `value`. + - one memory, `mem`, of size 10. - two registers, `next_write` and `next_read`. - two ref registers, `ans` and `err`. """ fifo: cb.ComponentBuilder = prog.component(name) - cmd = fifo.input("cmd", 32) - # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. + cmd = fifo.input("cmd", 2) + # If this is 0, we pop. If it is 1, we peek. + # If it is 2, we push `value` to the queue. + value = fifo.input("value", 32) # The value to push to the queue mem = fifo.seq_mem_d1("mem", 32, MAX_QUEUE_LEN, 32) write = fifo.reg("next_write", 32) # The next address to write to @@ -27,28 +29,28 @@ def insert_fifo(prog, name): # simulate a circular queue of size MAX_QUEUE_LEN. ans = fifo.reg("ans", 32, is_ref=True) - # If the user wants to pop, we will write the popped value to `ans` + # If the user wants to pop or peek, we will write the value to `ans`. err = fifo.reg("err", 1, is_ref=True) - # We'll raise this as a general error flag for overflow and underflow + # We'll raise this as a general error flag for overflow and underflow. - len = fifo.reg("len", 32) # The length of the FIFO + len = fifo.reg("len", 32) # The length of the FIFO. - # Cells and groups to compute equality - cmd_eq_0 = util.insert_eq(fifo, cmd, 0, "cmd_eq_0", 32) # `cmd` == 0 - cmd_eq_1 = util.insert_eq(fifo, cmd, 1, "cmd_eq_1", 32) # `cmd` == 1 - cmd_gt_1 = util.insert_gt(fifo, cmd, 1, "cmd_gt_1", 32) # `cmd` > 1 + # Cells and groups to compute equality. + cmd_eq_0 = util.insert_eq(fifo, cmd, 0, "cmd_eq_0", 2) + cmd_eq_1 = util.insert_eq(fifo, cmd, 1, "cmd_eq_1", 2) + cmd_eq_2 = util.insert_eq(fifo, cmd, 2, "cmd_eq_2", 2) write_eq_max_queue_len = util.insert_eq( fifo, write.out, MAX_QUEUE_LEN, "write_eq_MAX_QUEUE_LEN", 32 - ) # `write` == MAX_QUEUE_LEN + ) read_eq_max_queue_len = util.insert_eq( fifo, read.out, MAX_QUEUE_LEN, "read_eq_MAX_QUEUE_LEN", 32 - ) # `read` == MAX_QUEUE_LEN - len_eq_0 = util.insert_eq(fifo, len.out, 0, "len_eq_0", 32) # `len` == 0 + ) + len_eq_0 = util.insert_eq(fifo, len.out, 0, "len_eq_0", 32) len_eq_max_queue_len = util.insert_eq( fifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 - ) # `len` == MAX_QUEUE_LEN + ) # Cells and groups to increment read and write registers write_incr = util.insert_incr(fifo, write, "write_incr") # write++ @@ -56,19 +58,15 @@ def insert_fifo(prog, name): len_incr = util.insert_incr(fifo, len, "len_incr") # len++ len_decr = util.insert_decr(fifo, len, "len_decr") # len-- - # Cells and groups to modify flags, which are registers - write_wrap = util.insert_reg_store( - fifo, write, 0, "write_wraparound" - ) # zero out `write` - read_wrap = util.insert_reg_store( - fifo, read, 0, "read_wraparound" - ) # zero out `read` - raise_err = util.insert_reg_store(fifo, err, 1, "raise_err") # set `err` to 1 - zero_out_ans = util.insert_reg_store(fifo, ans, 0, "zero_out_ans") # zero out `ans` - - # Load and store into an arbitary slot in memory + # Cells and groups to modify flags, which are registers. + flash_write = util.insert_reg_store(fifo, write, 0, "flash_write") # write := 0 + flash_read = util.insert_reg_store(fifo, read, 0, "flash_read") # read := 0 + flash_ans = util.insert_reg_store(fifo, ans, 0, "flash_ans") # ans := 0 + raise_err = util.insert_reg_store(fifo, err, 1, "raise_err") # err := 1 + + # Load/store to/from an arbitary slot in `mem`. write_to_mem = util.mem_store_seq_d1( - fifo, mem, write.out, cmd, "write_payload_to_mem" + fifo, mem, write.out, value, "write_payload_to_mem" ) read_from_mem = util.mem_read_seq_d1( fifo, mem, read.out, "read_payload_from_mem_phase1" @@ -88,7 +86,7 @@ def insert_fifo(prog, name): # Yes, the user called pop. But is the queue empty? len_eq_0[0].out, len_eq_0[1], - [raise_err, zero_out_ans], # The queue is empty: underflow. + [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. read_from_mem, # Read from the queue. write_to_ans, # Write the answer to the answer register. @@ -97,7 +95,7 @@ def insert_fifo(prog, name): # Wrap around if necessary. read_eq_max_queue_len[0].out, read_eq_max_queue_len[1], - read_wrap, + flash_read, ), len_decr, # Decrement the length. ], @@ -110,7 +108,7 @@ def insert_fifo(prog, name): cb.if_( # Yes, the user called peek. But is the queue empty? len_eq_0[0].out, len_eq_0[1], - [raise_err, zero_out_ans], # The queue is empty: underflow. + [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. read_from_mem, # Read from the queue. write_to_ans, # Write the answer to the answer register. @@ -120,21 +118,21 @@ def insert_fifo(prog, name): ), cb.if_( # Did the user call push? - cmd_gt_1[0].out, - cmd_gt_1[1], + cmd_eq_2[0].out, + cmd_eq_2[1], cb.if_( # Yes, the user called push. But is the queue full? len_eq_max_queue_len[0].out, len_eq_max_queue_len[1], - [raise_err, zero_out_ans], # The queue is full: overflow. + [raise_err, flash_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. - write_to_mem, # Write to the queue. + write_to_mem, # Write `value` to the queue. write_incr, # Increment the write pointer. cb.if_( # Wrap around if necessary. write_eq_max_queue_len[0].out, write_eq_max_queue_len[1], - write_wrap, + flash_write, ), len_incr, # Increment the length. ], diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index 954df2114..fc06886e7 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -1,5 +1,29 @@ { "commands": { + "data": [ + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { "data": [ 101, 102, @@ -9,7 +33,7 @@ 104, 201, 202, - 1, + 0, 0, 0, 0, diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index 3e76673b6..0631155c8 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -12,6 +12,23 @@ 0 ], "commands": [ + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0 + ], + "values": [ 101, 102, 0, @@ -20,7 +37,7 @@ 104, 201, 202, - 1, + 0, 0, 0, 0, diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index d260eae5e..8688deffd 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -29,15 +29,17 @@ def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, boundary, group) return infer_flow_grp -def invoke_subqueue(queue_cell, cmd, ans, err) -> cb.invoke: +def invoke_subqueue(queue_cell, cmd, value, ans, err) -> cb.invoke: """Invokes the cell {queue_cell} with: {cmd} passed by value + {value} passed by value {ans} passed by reference {err} passed by reference """ return cb.invoke( queue_cell, in_cmd=cmd, + in_value=value, ref_ans=ans, ref_err=err, ) @@ -83,8 +85,10 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): """ pifo: cb.ComponentBuilder = prog.component(name) - cmd = pifo.input("cmd", 32) - # If this is 0, we pop. If it is 1, we peek. Otherwise, we push the value. + cmd = pifo.input("cmd", 2) + # If this is 0, we pop. If it is 1, we peek. + # If it is 2, we push `value` to the queue. + value = pifo.input("value", 32) # The value to push to the queue # Declare the two sub-queues as cells of this component. queue_l = pifo.cell("queue_l", queue_l) @@ -93,7 +97,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): flow = pifo.reg("flow", 1) # The flow to push to: 0 or 1. # We will infer this using a separate component; # it is a function of the value being pushed. - infer_flow = insert_flow_inference(pifo, cmd, flow, boundary, "infer_flow") + infer_flow = insert_flow_inference(pifo, value, flow, boundary, "infer_flow") ans = pifo.reg("ans", 32, is_ref=True) # If the user wants to pop, we will write the popped value to `ans`. @@ -115,9 +119,9 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): len_eq_max_queue_len = util.insert_eq( pifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 ) - cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 32) - cmd_eq_1 = util.insert_eq(pifo, cmd, 1, "cmd_eq_1", 32) - cmd_gt_1 = util.insert_gt(pifo, cmd, 1, "cmd_gt_1", 32) + cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 2) + cmd_eq_1 = util.insert_eq(pifo, cmd, 1, "cmd_eq_1", 2) + cmd_eq_2 = util.insert_eq(pifo, cmd, 2, "cmd_eq_2", 2) err_eq_0 = util.insert_eq(pifo, err.out, 0, "err_eq_0", 1) err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), "err_neq_0", 1) @@ -151,7 +155,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot_eq_0[0].out, hot_eq_0[1], [ # `hot` is 0. We'll invoke `pop` on `queue_l`. - invoke_subqueue(queue_l, cmd, ans, err), + invoke_subqueue(queue_l, cmd, value, ans, err), # Our next step depends on whether `queue_l` # raised the error flag. # We can check these cases in parallel. @@ -163,7 +167,9 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): # We'll try to pop from `queue_r`. # We'll pass it a lowered err lower_err, - invoke_subqueue(queue_r, cmd, ans, err), + invoke_subqueue( + queue_r, cmd, value, ans, err + ), ], ), cb.if_( @@ -184,14 +190,16 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot_eq_1[0].out, hot_eq_1[1], [ - invoke_subqueue(queue_r, cmd, ans, err), + invoke_subqueue(queue_r, cmd, value, ans, err), cb.par( cb.if_( err_neq_0[0].out, err_neq_0[1], [ lower_err, - invoke_subqueue(queue_l, cmd, ans, err), + invoke_subqueue( + queue_l, cmd, value, ans, err + ), ], ), cb.if_( @@ -229,7 +237,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot_eq_0[0].out, hot_eq_0[1], [ # `hot` is 0. We'll invoke `peek` on `queue_l`. - invoke_subqueue(queue_l, cmd, ans, err), + invoke_subqueue(queue_l, cmd, value, ans, err), # Our next step depends on whether `queue_l` # raised the error flag. cb.if_( @@ -239,7 +247,9 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): # We'll try to peek from `queue_r`. # We'll pass it a lowered `err`. lower_err, - invoke_subqueue(queue_r, cmd, ans, err), + invoke_subqueue( + queue_r, cmd, value, ans, err + ), ], ), # Peeking does not affect `hot`. @@ -251,13 +261,15 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot_eq_1[0].out, hot_eq_1[1], [ - invoke_subqueue(queue_r, cmd, ans, err), + invoke_subqueue(queue_r, cmd, value, ans, err), cb.if_( err_neq_0[0].out, err_neq_0[1], [ lower_err, - invoke_subqueue(queue_l, cmd, ans, err), + invoke_subqueue( + queue_l, cmd, value, ans, err + ), ], ), ], @@ -268,8 +280,8 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ), cb.if_( # Did the user call push? - cmd_gt_1[0].out, - cmd_gt_1[1], + cmd_eq_2[0].out, + cmd_eq_2[1], cb.if_( # Yes, the user called push. But is the queue full? len_eq_max_queue_len[0].out, @@ -284,13 +296,13 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): flow_eq_0[0].out, flow_eq_0[1], # This value should be pushed to queue_l. - invoke_subqueue(queue_l, cmd, ans, err), + invoke_subqueue(queue_l, cmd, value, ans, err), ), cb.if_( flow_eq_1[0].out, flow_eq_1[1], # This value should be pushed to queue_r. - invoke_subqueue(queue_r, cmd, ans, err), + invoke_subqueue(queue_r, cmd, value, ans, err), ), ), len_incr, # Increment the length. diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data index ca4781021..254f74da6 100644 --- a/calyx-py/test/correctness/pifo_tree.data +++ b/calyx-py/test/correctness/pifo_tree.data @@ -1,5 +1,29 @@ { "commands": { + "data": [ + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { "data": [ 11, 12, diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect index f2b418074..e72076fcf 100644 --- a/calyx-py/test/correctness/pifo_tree.expect +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -12,6 +12,23 @@ 0 ], "commands": [ + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "values": [ 11, 12, 201, diff --git a/calyx-py/test/correctness/pifo_tree_pre_tangerine.data b/calyx-py/test/correctness/pifo_tree_pre_tangerine.data index 32f99ddc4..62b60a327 100644 --- a/calyx-py/test/correctness/pifo_tree_pre_tangerine.data +++ b/calyx-py/test/correctness/pifo_tree_pre_tangerine.data @@ -1,5 +1,29 @@ { "commands": { + "data": [ + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { "data": [ 11, 12, From fa908489e4c8836e690c0114fd2f42a6ab29fcc5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 18 Aug 2023 11:02:24 +0530 Subject: [PATCH 029/189] Remove `PortDef::into` (#1671) * remove `PortDef::into` * changelog --- CHANGELOG.md | 1 + calyx-frontend/src/common.rs | 56 ++++++++++-------- calyx-frontend/src/parser.rs | 72 +++++++++++------------ calyx-ir/src/builder.rs | 37 +++++------- calyx-ir/src/component.rs | 24 ++++---- calyx-ir/src/from_ast.rs | 24 +++----- calyx-ir/src/printer.rs | 10 ++-- calyx-ir/src/structure.rs | 12 ++-- calyx-opt/src/analysis/dataflow_order.rs | 4 +- calyx-opt/src/analysis/port_interface.rs | 6 +- calyx-opt/src/passes/discover_external.rs | 6 +- calyx-opt/src/passes/static_promotion.rs | 8 +-- src/backend/verilog.rs | 8 +-- 13 files changed, 134 insertions(+), 134 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3989a023..09da00bdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Don't require `@clk` and `@reset` ports in `comb` components - `inline` pass supports inlining `ref` cells - `comb-prop`: disable rewrite from `wire.in = port` when the output of a wire is read. +- BREAKING: Remove `PortDef::into()` because it makes it easy to miss copying attributes. ## 0.4.0 diff --git a/calyx-frontend/src/common.rs b/calyx-frontend/src/common.rs index ccef18ba4..78dbe363a 100644 --- a/calyx-frontend/src/common.rs +++ b/calyx-frontend/src/common.rs @@ -95,7 +95,7 @@ impl GetName for Primitive { #[derive(Clone, Debug)] pub struct PortDef { /// The name of the port. - pub name: Id, + name: Id, /// The width of the port. . pub width: W, /// The direction of the port. Only allowed to be [Direction::Input] @@ -105,31 +105,29 @@ pub struct PortDef { pub attributes: Attributes, } -impl From<(I, u64, Direction)> for PortDef -where - I: Into, -{ - fn from(port: (I, u64, Direction)) -> Self { - PortDef { - name: port.0.into(), - width: Width::Const { value: port.1 }, - direction: port.2, - attributes: Attributes::default(), +impl PortDef { + pub fn new( + name: impl Into, + width: W, + direction: Direction, + attributes: Attributes, + ) -> Self { + assert!( + matches!(direction, Direction::Input | Direction::Output), + "Direction must be either Input or Output" + ); + + Self { + name: name.into(), + width, + direction, + attributes, } } -} -impl From<(I, u64, Direction)> for PortDef -where - I: Into, -{ - fn from(port: (I, u64, Direction)) -> Self { - PortDef { - name: port.0.into(), - width: port.1, - direction: port.2, - attributes: Attributes::default(), - } + /// Return the name of the port definition + pub fn name(&self) -> Id { + self.name } } @@ -151,6 +149,18 @@ impl std::fmt::Display for Width { } } +impl From for Width { + fn from(value: u64) -> Self { + Width::Const { value } + } +} + +impl From for Width { + fn from(value: Id) -> Self { + Width::Param { value } + } +} + impl PortDef { /// Given a map from names of parameters to their values, attempt to /// resolve this definition. diff --git a/calyx-frontend/src/parser.rs b/calyx-frontend/src/parser.rs index db8ddd745..b6088ddae 100644 --- a/calyx-frontend/src/parser.rs +++ b/calyx-frontend/src/parser.rs @@ -454,15 +454,15 @@ impl CalyxParser { Ok(match_nodes!( input.into_children(); [io_port((name, width, attributes))] => { - let pd = PortDef { - name, width, direction: Direction::Input, attributes - }; + let pd = PortDef::new( + name, width, Direction::Input, attributes + ); vec![pd] }, [io_port((name, width, attributes)), comma(_), inputs(rest)] => { - let pd = PortDef { - name, width, direction: Direction::Input, attributes - }; + let pd = PortDef::new( + name, width, Direction::Input, attributes + ); let mut v = vec![pd]; v.extend(rest); v @@ -474,15 +474,15 @@ impl CalyxParser { Ok(match_nodes!( input.into_children(); [io_port((name, width, attributes))] => { - let pd = PortDef { - name, width, direction: Direction::Output, attributes - }; + let pd = PortDef::new( + name, width, Direction::Output, attributes + ); vec![pd] }, [io_port((name, width, attributes)), comma(_), outputs(rest)] => { - let pd = PortDef { - name, width, direction: Direction::Output, attributes - }; + let pd = PortDef::new( + name, width, Direction::Output, attributes + ); let mut v = vec![pd]; v.extend(rest); v @@ -1094,14 +1094,14 @@ impl CalyxParser { Err(input.error("Static Component must have defined control"))?; } let (continuous_assignments, groups, static_groups) = connections; - let sig = sig.into_iter().map(|PortDef { name, width, direction, attributes }| { - if let Width::Const { value } = width { - Ok(PortDef { - name, - width: value, - direction, - attributes - }) + let sig = sig.into_iter().map(|pd| { + if let Width::Const { value } = pd.width { + Ok(PortDef::new( + pd.name(), + value, + pd.direction, + pd.attributes + )) } else { Err(input.error("Components cannot use parameters")) } @@ -1127,14 +1127,14 @@ impl CalyxParser { control(control) ] => { let (continuous_assignments, groups, static_groups) = connections; - let sig = sig.into_iter().map(|PortDef { name, width, direction, attributes }| { - if let Width::Const { value } = width { - Ok(PortDef { - name, - width: value, - direction, - attributes - }) + let sig = sig.into_iter().map(|pd| { + if let Width::Const { value } = pd.width { + Ok(PortDef::new( + pd.name(), + value, + pd.direction, + pd.attributes + )) } else { Err(input.error("Components cannot use parameters")) } @@ -1161,14 +1161,14 @@ impl CalyxParser { control(control), ] => { let (continuous_assignments, groups, static_groups) = connections; - let sig = sig.into_iter().map(|PortDef { name, width, direction, attributes }| { - if let Width::Const { value } = width { - Ok(PortDef { - name, - width: value, - direction, - attributes - }) + let sig = sig.into_iter().map(|pd| { + if let Width::Const { value } = pd.width { + Ok(PortDef::new( + pd.name(), + value, + pd.direction, + pd.attributes + )) } else { Err(input.error("Components cannot use parameters")) } diff --git a/calyx-ir/src/builder.rs b/calyx-ir/src/builder.rs index 3ca8397b6..14e928439 100644 --- a/calyx-ir/src/builder.rs +++ b/calyx-ir/src/builder.rs @@ -179,12 +179,12 @@ impl<'a> Builder<'a> { let cell = Self::cell_from_signature( name, ir::CellType::Constant { val, width }, - vec![ir::PortDef { - name: "out".into(), + vec![ir::PortDef::new( + ir::Id::from("out"), width, - direction: ir::Direction::Output, - attributes: ir::Attributes::default(), - }], + ir::Direction::Output, + ir::Attributes::default(), + )], ); // Add constant to the Component. @@ -347,23 +347,16 @@ impl<'a> Builder<'a> { ports: Vec>, ) -> RRC { let cell = Rc::new(RefCell::new(ir::Cell::new(name, typ))); - ports.into_iter().for_each( - |PortDef { - name, - width, - direction, - attributes, - }| { - let port = Rc::new(RefCell::new(ir::Port { - name, - width, - direction, - parent: ir::PortParent::Cell(WRC::from(&cell)), - attributes, - })); - cell.borrow_mut().ports.push(port); - }, - ); + ports.into_iter().for_each(|pd| { + let port = Rc::new(RefCell::new(ir::Port { + name: pd.name(), + width: pd.width, + direction: pd.direction, + parent: ir::PortParent::Cell(WRC::from(&cell)), + attributes: pd.attributes, + })); + cell.borrow_mut().ports.push(port); + }); cell } } diff --git a/calyx-ir/src/component.rs b/calyx-ir/src/component.rs index 165489cbb..a0018a2b7 100644 --- a/calyx-ir/src/component.rs +++ b/calyx-ir/src/component.rs @@ -68,7 +68,7 @@ pub struct Component { impl Component { /// Extend the signature with interface ports if they are missing. pub(super) fn extend_signature(sig: &mut Vec>) { - let port_names: HashSet<_> = sig.iter().map(|pd| pd.name).collect(); + let port_names: HashSet<_> = sig.iter().map(|pd| pd.name()).collect(); let mut namegen = NameGenerator::with_prev_defined_names(port_names); for (attr, width, direction) in INTERFACE_PORTS.iter() { // Check if there is already another interface port defined for the @@ -77,12 +77,12 @@ impl Component { let mut attributes = Attributes::default(); attributes.insert(*attr, 1); let name = Id::from(attr.to_string()); - sig.push(PortDef { - name: namegen.gen_name(name.to_string()), - width: *width, - direction: direction.clone(), + sig.push(PortDef::new( + namegen.gen_name(name.to_string()), + *width, + direction.clone(), attributes, - }); + )); } } } @@ -108,7 +108,7 @@ impl Component { Self::extend_signature(&mut ports); } - let prev_names: HashSet<_> = ports.iter().map(|pd| pd.name).collect(); + let prev_names: HashSet<_> = ports.iter().map(|pd| pd.name()).collect(); let this_sig = Builder::cell_from_signature( THIS_ID.into(), @@ -116,9 +116,13 @@ impl Component { ports .into_iter() // Reverse the port directions inside the component. - .map(|pd| PortDef { - direction: pd.direction.reverse(), - ..pd + .map(|pd| { + PortDef::new( + pd.name(), + pd.width, + pd.direction.reverse(), + pd.attributes, + ) }) .collect(), ); diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index 00f031664..d125faf9c 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -68,10 +68,10 @@ fn check_valid_port( if let Some(prim) = sig_ctx.lib.find_primitive(comp_name) { prim.signature .iter() - .map(|port_def| port_def.name) + .map(|port_def| port_def.name()) .collect() } else if let Some((comp_sigs, _)) = sig_ctx.comp_sigs.get(&comp_name) { - comp_sigs.iter().map(|port_def| port_def.name).collect() + comp_sigs.iter().map(|port_def| port_def.name()).collect() } else { return Err(Error::undefined( comp_name, @@ -91,31 +91,23 @@ fn check_valid_port( /// Validates a component signature to make sure there are not duplicate ports. fn check_signature(pds: &[PortDef]) -> CalyxResult<()> { - let mut ports: HashSet<&Id> = HashSet::new(); - for PortDef { - name, direction, .. - } in pds - { + let mut ports: HashSet = HashSet::new(); + for pd in pds { + let name = pd.name(); // check for uniqueness - match &direction { + match &pd.direction { Direction::Input => { if !ports.contains(&name) { ports.insert(name); } else { - return Err(Error::already_bound( - *name, - "port".to_string(), - )); + return Err(Error::already_bound(name, "port".to_string())); } } Direction::Output => { if !ports.contains(&name) { ports.insert(name); } else { - return Err(Error::already_bound( - *name, - "port".to_string(), - )); + return Err(Error::already_bound(name, "port".to_string())); } } Direction::Inout => { diff --git a/calyx-ir/src/printer.rs b/calyx-ir/src/printer.rs index 437b9e247..6c881506d 100644 --- a/calyx-ir/src/printer.rs +++ b/calyx-ir/src/printer.rs @@ -14,7 +14,7 @@ pub struct Printer; impl Printer { /// Format attributes of the form `@static(1)`. /// Returns the empty string if the `attrs` is empty. - fn format_at_attributes(attrs: &ir::Attributes) -> String { + pub fn format_at_attributes(attrs: &ir::Attributes) -> String { let mut buf = attrs.to_string_with(" ", |name, val| { if val == 1 { format!("@{}", name) @@ -30,7 +30,7 @@ impl Printer { /// Format attributes of the form `<"static"=1>`. /// Returns the empty string if the `attrs` is empty. - fn format_attributes(attrs: &ir::Attributes) -> String { + pub fn format_attributes(attrs: &ir::Attributes) -> String { if attrs.is_empty() { "".to_string() } else { @@ -44,7 +44,7 @@ impl Printer { } /// Formats port definitions in signatures - fn format_ports(ports: &[RRC]) -> String { + pub fn format_ports(ports: &[RRC]) -> String { ports .iter() .map(|p| { @@ -59,7 +59,7 @@ impl Printer { .join(", ") } - fn format_port_def( + pub fn format_port_def( port_defs: &[&ir::PortDef], ) -> String { port_defs @@ -68,7 +68,7 @@ impl Printer { format!( "{}{}: {}", Self::format_at_attributes(&pd.attributes), - pd.name, + pd.name(), pd.width ) }) diff --git a/calyx-ir/src/structure.rs b/calyx-ir/src/structure.rs index 0a08ce8ed..d722c34aa 100644 --- a/calyx-ir/src/structure.rs +++ b/calyx-ir/src/structure.rs @@ -429,12 +429,12 @@ impl Cell { .iter() .map(|port_ref| { let port = port_ref.borrow(); - PortDef { - name: port.name, - width: port.width, - direction: port.direction.clone(), - attributes: port.attributes.clone(), - } + PortDef::new( + port.name, + port.width, + port.direction.clone(), + port.attributes.clone(), + ) }) .collect() } diff --git a/calyx-opt/src/analysis/dataflow_order.rs b/calyx-opt/src/analysis/dataflow_order.rs index fec8baa55..1b6e0e415 100644 --- a/calyx-opt/src/analysis/dataflow_order.rs +++ b/calyx-opt/src/analysis/dataflow_order.rs @@ -36,10 +36,10 @@ fn prim_to_write_map(prim: &ir::Primitive) -> CalyxResult { } match port.direction { ir::Direction::Input => { - inputs.insert(port.name); + inputs.insert(port.name()); } ir::Direction::Output => outputs.push(( - port.name, + port.name(), attrs .get(ir::BoolAttr::Stable) .or_else(|| attrs.get(ir::NumAttr::Done)) diff --git a/calyx-opt/src/analysis/port_interface.rs b/calyx-opt/src/analysis/port_interface.rs index 335a69884..bb427599c 100644 --- a/calyx-opt/src/analysis/port_interface.rs +++ b/calyx-opt/src/analysis/port_interface.rs @@ -30,7 +30,7 @@ impl PortInterface { .map(|pd| { ( pd.attributes.get(ir::NumAttr::WriteTogether).unwrap(), - pd.name, + pd.name(), ) }) .into_group_map() @@ -69,10 +69,10 @@ impl PortInterface { } assert!(outputs.len() == 1); Ok(( - outputs[0].name, + outputs[0].name(), inputs .into_iter() - .map(|port| port.name) + .map(|port| port.name()) .collect::>(), )) }) diff --git a/calyx-opt/src/passes/discover_external.rs b/calyx-opt/src/passes/discover_external.rs index 6ece7f980..1067b75f1 100644 --- a/calyx-opt/src/passes/discover_external.rs +++ b/calyx-opt/src/passes/discover_external.rs @@ -131,7 +131,7 @@ impl Visitor for DiscoverExternal { !p.attributes.has(ir::BoolAttr::Clk) && !p.attributes.has(ir::BoolAttr::Reset) }) - .map(|p| p.name) + .map(|p| p.name()) .collect::>(); prim_ports.insert(prim.name, hs); } @@ -185,10 +185,10 @@ impl Visitor for DiscoverExternal { p.borrow() .name .as_ref() - .ends_with(abs.name.as_ref()) + .ends_with(abs.name().as_ref()) }) .unwrap_or_else(|| { - panic!("No port found for {}", abs.name) + panic!("No port found for {}", abs.name()) }); // Update the value of the parameter let v = params.get_mut(&value).unwrap(); diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 9f359ab98..a4fd888fa 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -52,7 +52,7 @@ impl From<&ir::Primitive> for GoDone { fn from(prim: &ir::Primitive) -> Self { let done_ports: HashMap<_, _> = prim .find_all_with_attr(ir::NumAttr::Done) - .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name)) + .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name())) .collect(); let go_ports = prim @@ -61,7 +61,7 @@ impl From<&ir::Primitive> for GoDone { pd.attributes.get(ir::NumAttr::Static).and_then(|st| { done_ports .get(&pd.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (pd.name, *done_port, st)) + .map(|done_port| (pd.name(), *done_port, st)) }) }) .collect_vec(); @@ -146,7 +146,7 @@ impl ConstructVisitor for StaticPromotion { for prim in ctx.lib.signatures() { let done_ports: HashMap<_, _> = prim .find_all_with_attr(ir::NumAttr::Done) - .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name)) + .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name())) .collect(); let go_ports = prim @@ -155,7 +155,7 @@ impl ConstructVisitor for StaticPromotion { pd.attributes.get(ir::NumAttr::Static).and_then(|st| { done_ports .get(&pd.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (pd.name, *done_port, st)) + .map(|done_port| (pd.name(), *done_port, st)) }) }) .collect_vec(); diff --git a/src/backend/verilog.rs b/src/backend/verilog.rs index 2359421d7..354657414 100644 --- a/src/backend/verilog.rs +++ b/src/backend/verilog.rs @@ -185,19 +185,19 @@ fn emit_prim_inline( write!(f, " output")?; } ir::Direction::Inout => { - panic!("Unexpected Inout port on Component: {}", port.name) + panic!("Unexpected Inout port on Component: {}", port.name()) } } match port.width { ir::Width::Const { value } => { if value == 1 { - write!(f, " logic {}", port.name)?; + write!(f, " logic {}", port.name())?; } else { - write!(f, " logic [{}:0] {}", value - 1, port.name)?; + write!(f, " logic [{}:0] {}", value - 1, port.name())?; } } ir::Width::Param { value } => { - write!(f, " logic [{}-1:0] {}", value, port.name)?; + write!(f, " logic [{}-1:0] {}", value, port.name())?; } } if idx == prim.signature.len() - 1 { From cdd90dbdc28d4d74ecc3d6bbece8b18c57708687 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:20:39 -0400 Subject: [PATCH 030/189] Builder: optional names for cells (#1664) --- calyx-py/calyx/builder.py | 109 ++++++++++------- calyx-py/calyx/builder_util.py | 150 ++++++++++++------------ calyx-py/calyx/queue_call.py | 8 +- calyx-py/test/builder_example.py | 2 +- calyx-py/test/correctness/arbiter_6.py | 16 +-- calyx-py/test/correctness/fifo.py | 24 ++-- calyx-py/test/correctness/pifo.py | 26 ++-- frontends/mrxl/mrxl/gen_calyx.py | 4 +- frontends/mrxl/mrxl/map.py | 2 +- frontends/systolic-lang/gen-systolic.py | 24 ++-- 10 files changed, 189 insertions(+), 176 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 3bbf0d867..d795faa83 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -48,6 +48,8 @@ def import_(self, filename: str): class ComponentBuilder: """Builds Calyx components definitions.""" + next_gen_idx = 0 + def __init__( self, prog: Builder, @@ -71,6 +73,15 @@ def __init__( for cell in cells: self.index[cell.id.name] = CellBuilder(cell) self.continuous = GroupBuilder(None, self) + self.next_gen_idx = 0 + + def generate_name(self, prefix: str) -> str: + """Generate a unique name with the given prefix.""" + while True: + self.next_gen_idx += 1 + name = f"{prefix}_{self.next_gen_idx}" + if name not in self.index: + return name def input(self, name: str, size: int) -> ExprBuilder: """Declare an input port on the component. @@ -180,8 +191,8 @@ def cell( self, name: str, comp: Union[ast.CompInst, ComponentBuilder], - is_external=False, - is_ref=False, + is_external: bool = False, + is_ref: bool = False, ) -> CellBuilder: """Declare a cell in the component. Returns a cell builder.""" # If we get a (non-primitive) component builder, instantiate it @@ -223,16 +234,18 @@ def comp_instance( return self.cell(cell_name, ast.CompInst(comp_name, [])) - def reg(self, name: str, size: int, is_ref=False) -> CellBuilder: + def reg(self, name: str, size: int, is_ref: bool = False) -> CellBuilder: """Generate a StdReg cell.""" return self.cell(name, ast.Stdlib.register(size), False, is_ref) - def wire(self, name: str, size: int, is_ref=False) -> CellBuilder: - """Generate a StdReg cell.""" + def wire(self, name: str, size: int, is_ref: bool = False) -> CellBuilder: + """Generate a StdWire cell.""" return self.cell(name, ast.Stdlib.wire(size), False, is_ref) - def slice(self, name: str, in_width: int, out_width, is_ref=False) -> CellBuilder: - """Generate a StdReg cell.""" + def slice( + self, name: str, in_width: int, out_width, is_ref: bool = False + ) -> CellBuilder: + """Generate a StdSlice cell.""" return self.cell(name, ast.Stdlib.slice(in_width, out_width), False, is_ref) def const(self, name: str, width: int, value: int) -> CellBuilder: @@ -245,8 +258,8 @@ def mem_d1( bitwidth: int, len: int, idx_size: int, - is_external=False, - is_ref=False, + is_external: bool = False, + is_ref: bool = False, ) -> CellBuilder: """Generate a StdMemD1 cell.""" return self.cell( @@ -259,8 +272,8 @@ def seq_mem_d1( bitwidth: int, len: int, idx_size: int, - is_external=False, - is_ref=False, + is_external: bool = False, + is_ref: bool = False, ) -> CellBuilder: """Generate a SeqMemD1 cell.""" self.prog.import_("primitives/memories.futil") @@ -268,53 +281,64 @@ def seq_mem_d1( name, ast.Stdlib.seq_mem_d1(bitwidth, len, idx_size), is_external, is_ref ) - def add(self, name: str, size: int, signed=False) -> CellBuilder: - """Generate a StdAdd cell.""" + def binary( + self, + operation: str, + size: int, + name: Optional[str] = None, + signed: bool = False, + ) -> CellBuilder: + """Generate a binary cell of the kind specified in `operation`.""" self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("add", size, signed)) + name = name or self.generate_name(operation) + assert isinstance(name, str) + return self.cell(name, ast.Stdlib.op(operation, size, signed)) + + def add(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: + """Generate a StdAdd cell.""" + return self.binary("add", size, name, signed) - def sub(self, name: str, size: int, signed=False): + def sub(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdSub cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("sub", size, signed)) + return self.binary("sub", size, name, signed) - def gt(self, name: str, size: int, signed=False): + def gt(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdGt cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("gt", size, signed)) + return self.binary("gt", size, name, signed) - def lt(self, name: str, size: int, signed=False): + def lt(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdLt cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("lt", size, signed)) + return self.binary("lt", size, name, signed) - def eq(self, name: str, size: int, signed=False): + def eq(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdEq cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("eq", size, signed)) + return self.binary("eq", size, name, signed) - def neq(self, name: str, size: int, signed=False): + def neq(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdNeq cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("neq", size, signed)) + return self.binary("neq", size, name, signed) - def ge(self, name: str, size: int, signed=False): + def ge(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdGe cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("ge", size, signed)) + return self.binary("ge", size, name, signed) - def le(self, name: str, size: int, signed=False): + def le(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdLe cell.""" - self.prog.import_("primitives/binary_operators.futil") - return self.cell(name, ast.Stdlib.op("le", size, signed)) + return self.binary("le", size, name, signed) + + def logic(self, operation, size: int, name: str = None) -> CellBuilder: + """Generate a logical operator cell, of the flavor specified in `operation`.""" + name = name or self.generate_name(operation) + assert isinstance(name, str) + return self.cell(name, ast.Stdlib.op(operation, size, False)) - def and_(self, name: str, size: int) -> CellBuilder: + def and_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdAnd cell.""" - return self.cell(name, ast.Stdlib.op("and", size, False)) + return self.logic("and", size, name) - def not_(self, name: str, size: int) -> CellBuilder: + def not_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdNot cell.""" - return self.cell(name, ast.Stdlib.op("not", size, False)) + return self.logic("not", size, name) def pipelined_mult(self, name: str) -> CellBuilder: """Generate a pipelined multiplier.""" @@ -618,7 +642,7 @@ def port(self, name: str) -> ExprBuilder: return ExprBuilder(ast.Atom(ast.CompPort(self._cell.id, name))) def is_primitive(self, prim_name) -> bool: - """Check if the cell is an instance of the primitive {prim_name}.""" + """Check if the cell is an instance of the primitive `prim_name`.""" return ( isinstance(self._cell.comp, ast.CompInst) and self._cell.comp.id == prim_name @@ -632,6 +656,11 @@ def is_seq_mem_d1(self) -> bool: """Check if the cell is a SeqMemD1 cell.""" return self.is_primitive("seq_mem_d1") + @property + def name(self) -> str: + """Get the name of the cell.""" + return self._cell.id.name + @classmethod def unwrap_id(cls, obj): if isinstance(obj, cls): diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py index e9b1a740d..03e83c646 100644 --- a/calyx-py/calyx/builder_util.py +++ b/calyx-py/calyx/builder_util.py @@ -2,19 +2,20 @@ import calyx.builder as cb -def insert_comb_group(comp: cb.ComponentBuilder, left, right, cell, groupname): - """Accepts a cell that performs some computation on values {left} and {right}. - Creates a combinational group {groupname} that wires up the cell with these ports. +def insert_comb_group(comp: cb.ComponentBuilder, left, right, cell, groupname=None): + """Accepts a cell that performs some computation on values `left` and `right`. + Creates a combinational group that wires up the cell with these ports. Returns the cell and the combintational group. """ + groupname = groupname or f"{cell.name}_group" with comp.comb_group(groupname) as comb_group: cell.left = left cell.right = right return cell, comb_group -def insert_eq(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to check if {left} == {right}. +def insert_eq(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` == `right`. = std_eq(); ... @@ -25,12 +26,11 @@ def insert_eq(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - eq_cell = comp.eq(cellname, width) - return insert_comb_group(comp, left, right, eq_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.eq(width, cellname)) -def insert_neq(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to check if {left} != {right}. +def insert_neq(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` != `right`. = std_neq(); ... @@ -41,12 +41,11 @@ def insert_neq(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - neq_cell = comp.neq(cellname, width) - return insert_comb_group(comp, left, right, neq_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.neq(width, cellname)) -def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to check if {left} < {right}. +def insert_lt(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` < `right`. = std_lt(); ... @@ -57,12 +56,11 @@ def insert_lt(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - lt_cell = comp.lt(cellname, width) - return insert_comb_group(comp, left, right, lt_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.lt(width, cellname)) -def insert_le(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to check if {left} <= {right}. +def insert_le(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` <= `right`. = std_le(); ... @@ -73,12 +71,11 @@ def insert_le(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - le_cell = comp.le(cellname, width) - return insert_comb_group(comp, left, right, le_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.le(width, cellname)) -def insert_gt(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to check if {left} > {right}. +def insert_gt(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` > `right`. = std_gt(); ... @@ -89,12 +86,11 @@ def insert_gt(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - gt_cell = comp.gt(cellname, width) - return insert_comb_group(comp, left, right, gt_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.gt(width, cellname)) -def insert_add(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to compute {left} + {right}. +def insert_add(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` > `right`. = std_add(); ... @@ -105,12 +101,11 @@ def insert_add(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - add_cell = comp.add(cellname, width) - return insert_comb_group(comp, left, right, add_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.add(width, cellname)) -def insert_sub(comp: cb.ComponentBuilder, left, right, cellname, width): - """Inserts wiring into component {comp} to compute {left} - {right}. +def insert_sub(comp: cb.ComponentBuilder, left, right, width, cellname=None): + """Inserts wiring into component `comp` to check if `left` > `right`. = std_sub(); ... @@ -121,16 +116,15 @@ def insert_sub(comp: cb.ComponentBuilder, left, right, cellname, width): Returns handles to the cell and the combinational group. """ - sub_cell = comp.sub(cellname, width) - return insert_comb_group(comp, left, right, sub_cell, f"{cellname}_group") + return insert_comb_group(comp, left, right, comp.sub(width, cellname)) def insert_bitwise_flip_reg(comp: cb.ComponentBuilder, reg, cellname, width): - """Inserts wiring into component {comp} to bitwise-flip the contents of {reg}. + """Inserts wiring into component `comp` to bitwise-flip the contents of `reg`. Returns a handle to the group that does this. """ - not_cell = comp.not_(cellname, width) + not_cell = comp.not_(width, cellname) with comp.group(f"{cellname}_group") as not_group: not_cell.in_ = reg.out reg.write_en = 1 @@ -140,14 +134,14 @@ def insert_bitwise_flip_reg(comp: cb.ComponentBuilder, reg, cellname, width): def insert_incr(comp: cb.ComponentBuilder, reg, cellname, val=1): - """Inserts wiring into component {comp} to increment register {reg} by {val}. - 1. Within component {comp}, creates a group called {cellname}_group. - 2. Within the group, adds a cell {cellname} that computes sums. - 3. Puts the values {reg} and {val} into the cell. - 4. Then puts the answer of the computation back into {reg}. + """Inserts wiring into component `comp` to increment register `reg` by `val`. + 1. Within component `comp`, creates a group called `cellname`_group. + 2. Within the group, adds a cell `cellname` that computes sums. + 3. Puts the values `reg` and `val` into the cell. + 4. Then puts the answer of the computation back into `reg`. 5. Returns the group that does this. """ - add_cell = comp.add(cellname, 32) + add_cell = comp.add(32, cellname) with comp.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out add_cell.right = cb.const(32, val) @@ -158,14 +152,14 @@ def insert_incr(comp: cb.ComponentBuilder, reg, cellname, val=1): def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): - """Inserts wiring into component {comp} to decrement register {reg} by {val}. - 1. Within component {comp}, creates a group called {cellname}_group. - 2. Within the group, adds a cell {cellname} that computes differences. - 3. Puts the values {reg} and {val} into the cell. - 4. Then puts the answer of the computation back into {reg}. + """Inserts wiring into component `comp` to decrement register `reg` by `val`. + 1. Within component `comp`, creates a group called `cellname`_group. + 2. Within the group, adds a cell `cellname` that computes differences. + 3. Puts the values `reg` and `val` into the cell. + 4. Then puts the answer of the computation back into `reg`. 5. Returns the group that does this. """ - sub_cell = comp.sub(cellname, 32) + sub_cell = comp.sub(32, cellname) with comp.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out sub_cell.right = cb.const(32, val) @@ -177,8 +171,8 @@ def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): """Stores a value in a register. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, sets the register {reg} to {val}. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, sets the register `reg` to `val`. 3. Returns the group that does this. """ with comp.group(group) as reg_grp: @@ -190,9 +184,9 @@ def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): def mem_load_std_d1(comp: cb.ComponentBuilder, mem, i, reg, group): """Loads a value from one memory (std_d1) into a register. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from memory {mem} at address {i}. - 3. Writes the value into register {reg}. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from memory `mem` at address `i`. + 3. Writes the value into register `reg`. 4. Returns the group that does this. """ assert mem.is_std_mem_d1() @@ -206,9 +200,9 @@ def mem_load_std_d1(comp: cb.ComponentBuilder, mem, i, reg, group): def mem_store_std_d1(comp: cb.ComponentBuilder, mem, i, val, group): """Stores a value into a (std_d1) memory. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from {val}. - 3. Writes the value into memory {mem} at address i. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from `val`. + 3. Writes the value into memory `mem` at address `i`. 4. Returns the group that does this. """ assert mem.is_std_mem_d1() @@ -224,8 +218,8 @@ def mem_read_seq_d1(comp: cb.ComponentBuilder, mem, i, group): """Given a seq_mem_d1, reads from memory at address i. Note that this does not write the value anywhere. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from memory {mem} at address {i}, + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from memory `mem` at address `i`, thereby "latching" the value. 3. Returns the group that does this. """ @@ -241,9 +235,9 @@ def mem_write_seq_d1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): """Given a seq_mem_d1 that is already assumed to have a latched value, reads the latched value and writes it to a register. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from memory {mem}. - 3. Writes the value into register {reg}. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from memory `mem`. + 3. Writes the value into register `reg`. 4. Returns the group that does this. """ assert mem.is_seq_mem_d1() @@ -257,9 +251,9 @@ def mem_write_seq_d1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): """Given a seq_mem_d1, stores a value into memory at address i. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from {val}. - 3. Writes the value into memory {mem} at address i. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from `val`. + 3. Writes the value into memory `mem` at address i. 4. Returns the group that does this. """ assert mem.is_seq_mem_d1() @@ -273,9 +267,9 @@ def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): """Loads a value from one std_mem_d1 memory into another. - 1. Within component {comp}, creates a group called {group}. - 2. Within {group}, reads from memory {mem} at address {i}. - 3. Writes the value into memory {ans} at address {j}. + 1. Within component `comp`, creates a group called `group`. + 2. Within `group`, reads from memory `mem` at address `i`. + 3. Writes the value into memory `ans` at address `j`. 4. Returns the group that does this. """ assert mem.is_std_mem_d1() and ans.is_std_mem_d1() @@ -295,15 +289,15 @@ def insert_add_store_in_reg( right, ans_reg=None, ): - """Inserts wiring into component {comp} to compute {left} + {right} and - store it in {ans_reg}. - 1. Within component {comp}, creates a group called {cellname}_group. - 2. Within {group}, create a cell {cellname} that computes sums. - 3. Puts the values of {left} and {right} into the cell. - 4. Then puts the answer of the computation into {ans_reg}. + """Inserts wiring into component `comp` to compute `left` + `right` and + store it in `ans_reg`. + 1. Within component `comp`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes sums. + 3. Puts the values of `left` and `right` into the cell. + 4. Then puts the answer of the computation into `ans_reg`. 4. Returns the summing group and the register. """ - add_cell = comp.add(cellname, 32) + add_cell = comp.add(32, cellname) ans_reg = ans_reg or comp.reg(f"reg_{cellname}", 32) with comp.group(f"{cellname}_group") as adder_group: add_cell.left = left @@ -322,15 +316,15 @@ def insert_sub_store_in_reg( width, ans_reg=None, ): - """Adds wiring into component {comp} to compute {left} - {right} - and store it in {ans_reg}. - 1. Within component {comp}, creates a group called {cellname}_group. - 2. Within {group}, create a cell {cellname} that computes differences. - 3. Puts the values of {left} and {right} into {cell}. - 4. Then puts the answer of the computation into {ans_reg}. + """Adds wiring into component `comp` to compute `left` - `right` + and store it in `ans_reg`. + 1. Within component `comp`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes differences. + 3. Puts the values of `left` and `right` into `cell`. + 4. Then puts the answer of the computation into `ans_reg`. 4. Returns the subtracting group and the register. """ - sub_cell = comp.sub(cellname, width) + sub_cell = comp.sub(width, cellname) ans_reg = ans_reg or comp.reg(f"reg_{cellname}", width) with comp.group(f"{cellname}_group") as sub_group: sub_cell.left = left diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index 5714e0227..a0fe133a8 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -21,9 +21,7 @@ def insert_raise_err_if_i_eq_max_cmds(prog): i = raise_err_if_i_eq_max_cmds.input("i", 32) err = raise_err_if_i_eq_max_cmds.reg("err", 1, is_ref=True) - i_eq_max_cmds = util.insert_eq( - raise_err_if_i_eq_max_cmds, i, MAX_CMDS, "i_eq_MAX_CMDS", 32 - ) + i_eq_max_cmds = util.insert_eq(raise_err_if_i_eq_max_cmds, i, MAX_CMDS, 32) raise_err = util.insert_reg_store(raise_err_if_i_eq_max_cmds, err, 1, "raise_err") raise_err_if_i_eq_max_cmds.control += [ @@ -92,8 +90,8 @@ def insert_main(prog, queue): incr_i = util.insert_incr(main, i, "incr_i") # i++ incr_j = util.insert_incr(main, j, "incr_j") # j++ - err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down? - cmd_le_1 = util.insert_le(main, cmd.out, 1, "cmd_le_1", 2) # cmd <= 1 + err_eq_0 = util.insert_eq(main, err.out, 0, 1) # is `err` flag down? + cmd_le_1 = util.insert_le(main, cmd.out, 1, 2) # cmd <= 1 read_cmd = util.mem_read_seq_d1(main, commands, i.out, "read_cmd_phase1") write_cmd_to_reg = util.mem_write_seq_d1_to_reg( diff --git a/calyx-py/test/builder_example.py b/calyx-py/test/builder_example.py index 317994056..71488ea48 100644 --- a/calyx-py/test/builder_example.py +++ b/calyx-py/test/builder_example.py @@ -13,7 +13,7 @@ def add_main_component(prog): lhs = main.reg("lhs", 32) rhs = main.reg("rhs", 32) sum = main.reg("sum", 32) - add = main.add("add", 32) + add = main.add(32, "add") # ANCHOR_END: cells # ANCHOR: bare diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index 294f77856..78fa3208e 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -30,10 +30,10 @@ def add_wrap2(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells and groups to compute equality and lt - i_eq_0_cell, i_eq_0_grp = util.insert_eq(wrap, i, 0, "i_eq_0", 32) - i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, "i_eq_1", 32) - j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, "j_lt_4", 32) - j_lt_8_cell, j_lt_8_group = util.insert_lt(wrap, j, 8, "j_lt_8", 32) + i_eq_0_cell, i_eq_0_grp = util.insert_eq(wrap, i, 0, 32) + i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, 32) + j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, 32) + j_lt_8_cell, j_lt_8_group = util.insert_lt(wrap, j, 8, 32) # Load `j` unchanged into `j_mod_4`. unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") @@ -126,10 +126,10 @@ def add_wrap3(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells to compute equality, and lt - i_eq_0_cell, i_eq_0_group = util.insert_eq(wrap, i, 0, "i_eq_0", 32) - i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, "i_eq_1", 32) - i_eq_2_cell, i_eq_2_group = util.insert_eq(wrap, i, 2, "i_eq_2", 32) - j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, "j_lt_4", 32) + i_eq_0_cell, i_eq_0_group = util.insert_eq(wrap, i, 0, 32) + i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, 32) + i_eq_2_cell, i_eq_2_group = util.insert_eq(wrap, i, 2, 32) + j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, 32) # Load `j` unchanged into `j_mod_4`. unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index c83e8345b..c6d27983a 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -36,21 +36,15 @@ def insert_fifo(prog, name): len = fifo.reg("len", 32) # The length of the FIFO. - # Cells and groups to compute equality. - cmd_eq_0 = util.insert_eq(fifo, cmd, 0, "cmd_eq_0", 2) - cmd_eq_1 = util.insert_eq(fifo, cmd, 1, "cmd_eq_1", 2) - cmd_eq_2 = util.insert_eq(fifo, cmd, 2, "cmd_eq_2", 2) - - write_eq_max_queue_len = util.insert_eq( - fifo, write.out, MAX_QUEUE_LEN, "write_eq_MAX_QUEUE_LEN", 32 - ) - read_eq_max_queue_len = util.insert_eq( - fifo, read.out, MAX_QUEUE_LEN, "read_eq_MAX_QUEUE_LEN", 32 - ) - len_eq_0 = util.insert_eq(fifo, len.out, 0, "len_eq_0", 32) - len_eq_max_queue_len = util.insert_eq( - fifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 - ) + # Cells and groups to compute equality + cmd_eq_0 = util.insert_eq(fifo, cmd, 0, 2) + cmd_eq_1 = util.insert_eq(fifo, cmd, 1, 2) + cmd_eq_2 = util.insert_eq(fifo, cmd, 2, 2) + + write_eq_max_queue_len = util.insert_eq(fifo, write.out, MAX_QUEUE_LEN, 32) + read_eq_max_queue_len = util.insert_eq(fifo, read.out, MAX_QUEUE_LEN, 32) + len_eq_0 = util.insert_eq(fifo, len.out, 0, 32) + len_eq_max_queue_len = util.insert_eq(fifo, len.out, MAX_QUEUE_LEN, 32) # Cells and groups to increment read and write registers write_incr = util.insert_incr(fifo, write, "write_incr") # write++ diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index 8688deffd..18623c647 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -19,7 +19,7 @@ def insert_flow_inference(comp: cb.ComponentBuilder, cmd, flow, boundary, group) 4. Then puts the answer of the computation into {flow}. 5. Returns the group that does this. """ - cell = comp.lt("flow_inf", 32) + cell = comp.lt(32) with comp.group(group) as infer_flow_grp: cell.left = boundary cell.right = cmd @@ -111,19 +111,17 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot = pifo.reg("hot", 1) # Some equality checks. - hot_eq_0 = util.insert_eq(pifo, hot.out, 0, "hot_eq_0", 1) - hot_eq_1 = util.insert_eq(pifo, hot.out, 1, "hot_eq_1", 1) - flow_eq_0 = util.insert_eq(pifo, flow.out, 0, "flow_eq_0", 1) - flow_eq_1 = util.insert_eq(pifo, flow.out, 1, "flow_eq_1", 1) - len_eq_0 = util.insert_eq(pifo, len.out, 0, "len_eq_0", 32) - len_eq_max_queue_len = util.insert_eq( - pifo, len.out, MAX_QUEUE_LEN, "len_eq_MAX_QUEUE_LEN", 32 - ) - cmd_eq_0 = util.insert_eq(pifo, cmd, 0, "cmd_eq_0", 2) - cmd_eq_1 = util.insert_eq(pifo, cmd, 1, "cmd_eq_1", 2) - cmd_eq_2 = util.insert_eq(pifo, cmd, 2, "cmd_eq_2", 2) - err_eq_0 = util.insert_eq(pifo, err.out, 0, "err_eq_0", 1) - err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), "err_neq_0", 1) + hot_eq_0 = util.insert_eq(pifo, hot.out, 0, 1) + hot_eq_1 = util.insert_eq(pifo, hot.out, 1, 1) + flow_eq_0 = util.insert_eq(pifo, flow.out, 0, 1) + flow_eq_1 = util.insert_eq(pifo, flow.out, 1, 1) + len_eq_0 = util.insert_eq(pifo, len.out, 0, 32) + len_eq_max_queue_len = util.insert_eq(pifo, len.out, MAX_QUEUE_LEN, 32) + cmd_eq_0 = util.insert_eq(pifo, cmd, 0, 2) + cmd_eq_1 = util.insert_eq(pifo, cmd, 1, 2) + cmd_eq_2 = util.insert_eq(pifo, cmd, 2, 2) + err_eq_0 = util.insert_eq(pifo, err.out, 0, 1) + err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), 1) flip_hot = util.insert_bitwise_flip_reg(pifo, hot, "flip_hot", 1) raise_err = util.insert_reg_store(pifo, err, 1, "raise_err") # set `err` to 1 diff --git a/frontends/mrxl/mrxl/gen_calyx.py b/frontends/mrxl/mrxl/gen_calyx.py index 775ed9de0..151e0f9b8 100644 --- a/frontends/mrxl/mrxl/gen_calyx.py +++ b/frontends/mrxl/mrxl/gen_calyx.py @@ -46,7 +46,7 @@ def incr_group(comp: cb.ComponentBuilder, idx: cb.CellBuilder, suffix: str) -> s """ # ANCHOR: incr_group group_name = f"incr_idx_{suffix}" - adder = comp.add(f"incr_{suffix}", 32) + adder = comp.add(32) with comp.group(group_name) as incr: adder.left = idx.out adder.right = 1 @@ -138,7 +138,7 @@ def expr_to_port(expr: ast.BaseExpr): if body.operation == "mul": operation = comp.cell(f"mul_{s_idx}", Stdlib.op("mult_pipe", 32, signed=False)) else: - operation = comp.add(f"add_{s_idx}", 32) + operation = comp.add(32) with comp.group(f"reduce{s_idx}") as evl: inp = comp.get_cell(f"{bind.src}_b0") inp.addr0 = idx.out diff --git a/frontends/mrxl/mrxl/map.py b/frontends/mrxl/mrxl/map.py index cad0faeb2..0a172b8d1 100644 --- a/frontends/mrxl/mrxl/map.py +++ b/frontends/mrxl/mrxl/map.py @@ -68,7 +68,7 @@ def expr_to_port(expr: ast.BaseExpr): f"mul_{suffix}", Stdlib.op("mult_pipe", 32, signed=False) ) else: - operation = comp.add(f"add_{suffix}", 32) + operation = comp.add(32, f"add_{suffix}") # ANCHOR_END: map_op assert ( diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 6bcac49ec..55631c1d1 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -65,7 +65,7 @@ def pe(prog: cb.Builder, leaky_relu): mul = comp.pipelined_fp_smult("mul", BITWIDTH, INTWIDTH, FRACWIDTH) # No leaky relu means integer operations else: - add = comp.add("add", BITWIDTH) + add = comp.add(BITWIDTH, "add") # XXX: pipelined mult assumes 32 bit multiplication mul = comp.pipelined_mult("mul") @@ -118,7 +118,7 @@ def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuil name = NAME_SCHEME["index name"].format(prefix=prefix) reg = comp.reg(name, width) - add = comp.add(f"{prefix}_add", width) + add = comp.add(width, f"{prefix}_add") init_name = NAME_SCHEME["index init"].format(prefix=prefix) with comp.static_group(init_name, 1): @@ -362,7 +362,7 @@ def try_build_calyx_add(comp, obj): if type(obj) == CalyxAdd: add_str = str(obj) if comp.try_get_cell(add_str) is None: - add = comp.add(add_str, BITWIDTH) + add = comp.add(BITWIDTH, add_str) with comp.static_group(add_str + "_group", 1): add.left = obj.port add.right = obj.const @@ -390,7 +390,7 @@ def instantiate_idx_cond_groups(comp: cb.ComponentBuilder, leaky_relu): and that sets cond_reg to idx + 1 < iter_limit """ idx = comp.reg("idx", BITWIDTH) - add = comp.add("idx_add", BITWIDTH) + add = comp.add(BITWIDTH, "idx_add") cond_reg = comp.reg("cond_reg", 1) with comp.static_group("init_idx", 1): idx.in_ = 0 @@ -408,7 +408,7 @@ def instantiate_idx_cond_groups(comp: cb.ComponentBuilder, leaky_relu): # operations are finished yet if not leaky_relu: iter_limit = comp.get_cell("iter_limit") - lt_iter_limit = comp.lt("lt_iter_limit", BITWIDTH) + lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") with comp.static_group("lt_iter_limit_group", 1): lt_iter_limit.left = add.out lt_iter_limit.right = iter_limit.out @@ -424,7 +424,7 @@ def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit, leaky_r If leaky_relu, we do not need to check iteration limit. """ min_depth_4 = comp.reg("min_depth_4", BITWIDTH) - lt_depth_4 = comp.lt("lt_depth_4", BITWIDTH) + lt_depth_4 = comp.lt(BITWIDTH, "lt_depth_4") with comp.static_group("init_min_depth", 1): lt_depth_4.left = depth_port lt_depth_4.right = 4 @@ -433,7 +433,7 @@ def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit, leaky_r min_depth_4.write_en = 1 if not leaky_relu: iter_limit = comp.reg("iter_limit", BITWIDTH) - iter_limit_add = comp.add("iter_limit_add", BITWIDTH) + iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") with comp.static_group("init_iter_limit", 1): iter_limit_add.left = rem_iter_limit iter_limit_add.right = depth_port @@ -471,7 +471,7 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: ge = ( comp.get_cell(index_ge) if comp.try_get_cell(index_ge) is not None - else comp.ge(index_ge, BITWIDTH) + else comp.ge(BITWIDTH, index_ge) ) with comp.static_group(group_str, 1): ge.left = idx_add.out @@ -481,7 +481,7 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: lt = ( comp.get_cell(index_lt) if comp.try_get_cell(index_lt) is not None - else comp.lt(index_lt, BITWIDTH) + else comp.lt(BITWIDTH, index_lt) ) # if lo == 0, then only need to check if reg < hi if type(lo) == int and lo == 0: @@ -495,9 +495,9 @@ def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: ge = ( comp.get_cell(index_ge) if comp.try_get_cell(index_ge) is not None - else comp.ge(index_ge, BITWIDTH) + else comp.ge(BITWIDTH, index_ge) ) - and_ = comp.and_(comb_str, 1) + and_ = comp.and_(1, comb_str) with comp.static_group(group_str, 1): ge.left = idx_add.out ge.right = lo_value @@ -564,7 +564,7 @@ def build_assignment( # either when a) value is positive or b) multiply operation has finished. go_next = comp.wire(f"relu_r{row}_go_next", BITWIDTH) # Increments idx_reg. - incr = comp.add(f"relu_r{row}_incr", BITWIDTH) + incr = comp.add(BITWIDTH, f"relu_r{row}_incr") # Performs multiplication for leaky relu. fp_mult = comp.fp_sop( f"relu_r{row}_val_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH From 4539202e80bd86378adeb510cb9d853766f44cdd Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:18:08 -0400 Subject: [PATCH 031/189] Builder: rehome `builder_util` (#1665) --- calyx-py/calyx/builder.py | 253 +++++++++++++++ calyx-py/calyx/builder_util.py | 335 -------------------- calyx-py/calyx/queue_call.py | 28 +- calyx-py/test/correctness/arbiter_6.py | 41 ++- calyx-py/test/correctness/fifo.py | 53 ++-- calyx-py/test/correctness/pifo.py | 41 ++- calyx-py/test/correctness/reduction_tree.py | 9 +- 7 files changed, 332 insertions(+), 428 deletions(-) delete mode 100644 calyx-py/calyx/builder_util.py diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index d795faa83..1bd1c820e 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -1,6 +1,7 @@ from __future__ import annotations import threading +import random from typing import Dict, Union, Optional, List from . import py_ast as ast @@ -384,6 +385,258 @@ def fp_sop( ast.Stdlib.fixed_point_op(op_name, width, int_width, frac_width, True), ) + def binary_use(self, left, right, cell, groupname=None): + """Accepts a cell that performs some computation on values `left` and `right`. + Creates a combinational group that wires up the cell with these ports. + Returns the cell and the combintational group. + + comb group `groupname` { + `cell.name`.left = `left`; + `cell.name`.right = `right`; + } + + Returns handles to the cell and the combinational group. + """ + groupname = groupname or f"{cell.name}_group" + with self.comb_group(groupname) as comb_group: + cell.left = left + cell.right = right + return cell, comb_group + + def eq_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` == `right`.""" + return self.binary_use(left, right, self.eq(width, cellname)) + + def neq_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` != `right`.""" + return self.binary_use(left, right, self.neq(width, cellname)) + + def lt_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` < `right`.""" + return self.binary_use(left, right, self.lt(width, cellname)) + + def le_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` <= `right`.""" + return self.binary_use(left, right, self.le(width, cellname)) + + def ge_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` >= `right`.""" + return self.binary_use(left, right, self.ge(width, cellname)) + + def gt_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to check if `left` > `right`.""" + return self.binary_use(left, right, self.gt(width, cellname)) + + def add_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to compute `left` + `right`.""" + return self.binary_use(left, right, self.add(width, cellname)) + + def sub_use(self, left, right, width, cellname=None): + """Inserts wiring into component `self` to compute `left` - `right`.""" + return self.binary_use(left, right, self.sub(width, cellname)) + + def bitwise_flip_reg(self, reg, width, cellname=None): + """Inserts wiring into component `self` to bitwise-flip the contents of `reg` + and put the result back into `reg`. + + Returns a handle to the group that does this. + """ + cellname = cellname or f"{reg.name}_not" + not_cell = self.not_(width, cellname) + with self.group(f"{cellname}_group") as not_group: + not_cell.in_ = reg.out + reg.write_en = 1 + reg.in_ = not_cell.out + not_group.done = reg.done + return not_group + + def incr(self, reg, width, val=1, cellname=None): + """Inserts wiring into component `self` to increment register `reg` by `val`. + 1. Within component `self`, creates a group. + 2. Within the group, adds a cell `cellname` that computes sums. + 3. Puts the values `reg` and `val` into the cell. + 4. Then puts the answer of the computation back into `reg`. + 5. Returns the group that does this. + """ + cellname = cellname or f"{reg.name}_incr" + add_cell = self.add(width, cellname) + with self.group(f"{cellname}_group") as incr_group: + add_cell.left = reg.out + add_cell.right = const(32, val) + reg.write_en = 1 + reg.in_ = add_cell.out + incr_group.done = reg.done + return incr_group + + def decr(self, reg, width, val=1, cellname=None): + """Inserts wiring into component `self` to decrement register `reg` by `val`. + 1. Within component `self`, creates a group. + 2. Within the group, adds a cell `cellname` that computes differences. + 3. Puts the values `reg` and `val` into the cell. + 4. Then puts the answer of the computation back into `reg`. + 5. Returns the group. + """ + cellname = cellname or f"{reg.name}_decr" + sub_cell = self.sub(width, cellname) + with self.group(f"{cellname}_group") as decr_group: + sub_cell.left = reg.out + sub_cell.right = const(32, val) + reg.write_en = 1 + reg.in_ = sub_cell.out + decr_group.done = reg.done + return decr_group + + def reg_store(self, reg, val, groupname=None): + """Stores a value in a register. + 1. Within component `self`, creates a group. + 2. Within the group, sets the register `reg` to `val`. + 3. Returns the group. + """ + groupname = groupname or f"{reg.name}_store_to_reg" + with self.group(groupname) as reg_grp: + reg.in_ = val + reg.write_en = 1 + reg_grp.done = reg.done + return reg_grp + + def mem_load_std_d1(self, mem, i, reg, groupname=None): + """Loads a value from one memory (std_d1) into a register. + 1. Within component `comp`, creates a group. + 2. Within the group, reads from memory `mem` at address `i`. + 3. Writes the value into register `reg`. + 4. Returns the group. + """ + assert mem.is_std_mem_d1() + groupname = groupname or f"{mem.name()}_load_to_reg" + with self.group(groupname) as load_grp: + mem.addr0 = i + reg.write_en = 1 + reg.in_ = mem.read_data + load_grp.done = reg.done + return load_grp + + def mem_store_std_d1(self, mem, i, val, groupname=None): + """Stores a value into a (std_d1) memory. + 1. Within component `self`, creates a group. + 2. Within the group, reads from `val`. + 3. Writes the value into memory `mem` at address i. + 4. Returns the group. + """ + assert mem.is_std_mem_d1() + groupname = groupname or f"store_into_{mem.name()}" + with self.group(groupname) as store_grp: + mem.addr0 = i + mem.write_en = 1 + mem.write_data = val + store_grp.done = mem.done + return store_grp + + def mem_read_seq_d1(self, mem, i, groupname=None): + """Given a seq_mem_d1, reads from memory at address i. + Note that this does not write the value anywhere. + + 1. Within component `self`, creates a group. + 2. Within the group, reads from memory `mem` at address `i`, + thereby "latching" the value. + 3. Returns the group. + """ + assert mem.is_seq_mem_d1() + groupname = groupname or f"read_from_{mem.name()}" + with self.group(groupname) as read_grp: + mem.addr0 = i + mem.read_en = 1 + read_grp.done = mem.read_done + return read_grp + + def mem_write_seq_d1_to_reg(self, mem, reg, groupname=None): + """Given a seq_mem_d1 that is already assumed to have a latched value, + reads the latched value and writes it to a register. + + 1. Within component `self`, creates a group. + 2. Within the group, reads from memory `mem`. + 3. Writes the value into register `reg`. + 4. Returns the group. + """ + assert mem.is_seq_mem_d1() + groupname = groupname or f"{mem.name()}_write_to_reg" + with self.group(groupname) as write_grp: + reg.write_en = 1 + reg.in_ = mem.read_data + write_grp.done = reg.done + return write_grp + + def mem_store_seq_d1(self, mem, i, val, groupname=None): + """Given a seq_mem_d1, stores a value into memory at address i. + + 1. Within component `self`, creates a group. + 2. Within the group, reads from `val`. + 3. Writes the value into memory `mem` at address i. + 4. Returns the group. + """ + assert mem.is_seq_mem_d1() + groupname = groupname or f"{mem.name()}_store" + with self.group(groupname) as store_grp: + mem.addr0 = i + mem.write_en = 1 + mem.write_data = val + store_grp.done = mem.write_done + return store_grp + + def mem_load_to_mem(self, mem, i, ans, j, groupname=None): + """Loads a value from one std_mem_d1 memory into another. + 1. Within component `self`, creates a group. + 2. Within the group, reads from memory `mem` at address `i`. + 3. Writes the value into memory `ans` at address `j`. + 4. Returns the group. + """ + assert mem.is_std_mem_d1() and ans.is_std_mem_d1() + groupname = groupname or f"{mem.name()}_load_to_mem" + with self.group(groupname) as load_grp: + mem.addr0 = i + ans.write_en = 1 + ans.addr0 = j + ans.write_data = mem.read_data + load_grp.done = ans.done + return load_grp + + def add_store_in_reg(self, cellname, left, right, ans_reg=None): + """Inserts wiring into component `self` to compute `left` + `right` and + store it in `ans_reg`. + 1. Within component `self`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes sums. + 3. Puts the values of `left` and `right` into the cell. + 4. Then puts the answer of the computation into `ans_reg`. + 4. Returns the summing group and the register. + """ + add_cell = self.add(32, cellname) + ans_reg = ans_reg or self.reg(f"reg_{cellname}", 32) + with self.group(f"{cellname}_group") as adder_group: + add_cell.left = left + add_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = add_cell.out + adder_group.done = ans_reg.done + return adder_group, ans_reg + + def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Adds wiring into component `self` to compute `left` - `right` + and store it in `ans_reg`. + 1. Within component `self`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes differences. + 3. Puts the values of `left` and `right` into `cell`. + 4. Then puts the answer of the computation into `ans_reg`. + 4. Returns the subtracting group and the register. + """ + sub_cell = self.sub(width, cellname) + ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) + with self.group(f"{cellname}_group") as sub_group: + sub_cell.left = left + sub_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = sub_cell.out + sub_group.done = ans_reg.done + return sub_group, ans_reg + def as_control(obj): """Convert a Python object into a control statement. diff --git a/calyx-py/calyx/builder_util.py b/calyx-py/calyx/builder_util.py deleted file mode 100644 index 03e83c646..000000000 --- a/calyx-py/calyx/builder_util.py +++ /dev/null @@ -1,335 +0,0 @@ -# pylint: disable=import-error -import calyx.builder as cb - - -def insert_comb_group(comp: cb.ComponentBuilder, left, right, cell, groupname=None): - """Accepts a cell that performs some computation on values `left` and `right`. - Creates a combinational group that wires up the cell with these ports. - Returns the cell and the combintational group. - """ - groupname = groupname or f"{cell.name}_group" - with comp.comb_group(groupname) as comb_group: - cell.left = left - cell.right = right - return cell, comb_group - - -def insert_eq(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` == `right`. - - = std_eq(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.eq(width, cellname)) - - -def insert_neq(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` != `right`. - - = std_neq(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.neq(width, cellname)) - - -def insert_lt(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` < `right`. - - = std_lt(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.lt(width, cellname)) - - -def insert_le(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` <= `right`. - - = std_le(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.le(width, cellname)) - - -def insert_gt(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` > `right`. - - = std_gt(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.gt(width, cellname)) - - -def insert_add(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` > `right`. - - = std_add(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.add(width, cellname)) - - -def insert_sub(comp: cb.ComponentBuilder, left, right, width, cellname=None): - """Inserts wiring into component `comp` to check if `left` > `right`. - - = std_sub(); - ... - comb group _group { - .left = ; - .right = ; - } - - Returns handles to the cell and the combinational group. - """ - return insert_comb_group(comp, left, right, comp.sub(width, cellname)) - - -def insert_bitwise_flip_reg(comp: cb.ComponentBuilder, reg, cellname, width): - """Inserts wiring into component `comp` to bitwise-flip the contents of `reg`. - - Returns a handle to the group that does this. - """ - not_cell = comp.not_(width, cellname) - with comp.group(f"{cellname}_group") as not_group: - not_cell.in_ = reg.out - reg.write_en = 1 - reg.in_ = not_cell.out - not_group.done = reg.done - return not_group - - -def insert_incr(comp: cb.ComponentBuilder, reg, cellname, val=1): - """Inserts wiring into component `comp` to increment register `reg` by `val`. - 1. Within component `comp`, creates a group called `cellname`_group. - 2. Within the group, adds a cell `cellname` that computes sums. - 3. Puts the values `reg` and `val` into the cell. - 4. Then puts the answer of the computation back into `reg`. - 5. Returns the group that does this. - """ - add_cell = comp.add(32, cellname) - with comp.group(f"{cellname}_group") as incr_group: - add_cell.left = reg.out - add_cell.right = cb.const(32, val) - reg.write_en = 1 - reg.in_ = add_cell.out - incr_group.done = reg.done - return incr_group - - -def insert_decr(comp: cb.ComponentBuilder, reg, cellname, val=1): - """Inserts wiring into component `comp` to decrement register `reg` by `val`. - 1. Within component `comp`, creates a group called `cellname`_group. - 2. Within the group, adds a cell `cellname` that computes differences. - 3. Puts the values `reg` and `val` into the cell. - 4. Then puts the answer of the computation back into `reg`. - 5. Returns the group that does this. - """ - sub_cell = comp.sub(32, cellname) - with comp.group(f"{cellname}_group") as decr_group: - sub_cell.left = reg.out - sub_cell.right = cb.const(32, val) - reg.write_en = 1 - reg.in_ = sub_cell.out - decr_group.done = reg.done - return decr_group - - -def insert_reg_store(comp: cb.ComponentBuilder, reg, val, group): - """Stores a value in a register. - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, sets the register `reg` to `val`. - 3. Returns the group that does this. - """ - with comp.group(group) as reg_grp: - reg.in_ = val - reg.write_en = 1 - reg_grp.done = reg.done - return reg_grp - - -def mem_load_std_d1(comp: cb.ComponentBuilder, mem, i, reg, group): - """Loads a value from one memory (std_d1) into a register. - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from memory `mem` at address `i`. - 3. Writes the value into register `reg`. - 4. Returns the group that does this. - """ - assert mem.is_std_mem_d1() - with comp.group(group) as load_grp: - mem.addr0 = i - reg.write_en = 1 - reg.in_ = mem.read_data - load_grp.done = reg.done - return load_grp - - -def mem_store_std_d1(comp: cb.ComponentBuilder, mem, i, val, group): - """Stores a value into a (std_d1) memory. - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from `val`. - 3. Writes the value into memory `mem` at address `i`. - 4. Returns the group that does this. - """ - assert mem.is_std_mem_d1() - with comp.group(group) as store_grp: - mem.addr0 = i - mem.write_en = 1 - mem.write_data = val - store_grp.done = mem.done - return store_grp - - -def mem_read_seq_d1(comp: cb.ComponentBuilder, mem, i, group): - """Given a seq_mem_d1, reads from memory at address i. - Note that this does not write the value anywhere. - - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from memory `mem` at address `i`, - thereby "latching" the value. - 3. Returns the group that does this. - """ - assert mem.is_seq_mem_d1() - with comp.group(group) as read_grp: - mem.addr0 = i - mem.read_en = 1 - read_grp.done = mem.read_done - return read_grp - - -def mem_write_seq_d1_to_reg(comp: cb.ComponentBuilder, mem, reg, group): - """Given a seq_mem_d1 that is already assumed to have a latched value, - reads the latched value and writes it to a register. - - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from memory `mem`. - 3. Writes the value into register `reg`. - 4. Returns the group that does this. - """ - assert mem.is_seq_mem_d1() - with comp.group(group) as write_grp: - reg.write_en = 1 - reg.in_ = mem.read_data - write_grp.done = reg.done - return write_grp - - -def mem_store_seq_d1(comp: cb.ComponentBuilder, mem, i, val, group): - """Given a seq_mem_d1, stores a value into memory at address i. - - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from `val`. - 3. Writes the value into memory `mem` at address i. - 4. Returns the group that does this. - """ - assert mem.is_seq_mem_d1() - with comp.group(group) as store_grp: - mem.addr0 = i - mem.write_en = 1 - mem.write_data = val - store_grp.done = mem.write_done - return store_grp - - -def insert_mem_load_to_mem(comp: cb.ComponentBuilder, mem, i, ans, j, group): - """Loads a value from one std_mem_d1 memory into another. - 1. Within component `comp`, creates a group called `group`. - 2. Within `group`, reads from memory `mem` at address `i`. - 3. Writes the value into memory `ans` at address `j`. - 4. Returns the group that does this. - """ - assert mem.is_std_mem_d1() and ans.is_std_mem_d1() - with comp.group(group) as load_grp: - mem.addr0 = i - ans.write_en = 1 - ans.addr0 = j - ans.write_data = mem.read_data - load_grp.done = ans.done - return load_grp - - -def insert_add_store_in_reg( - comp: cb.ComponentBuilder, - cellname, - left, - right, - ans_reg=None, -): - """Inserts wiring into component `comp` to compute `left` + `right` and - store it in `ans_reg`. - 1. Within component `comp`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes sums. - 3. Puts the values of `left` and `right` into the cell. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the summing group and the register. - """ - add_cell = comp.add(32, cellname) - ans_reg = ans_reg or comp.reg(f"reg_{cellname}", 32) - with comp.group(f"{cellname}_group") as adder_group: - add_cell.left = left - add_cell.right = right - ans_reg.write_en = 1 - ans_reg.in_ = add_cell.out - adder_group.done = ans_reg.done - return adder_group, ans_reg - - -def insert_sub_store_in_reg( - comp: cb.ComponentBuilder, - left, - right, - cellname, - width, - ans_reg=None, -): - """Adds wiring into component `comp` to compute `left` - `right` - and store it in `ans_reg`. - 1. Within component `comp`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes differences. - 3. Puts the values of `left` and `right` into `cell`. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the subtracting group and the register. - """ - sub_cell = comp.sub(width, cellname) - ans_reg = ans_reg or comp.reg(f"reg_{cellname}", width) - with comp.group(f"{cellname}_group") as sub_group: - sub_cell.left = left - sub_cell.right = right - ans_reg.write_en = 1 - ans_reg.in_ = sub_cell.out - sub_group.done = ans_reg.done - return sub_group, ans_reg diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index a0fe133a8..099fb457d 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -1,6 +1,5 @@ # pylint: disable=import-error import calyx.builder as cb -import calyx.builder_util as util MAX_CMDS = 15 ANS_MEM_LEN = 10 @@ -21,8 +20,8 @@ def insert_raise_err_if_i_eq_max_cmds(prog): i = raise_err_if_i_eq_max_cmds.input("i", 32) err = raise_err_if_i_eq_max_cmds.reg("err", 1, is_ref=True) - i_eq_max_cmds = util.insert_eq(raise_err_if_i_eq_max_cmds, i, MAX_CMDS, 32) - raise_err = util.insert_reg_store(raise_err_if_i_eq_max_cmds, err, 1, "raise_err") + i_eq_max_cmds = raise_err_if_i_eq_max_cmds.eq_use(i, MAX_CMDS, 32) + raise_err = raise_err_if_i_eq_max_cmds.reg_store(err, 1, "raise_err") raise_err_if_i_eq_max_cmds.control += [ cb.if_( @@ -88,22 +87,19 @@ def insert_main(prog, queue): cmd = main.reg("command", 2) # The command we're currently processing value = main.reg("value", 32) # The value we're currently processing - incr_i = util.insert_incr(main, i, "incr_i") # i++ - incr_j = util.insert_incr(main, j, "incr_j") # j++ - err_eq_0 = util.insert_eq(main, err.out, 0, 1) # is `err` flag down? - cmd_le_1 = util.insert_le(main, cmd.out, 1, 2) # cmd <= 1 + incr_i = main.incr(i, 32) # i++ + incr_j = main.incr(j, 32) # j++ + err_eq_0 = main.eq_use(err.out, 0, 1) # is `err` flag down? + cmd_le_1 = main.le_use(cmd.out, 1, 2) # cmd <= 1 - read_cmd = util.mem_read_seq_d1(main, commands, i.out, "read_cmd_phase1") - write_cmd_to_reg = util.mem_write_seq_d1_to_reg( - main, commands, cmd, "write_cmd_phase2" - ) + read_cmd = main.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") + write_cmd_to_reg = main.mem_write_seq_d1_to_reg(commands, cmd, "write_cmd_phase2") - read_value = util.mem_read_seq_d1(main, values, i.out, "read_value") - write_value_to_reg = util.mem_write_seq_d1_to_reg( - main, values, value, "write_value_to_reg" + read_value = main.mem_read_seq_d1(values, i.out, "read_value") + write_value_to_reg = main.mem_write_seq_d1_to_reg( + values, value, "write_value_to_reg" ) - - write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans") + write_ans = main.mem_store_seq_d1(ans_mem, j.out, ans.out, "write_ans") main.control += [ cb.while_( diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index 78fa3208e..436bd8dcf 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -1,5 +1,4 @@ # pylint: disable=import-error -import calyx.builder_util as util import calyx.builder as cb @@ -30,27 +29,27 @@ def add_wrap2(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells and groups to compute equality and lt - i_eq_0_cell, i_eq_0_grp = util.insert_eq(wrap, i, 0, 32) - i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, 32) - j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, 32) - j_lt_8_cell, j_lt_8_group = util.insert_lt(wrap, j, 8, 32) + i_eq_0_cell, i_eq_0_grp = wrap.eq_use(i, 0, 32) + i_eq_1_cell, i_eq_1_group = wrap.eq_use(i, 1, 32) + j_lt_4_cell, j_lt_4_group = wrap.lt_use(j, 4, 32) + j_lt_8_cell, j_lt_8_group = wrap.lt_use(j, 8, 32) # Load `j` unchanged into `j_mod_4`. - unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") + unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") # Wiring to perform j-4 and j-8. Either of these will store the result in `j_mod_4`. - j_minus_4, j_mod_4 = util.insert_sub_store_in_reg( - wrap, j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 + j_minus_4, j_mod_4 = wrap.sub_store_in_reg( + j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 ) - j_minus_8, j_mod_4 = util.insert_sub_store_in_reg( - wrap, j, cb.const(32, 8), "j_minus_8", 32, j_mod_4 + j_minus_8, j_mod_4 = wrap.sub_store_in_reg( + j, cb.const(32, 8), "j_minus_8", 32, j_mod_4 ) load_from_mems = [ # Add wiring to load the value `j_mod_4` from all of the memory cells. # We'll have to invoke the correct one of these groups later on. - util.insert_mem_load_to_mem( - wrap, mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" + wrap.mem_load_to_mem( + mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" ) for i in range(6) ] @@ -126,22 +125,22 @@ def add_wrap3(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells to compute equality, and lt - i_eq_0_cell, i_eq_0_group = util.insert_eq(wrap, i, 0, 32) - i_eq_1_cell, i_eq_1_group = util.insert_eq(wrap, i, 1, 32) - i_eq_2_cell, i_eq_2_group = util.insert_eq(wrap, i, 2, 32) - j_lt_4_cell, j_lt_4_group = util.insert_lt(wrap, j, 4, 32) + i_eq_0_cell, i_eq_0_group = wrap.eq_use(i, 0, 32) + i_eq_1_cell, i_eq_1_group = wrap.eq_use(i, 1, 32) + i_eq_2_cell, i_eq_2_group = wrap.eq_use(i, 2, 32) + j_lt_4_cell, j_lt_4_group = wrap.lt_use(j, 4, 32) # Load `j` unchanged into `j_mod_4`. - unchanged = util.insert_reg_store(wrap, j_mod_4, j, "j_unchanged") + unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") # Wiring to perform j-4 and store the result in `j_mod_4`. - subcell, j_mod_4 = util.insert_sub_store_in_reg( - wrap, j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 + subcell, j_mod_4 = wrap.sub_store_in_reg( + j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 ) emit_from_mems = [ - util.insert_mem_load_to_mem( - wrap, mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" + wrap.mem_load_to_mem( + mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" ) for i in range(6) ] diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index c6d27983a..a8515d785 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -1,6 +1,5 @@ # pylint: disable=import-error import calyx.builder as cb -import calyx.builder_util as util import calyx.queue_call as qc MAX_QUEUE_LEN = 10 @@ -37,41 +36,37 @@ def insert_fifo(prog, name): len = fifo.reg("len", 32) # The length of the FIFO. # Cells and groups to compute equality - cmd_eq_0 = util.insert_eq(fifo, cmd, 0, 2) - cmd_eq_1 = util.insert_eq(fifo, cmd, 1, 2) - cmd_eq_2 = util.insert_eq(fifo, cmd, 2, 2) + cmd_eq_0 = fifo.eq_use(cmd, 0, 2) + cmd_eq_1 = fifo.eq_use(cmd, 1, 2) + cmd_eq_2 = fifo.eq_use(cmd, 2, 2) - write_eq_max_queue_len = util.insert_eq(fifo, write.out, MAX_QUEUE_LEN, 32) - read_eq_max_queue_len = util.insert_eq(fifo, read.out, MAX_QUEUE_LEN, 32) - len_eq_0 = util.insert_eq(fifo, len.out, 0, 32) - len_eq_max_queue_len = util.insert_eq(fifo, len.out, MAX_QUEUE_LEN, 32) + write_eq_max_queue_len = fifo.eq_use(write.out, MAX_QUEUE_LEN, 32) + read_eq_max_queue_len = fifo.eq_use(read.out, MAX_QUEUE_LEN, 32) + len_eq_0 = fifo.eq_use(len.out, 0, 32) + len_eq_max_queue_len = fifo.eq_use(len.out, MAX_QUEUE_LEN, 32) # Cells and groups to increment read and write registers - write_incr = util.insert_incr(fifo, write, "write_incr") # write++ - read_incr = util.insert_incr(fifo, read, "read_incr") # read++ - len_incr = util.insert_incr(fifo, len, "len_incr") # len++ - len_decr = util.insert_decr(fifo, len, "len_decr") # len-- - - # Cells and groups to modify flags, which are registers. - flash_write = util.insert_reg_store(fifo, write, 0, "flash_write") # write := 0 - flash_read = util.insert_reg_store(fifo, read, 0, "flash_read") # read := 0 - flash_ans = util.insert_reg_store(fifo, ans, 0, "flash_ans") # ans := 0 - raise_err = util.insert_reg_store(fifo, err, 1, "raise_err") # err := 1 - - # Load/store to/from an arbitary slot in `mem`. - write_to_mem = util.mem_store_seq_d1( - fifo, mem, write.out, value, "write_payload_to_mem" - ) - read_from_mem = util.mem_read_seq_d1( - fifo, mem, read.out, "read_payload_from_mem_phase1" - ) - write_to_ans = util.mem_write_seq_d1_to_reg( - fifo, mem, ans, "read_payload_from_mem_phase2" + write_incr = fifo.incr(write, 32) # write++ + read_incr = fifo.incr(read, 32) # read++ + len_incr = fifo.incr(len, 32) # len++ + len_decr = fifo.decr(len, 32) # len-- + + # Cells and groups to modify flags, which are registers + flash_write = fifo.reg_store(write, 0, "flash_write") # write := 0 + flash_read = fifo.reg_store(read, 0, "flash_read") # read := 0 + raise_err = fifo.reg_store(err, 1, "raise_err") # err := 1 + flash_ans = fifo.reg_store(ans, 0, "flash_ans") # ans := 0 + + # Load and store into an arbitary slot in memory + write_to_mem = fifo.mem_store_seq_d1(mem, write.out, value, "write_payload_to_mem") + read_from_mem = fifo.mem_read_seq_d1(mem, read.out, "read_payload_from_mem_phase1") + write_to_ans = fifo.mem_write_seq_d1_to_reg( + mem, ans, "read_payload_from_mem_phase2" ) fifo.control += [ cb.par( - # Was it a pop or a push? We can do both cases in parallel. + # Was it a pop, peek, or a push? We can do all cases in parallel. cb.if_( # Did the user call pop? cmd_eq_0[0].out, diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index 18623c647..e052ba693 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -1,7 +1,6 @@ # pylint: disable=import-error import fifo import calyx.builder as cb -import calyx.builder_util as util import calyx.queue_call as qc MAX_QUEUE_LEN = 10 @@ -111,25 +110,25 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot = pifo.reg("hot", 1) # Some equality checks. - hot_eq_0 = util.insert_eq(pifo, hot.out, 0, 1) - hot_eq_1 = util.insert_eq(pifo, hot.out, 1, 1) - flow_eq_0 = util.insert_eq(pifo, flow.out, 0, 1) - flow_eq_1 = util.insert_eq(pifo, flow.out, 1, 1) - len_eq_0 = util.insert_eq(pifo, len.out, 0, 32) - len_eq_max_queue_len = util.insert_eq(pifo, len.out, MAX_QUEUE_LEN, 32) - cmd_eq_0 = util.insert_eq(pifo, cmd, 0, 2) - cmd_eq_1 = util.insert_eq(pifo, cmd, 1, 2) - cmd_eq_2 = util.insert_eq(pifo, cmd, 2, 2) - err_eq_0 = util.insert_eq(pifo, err.out, 0, 1) - err_neq_0 = util.insert_neq(pifo, err.out, cb.const(1, 0), 1) + hot_eq_0 = pifo.eq_use(hot.out, 0, 1) + hot_eq_1 = pifo.eq_use(hot.out, 1, 1) + flow_eq_0 = pifo.eq_use(flow.out, 0, 1) + flow_eq_1 = pifo.eq_use(flow.out, 1, 1) + len_eq_0 = pifo.eq_use(len.out, 0, 32) + len_eq_max_queue_len = pifo.eq_use(len.out, MAX_QUEUE_LEN, 32) + cmd_eq_0 = pifo.eq_use(cmd, 0, 2) + cmd_eq_1 = pifo.eq_use(cmd, 1, 2) + cmd_eq_2 = pifo.eq_use(cmd, 2, 2) + err_eq_0 = pifo.eq_use(err.out, 0, 1) + err_neq_0 = pifo.neq_use(err.out, cb.const(1, 0), 1) - flip_hot = util.insert_bitwise_flip_reg(pifo, hot, "flip_hot", 1) - raise_err = util.insert_reg_store(pifo, err, 1, "raise_err") # set `err` to 1 - lower_err = util.insert_reg_store(pifo, err, 0, "lower_err") # set `err` to 0 - zero_out_ans = util.insert_reg_store(pifo, ans, 0, "zero_out_ans") + flip_hot = pifo.bitwise_flip_reg(hot, 1) + raise_err = pifo.reg_store(err, 1, "raise_err") # err := 1 + lower_err = pifo.reg_store(err, 0, "lower_err") # err := 0 + flash_ans = pifo.reg_store(ans, 0, "flash_ans") # ans := 0 - len_incr = util.insert_incr(pifo, len, "len_incr") # len++ - len_decr = util.insert_decr(pifo, len, "len_decr") # len-- + len_incr = pifo.incr(len, 32) # len++ + len_decr = pifo.decr(len, 32) # len-- # The main logic. pifo.control += [ @@ -143,7 +142,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): # Yes, the user called pop. But is the queue empty? len_eq_0[0].out, len_eq_0[1], - [raise_err, zero_out_ans], # The queue is empty: underflow. + [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. # We must check if `hot` is 0 or 1. lower_err, @@ -225,7 +224,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): # Yes, the user called peek. But is the queue empty? len_eq_0[0].out, len_eq_0[1], - [raise_err, zero_out_ans], # The queue is empty: underflow. + [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. # We must check if `hot` is 0 or 1. lower_err, @@ -284,7 +283,7 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): # Yes, the user called push. But is the queue full? len_eq_max_queue_len[0].out, len_eq_max_queue_len[1], - [raise_err, zero_out_ans], # The queue is full: overflow. + [raise_err, flash_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. lower_err, # We need to check which flow this value should be pushed to. diff --git a/calyx-py/test/correctness/reduction_tree.py b/calyx-py/test/correctness/reduction_tree.py index c32eaa1ed..76bb9ab2d 100644 --- a/calyx-py/test/correctness/reduction_tree.py +++ b/calyx-py/test/correctness/reduction_tree.py @@ -1,6 +1,5 @@ # pylint: disable=import-error from typing import List -import calyx.builder_util as util import calyx.builder as cb @@ -24,11 +23,9 @@ def add_tree(prog): # Into the component `tree`, add the wiring for three adder groups that will # use the tree to perform their additions. # These need to be orchestrated in the control below. - add_l0_l1, left = util.insert_add_store_in_reg(tree, "add_l0_l1", leaf0, leaf1) - add_l2_l3, right = util.insert_add_store_in_reg(tree, "add_l2_l3", leaf2, leaf3) - add_l_r_nodes, root = util.insert_add_store_in_reg( - tree, "add_l_r", left.out, right.out - ) + add_l0_l1, left = tree.add_store_in_reg("add_l0_l1", leaf0, leaf1) + add_l2_l3, right = tree.add_store_in_reg("add_l2_l3", leaf2, leaf3) + add_l_r_nodes, root = tree.add_store_in_reg("add_l_r", left.out, right.out) # Continuously output the value of the root register. # It is the invoker's responsibility to ensure that the tree is done From 75250ace6f2290794c746f5c7f3a52464d292a6d Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:43:16 -0400 Subject: [PATCH 032/189] Builder: sugary variants of `if` and `while` (#1666) --- calyx-py/calyx/builder.py | 84 ++++++++++++++++------- calyx-py/calyx/gen_exp.py | 52 ++++++++------ calyx-py/calyx/gen_msb.py | 19 ++++-- calyx-py/calyx/queue_call.py | 17 ++--- calyx-py/test/correctness/arbiter_6.py | 82 +++++++++------------- calyx-py/test/correctness/fifo.py | 42 +++++------- calyx-py/test/correctness/pifo.py | 90 ++++++++++--------------- frontends/systolic-lang/gen-systolic.py | 2 +- 8 files changed, 197 insertions(+), 191 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 1bd1c820e..975e63c5a 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -3,6 +3,7 @@ import threading import random from typing import Dict, Union, Optional, List +from dataclasses import dataclass from . import py_ast as ast # Thread-local storage to keep track of the current GroupBuilder we have @@ -401,7 +402,7 @@ def binary_use(self, left, right, cell, groupname=None): with self.comb_group(groupname) as comb_group: cell.left = left cell.right = right - return cell, comb_group + return CellAndGroup(cell, comb_group) def eq_use(self, left, right, width, cellname=None): """Inserts wiring into component `self` to check if `left` == `right`.""" @@ -638,6 +639,20 @@ def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): return sub_group, ans_reg +@dataclass(frozen=True) +class CellAndGroup: + """Just a cell and a group, for when it is convenient to + pass them around together. + + Typically the group will be a combinational group, and `if_with` and + `while_with` will require that a CellAndGroup be passed in, not a + cell and a group separately. + """ + + cell: CellBuilder + group: GroupBuilder + + def as_control(obj): """Convert a Python object into a control statement. @@ -679,16 +694,12 @@ def as_control(obj): assert False, f"unsupported control type {type(obj)}" -def while_(port: ExprBuilder, cond: Optional[GroupBuilder], body) -> ast.While: - """Build a `while` control statement.""" - if cond: - assert isinstance( - cond.group_like, ast.CombGroup - ), "while condition must be a combinational group" - cg = cond.group_like.id - else: - cg = None - return ast.While(port.expr, cg, as_control(body)) +def while_(port: ExprBuilder, body) -> ast.While: + """Build a `while` control statement. + + To build a `while` statement with a combinational group, use `while_with`. + """ + return ast.While(port.expr, None, as_control(body)) def static_repeat(num_repeats: int, body) -> ast.StaticRepeat: @@ -698,21 +709,15 @@ def static_repeat(num_repeats: int, body) -> ast.StaticRepeat: def if_( port: ExprBuilder, - cond: Optional[GroupBuilder], body, else_body=None, ) -> ast.If: - """Build an `static if` control statement.""" - else_body = ast.Empty() if else_body is None else else_body - - if cond: - assert isinstance( - cond.group_like, ast.CombGroup - ), "if condition must be a combinational group" - cg = cond.group_like.id - else: - cg = None - return ast.If(port.expr, cg, as_control(body), as_control(else_body)) + """Build an `if` control statement. + + To build an `if` statement with a combinational group, use `if_with`. + """ + else_body = else_body or ast.Empty() + return ast.If(port.expr, None, as_control(body), as_control(else_body)) def static_if( @@ -720,11 +725,40 @@ def static_if( body, else_body=None, ) -> ast.If: - """Build an `if` control statement.""" - else_body = ast.Empty() if else_body is None else else_body + """Build a `static if` control statement.""" + else_body = else_body or ast.Empty() return ast.StaticIf(port.expr, as_control(body), as_control(else_body)) +def if_with(port_comb: CellAndGroup, body, else_body=None) -> ast.If: + """Build an if statement, where the cell and the combinational group + are provided together. + """ + port = port_comb.cell.out + cond = port_comb.group + else_body = else_body or ast.Empty() + + assert isinstance( + cond.group_like, ast.CombGroup + ), "if condition must be a combinational group" + return ast.If( + port.expr, cond.group_like.id, as_control(body), as_control(else_body) + ) + + +def while_with(port_comb: CellAndGroup, body) -> ast.While: + """Build a while statement, where the cell and the combinational + group are provided together. + """ + + port = port_comb.cell.out + cond = port_comb.group + assert isinstance( + cond.group_like, ast.CombGroup + ), "while condition must be a combinational group" + return ast.While(port.expr, cond.group_like.id, as_control(body)) + + def invoke(cell: CellBuilder, **kwargs) -> ast.Invoke: """Build an `invoke` control statement. diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index f43c2aa6f..df389290a 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -14,8 +14,9 @@ from calyx.builder import ( Builder, ComponentBuilder, - while_, - if_, + CellAndGroup, + while_with, + if_with, invoke, CellBuilder, ExprBuilder, @@ -85,7 +86,10 @@ def generate_fp_pow_component( comp.control += [ init, - while_(lt.out, cond, par(execute_mul, incr_count)), + while_with( + CellAndGroup(lt, cond), + par(execute_mul, incr_count), + ), ] return comp.component @@ -433,7 +437,13 @@ def generate_control(comp: ComponentBuilder, degree: int, is_signed: bool): x for x in ( init, - if_(lt.out, comp.get_group("is_negative"), comp.get_group("negate")) + if_with( + CellAndGroup( + lt, + comp.get_group("is_negative"), + ), + comp.get_group("negate"), + ) if is_signed else [], split_bits, @@ -443,7 +453,13 @@ def generate_control(comp: ComponentBuilder, degree: int, is_signed: bool): *divide_and_conquer, comp.get_group("add_degree_zero"), comp.get_group("final_multiply"), - if_(lt.out, comp.get_group("is_negative"), comp.get_group("reciprocal")) + if_with( + CellAndGroup( + lt, + comp.get_group("is_negative"), + ), + comp.get_group("reciprocal"), + ) if is_signed else [], ) @@ -658,28 +674,24 @@ def generate_fp_pow_full( const_one, ) - base_reciprocal = if_( - port=lt.out, - cond=comp.get_group("base_lt_one"), - body=comp.get_group("set_base_reciprocal"), + base_reciprocal = if_with( + CellAndGroup(lt, comp.get_group("base_lt_one")), + comp.get_group("set_base_reciprocal"), ) - res_reciprocal = if_( - port=lt.out, - cond=comp.get_group("base_lt_one"), - body=comp.get_group("set_res_reciprocal"), + res_reciprocal = if_with( + CellAndGroup(lt, comp.get_group("base_lt_one")), + comp.get_group("set_res_reciprocal"), ) if is_signed: - base_rev = if_( - lt.out, - comp.get_group("base_lt_zero"), + base_rev = if_with( + CellAndGroup(lt, comp.get_group("base_lt_zero")), comp.get_group("rev_base_sign"), ) - res_rev = if_( - port=lt.out, - cond=comp.get_group("base_lt_zero"), - body=comp.get_group("rev_res_sign"), + res_rev = if_with( + CellAndGroup(lt, comp.get_group("base_lt_zero")), + comp.get_group("rev_res_sign"), ) pre_process = [base_rev, store_old_reg_val, base_reciprocal] post_process = [res_rev, res_reciprocal] diff --git a/calyx-py/calyx/gen_msb.py b/calyx-py/calyx/gen_msb.py index 3f43f7d9b..d86481ad5 100644 --- a/calyx-py/calyx/gen_msb.py +++ b/calyx-py/calyx/gen_msb.py @@ -17,7 +17,14 @@ Control, CombGroup, ) -from calyx.builder import Builder, ComponentBuilder, const, HI, while_ +from calyx.builder import ( + Builder, + CellAndGroup, + ComponentBuilder, + const, + HI, + while_with, +) def gen_msb_calc(width: int, int_width: int) -> List[Component]: @@ -116,17 +123,15 @@ def gen_msb_calc(width: int, int_width: int) -> List[Component]: comp.control += [ wr_cur_val, - while_( - neq.out, - cur_val_cond, + while_with( + CellAndGroup(neq, cur_val_cond), [incr_count, shift_cur_val], ), decr_count, wr_count, wr_val_build, - while_( - neq.out, - count_cond, + while_with( + CellAndGroup(neq, count_cond), [decr_count, shift_val_build], ), wr_val, diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index 099fb457d..9af773d74 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -24,9 +24,8 @@ def insert_raise_err_if_i_eq_max_cmds(prog): raise_err = raise_err_if_i_eq_max_cmds.reg_store(err, 1, "raise_err") raise_err_if_i_eq_max_cmds.control += [ - cb.if_( - i_eq_max_cmds[0].out, - i_eq_max_cmds[1], + cb.if_with( + i_eq_max_cmds, raise_err, ) ] @@ -102,9 +101,8 @@ def insert_main(prog, queue): write_ans = main.mem_store_seq_d1(ans_mem, j.out, ans.out, "write_ans") main.control += [ - cb.while_( - err_eq_0[0].out, - err_eq_0[1], # Run while the `err` flag is down + cb.while_with( + err_eq_0, # Run while the `err` flag is down [ read_cmd, write_cmd_to_reg, @@ -119,10 +117,9 @@ def insert_main(prog, queue): ref_ans=ans, ref_err=err, ), - cb.if_( # If it was a pop or a peek, write ans to the answer list - cmd_le_1[0].out, - cmd_le_1[1], - [ # AM: I'd like to have an additional check here: + cb.if_with( # If it was a pop or a peek, write ans to the answer list + cmd_le_1, + [ # AM: I'd like to have an additional check hereL # if err flag comes back raised, # we do not perform this write_ans or this incr_j write_ans, diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index 436bd8dcf..c84ab8c90 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -29,10 +29,10 @@ def add_wrap2(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells and groups to compute equality and lt - i_eq_0_cell, i_eq_0_grp = wrap.eq_use(i, 0, 32) - i_eq_1_cell, i_eq_1_group = wrap.eq_use(i, 1, 32) - j_lt_4_cell, j_lt_4_group = wrap.lt_use(j, 4, 32) - j_lt_8_cell, j_lt_8_group = wrap.lt_use(j, 8, 32) + i_eq_0 = wrap.eq_use(i, 0, 32) + i_eq_1 = wrap.eq_use(i, 1, 32) + j_lt_4 = wrap.lt_use(j, 4, 32) + j_lt_8 = wrap.lt_use(j, 8, 32) # Load `j` unchanged into `j_mod_4`. unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") @@ -55,38 +55,31 @@ def add_wrap2(prog): ] wrap.control += [ - cb.if_( - j_lt_4_cell.out, - j_lt_4_group, + cb.if_with( + j_lt_4, unchanged, - cb.if_(j_lt_8_cell.out, j_lt_8_group, j_minus_4, j_minus_8), + cb.if_with(j_lt_8, j_minus_4, j_minus_8), ), cb.par( - cb.if_( - i_eq_0_cell.out, - i_eq_0_grp, - cb.if_( - j_lt_4_cell.out, - j_lt_4_group, + cb.if_with( + i_eq_0, + cb.if_with( + j_lt_4, load_from_mems[0], - cb.if_( - j_lt_8_cell.out, - j_lt_8_group, + cb.if_with( + j_lt_8, load_from_mems[1], load_from_mems[2], ), ), ), - cb.if_( - i_eq_1_cell.out, - i_eq_1_group, - cb.if_( - j_lt_4_cell.out, - j_lt_4_group, + cb.if_with( + i_eq_1, + cb.if_with( + j_lt_4, load_from_mems[3], - cb.if_( - j_lt_8_cell.out, - j_lt_8_group, + cb.if_with( + j_lt_8, load_from_mems[4], load_from_mems[5], ), @@ -125,10 +118,10 @@ def add_wrap3(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells to compute equality, and lt - i_eq_0_cell, i_eq_0_group = wrap.eq_use(i, 0, 32) - i_eq_1_cell, i_eq_1_group = wrap.eq_use(i, 1, 32) - i_eq_2_cell, i_eq_2_group = wrap.eq_use(i, 2, 32) - j_lt_4_cell, j_lt_4_group = wrap.lt_use(j, 4, 32) + i_eq_0 = wrap.eq_use(i, 0, 32) + i_eq_1 = wrap.eq_use(i, 1, 32) + i_eq_2 = wrap.eq_use(i, 2, 32) + j_lt_4 = wrap.lt_use(j, 4, 32) # Load `j` unchanged into `j_mod_4`. unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") @@ -146,28 +139,19 @@ def add_wrap3(prog): ] wrap.control += [ - cb.if_(j_lt_4_cell.out, j_lt_4_group, unchanged, subcell), + cb.if_with(j_lt_4, unchanged, subcell), cb.par( - cb.if_( - i_eq_0_cell.out, - i_eq_0_group, - cb.if_( - j_lt_4_cell.out, j_lt_4_group, emit_from_mems[0], emit_from_mems[1] - ), + cb.if_with( + i_eq_0, + cb.if_with(j_lt_4, emit_from_mems[0], emit_from_mems[1]), ), - cb.if_( - i_eq_1_cell.out, - i_eq_1_group, - cb.if_( - j_lt_4_cell.out, j_lt_4_group, emit_from_mems[2], emit_from_mems[3] - ), + cb.if_with( + i_eq_1, + cb.if_with(j_lt_4, emit_from_mems[2], emit_from_mems[3]), ), - cb.if_( - i_eq_2_cell.out, - i_eq_2_group, - cb.if_( - j_lt_4_cell.out, j_lt_4_group, emit_from_mems[4], emit_from_mems[5] - ), + cb.if_with( + i_eq_2, + cb.if_with(j_lt_4, emit_from_mems[4], emit_from_mems[5]), ), ), ] diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index a8515d785..a22a1db0a 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -66,37 +66,32 @@ def insert_fifo(prog, name): fifo.control += [ cb.par( - # Was it a pop, peek, or a push? We can do all cases in parallel. - cb.if_( + # Was it a pop or a push? We can do both cases in parallel. + cb.if_with( # Did the user call pop? - cmd_eq_0[0].out, - cmd_eq_0[1], - cb.if_( + cmd_eq_0, + cb.if_with( # Yes, the user called pop. But is the queue empty? - len_eq_0[0].out, - len_eq_0[1], + len_eq_0, [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. read_from_mem, # Read from the queue. write_to_ans, # Write the answer to the answer register. read_incr, # Increment the read pointer. - cb.if_( + cb.if_with( # Wrap around if necessary. - read_eq_max_queue_len[0].out, - read_eq_max_queue_len[1], + read_eq_max_queue_len, flash_read, ), len_decr, # Decrement the length. ], ), ), - cb.if_( + cb.if_with( # Did the user call peek? - cmd_eq_1[0].out, - cmd_eq_1[1], - cb.if_( # Yes, the user called peek. But is the queue empty? - len_eq_0[0].out, - len_eq_0[1], + cmd_eq_1, + cb.if_with( # Yes, the user called peek. But is the queue empty? + len_eq_0, [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. read_from_mem, # Read from the queue. @@ -105,22 +100,19 @@ def insert_fifo(prog, name): ], ), ), - cb.if_( + cb.if_with( # Did the user call push? - cmd_eq_2[0].out, - cmd_eq_2[1], - cb.if_( + cmd_eq_2, + cb.if_with( # Yes, the user called push. But is the queue full? - len_eq_max_queue_len[0].out, - len_eq_max_queue_len[1], + len_eq_max_queue_len, [raise_err, flash_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. write_to_mem, # Write `value` to the queue. write_incr, # Increment the write pointer. - cb.if_( + cb.if_with( # Wrap around if necessary. - write_eq_max_queue_len[0].out, - write_eq_max_queue_len[1], + write_eq_max_queue_len, flash_write, ), len_incr, # Increment the length. diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index e052ba693..bb2c7d6e9 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -134,32 +134,28 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): pifo.control += [ cb.par( # Was it a pop, peek, or a push? We can do all cases in parallel. - cb.if_( + cb.if_with( # Did the user call pop? - cmd_eq_0[0].out, - cmd_eq_0[1], - cb.if_( + cmd_eq_0, + cb.if_with( # Yes, the user called pop. But is the queue empty? - len_eq_0[0].out, - len_eq_0[1], + len_eq_0, [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. # We must check if `hot` is 0 or 1. lower_err, cb.par( # We'll check both cases in parallel. - cb.if_( + cb.if_with( # Check if `hot` is 0. - hot_eq_0[0].out, - hot_eq_0[1], + hot_eq_0, [ # `hot` is 0. We'll invoke `pop` on `queue_l`. invoke_subqueue(queue_l, cmd, value, ans, err), # Our next step depends on whether `queue_l` # raised the error flag. # We can check these cases in parallel. cb.par( - cb.if_( - err_neq_0[0].out, - err_neq_0[1], + cb.if_with( + err_neq_0, [ # `queue_l` raised an error. # We'll try to pop from `queue_r`. # We'll pass it a lowered err @@ -169,9 +165,8 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ), ], ), - cb.if_( - err_eq_0[0].out, - err_eq_0[1], + cb.if_with( + err_eq_0, [ # `queue_l` succeeded. # Its answer is our answer. flip_hot @@ -183,15 +178,13 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ], ), # If `hot` is 1, we proceed symmetrically. - cb.if_( - hot_eq_1[0].out, - hot_eq_1[1], + cb.if_with( + hot_eq_1, [ invoke_subqueue(queue_r, cmd, value, ans, err), cb.par( - cb.if_( - err_neq_0[0].out, - err_neq_0[1], + cb.if_with( + err_neq_0, [ lower_err, invoke_subqueue( @@ -199,9 +192,8 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ), ], ), - cb.if_( - err_eq_0[0].out, - err_eq_0[1], + cb.if_with( + err_eq_0, [flip_hot], ), ), @@ -216,30 +208,26 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ], ), ), - cb.if_( + cb.if_with( # Did the user call peek? - cmd_eq_1[0].out, - cmd_eq_1[1], - cb.if_( + cmd_eq_1, + cb.if_with( # Yes, the user called peek. But is the queue empty? - len_eq_0[0].out, - len_eq_0[1], + len_eq_0, [raise_err, flash_ans], # The queue is empty: underflow. [ # The queue is not empty. Proceed. # We must check if `hot` is 0 or 1. lower_err, cb.par( # We'll check both cases in parallel. - cb.if_( + cb.if_with( # Check if `hot` is 0. - hot_eq_0[0].out, - hot_eq_0[1], + hot_eq_0, [ # `hot` is 0. We'll invoke `peek` on `queue_l`. invoke_subqueue(queue_l, cmd, value, ans, err), # Our next step depends on whether `queue_l` # raised the error flag. - cb.if_( - err_neq_0[0].out, - err_neq_0[1], + cb.if_with( + err_neq_0, [ # `queue_l` raised an error. # We'll try to peek from `queue_r`. # We'll pass it a lowered `err`. @@ -254,14 +242,12 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ], ), # If `hot` is 1, we proceed symmetrically. - cb.if_( - hot_eq_1[0].out, - hot_eq_1[1], + cb.if_with( + hot_eq_1, [ invoke_subqueue(queue_r, cmd, value, ans, err), - cb.if_( - err_neq_0[0].out, - err_neq_0[1], + cb.if_with( + err_neq_0, [ lower_err, invoke_subqueue( @@ -275,29 +261,25 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): ], ), ), - cb.if_( + cb.if_with( # Did the user call push? - cmd_eq_2[0].out, - cmd_eq_2[1], - cb.if_( + cmd_eq_2, + cb.if_with( # Yes, the user called push. But is the queue full? - len_eq_max_queue_len[0].out, - len_eq_max_queue_len[1], + len_eq_max_queue_len, [raise_err, flash_ans], # The queue is full: overflow. [ # The queue is not full. Proceed. lower_err, # We need to check which flow this value should be pushed to. infer_flow, # Infer the flow and write it to `fifo_{flow}`. cb.par( - cb.if_( - flow_eq_0[0].out, - flow_eq_0[1], + cb.if_with( + flow_eq_0, # This value should be pushed to queue_l. invoke_subqueue(queue_l, cmd, value, ans, err), ), - cb.if_( - flow_eq_1[0].out, - flow_eq_1[1], + cb.if_with( + flow_eq_1, # This value should be pushed to queue_r. invoke_subqueue(queue_r, cmd, value, ans, err), ), diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 55631c1d1..8665f3a00 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -858,7 +858,7 @@ def counter(): # build the while loop with condition cond_reg. # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 cond_reg_port = comp.get_cell("cond_reg").port("out") - while_loop = cb.while_(cond_reg_port, None, while_body) + while_loop = cb.while_(cond_reg_port, while_body) control.append(while_loop) From ecd275647d514327f8ed25655cd289c1ae880ede Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 18 Aug 2023 12:55:12 -0400 Subject: [PATCH 033/189] Massage away magic width 32 (#1677) --- calyx-py/calyx/builder.py | 10 +++++----- calyx-py/test/correctness/reduction_tree.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 975e63c5a..5dddd67e8 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -463,7 +463,7 @@ def incr(self, reg, width, val=1, cellname=None): add_cell = self.add(width, cellname) with self.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out - add_cell.right = const(32, val) + add_cell.right = const(width, val) reg.write_en = 1 reg.in_ = add_cell.out incr_group.done = reg.done @@ -481,7 +481,7 @@ def decr(self, reg, width, val=1, cellname=None): sub_cell = self.sub(width, cellname) with self.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out - sub_cell.right = const(32, val) + sub_cell.right = const(width, val) reg.write_en = 1 reg.in_ = sub_cell.out decr_group.done = reg.done @@ -600,7 +600,7 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): load_grp.done = ans.done return load_grp - def add_store_in_reg(self, cellname, left, right, ans_reg=None): + def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): """Inserts wiring into component `self` to compute `left` + `right` and store it in `ans_reg`. 1. Within component `self`, creates a group called `cellname`_group. @@ -609,8 +609,8 @@ def add_store_in_reg(self, cellname, left, right, ans_reg=None): 4. Then puts the answer of the computation into `ans_reg`. 4. Returns the summing group and the register. """ - add_cell = self.add(32, cellname) - ans_reg = ans_reg or self.reg(f"reg_{cellname}", 32) + add_cell = self.add(width, cellname) + ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as adder_group: add_cell.left = left add_cell.right = right diff --git a/calyx-py/test/correctness/reduction_tree.py b/calyx-py/test/correctness/reduction_tree.py index 76bb9ab2d..475a293d3 100644 --- a/calyx-py/test/correctness/reduction_tree.py +++ b/calyx-py/test/correctness/reduction_tree.py @@ -23,9 +23,9 @@ def add_tree(prog): # Into the component `tree`, add the wiring for three adder groups that will # use the tree to perform their additions. # These need to be orchestrated in the control below. - add_l0_l1, left = tree.add_store_in_reg("add_l0_l1", leaf0, leaf1) - add_l2_l3, right = tree.add_store_in_reg("add_l2_l3", leaf2, leaf3) - add_l_r_nodes, root = tree.add_store_in_reg("add_l_r", left.out, right.out) + add_l0_l1, left = tree.add_store_in_reg(leaf0, leaf1, "add_l0_l1", 32) + add_l2_l3, right = tree.add_store_in_reg(leaf2, leaf3, "add_l2_l3", 32) + add_l_r_nodes, root = tree.add_store_in_reg(left.out, right.out, "add_l_r", 32) # Continuously output the value of the root register. # It is the invoker's responsibility to ensure that the tree is done From 1fb49f408ab34acbf0f066c4c72b941c26b2a472 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Sat, 19 Aug 2023 10:34:29 -0400 Subject: [PATCH 034/189] Builder: make PyLint a little happier (#1674) * Make FIFO use new eq * Tidying * Arbiter works * Pifo and Pifotrer work * Push insert_eq into builder proper * CellGroupBuilder, and sugary if and while * Update all users to use new sugary versions in case of eq * Drop optional names for other eq cell uses * Optional name for neq cells * Optional name for lt cells * Allow a buncha other cells to make names automatically * pipe change through to builder_util * Catch up all programs to new name-optional regime * Tidying * Move bitwise_flip into builder.py * Rehome incr and decr * Move rest of builder_util into builder * Catch up all eDSL files to rehome * if_with and while_with instead of sugary * make sugary versions independent of non-sugary ones * Disallow comb group in vanilla if and while * Catch up all eDSL users to new sugary variant * Fix in MrXL * Fixes in systolic * More auto-names * assert that names must be strings * Fixes in systolic and mrxl * Fixes in gen_exp * Labeled arg catch * Port need not say out * While witout a comb group * Fixes in gen_msb * Fix in static if docstring * rename CellGroupBuilder * Docstring cleanup * Backticks in docstrings * Make pylink a little happier --- calyx-py/calyx/builder.py | 60 ++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 5dddd67e8..b7b0930dc 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -1,7 +1,6 @@ from __future__ import annotations import threading -import random from typing import Dict, Union, Optional, List from dataclasses import dataclass from . import py_ast as ast @@ -12,6 +11,18 @@ TLS.groups = [] +class NotFoundError(Exception): + """Raised when a component or group is not found.""" + + +class WidthInferenceError(Exception): + """Raised when we cannot infer the width of an expression.""" + + +class MalformedGroupError(Exception): + """Raised when a group is malformed.""" + + class Builder: """The entry-point builder for top-level Calyx programs.""" @@ -36,7 +47,7 @@ def get_component(self, name: str) -> ComponentBuilder: """Retrieve a component builder by name.""" comp_builder = self._index.get(name) if comp_builder is None: - raise Exception(f"Component `{name}' not found in program.") + raise NotFoundError(f"Component `{name}' not found in program.") else: return comp_builder @@ -128,7 +139,9 @@ def get_port_width(self, name: str) -> int: for output in self.component.outputs: if output.id.name == name: return output.width - raise Exception(f"couldn't find port {name} on component {self.component.name}") + raise NotFoundError( + f"couldn't find port {name} on component {self.component.name}" + ) def get_cell(self, name: str) -> CellBuilder: """Retrieve a cell builder by name.""" @@ -136,7 +149,7 @@ def get_cell(self, name: str) -> CellBuilder: if out and isinstance(out, CellBuilder): return out else: - raise Exception( + raise NotFoundError( f"Cell `{name}' not found in component {self.component.name}.\n" f"Known cells: {list(map(lambda c: c.id.name, self.component.cells))}" ) @@ -155,7 +168,7 @@ def get_group(self, name: str) -> GroupBuilder: if out and isinstance(out, GroupBuilder): return out else: - raise Exception( + raise NotFoundError( f"Group `{name}' not found in component {self.component.name}" ) @@ -667,11 +680,11 @@ def as_control(obj): """ if isinstance(obj, ast.Control): return obj - elif isinstance(obj, str): + if isinstance(obj, str): return ast.Enable(obj) - elif isinstance(obj, ast.Group): + if isinstance(obj, ast.Group): return ast.Enable(obj.id.name) - elif isinstance(obj, GroupBuilder): + if isinstance(obj, GroupBuilder): gl = obj.group_like assert gl, ( "GroupBuilder represents continuous assignments and" @@ -681,14 +694,14 @@ def as_control(obj): gl, ast.CombGroup ), "Cannot use combinational group as control statement" return ast.Enable(gl.id.name) - elif isinstance(obj, list): + if isinstance(obj, list): return ast.SeqComp([as_control(o) for o in obj]) - elif isinstance(obj, set): + if isinstance(obj, set): raise TypeError( "Python sets are not supported in control programs. For a parallel" " composition use `Builder.par` instead." ) - elif obj is None: + if obj is None: return ast.Empty() else: assert False, f"unsupported control type {type(obj)}" @@ -859,16 +872,18 @@ def __ne__(self, other: ExprBuilder): @classmethod def unwrap(cls, obj): + """Unwrap an expression builder, or return the object if it is not one.""" if isinstance(obj, cls): return obj.expr - else: - return obj + return obj +@dataclass class CondExprBuilder: - def __init__(self, cond, value): - self.cond = cond - self.value = value + """Wraps a conditional expression.""" + + cond: ExprBuilder + value: ExprBuilder class CellLikeBuilder: @@ -1016,7 +1031,7 @@ def asgn( if isinstance(rhs, int): width = infer_width(lhs) if not width: - raise Exception(f"could not infer width for literal {rhs}") + raise WidthInferenceError(f"could not infer width for literal {rhs}") rhs = const(width, rhs) assert isinstance(rhs, (ExprBuilder, ast.Port)), ( @@ -1051,8 +1066,9 @@ def done(self): def done(self, expr): """Build an assignment to `done` in the group.""" if not self.group_like: - raise Exception( - "GroupBuilder represents continuous assignments and does not have a done hole" + raise MalformedGroupError( + "GroupBuilder represents continuous assignments and does " + "not have a done hole" ) self.asgn(self.done, expr) @@ -1163,10 +1179,8 @@ def ctx_asgn(lhs: ExprBuilder, rhs: Union[ExprBuilder, CondExprBuilder]): group_builder.asgn(lhs, rhs) -"""A one bit low signal""" -LO = const(1, 0) -"""A one bit high signal""" -HI = const(1, 1) +LO = const(1, 0) # A one bit low signal +HI = const(1, 1) # A one bit high signal def par(*args) -> ast.ParComp: From 0c8766440748d3ebb5c054187a9290efcd140dc4 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Sat, 19 Aug 2023 11:07:52 -0400 Subject: [PATCH 035/189] Builder: trim docstrings for readability (#1675) --- calyx-py/calyx/builder.py | 117 +++++++++++--------------------------- 1 file changed, 33 insertions(+), 84 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index b7b0930dc..005e2c3ff 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -209,8 +209,8 @@ def cell( is_external: bool = False, is_ref: bool = False, ) -> CellBuilder: - """Declare a cell in the component. Returns a cell builder.""" - # If we get a (non-primitive) component builder, instantiate it + """Declare a cell in the component. Return a cell builder.""" + # If given a (non-primitive) component builder, instantiate it # with no parameters. if isinstance(comp, ComponentBuilder): comp = ast.CompInst(comp.component.name, []) @@ -258,7 +258,11 @@ def wire(self, name: str, size: int, is_ref: bool = False) -> CellBuilder: return self.cell(name, ast.Stdlib.wire(size), False, is_ref) def slice( - self, name: str, in_width: int, out_width, is_ref: bool = False + self, + name: str, + in_width: int, + out_width: int, + is_ref: bool = False, ) -> CellBuilder: """Generate a StdSlice cell.""" return self.cell(name, ast.Stdlib.slice(in_width, out_width), False, is_ref) @@ -418,42 +422,40 @@ def binary_use(self, left, right, cell, groupname=None): return CellAndGroup(cell, comb_group) def eq_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` == `right`.""" + """Inserts wiring into `self` to check if `left` == `right`.""" return self.binary_use(left, right, self.eq(width, cellname)) def neq_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` != `right`.""" + """Inserts wiring into `self` to check if `left` != `right`.""" return self.binary_use(left, right, self.neq(width, cellname)) def lt_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` < `right`.""" + """Inserts wiring into `self` to check if `left` < `right`.""" return self.binary_use(left, right, self.lt(width, cellname)) def le_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` <= `right`.""" + """Inserts wiring into `self` to check if `left` <= `right`.""" return self.binary_use(left, right, self.le(width, cellname)) def ge_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` >= `right`.""" + """Inserts wiring into `self` to check if `left` >= `right`.""" return self.binary_use(left, right, self.ge(width, cellname)) def gt_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to check if `left` > `right`.""" + """Inserts wiring into `self` to check if `left` > `right`.""" return self.binary_use(left, right, self.gt(width, cellname)) def add_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to compute `left` + `right`.""" + """Inserts wiring into `self` to compute `left` + `right`.""" return self.binary_use(left, right, self.add(width, cellname)) def sub_use(self, left, right, width, cellname=None): - """Inserts wiring into component `self` to compute `left` - `right`.""" + """Inserts wiring into `self` to compute `left` - `right`.""" return self.binary_use(left, right, self.sub(width, cellname)) def bitwise_flip_reg(self, reg, width, cellname=None): - """Inserts wiring into component `self` to bitwise-flip the contents of `reg` + """Inserts wiring into `self` to bitwise-flip the contents of `reg` and put the result back into `reg`. - - Returns a handle to the group that does this. """ cellname = cellname or f"{reg.name}_not" not_cell = self.not_(width, cellname) @@ -465,13 +467,7 @@ def bitwise_flip_reg(self, reg, width, cellname=None): return not_group def incr(self, reg, width, val=1, cellname=None): - """Inserts wiring into component `self` to increment register `reg` by `val`. - 1. Within component `self`, creates a group. - 2. Within the group, adds a cell `cellname` that computes sums. - 3. Puts the values `reg` and `val` into the cell. - 4. Then puts the answer of the computation back into `reg`. - 5. Returns the group that does this. - """ + """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" add_cell = self.add(width, cellname) with self.group(f"{cellname}_group") as incr_group: @@ -483,13 +479,7 @@ def incr(self, reg, width, val=1, cellname=None): return incr_group def decr(self, reg, width, val=1, cellname=None): - """Inserts wiring into component `self` to decrement register `reg` by `val`. - 1. Within component `self`, creates a group. - 2. Within the group, adds a cell `cellname` that computes differences. - 3. Puts the values `reg` and `val` into the cell. - 4. Then puts the answer of the computation back into `reg`. - 5. Returns the group. - """ + """Inserts wiring into `self` to perform `reg := reg - val`.""" cellname = cellname or f"{reg.name}_decr" sub_cell = self.sub(width, cellname) with self.group(f"{cellname}_group") as decr_group: @@ -501,11 +491,7 @@ def decr(self, reg, width, val=1, cellname=None): return decr_group def reg_store(self, reg, val, groupname=None): - """Stores a value in a register. - 1. Within component `self`, creates a group. - 2. Within the group, sets the register `reg` to `val`. - 3. Returns the group. - """ + """Inserts wiring into `self` to perform `reg := val`.""" groupname = groupname or f"{reg.name}_store_to_reg" with self.group(groupname) as reg_grp: reg.in_ = val @@ -514,11 +500,8 @@ def reg_store(self, reg, val, groupname=None): return reg_grp def mem_load_std_d1(self, mem, i, reg, groupname=None): - """Loads a value from one memory (std_d1) into a register. - 1. Within component `comp`, creates a group. - 2. Within the group, reads from memory `mem` at address `i`. - 3. Writes the value into register `reg`. - 4. Returns the group. + """Inserts wiring into `self` to perform `reg := mem[i]`, + where `mem` is a std_d1 memory. """ assert mem.is_std_mem_d1() groupname = groupname or f"{mem.name()}_load_to_reg" @@ -530,12 +513,8 @@ def mem_load_std_d1(self, mem, i, reg, groupname=None): return load_grp def mem_store_std_d1(self, mem, i, val, groupname=None): - """Stores a value into a (std_d1) memory. - 1. Within component `self`, creates a group. - 2. Within the group, reads from `val`. - 3. Writes the value into memory `mem` at address i. - 4. Returns the group. - """ + """Inserts wiring into `self` to perform `mem[i] := val`, + where `mem` is a std_d1 memory.""" assert mem.is_std_mem_d1() groupname = groupname or f"store_into_{mem.name()}" with self.group(groupname) as store_grp: @@ -546,13 +525,9 @@ def mem_store_std_d1(self, mem, i, val, groupname=None): return store_grp def mem_read_seq_d1(self, mem, i, groupname=None): - """Given a seq_mem_d1, reads from memory at address i. + """Inserts wiring into `self` to latch `mem[i]` as the output of `mem`, + where `mem` is a seq_d1 memory. Note that this does not write the value anywhere. - - 1. Within component `self`, creates a group. - 2. Within the group, reads from memory `mem` at address `i`, - thereby "latching" the value. - 3. Returns the group. """ assert mem.is_seq_mem_d1() groupname = groupname or f"read_from_{mem.name()}" @@ -563,13 +538,8 @@ def mem_read_seq_d1(self, mem, i, groupname=None): return read_grp def mem_write_seq_d1_to_reg(self, mem, reg, groupname=None): - """Given a seq_mem_d1 that is already assumed to have a latched value, - reads the latched value and writes it to a register. - - 1. Within component `self`, creates a group. - 2. Within the group, reads from memory `mem`. - 3. Writes the value into register `reg`. - 4. Returns the group. + """Inserts wiring into `self` to perform reg := , + where `mem` is a seq_d1 memory that already has some latched value. """ assert mem.is_seq_mem_d1() groupname = groupname or f"{mem.name()}_write_to_reg" @@ -580,12 +550,8 @@ def mem_write_seq_d1_to_reg(self, mem, reg, groupname=None): return write_grp def mem_store_seq_d1(self, mem, i, val, groupname=None): - """Given a seq_mem_d1, stores a value into memory at address i. - - 1. Within component `self`, creates a group. - 2. Within the group, reads from `val`. - 3. Writes the value into memory `mem` at address i. - 4. Returns the group. + """Inserts wiring into `self` to perform `mem[i] := val`, + where `mem` is a seq_d1 memory. """ assert mem.is_seq_mem_d1() groupname = groupname or f"{mem.name()}_store" @@ -597,11 +563,8 @@ def mem_store_seq_d1(self, mem, i, val, groupname=None): return store_grp def mem_load_to_mem(self, mem, i, ans, j, groupname=None): - """Loads a value from one std_mem_d1 memory into another. - 1. Within component `self`, creates a group. - 2. Within the group, reads from memory `mem` at address `i`. - 3. Writes the value into memory `ans` at address `j`. - 4. Returns the group. + """Inserts wiring into `self` to perform `ans[j] := mem[i]`, + where `mem` and `ans` are both std_d1 memories. """ assert mem.is_std_mem_d1() and ans.is_std_mem_d1() groupname = groupname or f"{mem.name()}_load_to_mem" @@ -614,14 +577,7 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): return load_grp def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): - """Inserts wiring into component `self` to compute `left` + `right` and - store it in `ans_reg`. - 1. Within component `self`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes sums. - 3. Puts the values of `left` and `right` into the cell. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the summing group and the register. - """ + """Inserts wiring into `self` to perform `reg := left + right`.""" add_cell = self.add(width, cellname) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as adder_group: @@ -633,14 +589,7 @@ def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): return adder_group, ans_reg def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): - """Adds wiring into component `self` to compute `left` - `right` - and store it in `ans_reg`. - 1. Within component `self`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes differences. - 3. Puts the values of `left` and `right` into `cell`. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the subtracting group and the register. - """ + """Inserts wiring into `self` to perform `reg := left - right`.""" sub_cell = self.sub(width, cellname) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as sub_group: From 56c1845cb10ce99ab1de66868544e83f37d99a35 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan Date: Sun, 20 Aug 2023 15:41:58 -0400 Subject: [PATCH 036/189] Catch up gen_exp --- calyx-py/calyx/builder.py | 62 +++++++++++-------- calyx-py/calyx/gen_exp.py | 124 ++++++++++---------------------------- 2 files changed, 69 insertions(+), 117 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 005e2c3ff..ffcce965b 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -345,6 +345,10 @@ def le(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdLe cell.""" return self.binary("le", size, name, signed) + def rsh(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: + """Generate a StdRsh cell.""" + return self.binary("rsh", size, name, signed) + def logic(self, operation, size: int, name: str = None) -> CellBuilder: """Generate a logical operator cell, of the flavor specified in `operation`.""" name = name or self.generate_name(operation) @@ -353,10 +357,12 @@ def logic(self, operation, size: int, name: str = None) -> CellBuilder: def and_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdAnd cell.""" + name = name or self.generate_name("and") return self.logic("and", size, name) def not_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdNot cell.""" + name = name or self.generate_name("not") return self.logic("not", size, name) def pipelined_mult(self, name: str) -> CellBuilder: @@ -421,44 +427,44 @@ def binary_use(self, left, right, cell, groupname=None): cell.right = right return CellAndGroup(cell, comb_group) - def eq_use(self, left, right, width, cellname=None): + def eq_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` == `right`.""" - return self.binary_use(left, right, self.eq(width, cellname)) + return self.binary_use(left, right, self.eq(width, cellname, signed)) - def neq_use(self, left, right, width, cellname=None): + def neq_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` != `right`.""" - return self.binary_use(left, right, self.neq(width, cellname)) + return self.binary_use(left, right, self.neq(width, cellname, signed)) - def lt_use(self, left, right, width, cellname=None): + def lt_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` < `right`.""" - return self.binary_use(left, right, self.lt(width, cellname)) + return self.binary_use(left, right, self.lt(width, cellname, signed)) - def le_use(self, left, right, width, cellname=None): + def le_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` <= `right`.""" - return self.binary_use(left, right, self.le(width, cellname)) + return self.binary_use(left, right, self.le(width, cellname, signed)) - def ge_use(self, left, right, width, cellname=None): + def ge_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` >= `right`.""" - return self.binary_use(left, right, self.ge(width, cellname)) + return self.binary_use(left, right, self.ge(width, cellname, signed)) - def gt_use(self, left, right, width, cellname=None): + def gt_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` > `right`.""" - return self.binary_use(left, right, self.gt(width, cellname)) + return self.binary_use(left, right, self.gt(width, cellname, signed)) - def add_use(self, left, right, width, cellname=None): + def add_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to compute `left` + `right`.""" - return self.binary_use(left, right, self.add(width, cellname)) + return self.binary_use(left, right, self.add(width, cellname, signed)) - def sub_use(self, left, right, width, cellname=None): + def sub_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to compute `left` - `right`.""" - return self.binary_use(left, right, self.sub(width, cellname)) + return self.binary_use(left, right, self.sub(width, cellname, signed)) - def bitwise_flip_reg(self, reg, width, cellname=None): + def bitwise_flip_reg(self, reg, width, signed=False, cellname=None): """Inserts wiring into `self` to bitwise-flip the contents of `reg` and put the result back into `reg`. """ cellname = cellname or f"{reg.name}_not" - not_cell = self.not_(width, cellname) + not_cell = self.not_(width, cellname, signed) with self.group(f"{cellname}_group") as not_group: not_cell.in_ = reg.out reg.write_en = 1 @@ -466,10 +472,10 @@ def bitwise_flip_reg(self, reg, width, cellname=None): not_group.done = reg.done return not_group - def incr(self, reg, width, val=1, cellname=None): + def incr(self, reg, width, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" - add_cell = self.add(width, cellname) + add_cell = self.add(width, cellname, signed) with self.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out add_cell.right = const(width, val) @@ -478,10 +484,10 @@ def incr(self, reg, width, val=1, cellname=None): incr_group.done = reg.done return incr_group - def decr(self, reg, width, val=1, cellname=None): + def decr(self, reg, width, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg - val`.""" cellname = cellname or f"{reg.name}_decr" - sub_cell = self.sub(width, cellname) + sub_cell = self.sub(width, cellname, signed) with self.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out sub_cell.right = const(width, val) @@ -576,9 +582,11 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): load_grp.done = ans.done return load_grp - def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def add_store_in_reg( + self, left, right, cellname, width, ans_reg=None, signed=False + ): """Inserts wiring into `self` to perform `reg := left + right`.""" - add_cell = self.add(width, cellname) + add_cell = self.add(width, cellname, signed) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as adder_group: add_cell.left = left @@ -588,9 +596,11 @@ def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): adder_group.done = ans_reg.done return adder_group, ans_reg - def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def sub_store_in_reg( + self, left, right, cellname, width, ans_reg=None, signed=False + ): """Inserts wiring into `self` to perform `reg := left - right`.""" - sub_cell = self.sub(width, cellname) + sub_cell = self.sub(width, cellname, signed) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as sub_group: sub_cell.left = left diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index df389290a..3afdac7d7 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -49,7 +49,6 @@ def generate_fp_pow_component( "mult_pipe", width, int_width, frac_width, signed=is_signed ), ) - lt = comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) incr = comp.cell("incr", Stdlib.op("add", width, signed=is_signed)) # groups @@ -70,27 +69,14 @@ def generate_fp_pow_component( pow.in_ = mul.out execute_mul.done = pow.done - with comp.group("incr_count") as incr_count: - incr.left = const(width, 1) - incr.right = count.out - count.in_ = incr.out - count.write_en = 1 - incr_count.done = count.done + incr_count = comp.incr(count, width) - with comp.comb_group("cond") as cond: - lt.left = count.out - lt.right = comp.this().integer_exp + cond = comp.lt_use(count.out, comp.this().integer_exp, width, is_signed) with comp.continuous: comp.this().out = pow.out - comp.control += [ - init, - while_with( - CellAndGroup(lt, cond), - par(execute_mul, incr_count), - ), - ] + comp.control += [init, while_with(cond, par(execute_mul, incr_count))] return comp.component @@ -105,11 +91,12 @@ def generate_cells( comp.reg("int_x", width) comp.reg("frac_x", width) comp.reg("m", width) - comp.cell("and0", Stdlib.op("and", width, signed=False)) - comp.cell("and1", Stdlib.op("and", width, signed=False)) - comp.cell("rsh", Stdlib.op("rsh", width, signed=False)) + + comp.and_(width, "and0") + comp.and_(width, "and1") + comp.rsh(width, "rsh") if is_signed: - comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) + comp.lt(width, "lt", is_signed) # constants for i in range(2, degree + 1): @@ -541,21 +528,6 @@ def gen_reverse_sign( group.done = base_cell.done -def gen_comb_lt( - comp: ComponentBuilder, - name: str, - lhs: ExprBuilder, - lt: CellBuilder, - const_cell: CellBuilder, -): - """ - Generates lhs < const_cell - """ - with comp.comb_group(name): - lt.left = lhs - lt.right = const_cell.out - - # This appears to be unused. Brilliant. # TODO (griffin): Double check that this is unused and, if so, remove it. def gen_constant_cell( @@ -590,7 +562,8 @@ def generate_fp_pow_full( comp.input("base", width) comp.input("exp_value", width) comp.output("out", width) - lt = comp.cell("lt", Stdlib.op("lt", width, is_signed)) + lt = comp.lt(width, "lt", is_signed) + div = comp.cell( "div", Stdlib.fixed_point_op( @@ -632,7 +605,13 @@ def generate_fp_pow_full( ) gen_reverse_sign(comp, "rev_base_sign", new_base_reg, mult, const_neg_one), gen_reverse_sign(comp, "rev_res_sign", res, mult, const_neg_one), - gen_comb_lt(comp, "base_lt_zero", comp.this().base, lt, const_zero), + + base_lt_zero = comp.lt_use( + comp.this().base, + const_zero.out, + width, + is_signed, + ) new_exp_val = comp.reg("new_exp_val", width) e = comp.comp_instance("e", "exp", check_undeclared=False) @@ -649,48 +628,29 @@ def generate_fp_pow_full( with comp.continuous: comp.this().out = res.out - with comp.group("write_to_base_reg") as write_to_base_reg: - new_base_reg.write_en = 1 - new_base_reg.in_ = comp.this().base - write_to_base_reg.done = new_base_reg.done - - with comp.group("store_old_reg_val") as store_old_reg_val: - stored_base_reg.write_en = 1 - stored_base_reg.in_ = new_base_reg.out - store_old_reg_val.done = stored_base_reg.done - - with comp.group("write_e_to_res") as write_e_to_res: - res.write_en = 1 - res.in_ = e.out - write_e_to_res.done = res.done + write_to_base_reg = comp.reg_store( + new_base_reg, comp.this().base, "write_to_base_reg" + ) + store_old_reg_val = comp.reg_store( + stored_base_reg, new_base_reg.out, "store_old_reg_val" + ) + write_e_to_res = comp.reg_store(res, e.out, "write_e_to_res") gen_reciprocal(comp, "set_base_reciprocal", new_base_reg, div, const_one) gen_reciprocal(comp, "set_res_reciprocal", res, div, const_one), - gen_comb_lt( - comp, - "base_lt_one", - stored_base_reg.out, - lt, - const_one, - ) + base_lt_one = comp.lt_use(stored_base_reg.out, const_one.out, width, is_signed) - base_reciprocal = if_with( - CellAndGroup(lt, comp.get_group("base_lt_one")), - comp.get_group("set_base_reciprocal"), - ) + base_reciprocal = if_with(base_lt_one, comp.get_group("set_base_reciprocal")) - res_reciprocal = if_with( - CellAndGroup(lt, comp.get_group("base_lt_one")), - comp.get_group("set_res_reciprocal"), - ) + res_reciprocal = if_with(base_lt_one, comp.get_group("set_res_reciprocal")) if is_signed: base_rev = if_with( - CellAndGroup(lt, comp.get_group("base_lt_zero")), + base_lt_zero, comp.get_group("rev_base_sign"), ) res_rev = if_with( - CellAndGroup(lt, comp.get_group("base_lt_zero")), + base_lt_zero, comp.get_group("rev_res_sign"), ) pre_process = [base_rev, store_old_reg_val, base_reciprocal] @@ -741,23 +701,9 @@ def build_base_not_e(degree, width, int_width, is_signed) -> Program: ret = main.mem_d1("ret", width, 1, 1, is_external=True) f = main.comp_instance("f", "fp_pow_full") - with main.group("read_base") as read_base: - b.addr0 = 0 - base_reg.in_ = b.read_data - base_reg.write_en = 1 - read_base.done = base_reg.done - - with main.group("read_exp") as read_exp: - x.addr0 = 0 - exp_reg.in_ = x.read_data - exp_reg.write_en = 1 - read_exp.done = exp_reg.done - - with main.group("write_to_memory") as write_to_memory: - ret.addr0 = 0 - ret.write_en = 1 - ret.write_data = f.out - write_to_memory.done = ret.done + read_base = main.mem_load_std_d1(b, 0, base_reg, "read_base") + read_exp = main.mem_load_std_d1(x, 0, exp_reg, "read_exp") + write_to_memory = main.mem_store_std_d1(ret, 0, f.out, "write_to_memory") main.control += [ read_base, @@ -796,11 +742,7 @@ def build_base_is_e(degree, width, int_width, is_signed) -> Program: t.write_en = 1 init.done = t.done - with main.group("write_to_memory") as write_to_memory: - ret.addr0 = 0 - ret.write_en = 1 - ret.write_data = e.out - write_to_memory.done = ret.done + write_to_memory = main.mem_store_std_d1(ret, 0, e.out, "write_to_memory") main.control += [ init, From de49ca334cd1502a6cea05fbf0d67c1d7e01229c Mon Sep 17 00:00:00 2001 From: Anshuman Mohan Date: Sun, 20 Aug 2023 15:44:14 -0400 Subject: [PATCH 037/189] Revert "Catch up gen_exp" This reverts commit 4997e9c4352c4251ee6d5a6f65afbd409a104502. --- calyx-py/calyx/builder.py | 62 ++++++++----------- calyx-py/calyx/gen_exp.py | 124 ++++++++++++++++++++++++++++---------- 2 files changed, 117 insertions(+), 69 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index ffcce965b..005e2c3ff 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -345,10 +345,6 @@ def le(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdLe cell.""" return self.binary("le", size, name, signed) - def rsh(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: - """Generate a StdRsh cell.""" - return self.binary("rsh", size, name, signed) - def logic(self, operation, size: int, name: str = None) -> CellBuilder: """Generate a logical operator cell, of the flavor specified in `operation`.""" name = name or self.generate_name(operation) @@ -357,12 +353,10 @@ def logic(self, operation, size: int, name: str = None) -> CellBuilder: def and_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdAnd cell.""" - name = name or self.generate_name("and") return self.logic("and", size, name) def not_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdNot cell.""" - name = name or self.generate_name("not") return self.logic("not", size, name) def pipelined_mult(self, name: str) -> CellBuilder: @@ -427,44 +421,44 @@ def binary_use(self, left, right, cell, groupname=None): cell.right = right return CellAndGroup(cell, comb_group) - def eq_use(self, left, right, width, signed=False, cellname=None): + def eq_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` == `right`.""" - return self.binary_use(left, right, self.eq(width, cellname, signed)) + return self.binary_use(left, right, self.eq(width, cellname)) - def neq_use(self, left, right, width, signed=False, cellname=None): + def neq_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` != `right`.""" - return self.binary_use(left, right, self.neq(width, cellname, signed)) + return self.binary_use(left, right, self.neq(width, cellname)) - def lt_use(self, left, right, width, signed=False, cellname=None): + def lt_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` < `right`.""" - return self.binary_use(left, right, self.lt(width, cellname, signed)) + return self.binary_use(left, right, self.lt(width, cellname)) - def le_use(self, left, right, width, signed=False, cellname=None): + def le_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` <= `right`.""" - return self.binary_use(left, right, self.le(width, cellname, signed)) + return self.binary_use(left, right, self.le(width, cellname)) - def ge_use(self, left, right, width, signed=False, cellname=None): + def ge_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` >= `right`.""" - return self.binary_use(left, right, self.ge(width, cellname, signed)) + return self.binary_use(left, right, self.ge(width, cellname)) - def gt_use(self, left, right, width, signed=False, cellname=None): + def gt_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to check if `left` > `right`.""" - return self.binary_use(left, right, self.gt(width, cellname, signed)) + return self.binary_use(left, right, self.gt(width, cellname)) - def add_use(self, left, right, width, signed=False, cellname=None): + def add_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to compute `left` + `right`.""" - return self.binary_use(left, right, self.add(width, cellname, signed)) + return self.binary_use(left, right, self.add(width, cellname)) - def sub_use(self, left, right, width, signed=False, cellname=None): + def sub_use(self, left, right, width, cellname=None): """Inserts wiring into `self` to compute `left` - `right`.""" - return self.binary_use(left, right, self.sub(width, cellname, signed)) + return self.binary_use(left, right, self.sub(width, cellname)) - def bitwise_flip_reg(self, reg, width, signed=False, cellname=None): + def bitwise_flip_reg(self, reg, width, cellname=None): """Inserts wiring into `self` to bitwise-flip the contents of `reg` and put the result back into `reg`. """ cellname = cellname or f"{reg.name}_not" - not_cell = self.not_(width, cellname, signed) + not_cell = self.not_(width, cellname) with self.group(f"{cellname}_group") as not_group: not_cell.in_ = reg.out reg.write_en = 1 @@ -472,10 +466,10 @@ def bitwise_flip_reg(self, reg, width, signed=False, cellname=None): not_group.done = reg.done return not_group - def incr(self, reg, width, val=1, signed=False, cellname=None): + def incr(self, reg, width, val=1, cellname=None): """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" - add_cell = self.add(width, cellname, signed) + add_cell = self.add(width, cellname) with self.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out add_cell.right = const(width, val) @@ -484,10 +478,10 @@ def incr(self, reg, width, val=1, signed=False, cellname=None): incr_group.done = reg.done return incr_group - def decr(self, reg, width, val=1, signed=False, cellname=None): + def decr(self, reg, width, val=1, cellname=None): """Inserts wiring into `self` to perform `reg := reg - val`.""" cellname = cellname or f"{reg.name}_decr" - sub_cell = self.sub(width, cellname, signed) + sub_cell = self.sub(width, cellname) with self.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out sub_cell.right = const(width, val) @@ -582,11 +576,9 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): load_grp.done = ans.done return load_grp - def add_store_in_reg( - self, left, right, cellname, width, ans_reg=None, signed=False - ): + def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): """Inserts wiring into `self` to perform `reg := left + right`.""" - add_cell = self.add(width, cellname, signed) + add_cell = self.add(width, cellname) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as adder_group: add_cell.left = left @@ -596,11 +588,9 @@ def add_store_in_reg( adder_group.done = ans_reg.done return adder_group, ans_reg - def sub_store_in_reg( - self, left, right, cellname, width, ans_reg=None, signed=False - ): + def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): """Inserts wiring into `self` to perform `reg := left - right`.""" - sub_cell = self.sub(width, cellname, signed) + sub_cell = self.sub(width, cellname) ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) with self.group(f"{cellname}_group") as sub_group: sub_cell.left = left diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index 3afdac7d7..df389290a 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -49,6 +49,7 @@ def generate_fp_pow_component( "mult_pipe", width, int_width, frac_width, signed=is_signed ), ) + lt = comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) incr = comp.cell("incr", Stdlib.op("add", width, signed=is_signed)) # groups @@ -69,14 +70,27 @@ def generate_fp_pow_component( pow.in_ = mul.out execute_mul.done = pow.done - incr_count = comp.incr(count, width) + with comp.group("incr_count") as incr_count: + incr.left = const(width, 1) + incr.right = count.out + count.in_ = incr.out + count.write_en = 1 + incr_count.done = count.done - cond = comp.lt_use(count.out, comp.this().integer_exp, width, is_signed) + with comp.comb_group("cond") as cond: + lt.left = count.out + lt.right = comp.this().integer_exp with comp.continuous: comp.this().out = pow.out - comp.control += [init, while_with(cond, par(execute_mul, incr_count))] + comp.control += [ + init, + while_with( + CellAndGroup(lt, cond), + par(execute_mul, incr_count), + ), + ] return comp.component @@ -91,12 +105,11 @@ def generate_cells( comp.reg("int_x", width) comp.reg("frac_x", width) comp.reg("m", width) - - comp.and_(width, "and0") - comp.and_(width, "and1") - comp.rsh(width, "rsh") + comp.cell("and0", Stdlib.op("and", width, signed=False)) + comp.cell("and1", Stdlib.op("and", width, signed=False)) + comp.cell("rsh", Stdlib.op("rsh", width, signed=False)) if is_signed: - comp.lt(width, "lt", is_signed) + comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) # constants for i in range(2, degree + 1): @@ -528,6 +541,21 @@ def gen_reverse_sign( group.done = base_cell.done +def gen_comb_lt( + comp: ComponentBuilder, + name: str, + lhs: ExprBuilder, + lt: CellBuilder, + const_cell: CellBuilder, +): + """ + Generates lhs < const_cell + """ + with comp.comb_group(name): + lt.left = lhs + lt.right = const_cell.out + + # This appears to be unused. Brilliant. # TODO (griffin): Double check that this is unused and, if so, remove it. def gen_constant_cell( @@ -562,8 +590,7 @@ def generate_fp_pow_full( comp.input("base", width) comp.input("exp_value", width) comp.output("out", width) - lt = comp.lt(width, "lt", is_signed) - + lt = comp.cell("lt", Stdlib.op("lt", width, is_signed)) div = comp.cell( "div", Stdlib.fixed_point_op( @@ -605,13 +632,7 @@ def generate_fp_pow_full( ) gen_reverse_sign(comp, "rev_base_sign", new_base_reg, mult, const_neg_one), gen_reverse_sign(comp, "rev_res_sign", res, mult, const_neg_one), - - base_lt_zero = comp.lt_use( - comp.this().base, - const_zero.out, - width, - is_signed, - ) + gen_comb_lt(comp, "base_lt_zero", comp.this().base, lt, const_zero), new_exp_val = comp.reg("new_exp_val", width) e = comp.comp_instance("e", "exp", check_undeclared=False) @@ -628,29 +649,48 @@ def generate_fp_pow_full( with comp.continuous: comp.this().out = res.out - write_to_base_reg = comp.reg_store( - new_base_reg, comp.this().base, "write_to_base_reg" - ) - store_old_reg_val = comp.reg_store( - stored_base_reg, new_base_reg.out, "store_old_reg_val" - ) - write_e_to_res = comp.reg_store(res, e.out, "write_e_to_res") + with comp.group("write_to_base_reg") as write_to_base_reg: + new_base_reg.write_en = 1 + new_base_reg.in_ = comp.this().base + write_to_base_reg.done = new_base_reg.done + + with comp.group("store_old_reg_val") as store_old_reg_val: + stored_base_reg.write_en = 1 + stored_base_reg.in_ = new_base_reg.out + store_old_reg_val.done = stored_base_reg.done + + with comp.group("write_e_to_res") as write_e_to_res: + res.write_en = 1 + res.in_ = e.out + write_e_to_res.done = res.done gen_reciprocal(comp, "set_base_reciprocal", new_base_reg, div, const_one) gen_reciprocal(comp, "set_res_reciprocal", res, div, const_one), - base_lt_one = comp.lt_use(stored_base_reg.out, const_one.out, width, is_signed) + gen_comb_lt( + comp, + "base_lt_one", + stored_base_reg.out, + lt, + const_one, + ) - base_reciprocal = if_with(base_lt_one, comp.get_group("set_base_reciprocal")) + base_reciprocal = if_with( + CellAndGroup(lt, comp.get_group("base_lt_one")), + comp.get_group("set_base_reciprocal"), + ) - res_reciprocal = if_with(base_lt_one, comp.get_group("set_res_reciprocal")) + res_reciprocal = if_with( + CellAndGroup(lt, comp.get_group("base_lt_one")), + comp.get_group("set_res_reciprocal"), + ) if is_signed: base_rev = if_with( - base_lt_zero, + CellAndGroup(lt, comp.get_group("base_lt_zero")), comp.get_group("rev_base_sign"), ) res_rev = if_with( - base_lt_zero, + CellAndGroup(lt, comp.get_group("base_lt_zero")), comp.get_group("rev_res_sign"), ) pre_process = [base_rev, store_old_reg_val, base_reciprocal] @@ -701,9 +741,23 @@ def build_base_not_e(degree, width, int_width, is_signed) -> Program: ret = main.mem_d1("ret", width, 1, 1, is_external=True) f = main.comp_instance("f", "fp_pow_full") - read_base = main.mem_load_std_d1(b, 0, base_reg, "read_base") - read_exp = main.mem_load_std_d1(x, 0, exp_reg, "read_exp") - write_to_memory = main.mem_store_std_d1(ret, 0, f.out, "write_to_memory") + with main.group("read_base") as read_base: + b.addr0 = 0 + base_reg.in_ = b.read_data + base_reg.write_en = 1 + read_base.done = base_reg.done + + with main.group("read_exp") as read_exp: + x.addr0 = 0 + exp_reg.in_ = x.read_data + exp_reg.write_en = 1 + read_exp.done = exp_reg.done + + with main.group("write_to_memory") as write_to_memory: + ret.addr0 = 0 + ret.write_en = 1 + ret.write_data = f.out + write_to_memory.done = ret.done main.control += [ read_base, @@ -742,7 +796,11 @@ def build_base_is_e(degree, width, int_width, is_signed) -> Program: t.write_en = 1 init.done = t.done - write_to_memory = main.mem_store_std_d1(ret, 0, e.out, "write_to_memory") + with main.group("write_to_memory") as write_to_memory: + ret.addr0 = 0 + ret.write_en = 1 + ret.write_data = e.out + write_to_memory.done = ret.done main.control += [ init, From 7ff92135d5f76f2089d338a147943b7a91a4c080 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Mon, 21 Aug 2023 16:20:55 -0400 Subject: [PATCH 038/189] Builder: use register to make the queue nicer (#1681) --- calyx-py/calyx/builder.py | 38 +++++++++++++++ calyx-py/calyx/queue_call.py | 89 ++++++++++++++++-------------------- 2 files changed, 77 insertions(+), 50 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 005e2c3ff..b3eab910b 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -600,6 +600,44 @@ def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): sub_group.done = ans_reg.done return sub_group, ans_reg + def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Adds wiring into component `self` to compute `left` == `right` + and store it in `ans_reg`. + 1. Within component `self`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes equality. + 3. Puts the values of `left` and `right` into `cell`. + 4. Then puts the answer of the computation into `ans_reg`. + 4. Returns the equality group and the register. + """ + eq_cell = self.eq(width, cellname) + ans_reg = ans_reg or self.reg(f"reg_{cellname}", 1) + with self.group(f"{cellname}_group") as eq_group: + eq_cell.left = left + eq_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = eq_cell.out + eq_group.done = ans_reg.done + return eq_group, ans_reg + + def neq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Adds wiring into component `self` to compute `left` != `right` + and store it in `ans_reg`. + 1. Within component `self`, creates a group called `cellname`_group. + 2. Within `group`, create a cell `cellname` that computes inequality. + 3. Puts the values of `left` and `right` into `cell`. + 4. Then puts the answer of the computation into `ans_reg`. + 4. Returns the inequality group and the register. + """ + neq_cell = self.neq(width, cellname) + ans_reg = ans_reg or self.reg(f"reg_{cellname}", 1) + with self.group(f"{cellname}_group") as neq_group: + neq_cell.left = left + neq_cell.right = right + ans_reg.write_en = 1 + ans_reg.in_ = neq_cell.out + neq_group.done = ans_reg.done + return neq_group, ans_reg + @dataclass(frozen=True) class CellAndGroup: diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index 9af773d74..f1c37d8be 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -5,34 +5,6 @@ ANS_MEM_LEN = 10 -def insert_raise_err_if_i_eq_max_cmds(prog): - """Inserts a the component `raise_err_if_i_eq_MAX_CMDS` into the program. - - It has: - - one input, `i`. - - one ref register, `err`. - - If `i` equals MAX_CMDS, it raises the `err` flag. - """ - raise_err_if_i_eq_max_cmds: cb.ComponentBuilder = prog.component( - "raise_err_if_i_eq_MAX_CMDS" - ) - i = raise_err_if_i_eq_max_cmds.input("i", 32) - err = raise_err_if_i_eq_max_cmds.reg("err", 1, is_ref=True) - - i_eq_max_cmds = raise_err_if_i_eq_max_cmds.eq_use(i, MAX_CMDS, 32) - raise_err = raise_err_if_i_eq_max_cmds.reg_store(err, 1, "raise_err") - - raise_err_if_i_eq_max_cmds.control += [ - cb.if_with( - i_eq_max_cmds, - raise_err, - ) - ] - - return raise_err_if_i_eq_max_cmds - - def insert_main(prog, queue): """Inserts the component `main` into the program. This will be used to `invoke` the component `queue` and feed it a list of commands. @@ -67,15 +39,12 @@ def insert_main(prog, queue): # The two components we'll use: queue = main.cell("myqueue", queue) - raise_err_if_i_eq_max_cmds = main.cell( - "raise_err_if_i_eq_MAX_CMDS", insert_raise_err_if_i_eq_max_cmds(prog) - ) # We will use the `invoke` method to call the `queue` component. # The queue component takes two inputs by reference and one input directly. # The two `ref` inputs: err = main.reg("err", 1) # A flag to indicate an error - ans = main.reg("ans", 32) # A memory to hold the answer of a pop + ans = main.reg("ans", 32) # A memory to hold the answer of a pop or peek # We will set up a while loop that runs over the command list, relaying # the commands to the `queue` component. @@ -88,7 +57,6 @@ def insert_main(prog, queue): incr_i = main.incr(i, 32) # i++ incr_j = main.incr(j, 32) # j++ - err_eq_0 = main.eq_use(err.out, 0, 1) # is `err` flag down? cmd_le_1 = main.le_use(cmd.out, 1, 2) # cmd <= 1 read_cmd = main.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") @@ -100,16 +68,35 @@ def insert_main(prog, queue): ) write_ans = main.mem_store_seq_d1(ans_mem, j.out, ans.out, "write_ans") + loop_goes_on = main.reg( + "loop_goes_on", 1 + ) # A flag to indicate whether the loop should continue + update_err_is_down, _ = main.eq_store_in_reg( + err.out, + 0, + "err_is_down", + 1, + loop_goes_on + # Does the `err` flag say that the loop should continue? + ) + update_i_neq_15, _ = main.neq_store_in_reg( + i.out, + cb.const(32, 15), + "i_neq_15", + 32, + loop_goes_on + # Does the `i` index say that the loop should continue? + ) + main.control += [ - cb.while_with( - err_eq_0, # Run while the `err` flag is down + update_err_is_down, + cb.while_( + loop_goes_on.out, # Run while the `err` flag is down [ read_cmd, - write_cmd_to_reg, - # `cmd := commands[i]` + write_cmd_to_reg, # `cmd := commands[i]` read_value, - write_value_to_reg, - # `value := values[i]` + write_value_to_reg, # `value := values[i]` cb.invoke( # Invoke the queue. queue, in_cmd=cmd.out, @@ -117,19 +104,21 @@ def insert_main(prog, queue): ref_ans=ans, ref_err=err, ), - cb.if_with( # If it was a pop or a peek, write ans to the answer list - cmd_le_1, - [ # AM: I'd like to have an additional check hereL - # if err flag comes back raised, - # we do not perform this write_ans or this incr_j - write_ans, - incr_j, + update_err_is_down, # Does `err` say that the loop should be broken? + cb.if_( + loop_goes_on.out, # If the loop is not meant to be broken... + [ + cb.if_with( + cmd_le_1, # If the command was a pop or peek, + [ + write_ans, # Write the answer to the answer list + incr_j, # And increment the answer index. + ], + ), + incr_i, # Increment the command index + update_i_neq_15, # Did this increment make us need to break? ], ), - incr_i, # Increment the command index - cb.invoke( # If i = MAX_CMDS, raise error flag - raise_err_if_i_eq_max_cmds, in_i=i.out, ref_err=err - ), # AM: hella hacky ], ), ] From 6eaee6c59651ce5076c0384f2602c9bf0f527d27 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 22 Aug 2023 15:23:22 +0530 Subject: [PATCH 039/189] Include the primitive implements with `calyx` binary (#1678) * Include the primitive implements with `calyx` binary * add build script to install and bundle primitives * update MLIR backend tests * specify library location for tests * docs * link to make cargo package happy --- CHANGELOG.md | 3 ++ Cargo.lock | 5 ++ Cargo.toml | 14 ++++- calyx-stdlib/Cargo.toml | 16 ++++++ calyx-stdlib/primitives | 1 + calyx-stdlib/src/lib.rs | 3 ++ calyx-stdlib/src/primitives.rs | 40 +++++++++++++++ docs/SUMMARY.md | 2 +- docs/compiler-as-library.md | 17 +++++- runt.toml | 74 +++++++++++---------------- src/backend/mlir.rs | 39 +++++++++----- src/build.rs | 43 ++++++++++++++++ src/cmdline.rs | 6 ++- tests/backend/mlir/attributes.expect | 3 +- tests/backend/mlir/no-guards.expect | 3 +- tests/backend/mlir/simple.expect | 3 +- tests/backend/mlir/with-guards.expect | 3 +- 17 files changed, 205 insertions(+), 70 deletions(-) create mode 100644 calyx-stdlib/Cargo.toml create mode 120000 calyx-stdlib/primitives create mode 100644 calyx-stdlib/src/lib.rs create mode 100644 calyx-stdlib/src/primitives.rs create mode 100644 src/build.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 09da00bdd..fa9d91ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ - `inline` pass supports inlining `ref` cells - `comb-prop`: disable rewrite from `wire.in = port` when the output of a wire is read. - BREAKING: Remove `PortDef::into()` because it makes it easy to miss copying attributes. +- The `calyx` binary ships all the primitives and therefore self-contained now. + - Add the `calyx-stdlib` package + - Add a new build script that installs primitives when the package is installed. ## 0.4.0 diff --git a/Cargo.lock b/Cargo.lock index e2b818658..92dbe4d51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,7 @@ dependencies = [ "calyx-frontend", "calyx-ir", "calyx-opt", + "calyx-stdlib", "calyx-utils", "criterion", "csv", @@ -257,6 +258,10 @@ dependencies = [ "smallvec", ] +[[package]] +name = "calyx-stdlib" +version = "0.4.0" + [[package]] name = "calyx-utils" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index b9afb82fb..247ea4832 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "calyx-utils", "calyx-opt", "calyx-frontend", + "calyx-stdlib", "interp", "web/rust", "tools/data_gen", @@ -54,7 +55,6 @@ features = ["matrix_graph"] [package] name = "calyx" -build = false default-run = "calyx" version.workspace = true edition.workspace = true @@ -67,6 +67,7 @@ homepage.workspace = true categories.workspace = true readme.workspace = true rust-version.workspace = true +build = "src/build.rs" [[bin]] name = "calyx" @@ -78,7 +79,16 @@ path = "src/futil.rs" [features] default = [] -serialize = ["dep:serde_with", "calyx-ir/serialize", "dep:serde_sexpr", "serde/rc"] +serialize = [ + "dep:serde_with", + "calyx-ir/serialize", + "dep:serde_sexpr", + "serde/rc", +] + +[build-dependencies] +calyx-stdlib = { path = "calyx-stdlib", version = "0.4.0" } + [dependencies] atty.workspace = true diff --git a/calyx-stdlib/Cargo.toml b/calyx-stdlib/Cargo.toml new file mode 100644 index 000000000..328a07776 --- /dev/null +++ b/calyx-stdlib/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "calyx-stdlib" +version.workspace = true +edition.workspace = true +description.workspace = true +authors.workspace = true +license-file.workspace = true +keywords.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +readme.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/calyx-stdlib/primitives b/calyx-stdlib/primitives new file mode 120000 index 000000000..3a0922530 --- /dev/null +++ b/calyx-stdlib/primitives @@ -0,0 +1 @@ +../primitives \ No newline at end of file diff --git a/calyx-stdlib/src/lib.rs b/calyx-stdlib/src/lib.rs new file mode 100644 index 000000000..e930bb068 --- /dev/null +++ b/calyx-stdlib/src/lib.rs @@ -0,0 +1,3 @@ +mod primitives; + +pub use primitives::{COMPILE_LIB, KNOWN_LIBS}; diff --git a/calyx-stdlib/src/primitives.rs b/calyx-stdlib/src/primitives.rs new file mode 100644 index 000000000..9616973ca --- /dev/null +++ b/calyx-stdlib/src/primitives.rs @@ -0,0 +1,40 @@ +//! Inlcude all of the base primitives defined by the Calyx compiler. + +/// A macro that defines an array that maps the file paths to the contents. +/// Usage: +/// ``` +/// load_prims! { CORE, "core.futil", "core.sv" } +/// ``` +/// This will define the variables `CORE_FUTIL` and `CORE_SV` and the array +/// `CORE`. +macro_rules! load_prims { + ($name:ident, $futil_path:literal, $sv_path:literal) => { + pub const $name: [(&str, &str); 2] = [ + ( + $futil_path, + include_str!(concat!("../primitives/", $futil_path)), + ), + ($sv_path, include_str!(concat!("../primitives/", $sv_path))), + ]; + }; +} + +load_prims! { CORE, "core.futil", "core.sv" } +load_prims! { BINARY_OPERATORS, "binary_operators.futil", "binary_operators.sv" } +load_prims! { MATH, "math.futil", "math.sv" } +load_prims! { MEMORIES, "memories.futil", "memories.sv" } +load_prims! { PIPELINED, "pipelined.futil", "pipelined.sv" } +load_prims! { SYNC, "sync.futil", "sync.sv" } + +/// The core primitive in the compiler +pub const COMPILE_LIB: (&str, &str) = + ("compile.futil", include_str!("../primitives/compile.futil")); + +pub const KNOWN_LIBS: [(&str, [(&str, &str); 2]); 6] = [ + ("core", CORE), + ("binary_operators", BINARY_OPERATORS), + ("math", MATH), + ("memories", MEMORIES), + ("pipelined", PIPELINED), + ("sync", SYNC), +]; diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 95c7219bf..76595ae44 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -24,7 +24,7 @@ - [Resource Estimation](./fud/resource-estimation.md) - [The Calyx Interpreter](./interpreter.md) -# Compile Development Guide +# Compiler Development Guide - [The Calyx Compiler](./compiler.md) - [Adding a New Pass](./new-pass.md) diff --git a/docs/compiler-as-library.md b/docs/compiler-as-library.md index f67a010b4..b4336f32c 100644 --- a/docs/compiler-as-library.md +++ b/docs/compiler-as-library.md @@ -7,6 +7,21 @@ The `calyx` implements the compiler driver and plumbs together all the other cra You mostly likely want to include the `calyx-opt` crate if you're working passes or just the `calyx-ir` crate if you're working with the IR. You'll also need `calyx-frontend` and `calyx-utils` if you're parsing frontend code. +## Building the `calyx` Binary + +The [`calyx` binary][calyx-crate] is published using Rust's crates.io repository. It provides the [compiler interface](./compiler.md) which can be used without requiring the user to build the compiler from source. The `calyx` binary also ships all its [primitives library][prims-lib] which is done through a somewhat complex bootstrapping process (see [#1678](https://github.com/cucapra/calyx/pull/1678)) + +1. The [`calyx-stdlib`][calyx-stdlib] package pulls in the sources of all the primitives using the Rust `include_str!` macro. +2. The `calyx` binary defines a build script that depends on `calyx-stdlib` as a build dependency. +3. During build time, the script loads the string representation of all the primitives files and writes them to `$OUT_DIR/primitives`. The `OUT_DIR` environment variable is defined by `cargo`. +4. If (3) succeeds, the build scripts defines the `CALYX_PRIMITIVES_LIB` environment variable which is used when compiling the `calyx` crate. +5. During compilation, `calyx` embeds the value of this environment variable as the default argument to the `-l` flag. If the variable is not defined, the default value of the `-l` flag is `.`. + +Users of the `calyx` binary can still specify a value for `-l` to override the default primitives file. For example, the `fud` configuration for the `calyx` stage override the value of `-l` to the location of the Calyx repo. + [crates]: https://docs.rs/releases/search?query=calyx -[opt-ex]: https://docs.rs/calyx-opt/0.2.1/calyx_opt/ \ No newline at end of file +[opt-ex]: https://docs.rs/calyx-opt/0.2.1/calyx_opt/ +[calyx-crate]: https://crates.io/crates/calyx +[prims-lib]: ./libraries/core.md +[calyx-stdlib]: https://crates.io/crates/calyx-stdlib \ No newline at end of file diff --git a/runt.toml b/runt.toml index 247947a14..dec851872 100644 --- a/runt.toml +++ b/runt.toml @@ -4,30 +4,28 @@ ver = "0.4.0" ## Test each pass in isolation. Gets the pass flags from a comment on the first line of the file [[tests]] name = "[core] passes" -paths = [ - "tests/passes/**/*.futil", -] +paths = ["tests/passes/**/*.futil"] # gets the pass flags a comment on the first line of the test file cmd = """ flags="$(head -n 1 {} | cut -c 3-) -m file" -./target/debug/calyx {} $flags \ +./target/debug/calyx {} $flags -l . \ | sed 's/extern \".*\\(calyx\\/.*\\)\"/extern \"\\/\\1\"/' """ [[tests]] name = "[core] parsing" # Round-tripping from the compiler should not change anything. -paths = [ "./tests/parsing/*.expect" ] +paths = ["./tests/parsing/*.expect"] cmd = """ -./target/debug/calyx {} -m file -p none +./target/debug/calyx {} -m file -p none -l . """ [[tests]] name = "[core] import" # Round-tripping from the compiler should not change anything. -paths = [ "./tests/import/a.futil" ] +paths = ["./tests/import/a.futil"] cmd = """ -./target/debug/calyx {} -p none \ +./target/debug/calyx {} -p none -l . \ | sed 's/extern \".*\\(calyx\\/.*\\)\"/extern \"\\/\\1\"/' """ @@ -38,32 +36,32 @@ name = "[core] errors" paths = [ "tests/errors/*.futil", "tests/errors/papercut/*.futil", - "tests/errors/parser/*.futil" + "tests/errors/parser/*.futil", ] cmd = """ -./target/debug/calyx {} -p well-formed -p papercut -p synthesis-papercut +./target/debug/calyx {} -p well-formed -p papercut -p synthesis-papercut -l . """ [[tests]] name = "[core] futil examples" paths = ["examples/futil/*.futil"] cmd = """ -./target/debug/calyx {} -m file -d tdst +./target/debug/calyx {} -m file -d tdst -l . """ ##### Backend Tests ##### [[tests]] name = "[core] backends" -paths = [ "tests/backend/**/*.futil" ] +paths = ["tests/backend/**/*.futil"] cmd = """ flags=$(head -n 1 {} | cut -c 3-) -./target/debug/calyx {} $flags +./target/debug/calyx {} $flags -l . """ ##### Frontend Tests ##### [[tests]] name = "[frontend] dahlia" -paths = [ "tests/frontend/dahlia/*.fuse" ] +paths = ["tests/frontend/dahlia/*.fuse"] cmd = """ fud e {} --to calyx -q \ -s calyx.exec './target/debug/calyx' \ @@ -72,14 +70,14 @@ fud e {} --to calyx -q \ [[tests]] name = "[frontend] systolic array" -paths = [ "tests/frontend/systolic/array-*.systolic" ] +paths = ["tests/frontend/systolic/array-*.systolic"] cmd = """ ./frontends/systolic-lang/gen-systolic.py {} """ [[tests]] name = "[frontend] NTT pipeline generation" -paths = [ "tests/frontend/ntt-pipeline/*.txt" ] +paths = ["tests/frontend/ntt-pipeline/*.txt"] cmd = """ fud e --from ntt {} --to calyx -q """ @@ -125,7 +123,7 @@ name = "correctness dynamic" paths = [ "tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil", - "tests/correctness/sync/*.futil" + "tests/correctness/sync/*.futil", ] cmd = """ fud exec --from calyx --to jq \ @@ -142,10 +140,7 @@ timeout = 120 [[tests]] name = "correctness static timing" -paths = [ - "tests/correctness/*.futil", - "tests/correctness/ref-cells/*.futil" -] +paths = ["tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil"] cmd = """ fud exec --from calyx --to jq \ --through verilog \ @@ -161,9 +156,7 @@ timeout = 120 # Variants of the above but for `--nested` (non-ANF Verilog emission) mode. [[tests]] name = "correctness nested" -paths = [ - "tests/correctness/*.futil", -] +paths = ["tests/correctness/*.futil"] cmd = """ fud exec --from calyx --to jq \ --through verilog \ @@ -181,9 +174,7 @@ timeout = 120 # See: https://github.com/cucapra/calyx/discussions/1331 [[tests]] name = "correctness static scheduling" -paths = [ - "tests/correctness/static/*.futil" -] +paths = ["tests/correctness/static/*.futil"] cmd = """ fud exec --from calyx --to jq \ --through verilog \ @@ -202,7 +193,7 @@ timeout = 120 name = "correctness static control" paths = [ "tests/correctness/static-control/*.futil", - "tests/correctness/group-static-promotion/*.futil" + "tests/correctness/group-static-promotion/*.futil", ] cmd = """ fud exec --from calyx --to jq \ @@ -221,7 +212,7 @@ name = "numeric types correctness and parsing" paths = [ "tests/correctness/numeric-types/parsing/*.futil", "tests/correctness/numeric-types/bitnum/*.futil", - "tests/correctness/numeric-types/fixed-point/*.futil" + "tests/correctness/numeric-types/fixed-point/*.futil", ] cmd = """ fud exec --from calyx --to jq \ @@ -234,9 +225,7 @@ fud exec --from calyx --to jq \ [[tests]] name = "correctness test of static islands without static promotion" -paths = [ - "tests/correctness/static-islands/*.futil", -] +paths = ["tests/correctness/static-islands/*.futil"] cmd = """ fud exec --from calyx --to jq \ --through dat \ @@ -249,9 +238,7 @@ fud exec --from calyx --to jq \ [[tests]] name = "[frontend] tcam testing" -paths = [ - "tests/correctness/tcam/*.futil" -] +paths = ["tests/correctness/tcam/*.futil"] cmd = """ fud exec --from calyx --to jq \ --through verilog \ @@ -263,7 +250,7 @@ fud exec --from calyx --to jq \ [[tests]] name = "[frontend] systolic array PE correctness" -paths = [ "tests/correctness/systolic/pe/*.systolic" ] +paths = ["tests/correctness/systolic/pe/*.systolic"] cmd = """ fud e --from systolic --to jq \ --through verilog \ @@ -276,7 +263,10 @@ fud e --from systolic --to jq \ [[tests]] name = "[frontend] systolic array output correctness" -paths = [ "tests/correctness/systolic/output/*.systolic", "tests/correctness/systolic/leaky-relu/*.systolic" ] +paths = [ + "tests/correctness/systolic/output/*.systolic", + "tests/correctness/systolic/leaky-relu/*.systolic", +] cmd = """ fud e --from systolic --to dat \ --through verilog \ @@ -287,14 +277,14 @@ fud e --from systolic --to dat \ [[tests]] name = "[frontend] NTT pipeline correctness" -paths = [ "tests/correctness/ntt-pipeline/*.txt" ] +paths = ["tests/correctness/ntt-pipeline/*.txt"] cmd = """ fud e --from ntt {} --through verilog --to dat -s verilog.data {}.data -q """ [[tests]] name = "exp correctness" -paths = [ "tests/correctness/exp/*.txt" ] +paths = ["tests/correctness/exp/*.txt"] cmd = """ python3 calyx-py/calyx/gen_exp.py {} |\ fud e --from calyx --to dat --through verilog -s verilog.data {}.data -q @@ -302,7 +292,7 @@ fud e --from calyx --to dat --through verilog -s verilog.data {}.data -q [[tests]] name = "[frontend] mrxl correctness" -paths = [ "frontends/mrxl/test/*.mrxl" ] +paths = ["frontends/mrxl/test/*.mrxl"] expect_dir = "frontends/mrxl/test/expect/simulate_out/" cmd = """ fud e --from mrxl {} \ @@ -328,9 +318,7 @@ fud e -q {} --from relay --to jq \ ## Tests errors that occur at runtime [[tests]] name = "runtime errors" -paths = [ - "tests/errors/runtime/*.futil" -] +paths = ["tests/errors/runtime/*.futil"] cmd = """ fud exec -s calyx.exec './target/debug/calyx' \ -s verilog.cycle_limit 500 \ diff --git a/src/backend/mlir.rs b/src/backend/mlir.rs index 713fcb22a..20c76f4d8 100644 --- a/src/backend/mlir.rs +++ b/src/backend/mlir.rs @@ -24,7 +24,11 @@ impl Backend for MlirBackend { ) -> calyx_utils::CalyxResult<()> { let res = { let f = &mut file.get_write(); - writeln!(f, "calyx.program \"{}\" {{\n", ctx.entrypoint)?; + writeln!( + f, + "module attributes {{calyx.entrypoint = \"{}\" }} {{", + ctx.entrypoint + )?; ctx.components.iter().try_for_each(|comp| { Self::write_component(comp, f)?; writeln!(f) @@ -130,11 +134,13 @@ impl MlirBackend { write!(f, "}}") } + /// Write the operation corresponding to the primitve and return true if the + /// operation accepts attributes. pub fn write_prototype_sig( cell_type: &ir::CellType, cell_name: S, f: &mut F, - ) -> io::Result<()> { + ) -> io::Result { let cell_name = cell_name.to_string(); match cell_type { ir::CellType::Primitive { @@ -148,7 +154,7 @@ impl MlirBackend { .collect(); match name.as_ref() { "std_reg" => { - write!(f, "calyx.register @{}", cell_name) + write!(f, "calyx.register @{}", cell_name)? } "std_mem_d1" => write!( f, @@ -157,7 +163,7 @@ impl MlirBackend { bind["SIZE"], bind["WIDTH"], bind["IDX_SIZE"] - ), + )?, "std_mem_d2" => write!( f, "calyx.memory @{} <[{}, {}] x {}> [{}, {}]", @@ -167,7 +173,7 @@ impl MlirBackend { bind["WIDTH"], bind["D0_IDX_SIZE"], bind["D1_IDX_SIZE"] - ), + )?, "std_mem_d3" => write!( f, "calyx.memory @{} <[{}, {}, {}] x {}> [{}, {}, {}]", @@ -179,7 +185,7 @@ impl MlirBackend { bind["D0_IDX_SIZE"], bind["D1_IDX_SIZE"], bind["D2_IDX_SIZE"] - ), + )?, "std_mem_d4" => write!( f, "calyx.memory @{} <[{}, {}, {}, {}] x {}> [{}, {}, {}, {}]", @@ -193,18 +199,20 @@ impl MlirBackend { bind["D1_IDX_SIZE"], bind["D2_IDX_SIZE"], bind["D3_IDX_SIZE"] - ), - prim => write!(f, "calyx.{} @{}", prim, cell_name) + )?, + prim => write!(f, "calyx.{} @{}", prim, cell_name)?, } } ir::CellType::Component { name } => { - write!(f, "calyx.instance @{} of @{}", cell_name, name) + write!(f, "calyx.instance @{} of @{}", cell_name, name)?; } ir::CellType::Constant { val, .. } => { - write!(f, "hw.constant {}", val) + write!(f, "hw.constant {}", val)?; + return Ok(false); } - _ => Ok(()), - } + _ => (), + }; + Ok(true) } /// Format and write a cell. @@ -222,8 +230,11 @@ impl MlirBackend { .collect::>() .join(", "); write!(f, "{} = ", all_ports)?; - Self::write_prototype_sig(&cell.prototype, name.as_str(), f)?; - write!(f, "{}", Self::format_attributes(&cell.attributes))?; + let supports_attrs = + Self::write_prototype_sig(&cell.prototype, name.as_str(), f)?; + if supports_attrs { + write!(f, "{}", Self::format_attributes(&cell.attributes))?; + } write!(f, " : ")?; let all_port_widths = cell .ports() diff --git a/src/build.rs b/src/build.rs new file mode 100644 index 000000000..3a916d1f6 --- /dev/null +++ b/src/build.rs @@ -0,0 +1,43 @@ +use std::fs; +use std::io::Result; +use std::path; + +fn write_primitive() -> Result { + // Get the OUT_DIR environment variable from Cargo. + let base: path::PathBuf = std::env::var("OUT_DIR").unwrap().into(); + let mut prims = base.clone(); + prims.push("primitives"); + fs::create_dir_all(&prims)?; + // Write the compile primitives + for (loc, src) in calyx_stdlib::KNOWN_LIBS + .into_iter() + .flat_map(|(_, info)| info) + .chain(Some(calyx_stdlib::COMPILE_LIB)) + { + let mut path = prims.clone(); + path.push(loc); + fs::write(path, src)?; + } + Ok(base) +} + +// The build script does not fail +fn main() { + println!("cargo:rerun-if-changed=src/build.rs"); + println!("cargo:rerun-if-changed=src/cmdline.rs"); + match write_primitive() { + Ok(p) => { + // The build succeeded. We're going to define the CALYX_PRIMITVE_DIR environment variable + // so that it can be used by the compiler. + println!( + "cargo:rustc-env=CALYX_PRIMITIVES_DIR={}", + p.to_string_lossy() + ); + } + Err(e) => { + println!( + "cargo:warning=Failed to create the `primitives` folder. Importing `primitives` will require passing an explicit `-l` when running the Calyx compiler. Error: {e}", + ); + } + } +} diff --git a/src/cmdline.rs b/src/cmdline.rs index a8f936c44..b5da25720 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -25,7 +25,11 @@ pub struct Opts { pub output: OutputFile, /// path to the primitives library - #[argh(option, short = 'l', default = "Path::new(\".\").into()")] + #[argh( + option, + short = 'l', + default = "Path::new(option_env!(\"CALYX_PRIMITIVES_DIR\").unwrap_or(\".\")).into()" + )] pub lib_path: PathBuf, /// compilation mode diff --git a/tests/backend/mlir/attributes.expect b/tests/backend/mlir/attributes.expect index 41703ed49..07f2a7c68 100644 --- a/tests/backend/mlir/attributes.expect +++ b/tests/backend/mlir/attributes.expect @@ -1,5 +1,4 @@ -calyx.program "main" { - +module attributes {calyx.entrypoint = "main" } { calyx.component @main(%in: i32 {foo=32}, %go: i1 {static=10, go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i32 {static=0}, %done: i1 {done=1}) { %r.in, %r.write_en, %r.clk, %r.reset, %r.out, %r.done = calyx.register @r {precious=1} : i32, i1, i1, i1, i32, i1 %le.left, %le.right, %le.out = calyx.std_le @le {bar=32} : i32, i32, i1 diff --git a/tests/backend/mlir/no-guards.expect b/tests/backend/mlir/no-guards.expect index bd1e4f559..33ec7bdba 100644 --- a/tests/backend/mlir/no-guards.expect +++ b/tests/backend/mlir/no-guards.expect @@ -1,5 +1,4 @@ -calyx.program "main" { - +module attributes {calyx.entrypoint = "main" } { calyx.component @A(%in: i8, %go: i1, %clk: i1, %reset: i1, %go0: i1 {go=1}, %clk0: i1 {clk=1}, %reset0: i1 {reset=1}) -> (%out: i8, %done: i1, %done0: i1 {done=1}) { calyx.wires { } diff --git a/tests/backend/mlir/simple.expect b/tests/backend/mlir/simple.expect index 2f84c1a2b..a20f2c617 100644 --- a/tests/backend/mlir/simple.expect +++ b/tests/backend/mlir/simple.expect @@ -1,5 +1,4 @@ -calyx.program "main" { - +module attributes {calyx.entrypoint = "main" } { calyx.component @main(%go: i1 {go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i1, %done: i1 {done=1}) { %r1.in, %r1.write_en, %r1.clk, %r1.reset, %r1.out, %r1.done = calyx.register @r1 : i1, i1, i1, i1, i1, i1 %_1_1.out = hw.constant 1 : i1 diff --git a/tests/backend/mlir/with-guards.expect b/tests/backend/mlir/with-guards.expect index 9075bb761..d32a0bc29 100644 --- a/tests/backend/mlir/with-guards.expect +++ b/tests/backend/mlir/with-guards.expect @@ -1,5 +1,4 @@ -calyx.program "main" { - +module attributes {calyx.entrypoint = "main" } { calyx.component @A(%in: i8, %go: i1 {go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i8, %flag: i1, %done: i1 {done=1}) { %_1_1.out = hw.constant 1 : i1 calyx.wires { From f8de521f1248ac675f200210a45fdb041b9390f4 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 22 Aug 2023 16:28:21 +0530 Subject: [PATCH 040/189] Remove the `futil` binary (#1685) --- CHANGELOG.md | 1 + Cargo.toml | 5 ----- src/futil.rs | 8 -------- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 src/futil.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index fa9d91ee8..faf31510b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - `inline` pass supports inlining `ref` cells - `comb-prop`: disable rewrite from `wire.in = port` when the output of a wire is read. - BREAKING: Remove `PortDef::into()` because it makes it easy to miss copying attributes. +- Remove the `futil` binary. - The `calyx` binary ships all the primitives and therefore self-contained now. - Add the `calyx-stdlib` package - Add a new build script that installs primitives when the package is installed. diff --git a/Cargo.toml b/Cargo.toml index 247ea4832..f1cfed8ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,10 +73,6 @@ build = "src/build.rs" name = "calyx" path = "src/main.rs" -[[bin]] -name = "futil" -path = "src/futil.rs" - [features] default = [] serialize = [ @@ -89,7 +85,6 @@ serialize = [ [build-dependencies] calyx-stdlib = { path = "calyx-stdlib", version = "0.4.0" } - [dependencies] atty.workspace = true itertools.workspace = true diff --git a/src/futil.rs b/src/futil.rs deleted file mode 100644 index 7229f9ff9..000000000 --- a/src/futil.rs +++ /dev/null @@ -1,8 +0,0 @@ -use calyx::driver; -use calyx_utils::CalyxResult; - -fn main() -> CalyxResult<()> { - driver::run_compiler()?; - log::warn!("The `futil` binary is deprecated. Please use `calyx` instead."); - Ok(()) -} From 0dbdc644f227977e7b948a45a07c7e36cc50da4a Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:08:16 -0400 Subject: [PATCH 041/189] Builder: perform op and store in reg (#1682) * Pushing what I'd like to run * Push the futil file too * Stash * Look running as desired! * Nix extra component * Tidy comments, var names * Lift op-then-store into a helper * width of reg for eq and neq * Nits --- calyx-py/calyx/builder.py | 49 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index b3eab910b..4e7ecd58f 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -576,29 +576,42 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): load_grp.done = ans.done return load_grp - def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): - """Inserts wiring into `self` to perform `reg := left + right`.""" - add_cell = self.add(width, cellname) + def op_store_in_reg(self, op_cell, left, right, cellname, width, ans_reg=None): + """Inserts wiring into `self` to perform `reg := left op right`, + where `op_cell`, a Cell that performs some `op`, is provided. + """ ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) - with self.group(f"{cellname}_group") as adder_group: - add_cell.left = left - add_cell.right = right + with self.group(f"{cellname}_group") as op_group: + op_cell.left = left + op_cell.right = right ans_reg.write_en = 1 - ans_reg.in_ = add_cell.out - adder_group.done = ans_reg.done - return adder_group, ans_reg + ans_reg.in_ = op_cell.out + op_group.done = ans_reg.done + return op_group, ans_reg + + def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Inserts wiring into `self` to perform `reg := left + right`.""" + return self.op_store_in_reg( + self.add(width, cellname), left, right, cellname, width, ans_reg + ) def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): """Inserts wiring into `self` to perform `reg := left - right`.""" - sub_cell = self.sub(width, cellname) - ans_reg = ans_reg or self.reg(f"reg_{cellname}", width) - with self.group(f"{cellname}_group") as sub_group: - sub_cell.left = left - sub_cell.right = right - ans_reg.write_en = 1 - ans_reg.in_ = sub_cell.out - sub_group.done = ans_reg.done - return sub_group, ans_reg + return self.op_store_in_reg( + self.sub(width, cellname), left, right, cellname, width, ans_reg + ) + + def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Adds wiring into `self to perform `reg := left == right`.""" + return self.op_store_in_reg( + self.eq(width, cellname), left, right, cellname, 1, ans_reg + ) + + def neq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + """Adds wiring into `self to perform `reg := left != right`.""" + return self.op_store_in_reg( + self.neq(width, cellname), left, right, cellname, 1, ans_reg + ) def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None): """Adds wiring into component `self` to compute `left` == `right` From ed05431beb213f1e17c9550fef36c2015617ad95 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 22 Aug 2023 18:42:53 +0530 Subject: [PATCH 042/189] bump version --- CHANGELOG.md | 2 +- Cargo.lock | 12 ++++++------ Cargo.toml | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faf31510b..202e0626d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Unreleased +## 0.5.0 - Don't require `@clk` and `@reset` ports in `comb` components - `inline` pass supports inlining `ref` cells - `comb-prop`: disable rewrite from `wire.in = port` when the output of a wire is read. diff --git a/Cargo.lock b/Cargo.lock index 92dbe4d51..ddb4982bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,7 +184,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "calyx" -version = "0.4.0" +version = "0.5.0" dependencies = [ "argh", "atty", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "calyx-frontend" -version = "0.4.0" +version = "0.5.0" dependencies = [ "atty", "calyx-utils", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "calyx-ir" -version = "0.4.0" +version = "0.5.0" dependencies = [ "calyx-frontend", "calyx-utils", @@ -243,7 +243,7 @@ dependencies = [ [[package]] name = "calyx-opt" -version = "0.4.0" +version = "0.5.0" dependencies = [ "boolean_expression", "calyx-ir", @@ -260,11 +260,11 @@ dependencies = [ [[package]] name = "calyx-stdlib" -version = "0.4.0" +version = "0.5.0" [[package]] name = "calyx-utils" -version = "0.4.0" +version = "0.5.0" dependencies = [ "atty", "itertools 0.10.5", diff --git a/Cargo.toml b/Cargo.toml index f1cfed8ad..7f6eafdbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ description = "Compiler Infrastructure for Hardware Accelerator Generation" categories = ["compilers"] homepage = "https://calyxir.org" edition = "2021" -version = "0.4.0" +version = "0.5.0" rust-version = "1.66" [workspace.dependencies] @@ -41,10 +41,10 @@ pest = "2.0" pest_derive = "2" pest_consume = "1" argh = "0.1" -calyx-utils = { path = "calyx-utils", version = "0.4.0" } -calyx-ir = { path = "calyx-ir", version = "0.4.0" } -calyx-frontend = { path = "calyx-frontend", version = "0.4.0" } -calyx-opt = { path = "calyx-opt", version = "0.4.0" } +calyx-utils = { path = "calyx-utils", version = "0.5.0" } +calyx-ir = { path = "calyx-ir", version = "0.5.0" } +calyx-frontend = { path = "calyx-frontend", version = "0.5.0" } +calyx-opt = { path = "calyx-opt", version = "0.5.0" } [workspace.dependencies.petgraph] version = "0.6" @@ -83,7 +83,7 @@ serialize = [ ] [build-dependencies] -calyx-stdlib = { path = "calyx-stdlib", version = "0.4.0" } +calyx-stdlib = { path = "calyx-stdlib", version = "0.5.0" } [dependencies] atty.workspace = true From 861c2aded7814c3c3ff891f7ac7fa8bb61c77013 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Tue, 22 Aug 2023 11:22:57 -0400 Subject: [PATCH 043/189] Builder: catch up `gen_exp` to new features of eDSL (#1684) --- calyx-py/calyx/builder.py | 106 +++++++---------- calyx-py/calyx/gen_exp.py | 125 ++++++-------------- tests/frontend/exp/degree-2-unsigned.expect | 24 ++-- tests/frontend/exp/degree-4-signed.expect | 24 ++-- tests/frontend/exp/degree-4-unsigned.expect | 24 ++-- tests/frontend/relay/softmax.expect | 24 ++-- 6 files changed, 121 insertions(+), 206 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 4e7ecd58f..b55aa4516 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -345,6 +345,10 @@ def le(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: """Generate a StdLe cell.""" return self.binary("le", size, name, signed) + def rsh(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: + """Generate a StdRsh cell.""" + return self.binary("rsh", size, name, signed) + def logic(self, operation, size: int, name: str = None) -> CellBuilder: """Generate a logical operator cell, of the flavor specified in `operation`.""" name = name or self.generate_name(operation) @@ -353,10 +357,12 @@ def logic(self, operation, size: int, name: str = None) -> CellBuilder: def and_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdAnd cell.""" + name = name or self.generate_name("and") return self.logic("and", size, name) def not_(self, size: int, name: str = None) -> CellBuilder: """Generate a StdNot cell.""" + name = name or self.generate_name("not") return self.logic("not", size, name) def pipelined_mult(self, name: str) -> CellBuilder: @@ -421,37 +427,37 @@ def binary_use(self, left, right, cell, groupname=None): cell.right = right return CellAndGroup(cell, comb_group) - def eq_use(self, left, right, width, cellname=None): + def eq_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` == `right`.""" - return self.binary_use(left, right, self.eq(width, cellname)) + return self.binary_use(left, right, self.eq(width, cellname, signed)) - def neq_use(self, left, right, width, cellname=None): + def neq_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` != `right`.""" - return self.binary_use(left, right, self.neq(width, cellname)) + return self.binary_use(left, right, self.neq(width, cellname, signed)) - def lt_use(self, left, right, width, cellname=None): + def lt_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` < `right`.""" - return self.binary_use(left, right, self.lt(width, cellname)) + return self.binary_use(left, right, self.lt(width, cellname, signed)) - def le_use(self, left, right, width, cellname=None): + def le_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` <= `right`.""" - return self.binary_use(left, right, self.le(width, cellname)) + return self.binary_use(left, right, self.le(width, cellname, signed)) - def ge_use(self, left, right, width, cellname=None): + def ge_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` >= `right`.""" - return self.binary_use(left, right, self.ge(width, cellname)) + return self.binary_use(left, right, self.ge(width, cellname, signed)) - def gt_use(self, left, right, width, cellname=None): + def gt_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to check if `left` > `right`.""" - return self.binary_use(left, right, self.gt(width, cellname)) + return self.binary_use(left, right, self.gt(width, cellname, signed)) - def add_use(self, left, right, width, cellname=None): + def add_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to compute `left` + `right`.""" - return self.binary_use(left, right, self.add(width, cellname)) + return self.binary_use(left, right, self.add(width, cellname, signed)) - def sub_use(self, left, right, width, cellname=None): + def sub_use(self, left, right, width, signed=False, cellname=None): """Inserts wiring into `self` to compute `left` - `right`.""" - return self.binary_use(left, right, self.sub(width, cellname)) + return self.binary_use(left, right, self.sub(width, cellname, signed)) def bitwise_flip_reg(self, reg, width, cellname=None): """Inserts wiring into `self` to bitwise-flip the contents of `reg` @@ -466,10 +472,10 @@ def bitwise_flip_reg(self, reg, width, cellname=None): not_group.done = reg.done return not_group - def incr(self, reg, width, val=1, cellname=None): + def incr(self, reg, width, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" - add_cell = self.add(width, cellname) + add_cell = self.add(width, cellname, signed) with self.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out add_cell.right = const(width, val) @@ -478,10 +484,10 @@ def incr(self, reg, width, val=1, cellname=None): incr_group.done = reg.done return incr_group - def decr(self, reg, width, val=1, cellname=None): + def decr(self, reg, width, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg - val`.""" cellname = cellname or f"{reg.name}_decr" - sub_cell = self.sub(width, cellname) + sub_cell = self.sub(width, cellname, signed) with self.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out sub_cell.right = const(width, val) @@ -589,68 +595,36 @@ def op_store_in_reg(self, op_cell, left, right, cellname, width, ans_reg=None): op_group.done = ans_reg.done return op_group, ans_reg - def add_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def add_store_in_reg( + self, left, right, cellname, width, ans_reg=None, signed=False + ): """Inserts wiring into `self` to perform `reg := left + right`.""" return self.op_store_in_reg( - self.add(width, cellname), left, right, cellname, width, ans_reg + self.add(width, cellname, signed), left, right, cellname, width, ans_reg ) - def sub_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def sub_store_in_reg( + self, left, right, cellname, width, ans_reg=None, signed=False + ): """Inserts wiring into `self` to perform `reg := left - right`.""" return self.op_store_in_reg( - self.sub(width, cellname), left, right, cellname, width, ans_reg + self.sub(width, cellname, signed), left, right, cellname, width, ans_reg ) - def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None, signed=False): """Adds wiring into `self to perform `reg := left == right`.""" return self.op_store_in_reg( - self.eq(width, cellname), left, right, cellname, 1, ans_reg + self.eq(width, cellname, signed), left, right, cellname, 1, ans_reg ) - def neq_store_in_reg(self, left, right, cellname, width, ans_reg=None): + def neq_store_in_reg( + self, left, right, cellname, width, ans_reg=None, signed=False + ): """Adds wiring into `self to perform `reg := left != right`.""" return self.op_store_in_reg( - self.neq(width, cellname), left, right, cellname, 1, ans_reg + self.neq(width, cellname, signed), left, right, cellname, 1, ans_reg ) - def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None): - """Adds wiring into component `self` to compute `left` == `right` - and store it in `ans_reg`. - 1. Within component `self`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes equality. - 3. Puts the values of `left` and `right` into `cell`. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the equality group and the register. - """ - eq_cell = self.eq(width, cellname) - ans_reg = ans_reg or self.reg(f"reg_{cellname}", 1) - with self.group(f"{cellname}_group") as eq_group: - eq_cell.left = left - eq_cell.right = right - ans_reg.write_en = 1 - ans_reg.in_ = eq_cell.out - eq_group.done = ans_reg.done - return eq_group, ans_reg - - def neq_store_in_reg(self, left, right, cellname, width, ans_reg=None): - """Adds wiring into component `self` to compute `left` != `right` - and store it in `ans_reg`. - 1. Within component `self`, creates a group called `cellname`_group. - 2. Within `group`, create a cell `cellname` that computes inequality. - 3. Puts the values of `left` and `right` into `cell`. - 4. Then puts the answer of the computation into `ans_reg`. - 4. Returns the inequality group and the register. - """ - neq_cell = self.neq(width, cellname) - ans_reg = ans_reg or self.reg(f"reg_{cellname}", 1) - with self.group(f"{cellname}_group") as neq_group: - neq_cell.left = left - neq_cell.right = right - ans_reg.write_en = 1 - ans_reg.in_ = neq_cell.out - neq_group.done = ans_reg.done - return neq_group, ans_reg - @dataclass(frozen=True) class CellAndGroup: diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index df389290a..9a7412282 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -49,8 +49,6 @@ def generate_fp_pow_component( "mult_pipe", width, int_width, frac_width, signed=is_signed ), ) - lt = comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) - incr = comp.cell("incr", Stdlib.op("add", width, signed=is_signed)) # groups with comp.group("init") as init: @@ -70,27 +68,14 @@ def generate_fp_pow_component( pow.in_ = mul.out execute_mul.done = pow.done - with comp.group("incr_count") as incr_count: - incr.left = const(width, 1) - incr.right = count.out - count.in_ = incr.out - count.write_en = 1 - incr_count.done = count.done + incr_count = comp.incr(count, width, 1, is_signed) - with comp.comb_group("cond") as cond: - lt.left = count.out - lt.right = comp.this().integer_exp + cond = comp.lt_use(count.out, comp.this().integer_exp, width, is_signed) with comp.continuous: comp.this().out = pow.out - comp.control += [ - init, - while_with( - CellAndGroup(lt, cond), - par(execute_mul, incr_count), - ), - ] + comp.control += [init, while_with(cond, par(execute_mul, incr_count))] return comp.component @@ -105,11 +90,12 @@ def generate_cells( comp.reg("int_x", width) comp.reg("frac_x", width) comp.reg("m", width) - comp.cell("and0", Stdlib.op("and", width, signed=False)) - comp.cell("and1", Stdlib.op("and", width, signed=False)) - comp.cell("rsh", Stdlib.op("rsh", width, signed=False)) + + comp.and_(width, "and0") + comp.and_(width, "and1") + comp.rsh(width, "rsh") if is_signed: - comp.cell("lt", Stdlib.op("lt", width, signed=is_signed)) + comp.lt(width, "lt", is_signed) # constants for i in range(2, degree + 1): @@ -541,21 +527,6 @@ def gen_reverse_sign( group.done = base_cell.done -def gen_comb_lt( - comp: ComponentBuilder, - name: str, - lhs: ExprBuilder, - lt: CellBuilder, - const_cell: CellBuilder, -): - """ - Generates lhs < const_cell - """ - with comp.comb_group(name): - lt.left = lhs - lt.right = const_cell.out - - # This appears to be unused. Brilliant. # TODO (griffin): Double check that this is unused and, if so, remove it. def gen_constant_cell( @@ -590,7 +561,8 @@ def generate_fp_pow_full( comp.input("base", width) comp.input("exp_value", width) comp.output("out", width) - lt = comp.cell("lt", Stdlib.op("lt", width, is_signed)) + lt = comp.lt(width, "lt", is_signed) + div = comp.cell( "div", Stdlib.fixed_point_op( @@ -632,7 +604,13 @@ def generate_fp_pow_full( ) gen_reverse_sign(comp, "rev_base_sign", new_base_reg, mult, const_neg_one), gen_reverse_sign(comp, "rev_res_sign", res, mult, const_neg_one), - gen_comb_lt(comp, "base_lt_zero", comp.this().base, lt, const_zero), + + base_lt_zero = comp.lt_use( + comp.this().base, + const_zero.out, + width, + is_signed, + ) new_exp_val = comp.reg("new_exp_val", width) e = comp.comp_instance("e", "exp", check_undeclared=False) @@ -649,48 +627,29 @@ def generate_fp_pow_full( with comp.continuous: comp.this().out = res.out - with comp.group("write_to_base_reg") as write_to_base_reg: - new_base_reg.write_en = 1 - new_base_reg.in_ = comp.this().base - write_to_base_reg.done = new_base_reg.done - - with comp.group("store_old_reg_val") as store_old_reg_val: - stored_base_reg.write_en = 1 - stored_base_reg.in_ = new_base_reg.out - store_old_reg_val.done = stored_base_reg.done - - with comp.group("write_e_to_res") as write_e_to_res: - res.write_en = 1 - res.in_ = e.out - write_e_to_res.done = res.done + write_to_base_reg = comp.reg_store( + new_base_reg, comp.this().base, "write_to_base_reg" + ) + store_old_reg_val = comp.reg_store( + stored_base_reg, new_base_reg.out, "store_old_reg_val" + ) + write_e_to_res = comp.reg_store(res, e.out, "write_e_to_res") gen_reciprocal(comp, "set_base_reciprocal", new_base_reg, div, const_one) gen_reciprocal(comp, "set_res_reciprocal", res, div, const_one), - gen_comb_lt( - comp, - "base_lt_one", - stored_base_reg.out, - lt, - const_one, - ) + base_lt_one = comp.lt_use(stored_base_reg.out, const_one.out, width, is_signed) - base_reciprocal = if_with( - CellAndGroup(lt, comp.get_group("base_lt_one")), - comp.get_group("set_base_reciprocal"), - ) + base_reciprocal = if_with(base_lt_one, comp.get_group("set_base_reciprocal")) - res_reciprocal = if_with( - CellAndGroup(lt, comp.get_group("base_lt_one")), - comp.get_group("set_res_reciprocal"), - ) + res_reciprocal = if_with(base_lt_one, comp.get_group("set_res_reciprocal")) if is_signed: base_rev = if_with( - CellAndGroup(lt, comp.get_group("base_lt_zero")), + base_lt_zero, comp.get_group("rev_base_sign"), ) res_rev = if_with( - CellAndGroup(lt, comp.get_group("base_lt_zero")), + base_lt_zero, comp.get_group("rev_res_sign"), ) pre_process = [base_rev, store_old_reg_val, base_reciprocal] @@ -741,23 +700,9 @@ def build_base_not_e(degree, width, int_width, is_signed) -> Program: ret = main.mem_d1("ret", width, 1, 1, is_external=True) f = main.comp_instance("f", "fp_pow_full") - with main.group("read_base") as read_base: - b.addr0 = 0 - base_reg.in_ = b.read_data - base_reg.write_en = 1 - read_base.done = base_reg.done - - with main.group("read_exp") as read_exp: - x.addr0 = 0 - exp_reg.in_ = x.read_data - exp_reg.write_en = 1 - read_exp.done = exp_reg.done - - with main.group("write_to_memory") as write_to_memory: - ret.addr0 = 0 - ret.write_en = 1 - ret.write_data = f.out - write_to_memory.done = ret.done + read_base = main.mem_load_std_d1(b, 0, base_reg, "read_base") + read_exp = main.mem_load_std_d1(x, 0, exp_reg, "read_exp") + write_to_memory = main.mem_store_std_d1(ret, 0, f.out, "write_to_memory") main.control += [ read_base, @@ -796,11 +741,7 @@ def build_base_is_e(degree, width, int_width, is_signed) -> Program: t.write_en = 1 init.done = t.done - with main.group("write_to_memory") as write_to_memory: - ret.addr0 = 0 - ret.write_en = 1 - ret.write_data = e.out - write_to_memory.done = ret.done + write_to_memory = main.mem_store_std_d1(ret, 0, e.out, "write_to_memory") main.control += [ init, diff --git a/tests/frontend/exp/degree-2-unsigned.expect b/tests/frontend/exp/degree-2-unsigned.expect index b2e781ae3..b6ef1de1e 100644 --- a/tests/frontend/exp/degree-2-unsigned.expect +++ b/tests/frontend/exp/degree-2-unsigned.expect @@ -105,8 +105,8 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow = std_reg(32); count = std_reg(32); mul = std_fp_mult_pipe(32, 16, 16); - lt = std_lt(32); - incr = std_add(32); + count_incr = std_add(32); + lt_1 = std_lt(32); } wires { group init { @@ -124,26 +124,26 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow.in = mul.out; execute_mul[done] = pow.done; } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; + group count_incr_group { + count_incr.left = count.out; + count_incr.right = 32'd1; count.write_en = 1'd1; - incr_count[done] = count.done; + count.in = count_incr.out; + count_incr_group[done] = count.done; } - comb group cond { - lt.left = count.out; - lt.right = integer_exp; + comb group lt_1_group { + lt_1.left = count.out; + lt_1.right = integer_exp; } out = pow.out; } control { seq { init; - while lt.out with cond { + while lt_1.out with lt_1_group { par { execute_mul; - incr_count; + count_incr_group; } } } diff --git a/tests/frontend/exp/degree-4-signed.expect b/tests/frontend/exp/degree-4-signed.expect index cfe43411c..c530c34b2 100644 --- a/tests/frontend/exp/degree-4-signed.expect +++ b/tests/frontend/exp/degree-4-signed.expect @@ -198,8 +198,8 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow = std_reg(16); count = std_reg(16); mul = std_fp_smult_pipe(16, 8, 8); - lt = std_slt(16); - incr = std_sadd(16); + count_incr = std_sadd(16); + lt_1 = std_slt(16); } wires { group init { @@ -217,26 +217,26 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow.in = mul.out; execute_mul[done] = pow.done; } - group incr_count { - incr.left = 16'd1; - incr.right = count.out; - count.in = incr.out; + group count_incr_group { + count_incr.left = count.out; + count_incr.right = 16'd1; count.write_en = 1'd1; - incr_count[done] = count.done; + count.in = count_incr.out; + count_incr_group[done] = count.done; } - comb group cond { - lt.left = count.out; - lt.right = integer_exp; + comb group lt_1_group { + lt_1.left = count.out; + lt_1.right = integer_exp; } out = pow.out; } control { seq { init; - while lt.out with cond { + while lt_1.out with lt_1_group { par { execute_mul; - incr_count; + count_incr_group; } } } diff --git a/tests/frontend/exp/degree-4-unsigned.expect b/tests/frontend/exp/degree-4-unsigned.expect index f977c57bb..91fa24244 100644 --- a/tests/frontend/exp/degree-4-unsigned.expect +++ b/tests/frontend/exp/degree-4-unsigned.expect @@ -169,8 +169,8 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow = std_reg(16); count = std_reg(16); mul = std_fp_mult_pipe(16, 8, 8); - lt = std_lt(16); - incr = std_add(16); + count_incr = std_add(16); + lt_1 = std_lt(16); } wires { group init { @@ -188,26 +188,26 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow.in = mul.out; execute_mul[done] = pow.done; } - group incr_count { - incr.left = 16'd1; - incr.right = count.out; - count.in = incr.out; + group count_incr_group { + count_incr.left = count.out; + count_incr.right = 16'd1; count.write_en = 1'd1; - incr_count[done] = count.done; + count.in = count_incr.out; + count_incr_group[done] = count.done; } - comb group cond { - lt.left = count.out; - lt.right = integer_exp; + comb group lt_1_group { + lt_1.left = count.out; + lt_1.right = integer_exp; } out = pow.out; } control { seq { init; - while lt.out with cond { + while lt_1.out with lt_1_group { par { execute_mul; - incr_count; + count_incr_group; } } } diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index 8730bd907..e1186d3ba 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -619,8 +619,8 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow = std_reg(32); count = std_reg(32); mul = std_fp_smult_pipe(32, 16, 16); - lt = std_slt(32); - incr = std_sadd(32); + count_incr = std_sadd(32); + lt_1 = std_slt(32); } wires { group init { @@ -638,26 +638,26 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow.in = mul.out; execute_mul[done] = pow.done; } - group incr_count { - incr.left = 32'd1; - incr.right = count.out; - count.in = incr.out; + group count_incr_group { + count_incr.left = count.out; + count_incr.right = 32'd1; count.write_en = 1'd1; - incr_count[done] = count.done; + count.in = count_incr.out; + count_incr_group[done] = count.done; } - comb group cond { - lt.left = count.out; - lt.right = integer_exp; + comb group lt_1_group { + lt_1.left = count.out; + lt_1.right = integer_exp; } out = pow.out; } control { seq { init; - while lt.out with cond { + while lt_1.out with lt_1_group { par { execute_mul; - incr_count; + count_incr_group; } } } From 83faabd2b6cc81351c75785af2dbd50c003ba491 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 22 Aug 2023 22:03:36 +0530 Subject: [PATCH 044/189] Install primitives in global folder (#1687) * Install calyx primitives in global directory * update docs * handle old primitives folder gracefully * clippy --- docs/compiler-as-library.md | 2 +- src/build.rs | 78 +++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/docs/compiler-as-library.md b/docs/compiler-as-library.md index b4336f32c..473c0ba47 100644 --- a/docs/compiler-as-library.md +++ b/docs/compiler-as-library.md @@ -13,7 +13,7 @@ The [`calyx` binary][calyx-crate] is published using Rust's crates.io repository 1. The [`calyx-stdlib`][calyx-stdlib] package pulls in the sources of all the primitives using the Rust `include_str!` macro. 2. The `calyx` binary defines a build script that depends on `calyx-stdlib` as a build dependency. -3. During build time, the script loads the string representation of all the primitives files and writes them to `$OUT_DIR/primitives`. The `OUT_DIR` environment variable is defined by `cargo`. +3. During build time, the script loads the string representation of all the primitives files and writes them to `$CALYX_PRIMITIVE_DIR/primitives`. If the variable is not set, the location defaults to `$HOME/.calyx`. 4. If (3) succeeds, the build scripts defines the `CALYX_PRIMITIVES_LIB` environment variable which is used when compiling the `calyx` crate. 5. During compilation, `calyx` embeds the value of this environment variable as the default argument to the `-l` flag. If the variable is not defined, the default value of the `-l` flag is `.`. diff --git a/src/build.rs b/src/build.rs index 3a916d1f6..a66c4f445 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,23 +1,80 @@ -use std::fs; -use std::io::Result; -use std::path; +use std::{env, fs, io::Result, path}; -fn write_primitive() -> Result { - // Get the OUT_DIR environment variable from Cargo. - let base: path::PathBuf = std::env::var("OUT_DIR").unwrap().into(); +/// Location to install the primitives library +const PRIM_DIR: &str = "CALYX_PRIMITIVES_DIR"; + +struct PrimState { + base: path::PathBuf, + old_prims: Option, + new_prims: path::PathBuf, +} + +/// Move the old primitives directory to a different location if present and create a new one. +fn move_primitives() -> Result { + let base: path::PathBuf = match env::var_os(PRIM_DIR) { + Some(v) => path::PathBuf::from(v), + None => { + let mut path: path::PathBuf = env::var_os("HOME").unwrap().into(); + path.push(".calyx"); + path + } + }; let mut prims = base.clone(); prims.push("primitives"); + let old_prims = if prims.exists() { + let mut old_prims = base.clone(); + old_prims.push("old_primitives"); + fs::rename(&prims, &old_prims)?; + Some(old_prims) + } else { + None + }; + + // Create the directory again fs::create_dir_all(&prims)?; + Ok(PrimState { + base, + old_prims, + new_prims: prims, + }) +} + +fn write_primitive(prims: &path::Path) -> Result<()> { + // Get the OUT_DIR environment variable from Cargo. // Write the compile primitives for (loc, src) in calyx_stdlib::KNOWN_LIBS .into_iter() .flat_map(|(_, info)| info) .chain(Some(calyx_stdlib::COMPILE_LIB)) { - let mut path = prims.clone(); + let mut path = prims.to_owned().clone(); path.push(loc); fs::write(path, src)?; } + Ok(()) +} + +fn create_primitives() -> Result { + let PrimState { + base, + old_prims, + new_prims: prims, + } = move_primitives()?; + match write_primitive(prims.as_path()) { + Ok(_) => { + if let Some(old) = old_prims { + fs::remove_dir_all(old)?; + } + } + Err(e) => { + // Move the old primitives back + println!("cargo:warning=Failed to write primitives directory. Restoring old directory"); + if let Some(old) = old_prims { + fs::rename(old, &prims)?; + } + return Err(e); + } + } Ok(base) } @@ -25,14 +82,11 @@ fn write_primitive() -> Result { fn main() { println!("cargo:rerun-if-changed=src/build.rs"); println!("cargo:rerun-if-changed=src/cmdline.rs"); - match write_primitive() { + match create_primitives() { Ok(p) => { // The build succeeded. We're going to define the CALYX_PRIMITVE_DIR environment variable // so that it can be used by the compiler. - println!( - "cargo:rustc-env=CALYX_PRIMITIVES_DIR={}", - p.to_string_lossy() - ); + println!("cargo:rustc-env={PRIM_DIR}={}", p.to_string_lossy()); } Err(e) => { println!( From eb6edb5f7f5788cbef8478bdf664fb3e3103ae83 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 23 Aug 2023 07:05:18 +0530 Subject: [PATCH 045/189] version 0.5.1 --- CHANGELOG.md | 3 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 202e0626d..3790c6c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.5.1 +- Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. + ## 0.5.0 - Don't require `@clk` and `@reset` ports in `comb` components - `inline` pass supports inlining `ref` cells diff --git a/Cargo.lock b/Cargo.lock index ddb4982bb..f5aa4e361 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,7 +184,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "calyx" -version = "0.5.0" +version = "0.5.1" dependencies = [ "argh", "atty", diff --git a/Cargo.toml b/Cargo.toml index 7f6eafdbb..d7f1905bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ features = ["matrix_graph"] [package] name = "calyx" default-run = "calyx" -version.workspace = true +version = "0.5.1" edition.workspace = true description.workspace = true authors.workspace = true From 4395468fe03b0396bedd8b75061900f09684d8a5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 23 Aug 2023 09:12:46 +0530 Subject: [PATCH 046/189] run cell sharing before compile ref (#1688) --- calyx-opt/src/default_passes.rs | 4 +- .../cell-share/live-register-analysis.fuse | 14 ------- tests/passes/cell-share/ref-share.expect | 34 +++++++++++++++++ tests/passes/cell-share/ref-share.futil | 37 +++++++++++++++++++ 4 files changed, 73 insertions(+), 16 deletions(-) delete mode 100644 tests/passes/cell-share/live-register-analysis.fuse create mode 100644 tests/passes/cell-share/ref-share.expect create mode 100644 tests/passes/cell-share/ref-share.futil diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 9455f95b7..7e2480a14 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -89,9 +89,9 @@ impl PassManager { InferShare, ComponentInliner, CombProp, + CellShare, // LiveRangeAnalaysis should handle comb groups + SimplifyWithControl, // Must run before compile-invoke CompileRef, //Must run before cell-share, and before component-inliner - CellShare, // LiveRangeAnalaysis should handle comb groups - SimplifyWithControl, // Must run before infer-static-timing CompileInvoke, // creates dead comb groups AttributePromotion, StaticPromotion, diff --git a/tests/passes/cell-share/live-register-analysis.fuse b/tests/passes/cell-share/live-register-analysis.fuse deleted file mode 100644 index 1a3349420..000000000 --- a/tests/passes/cell-share/live-register-analysis.fuse +++ /dev/null @@ -1,14 +0,0 @@ -// swap the contents of A and B - -decl A: ubit<32>[32]; -decl B: ubit<32>[32]; -decl C: ubit<32>[32]; - -for (let i: ubit<6> = 0..32) { - C[i] := A[i]; - A[i] := B[i]; -} - -for (let i: ubit<6> = 0..32) { - B[i] := C[i]; -} diff --git a/tests/passes/cell-share/ref-share.expect b/tests/passes/cell-share/ref-share.expect new file mode 100644 index 000000000..fcf531a2c --- /dev/null +++ b/tests/passes/cell-share/ref-share.expect @@ -0,0 +1,34 @@ +import "primitives/compile.futil"; +component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + ref r1 = std_reg(32); + ref r2 = std_reg(32); + } + wires { + group write_r1 { + r1.in = 32'd0; + r1.write_en = 1'd1; + write_r1[done] = r1.done; + } + group write_r2 { + r2.in = 32'd0; + r2.write_en = 1'd1; + write_r2[done] = r2.done; + } + } + control { + seq { + write_r1; + write_r2; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = foo(); + } + wires {} + control { + invoke f[r1 = r1,r2 = r2]()(); + } +} diff --git a/tests/passes/cell-share/ref-share.futil b/tests/passes/cell-share/ref-share.futil new file mode 100644 index 000000000..67f571074 --- /dev/null +++ b/tests/passes/cell-share/ref-share.futil @@ -0,0 +1,37 @@ +// -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids +import "primitives/compile.futil"; + +component foo() -> () { + cells { + ref r1 = std_reg(32); + ref r2 = std_reg(32); + } + wires { + group write_r1 { + r1.in = 32'd0; + r1.write_en = 1'd1; + write_r1[done] = r1.done; + } + group write_r2 { + r2.in = 32'd0; + r2.write_en = 1'd1; + write_r2[done] = r2.done; + } + } + control { + write_r1; + write_r2; + } +} + +component main() -> () { + cells { + f = foo(); + r1 = std_reg(32); + r2 = std_reg(32); + } + wires {} + control { + invoke f[r1=r1, r2=r2]()(); + } +} \ No newline at end of file From 14e735ca41f2770406df802197edbfd46f79a3ab Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 23 Aug 2023 10:42:29 +0530 Subject: [PATCH 047/189] remove `debug_name` field for WRC in release mode (#1689) --- calyx-ir/src/common.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/calyx-ir/src/common.rs b/calyx-ir/src/common.rs index 2c74148f0..f84bd270c 100644 --- a/calyx-ir/src/common.rs +++ b/calyx-ir/src/common.rs @@ -1,4 +1,6 @@ -use calyx_utils::{GetName, Id}; +use calyx_utils::GetName; +#[cfg(debug_assertions)] +use calyx_utils::Id; use std::cell::RefCell; use std::rc::{Rc, Weak}; @@ -15,6 +17,7 @@ where T: GetName, { pub(super) internal: Weak>, + #[cfg(debug_assertions)] debug_name: Id, } @@ -23,7 +26,10 @@ impl WRC { /// pointer. pub fn upgrade(&self) -> RRC { let Some(r) = self.internal.upgrade() else { - unreachable!("weak reference points to a dropped. Original object's name: `{}'", self.debug_name) + #[cfg(debug_assertions)] + unreachable!("weak reference points to a dropped. Original object's name: `{}'", self.debug_name); + #[cfg(not(debug_assertions))] + unreachable!("weak reference points to a dropped."); }; r } @@ -32,10 +38,10 @@ impl WRC { /// From implementation with the same signature as `Rc::downgrade`. impl From<&RRC> for WRC { fn from(internal: &RRC) -> Self { - let debug_name = internal.borrow().name(); Self { internal: Rc::downgrade(internal), - debug_name, + #[cfg(debug_assertions)] + debug_name: internal.borrow().name(), } } } @@ -45,6 +51,7 @@ impl Clone for WRC { fn clone(&self) -> Self { Self { internal: Weak::clone(&self.internal), + #[cfg(debug_assertions)] debug_name: self.debug_name, } } From 0e1e815fc9a0cb410f5f6a52f27b8e612196b09c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 23 Aug 2023 11:06:02 +0530 Subject: [PATCH 048/189] Deprecate `Cell::find_with_attr` (#1690) * Deprecate `find_with_attr` in favor of `find_with_unique_attr` * update changelog --- CHANGELOG.md | 3 ++ calyx-ir/src/structure.rs | 46 ++++++++++++------- calyx-opt/src/analysis/variable_detection.rs | 3 +- calyx-opt/src/passes/clk_insertion.rs | 8 ++-- calyx-opt/src/passes/compile_invoke.rs | 17 ++++--- calyx-opt/src/passes/group_to_invoke.rs | 27 ++++------- calyx-opt/src/passes/hole_inliner.rs | 4 +- calyx-opt/src/passes/reset_insertion.rs | 8 ++-- interp/src/interpreter/control_interpreter.rs | 15 ++++-- 9 files changed, 78 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3790c6c81..5d7a8f6d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Unreleased +- Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. + ## 0.5.1 - Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. diff --git a/calyx-ir/src/structure.rs b/calyx-ir/src/structure.rs index d722c34aa..8d40bd8f8 100644 --- a/calyx-ir/src/structure.rs +++ b/calyx-ir/src/structure.rs @@ -7,7 +7,7 @@ use super::{ Attributes, Direction, GetAttributes, Guard, Id, PortDef, RRC, WRC, }; use calyx_frontend::Attribute; -use calyx_utils::GetName; +use calyx_utils::{CalyxResult, Error, GetName}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; use std::hash::Hash; @@ -292,31 +292,45 @@ impl Cell { .map(Rc::clone) } - /// Get a reference to the first port that has the attribute `attr`. - pub fn find_with_attr(&self, attr: A) -> Option> + /// Return all ports that have the attribute `attr`. + pub fn find_all_with_attr( + &self, + attr: A, + ) -> impl Iterator> + '_ where A: Into, { let attr = attr.into(); self.ports .iter() - .find(|&g| g.borrow().attributes.has(attr)) + .filter(move |&p| p.borrow().attributes.has(attr)) .map(Rc::clone) } - /// Return all ports that have the attribute `attr`. - pub fn find_all_with_attr( + /// Return the unique port with the given attribute. + /// If multiple ports have the same attribute, then we panic. + /// If there are not ports with the give attribute, then we return None. + pub fn find_unique_with_attr( &self, attr: A, - ) -> impl Iterator> + '_ + ) -> CalyxResult>> where A: Into, { let attr = attr.into(); - self.ports - .iter() - .filter(move |&p| p.borrow().attributes.has(attr)) - .map(Rc::clone) + let mut ports = self.find_all_with_attr(attr); + if let Some(port) = ports.next() { + if ports.next().is_some() { + Err(Error::malformed_structure(format!( + "Multiple ports with attribute `{}` found on cell `{}`", + attr, self.name + ))) + } else { + Ok(Some(port)) + } + } else { + Ok(None) + } } /// Get a reference to the named port and throw an error if it doesn't @@ -362,18 +376,18 @@ impl Cell { } } - /// Get a reference to the first port with the attribute `attr` and throw an error if none - /// exist. - pub fn get_with_attr(&self, attr: A) -> RRC + /// Get the unique port with the given attribute. + /// Panic if no port with the attribute is found and returns an error if multiple ports with the attribute are found. + pub fn get_unique_with_attr(&self, attr: A) -> CalyxResult> where A: Into + std::fmt::Display + Copy, { - self.find_with_attr(attr).unwrap_or_else(|| { + Ok(self.find_unique_with_attr(attr)?.unwrap_or_else(|| { panic!( "Port with attribute `{attr}' not found on cell `{}'", self.name, ) - }) + })) } /// Returns the name of the component that is this cells type. diff --git a/calyx-opt/src/analysis/variable_detection.rs b/calyx-opt/src/analysis/variable_detection.rs index a965eb6b6..46535f5a3 100644 --- a/calyx-opt/src/analysis/variable_detection.rs +++ b/calyx-opt/src/analysis/variable_detection.rs @@ -37,7 +37,8 @@ impl VariableDetection { // if guard is empty, because if it isn't this would show up as // a write let graph = GraphAnalysis::from(&*group); - let go_port = cell.find_with_attr(ir::NumAttr::Go)?; + let go_port = + cell.find_unique_with_attr(ir::NumAttr::Go).ok().flatten()?; let activation = graph .writes_to(&go_port.borrow()) .map(|src| src.borrow().is_constant(1, 1)) diff --git a/calyx-opt/src/passes/clk_insertion.rs b/calyx-opt/src/passes/clk_insertion.rs index e0ca0dbea..28dd9b982 100644 --- a/calyx-opt/src/passes/clk_insertion.rs +++ b/calyx-opt/src/passes/clk_insertion.rs @@ -32,12 +32,14 @@ impl Visitor for ClkInsertion { .component .signature .borrow() - .find_with_attr(ir::BoolAttr::Clk); + .find_unique_with_attr(ir::BoolAttr::Clk)?; if let Some(clk) = clk { for cell_ref in builder.component.cells.iter() { let cell = cell_ref.borrow(); - if let Some(port) = cell.find_with_attr(ir::BoolAttr::Clk) { + if let Some(port) = + cell.find_unique_with_attr(ir::BoolAttr::Clk)? + { builder.component.continuous_assignments.push( builder.build_assignment( port, @@ -50,7 +52,7 @@ impl Visitor for ClkInsertion { } else { for cell_ref in builder.component.cells.iter() { let cell = cell_ref.borrow(); - if cell.find_with_attr(ir::BoolAttr::Clk).is_some() { + if cell.find_unique_with_attr(ir::BoolAttr::Clk)?.is_some() { return Err(Error::malformed_structure(format!( "Cell `{}' in component `{}' has a clk port, \ but the component does not have a clk port.", diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 157431b7e..8cf367681 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -13,14 +13,17 @@ fn get_go_port(cell_ref: ir::RRC) -> CalyxResult> { let name = cell.name(); // Get the go port - let mut go_ports = cell.find_all_with_attr(ir::NumAttr::Go).collect_vec(); - if go_ports.len() > 1 { - return Err(Error::malformed_control(format!("Invoked component `{name}` defines multiple @go signals. Cannot compile the invoke"))); - } else if go_ports.is_empty() { - return Err(Error::malformed_control(format!("Invoked component `{name}` does not define a @go signal. Cannot compile the invoke"))); + match cell.find_unique_with_attr(ir::NumAttr::Go) { + Ok(Some(p)) => Ok(p), + Ok(None) => Err(Error::malformed_control(format!( + "Invoked component `{name}` does not define a @go signal. Cannot compile the invoke", + ))), + Err(_) => { + Err(Error::malformed_control(format!( + "Invoked component `{name}` defines multiple @go signals. Cannot compile the invoke", + ))) + } } - - Ok(go_ports.pop().unwrap()) } // given inputs and outputs (of the invoke), and the `enable_assignments` (e.g., invoked_component.go = 1'd1) diff --git a/calyx-opt/src/passes/group_to_invoke.rs b/calyx-opt/src/passes/group_to_invoke.rs index 69161d7f3..441d847a3 100644 --- a/calyx-opt/src/passes/group_to_invoke.rs +++ b/calyx-opt/src/passes/group_to_invoke.rs @@ -105,7 +105,8 @@ fn construct_invoke( // inputs. we can ignore the cell.go assignment, since that is not // going to be part of the `invoke`. else if parent_is_cell(&assign.dst.borrow()) - && assign.dst != comp.borrow().get_with_attr(ir::NumAttr::Go) + && assign.dst + != comp.borrow().get_unique_with_attr(ir::NumAttr::Go).unwrap() { let name = assign.dst.borrow().name; if assign.guard.is_true() { @@ -264,22 +265,14 @@ impl GroupToInvoke { return; } - // Component must define a @go/@done interface - let maybe_go_port = cell.find_with_attr(ir::NumAttr::Go); - let maybe_done_port = cell.find_with_attr(ir::NumAttr::Done); - if maybe_go_port.is_none() || maybe_done_port.is_none() { + // Component must define exactly one @go/@done interface + let Ok(Some(go_port)) = cell.find_unique_with_attr(ir::NumAttr::Go) else { return; - } - - // Component must have a single @go/@done pair - let go_ports = cell.find_all_with_attr(ir::NumAttr::Go).count(); - let done_ports = cell.find_all_with_attr(ir::NumAttr::Done).count(); - if go_ports > 1 || done_ports > 1 { + }; + let Ok(Some(done_port)) = cell.find_unique_with_attr(ir::NumAttr::Done) else { return; - } + }; - let go_port = maybe_go_port.unwrap(); - let done_port = maybe_done_port.unwrap(); let mut go_wr_cnt = 0; let mut done_wr_cnt = 0; @@ -288,9 +281,9 @@ impl GroupToInvoke { if assign.dst == go_port { if go_wr_cnt > 0 { log::info!( - "Cannot transform `{}` due to multiple writes to @go port", - group_name, - ); + "Cannot transform `{}` due to multiple writes to @go port", + group_name, + ); return; } else if !assign.guard.is_true() { log::info!( diff --git a/calyx-opt/src/passes/hole_inliner.rs b/calyx-opt/src/passes/hole_inliner.rs index 75b32d5ac..b453cd2ba 100644 --- a/calyx-opt/src/passes/hole_inliner.rs +++ b/calyx-opt/src/passes/hole_inliner.rs @@ -123,11 +123,11 @@ impl Visitor for HoleInliner { let mut asgns = vec![ builder.build_assignment( top_level.borrow().get("go"), - this_comp.borrow().get_with_attr(ir::NumAttr::Go), + this_comp.borrow().get_unique_with_attr(ir::NumAttr::Go)?, ir::Guard::True, ), builder.build_assignment( - this_comp.borrow().get_with_attr(ir::NumAttr::Done), + this_comp.borrow().get_unique_with_attr(ir::NumAttr::Done)?, top_level.borrow().get("done"), ir::Guard::True, ), diff --git a/calyx-opt/src/passes/reset_insertion.rs b/calyx-opt/src/passes/reset_insertion.rs index ef105404d..cfe9223f8 100644 --- a/calyx-opt/src/passes/reset_insertion.rs +++ b/calyx-opt/src/passes/reset_insertion.rs @@ -30,12 +30,14 @@ impl Visitor for ResetInsertion { .component .signature .borrow() - .find_with_attr(ir::BoolAttr::Reset); + .find_unique_with_attr(ir::BoolAttr::Reset)?; if let Some(reset) = reset { for cell_ref in builder.component.cells.iter() { let cell = cell_ref.borrow(); - if let Some(port) = cell.find_with_attr(ir::BoolAttr::Reset) { + if let Some(port) = + cell.find_unique_with_attr(ir::BoolAttr::Reset)? + { builder.component.continuous_assignments.push( builder.build_assignment( port, @@ -48,7 +50,7 @@ impl Visitor for ResetInsertion { } else { for cell_ref in builder.component.cells.iter() { let cell = cell_ref.borrow(); - if cell.find_with_attr(ir::BoolAttr::Reset).is_some() { + if cell.find_unique_with_attr(ir::BoolAttr::Reset)?.is_some() { return Err(Error::malformed_structure(format!( "Cell `{}' in component `{}' has a reset port, \ but the component does not have a reset port.", diff --git a/interp/src/interpreter/control_interpreter.rs b/interp/src/interpreter/control_interpreter.rs index db406bea1..75d75b792 100644 --- a/interp/src/interpreter/control_interpreter.rs +++ b/interp/src/interpreter/control_interpreter.rs @@ -1042,12 +1042,13 @@ impl InvokeInterpreter { assignment_vec.extend(w_ref.assignments.iter().cloned()); } - let go_port = comp_cell.get_with_attr(ir::NumAttr::Go); + let go_port = comp_cell.get_unique_with_attr(ir::NumAttr::Go).unwrap(); // insert one into the go_port // should probably replace with an actual assignment from a constant one env.insert(go_port, Value::bit_high()); - let comp_done_port = comp_cell.get_with_attr(ir::NumAttr::Done); + let comp_done_port = + comp_cell.get_unique_with_attr(ir::NumAttr::Done).unwrap(); let interp = AssignmentInterpreter::new( env, comp_done_port.into(), @@ -1078,7 +1079,12 @@ impl Interpreter for InvokeInterpreter { let mut env = self.assign_interp.reset()?; // set go low - let go_port = self.invoke.comp.borrow().get_with_attr(ir::NumAttr::Go); + let go_port = self + .invoke + .comp + .borrow() + .get_unique_with_attr(ir::NumAttr::Go) + .unwrap(); // insert one into the go_port // should probably replace with an actual assignment from a constant one env.insert(go_port, Value::bit_low()); @@ -1238,7 +1244,8 @@ impl StructuralInterpreter { env: InterpreterState, ) -> Self { let comp_sig = comp.signature.borrow(); - let done_port = comp_sig.get_with_attr(ir::NumAttr::Done); + let done_port = + comp_sig.get_unique_with_attr(ir::NumAttr::Done).unwrap(); let done_raw = done_port.as_raw(); let continuous = Rc::clone(&comp.continuous_assignments); let assigns: Vec> = vec![]; From 73c242201959790b1eba2c376f2a31d5609a7e76 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 23 Aug 2023 11:55:00 +0530 Subject: [PATCH 049/189] Redesign `ir::Rewriter` interface (#1691) * Redesign `ir::Rewriter` interface * update changelog --- CHANGELOG.md | 3 +- calyx-ir/src/rewriter.rs | 107 ++++++--------------- calyx-opt/src/passes/cell_share.rs | 13 +-- calyx-opt/src/passes/comb_prop.rs | 14 +-- calyx-opt/src/passes/compile_ref.rs | 26 +++-- calyx-opt/src/passes/component_iniliner.rs | 21 ++-- calyx-opt/src/passes/dump_ports.rs | 47 +++++---- calyx-opt/src/passes/externalize.rs | 29 +++--- calyx-opt/src/passes/register_unsharing.rs | 32 +++--- 9 files changed, 125 insertions(+), 167 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d7a8f6d7..0bfe040c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## Unreleased -- Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. +- BREAKING: Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. +- BREAKING: Redesign the `ir::Rewriter` interface to take all the rewrite maps when constructing the `ir::Rewriter` struct. ## 0.5.1 - Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. diff --git a/calyx-ir/src/rewriter.rs b/calyx-ir/src/rewriter.rs index 297d4ebfa..0d6c65ff5 100644 --- a/calyx-ir/src/rewriter.rs +++ b/calyx-ir/src/rewriter.rs @@ -11,22 +11,24 @@ pub type RewriteMap = HashMap>; /// [ir::Port::canonical]) to the new [ir::Port] instance. pub type PortRewriteMap = HashMap>; +#[derive(Default)] /// A structure to track rewrite maps for ports. Stores both cell rewrites and direct port /// rewrites. Attempts to apply port rewrites first before trying the cell /// rewrite. -pub struct Rewriter<'a> { - cell_map: &'a RewriteMap, - port_map: &'a PortRewriteMap, +pub struct Rewriter { + /// Mapping from canonical names of ports to port instances + pub port_map: PortRewriteMap, + /// Mapping from names of cells to cell instance. + pub cell_map: RewriteMap, + /// Mapping from names of groups to group instance. + pub group_map: RewriteMap, + /// Mapping from names of combinational groups to combinational group instance. + pub comb_group_map: RewriteMap, + /// Mapping from names of static groups to static group instance. + pub static_group_map: RewriteMap, } -impl<'a> Rewriter<'a> { - pub fn new( - cell_map: &'a RewriteMap, - port_map: &'a PortRewriteMap, - ) -> Self { - Self { cell_map, port_map } - } - +impl Rewriter { /// Return the rewrite for a cell pub fn get_cell_rewrite(&self, cell: &ir::Id) -> Option> { self.cell_map.get(cell).map(Rc::clone) @@ -123,11 +125,7 @@ impl<'a> Rewriter<'a> { // =========== Control Rewriting Methods ============= /// Rewrite a `invoke` node using a [RewriteMap] and a [RewriteMap] - pub fn rewrite_invoke( - &self, - inv: &mut ir::Invoke, - comb_group_map: &RewriteMap, - ) { + pub fn rewrite_invoke(&self, inv: &mut ir::Invoke) { // Rewrite the name of the cell let name = inv.comp.borrow().name(); if let Some(new_cell) = &self.get_cell_rewrite(&name) { @@ -137,7 +135,7 @@ impl<'a> Rewriter<'a> { // Rewrite the combinational group if let Some(cg_ref) = &inv.comb_group { let cg = cg_ref.borrow().name(); - if let Some(new_cg) = &comb_group_map.get(&cg) { + if let Some(new_cg) = &self.comb_group_map.get(&cg) { inv.comb_group = Some(Rc::clone(new_cg)); } } @@ -174,34 +172,30 @@ impl<'a> Rewriter<'a> { /// Given a control program, rewrite all uses of cells, groups, and comb groups using the given /// rewrite maps. - pub fn rewrite_static_control( - &self, - sc: &mut ir::StaticControl, - static_group_map: &RewriteMap, - ) { + pub fn rewrite_static_control(&self, sc: &mut ir::StaticControl) { match sc { ir::StaticControl::Empty(_) => (), ir::StaticControl::Enable(sen) => { let g = &sen.group.borrow().name(); - if let Some(new_group) = static_group_map.get(g) { + if let Some(new_group) = self.static_group_map.get(g) { sen.group = Rc::clone(new_group); } } ir::StaticControl::Repeat(rep) => { - self.rewrite_static_control(&mut rep.body, static_group_map) + self.rewrite_static_control(&mut rep.body) } ir::StaticControl::Seq(ir::StaticSeq { stmts, .. }) | ir::StaticControl::Par(ir::StaticPar { stmts, .. }) => stmts .iter_mut() - .for_each(|c| self.rewrite_static_control(c, static_group_map)), + .for_each(|c| self.rewrite_static_control(c)), ir::StaticControl::If(sif) => { // Rewrite port use if let Some(new_port) = self.get(&sif.port) { sif.port = new_port; } // rewrite branches - self.rewrite_static_control(&mut sif.tbranch, static_group_map); - self.rewrite_static_control(&mut sif.fbranch, static_group_map); + self.rewrite_static_control(&mut sif.tbranch); + self.rewrite_static_control(&mut sif.fbranch); } ir::StaticControl::Invoke(sin) => { self.rewrite_static_invoke(sin); @@ -211,31 +205,18 @@ impl<'a> Rewriter<'a> { /// Given a control program, rewrite all uses of cells, groups, and comb groups using the given /// rewrite maps. - pub fn rewrite_control( - &self, - c: &mut ir::Control, - group_map: &RewriteMap, - comb_group_map: &RewriteMap, - static_group_map: &RewriteMap, - ) { + pub fn rewrite_control(&self, c: &mut ir::Control) { match c { ir::Control::Empty(_) => (), ir::Control::Enable(en) => { let g = &en.group.borrow().name(); - if let Some(new_group) = group_map.get(g) { + if let Some(new_group) = self.group_map.get(g) { en.group = Rc::clone(new_group); } } ir::Control::Seq(ir::Seq { stmts, .. }) | ir::Control::Par(ir::Par { stmts, .. }) => { - stmts.iter_mut().for_each(|c| { - self.rewrite_control( - c, - group_map, - comb_group_map, - static_group_map, - ) - }) + stmts.iter_mut().for_each(|c| self.rewrite_control(c)) } ir::Control::If(ife) => { // Rewrite port use @@ -245,23 +226,13 @@ impl<'a> Rewriter<'a> { // Rewrite conditional comb group if defined if let Some(cg_ref) = &ife.cond { let cg = cg_ref.borrow().name(); - if let Some(new_cg) = &comb_group_map.get(&cg) { + if let Some(new_cg) = &self.comb_group_map.get(&cg) { ife.cond = Some(Rc::clone(new_cg)); } } // rewrite branches - self.rewrite_control( - &mut ife.tbranch, - group_map, - comb_group_map, - static_group_map, - ); - self.rewrite_control( - &mut ife.fbranch, - group_map, - comb_group_map, - static_group_map, - ); + self.rewrite_control(&mut ife.tbranch); + self.rewrite_control(&mut ife.fbranch); } ir::Control::While(wh) => { // Rewrite port use @@ -271,33 +242,19 @@ impl<'a> Rewriter<'a> { // Rewrite conditional comb group if defined if let Some(cg_ref) = &wh.cond { let cg = cg_ref.borrow().name(); - if let Some(new_cg) = &comb_group_map.get(&cg) { + if let Some(new_cg) = &self.comb_group_map.get(&cg) { wh.cond = Some(Rc::clone(new_cg)); } } // rewrite body - self.rewrite_control( - &mut wh.body, - group_map, - comb_group_map, - static_group_map, - ); + self.rewrite_control(&mut wh.body); } ir::Control::Repeat(rep) => { // rewrite body - self.rewrite_control( - &mut rep.body, - group_map, - comb_group_map, - static_group_map, - ); - } - ir::Control::Invoke(inv) => { - self.rewrite_invoke(inv, comb_group_map) - } - ir::Control::Static(s) => { - self.rewrite_static_control(s, static_group_map) + self.rewrite_control(&mut rep.body); } + ir::Control::Invoke(inv) => self.rewrite_invoke(inv), + ir::Control::Static(s) => self.rewrite_static_control(s), } } } diff --git a/calyx-opt/src/passes/cell_share.rs b/calyx-opt/src/passes/cell_share.rs index 46ac420f4..def1c69b1 100644 --- a/calyx-opt/src/passes/cell_share.rs +++ b/calyx-opt/src/passes/cell_share.rs @@ -518,8 +518,10 @@ impl Visitor for CellShare { } // Rewrite assignments using the coloring generated. - let empty_map: ir::rewriter::PortRewriteMap = HashMap::new(); - let rewriter = ir::Rewriter::new(&coloring, &empty_map); + let rewriter = ir::Rewriter { + cell_map: coloring, + ..Default::default() + }; comp.for_each_assignment(|assign| { assign.for_each_port(|port| rewriter.get(port)); }); @@ -528,12 +530,7 @@ impl Visitor for CellShare { }); // Rewrite control uses of ports - rewriter.rewrite_control( - &mut comp.control.borrow_mut(), - &HashMap::new(), - &HashMap::new(), - &HashMap::new(), - ); + rewriter.rewrite_control(&mut comp.control.borrow_mut()); Ok(Action::Stop) } diff --git a/calyx-opt/src/passes/comb_prop.rs b/calyx-opt/src/passes/comb_prop.rs index 9ea00ee09..e4455abb8 100644 --- a/calyx-opt/src/passes/comb_prop.rs +++ b/calyx-opt/src/passes/comb_prop.rs @@ -1,7 +1,6 @@ use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir, RRC}; use itertools::Itertools; -use std::collections::HashMap; use std::rc::Rc; /// A data structure to track rewrites of ports with added functionality to declare @@ -369,14 +368,11 @@ impl Visitor for CombProp { } }); - let cell_rewrites = HashMap::new(); - let rewriter = ir::Rewriter::new(&cell_rewrites, &rewrites); - rewriter.rewrite_control( - &mut comp.control.borrow_mut(), - &HashMap::new(), - &HashMap::new(), - &HashMap::new(), - ); + let rewriter = ir::Rewriter { + port_map: rewrites, + ..Default::default() + }; + rewriter.rewrite_control(&mut comp.control.borrow_mut()); Ok(Action::Stop) } diff --git a/calyx-opt/src/passes/compile_ref.rs b/calyx-opt/src/passes/compile_ref.rs index 6f4293e66..5eb35c5ff 100644 --- a/calyx-opt/src/passes/compile_ref.rs +++ b/calyx-opt/src/passes/compile_ref.rs @@ -164,13 +164,11 @@ impl Visitor for CompileRef { _comps: &[ir::Component], ) -> VisResult { log::debug!("compile-ref: {}", comp.name); - self.ref_cells = dump_ports::dump_ports_to_signature( - comp, - is_external_cell, - true, - &mut self.port_names, - &mut self.removed, - ); + let dump_ports::DumpResults { cells, rewrites } = + dump_ports::dump_ports_to_signature(comp, is_external_cell, true); + self.removed.extend(rewrites.clone()); + self.port_names.insert(comp.name, rewrites); + self.ref_cells = cells; // For all subcomponents that had a `ref` cell in them, we need to // update their cell to have the new ports added from inlining the @@ -237,21 +235,19 @@ impl Visitor for CompileRef { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { + let port_map = std::mem::take(&mut self.removed); // Rewrite all of the ref cell ports - let empty = HashMap::new(); - let rw = ir::Rewriter::new(&empty, &self.removed); + let rw = ir::Rewriter { + port_map, + ..Default::default() + }; comp.for_each_assignment(|assign| { rw.rewrite_assign(assign); }); comp.for_each_static_assignment(|assign| { rw.rewrite_assign(assign); }); - rw.rewrite_control( - &mut comp.control.borrow_mut(), - &HashMap::new(), - &HashMap::new(), - &HashMap::new(), - ); + rw.rewrite_control(&mut comp.control.borrow_mut()); Ok(Action::Continue) } } diff --git a/calyx-opt/src/passes/component_iniliner.rs b/calyx-opt/src/passes/component_iniliner.rs index f2736ae9b..f7dd93d42 100644 --- a/calyx-opt/src/passes/component_iniliner.rs +++ b/calyx-opt/src/passes/component_iniliner.rs @@ -290,21 +290,25 @@ impl ComponentInliner { // Rewrites to inline the interface. let interface_map = Self::inline_interface(builder, comp, name); - let rewrite = ir::Rewriter::new(&cell_map, &interface_map); + let mut rewrite = ir::Rewriter { + cell_map, + port_map: interface_map, + ..Default::default() + }; // For each group, create a new group and rewrite all assignments within // it using the `rewrite_map`. - let group_map: rewriter::RewriteMap = comp + rewrite.group_map = comp .get_groups() .iter() .map(|gr| Self::inline_group(builder, &rewrite, gr)) .collect(); - let static_group_map: rewriter::RewriteMap = comp + rewrite.static_group_map = comp .get_static_groups() .iter() .map(|gr| Self::inline_static_group(builder, &rewrite, gr)) .collect(); - let comb_group_map: rewriter::RewriteMap = comp + rewrite.comb_group_map = comp .comb_groups .iter() .map(|gr| Self::inline_comb_group(builder, &rewrite, gr)) @@ -320,17 +324,12 @@ impl ComponentInliner { // Generate a control program associated with this instance let mut con = ir::Cloner::control(&comp.control.borrow()); - rewrite.rewrite_control( - &mut con, - &group_map, - &comb_group_map, - &static_group_map, - ); + rewrite.rewrite_control(&mut con); // Generate interface map for use in the parent cell. // Return as an iterator because it's immediately merged into the global rewrite map. let rev_interface_map = - interface_map.into_iter().map(move |(cp, pr)| { + rewrite.port_map.into_iter().map(move |(cp, pr)| { let ir::Canonical(_, p) = cp; let port = pr.borrow(); let np = match port.name.id.as_str() { diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index d9f0fa49b..532e1ab5d 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -1,7 +1,17 @@ -use crate::passes::compile_ref::RefPortMap; use calyx_ir::{self as ir, RRC, WRC}; +use ir::rewriter; use itertools::Itertools; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; + +#[derive(Default)] +/// Results generated from the process of dumping out ports. +pub struct DumpResults { + /// The cells that were removed from the component. + pub cells: Vec>, + /// Rewrites from (cell, port) to the new port. + /// Usually consumed by an [`ir::rewriter::Rewriter`]. + pub rewrites: rewriter::PortRewriteMap, +} /// Formats name of a port given the id of the cell and the port pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id { @@ -12,15 +22,17 @@ pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id { /// the component and inline all the ports of the removed cells to the component /// signature. /// -/// If remove_signals is true, does not inline ports marked with @clk and @reset. -pub(super) fn dump_ports_to_signature( +/// If `remove_clk_and_reset` is true, does not inline ports marked with @clk and @reset. +pub(super) fn dump_ports_to_signature( component: &mut ir::Component, - cell_filter: fn(&RRC) -> bool, - remove_signals: bool, - port_names: &mut RefPortMap, - removed: &mut HashMap>, -) -> Vec> { - let comp_name = component.name; + cell_filter: F, + remove_clk_and_reset: bool, +) -> DumpResults +where + F: Fn(&RRC) -> bool, +{ + let mut removed = rewriter::PortRewriteMap::default(); + let (ext_cells, cells): (Vec<_>, Vec<_>) = component.cells.drain().partition(cell_filter); component.cells.append(cells.into_iter()); @@ -36,8 +48,8 @@ pub(super) fn dump_ports_to_signature( .ports .iter() .filter(|pr| { - let p = pr.borrow(); - if remove_signals { + if remove_clk_and_reset { + let p = pr.borrow(); !p.attributes.has(ir::BoolAttr::Clk) && !p.attributes.has(ir::BoolAttr::Reset) } else { @@ -65,13 +77,10 @@ pub(super) fn dump_ports_to_signature( // Record the port as removed removed.insert(canon.clone(), Rc::clone(&new_port)); - - // Record the port to add to cells - port_names - .entry(comp_name) - .or_default() - .insert(canon, Rc::clone(&new_port)); } } - ext_cells + DumpResults { + cells: ext_cells, + rewrites: removed, + } } diff --git a/calyx-opt/src/passes/externalize.rs b/calyx-opt/src/passes/externalize.rs index 0a8d7002c..1c743345d 100644 --- a/calyx-opt/src/passes/externalize.rs +++ b/calyx-opt/src/passes/externalize.rs @@ -2,7 +2,6 @@ use super::dump_ports; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures, RRC}; use calyx_utils::CalyxResult; -use std::collections::HashMap; /// Externalize input/output ports for cells marked with the `@external(1)` attribute. /// The ports of these cells are exposed through the ports of the parent @@ -75,30 +74,24 @@ impl Visitor for Externalize { _ctx: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - let mut port_names = HashMap::new(); - let mut renamed = HashMap::new(); - let cells = dump_ports::dump_ports_to_signature( - comp, - has_external_attribute, - false, - &mut port_names, - &mut renamed, - ); + let dump_ports::DumpResults { cells, rewrites } = + dump_ports::dump_ports_to_signature( + comp, + has_external_attribute, + false, + ); - let cell_map = HashMap::default(); - let rw = ir::Rewriter::new(&cell_map, &renamed); + let rw = ir::Rewriter { + port_map: rewrites, + ..Default::default() + }; comp.for_each_assignment(|assign| { rw.rewrite_assign(assign); }); comp.for_each_static_assignment(|assign| { rw.rewrite_assign(assign); }); - rw.rewrite_control( - &mut comp.control.borrow_mut(), - &HashMap::new(), - &HashMap::new(), - &HashMap::new(), - ); + rw.rewrite_control(&mut comp.control.borrow_mut()); // Don't allow cells to be dropped before this because otherwise rewriting will fail drop(cells); diff --git a/calyx-opt/src/passes/register_unsharing.rs b/calyx-opt/src/passes/register_unsharing.rs index 772b750e5..c4469da71 100644 --- a/calyx-opt/src/passes/register_unsharing.rs +++ b/calyx-opt/src/passes/register_unsharing.rs @@ -163,8 +163,10 @@ impl Bookkeeper { for (grp, rename_cells) in grp_map { let group_ref = comp.find_group(grp).unwrap(); let mut group = group_ref.borrow_mut(); - let empty_map = HashMap::new(); - let rewriter = ir::Rewriter::new(&rename_cells, &empty_map); + let rewriter = ir::Rewriter { + cell_map: rename_cells, + ..Default::default() + }; group .assignments .iter_mut() @@ -198,14 +200,18 @@ impl Visitor for RegisterUnsharing { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - let book = &self.bookkeeper; + let book = &mut self.bookkeeper; if let Some(name) = book.analysis.meta.fetch_label(invoke) { // only do rewrites if there is actually rewriting to do - if let Some(rename_vec) = book.invoke_map.get(name) { - let empty_map = HashMap::new(); - let rewriter = ir::Rewriter::new(rename_vec, &empty_map); - rewriter.rewrite_invoke(invoke, &HashMap::new()); + if let Some(rename_vec) = book.invoke_map.get_mut(name) { + let cell_map = std::mem::take(rename_vec); + let rewriter = ir::Rewriter { + cell_map, + ..Default::default() + }; + rewriter.rewrite_invoke(invoke); + *rename_vec = rewriter.cell_map; } } @@ -219,14 +225,18 @@ impl Visitor for RegisterUnsharing { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - let book = &self.bookkeeper; + let book = &mut self.bookkeeper; if let Some(name) = book.analysis.meta.fetch_label_static(invoke) { // only do rewrites if there is actually rewriting to do - if let Some(rename_vec) = book.invoke_map.get(name) { - let empty_map = HashMap::new(); - let rewriter = ir::Rewriter::new(rename_vec, &empty_map); + if let Some(rename_vec) = book.invoke_map.get_mut(name) { + let cell_map = std::mem::take(rename_vec); + let rewriter = ir::Rewriter { + cell_map, + ..Default::default() + }; rewriter.rewrite_static_invoke(invoke); + *rename_vec = rewriter.cell_map; } } From 84524583965e12730ee771b7aa88f1568721c0ed Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 24 Aug 2023 23:03:10 +0530 Subject: [PATCH 050/189] Compile-invoke compiles `ref` cells as well (#1692) * compile-invoke compiles `ref` cells as well * update tests and remove compile-ref pass * add changelog * invoke ref test * add higher-order test --- CHANGELOG.md | 1 + calyx-ir/src/rewriter.rs | 15 + calyx-opt/src/default_passes.rs | 13 +- calyx-opt/src/passes/compile_invoke.rs | 303 +++++++++++++++--- calyx-opt/src/passes/compile_ref.rs | 253 --------------- calyx-opt/src/passes/dump_ports.rs | 2 +- calyx-opt/src/passes/mod.rs | 2 - .../correctness/ref-cells/higher-order.expect | 42 +++ .../correctness/ref-cells/higher-order.futil | 137 ++++++++ .../ref-cells/higher-order.futil.data | 70 ++++ .../compile-invoke/compile-invoke.expect | 8 +- .../compile-static-invoke.expect | 2 +- tests/passes/compile-invoke/invoke-ref.expect | 34 ++ tests/passes/compile-invoke/invoke-ref.futil | 23 ++ .../ref-chain.expect | 38 ++- .../ref-chain.futil | 3 +- .../ref-invoke.expect | 38 ++- .../ref-invoke.futil | 5 +- tests/passes/compile-invoke/ref.expect | 38 +++ tests/passes/compile-invoke/ref.futil | 35 ++ .../static-ref.expect | 13 +- .../static-ref.futil | 3 +- tests/passes/compile-ref/ref.expect | 67 ---- tests/passes/compile-ref/ref.futil | 69 ---- 24 files changed, 713 insertions(+), 501 deletions(-) delete mode 100644 calyx-opt/src/passes/compile_ref.rs create mode 100644 tests/correctness/ref-cells/higher-order.expect create mode 100644 tests/correctness/ref-cells/higher-order.futil create mode 100644 tests/correctness/ref-cells/higher-order.futil.data create mode 100644 tests/passes/compile-invoke/invoke-ref.expect create mode 100644 tests/passes/compile-invoke/invoke-ref.futil rename tests/passes/{compile-ref => compile-invoke}/ref-chain.expect (64%) rename tests/passes/{compile-ref => compile-invoke}/ref-chain.futil (95%) rename tests/passes/{compile-ref => compile-invoke}/ref-invoke.expect (52%) rename tests/passes/{compile-ref => compile-invoke}/ref-invoke.futil (85%) create mode 100644 tests/passes/compile-invoke/ref.expect create mode 100644 tests/passes/compile-invoke/ref.futil rename tests/passes/{compile-ref => compile-invoke}/static-ref.expect (81%) rename tests/passes/{compile-ref => compile-invoke}/static-ref.futil (93%) delete mode 100644 tests/passes/compile-ref/ref.expect delete mode 100644 tests/passes/compile-ref/ref.futil diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bfe040c3..d904b5d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Unreleased - BREAKING: Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. - BREAKING: Redesign the `ir::Rewriter` interface to take all the rewrite maps when constructing the `ir::Rewriter` struct. +- Merge the logic of `compile-ref` pass into `compile-invoke` so that `ref` cells can be invoked. ## 0.5.1 - Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. diff --git a/calyx-ir/src/rewriter.rs b/calyx-ir/src/rewriter.rs index 0d6c65ff5..d3815d926 100644 --- a/calyx-ir/src/rewriter.rs +++ b/calyx-ir/src/rewriter.rs @@ -1,6 +1,7 @@ use crate::control::StaticInvoke; use crate::{self as ir, RRC}; use std::borrow::BorrowMut; +use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -257,4 +258,18 @@ impl Rewriter { ir::Control::Static(s) => self.rewrite_static_control(s), } } + + /// Rewrite the component using the given maps + pub fn rewrite(&self, comp: &mut ir::Component) { + // Rewrite all of the ref cell ports + comp.for_each_assignment(|assign| { + self.rewrite_assign(assign); + }); + comp.for_each_static_assignment(|assign| { + self.rewrite_assign(assign); + }); + self.rewrite_control(&mut RefCell::borrow_mut( + comp.control.borrow_mut(), + )); + } } diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 7e2480a14..517fca366 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -1,11 +1,11 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ AttributePromotion, Canonicalize, CellShare, ClkInsertion, CollapseControl, - CombProp, CompileEmpty, CompileInvoke, CompileRef, CompileRepeat, - CompileStatic, CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, - DataPathInfer, DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, - DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, - HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, + CombProp, CompileEmpty, CompileInvoke, CompileRepeat, CompileStatic, + CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, + DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, + Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, + InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, RegisterUnsharing, RemoveIds, ResetInsertion, SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticPromotion, SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, @@ -49,7 +49,6 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -91,7 +90,6 @@ impl PassManager { CombProp, CellShare, // LiveRangeAnalaysis should handle comb groups SimplifyWithControl, // Must run before compile-invoke - CompileRef, //Must run before cell-share, and before component-inliner CompileInvoke, // creates dead comb groups AttributePromotion, StaticPromotion, @@ -150,7 +148,6 @@ impl PassManager { [ "validate", CompileSync, - CompileRef, SimplifyWithControl, CompileInvoke, "compile", diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 8cf367681..8e0458e5b 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -1,15 +1,21 @@ -use crate::traversal::{Action, Named, VisResult, Visitor}; +use crate::traversal::{ + self, Action, ConstructVisitor, Named, VisResult, Visitor, +}; use calyx_ir::structure; use calyx_ir::{self as ir, Attributes, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; +use ir::{RRC, WRC}; use itertools::Itertools; +use std::cell::RefCell; +use std::collections::HashMap; use std::rc::Rc; +use super::dump_ports; + // given `cell_ref` returns the `go` port of the cell (if it only has one `go` port), // or an error otherwise fn get_go_port(cell_ref: ir::RRC) -> CalyxResult> { let cell = cell_ref.borrow(); - let name = cell.name(); // Get the go port @@ -31,7 +37,6 @@ fn get_go_port(cell_ref: ir::RRC) -> CalyxResult> { fn build_assignments( inputs: &mut Vec<(ir::Id, ir::RRC)>, outputs: &mut Vec<(ir::Id, ir::RRC)>, - mut enable_assignments: Vec>, builder: &mut ir::Builder, cell: &ir::Cell, ) -> Vec> { @@ -43,14 +48,69 @@ fn build_assignments( .chain(outputs.drain(..).map(|(out, p)| { builder.build_assignment(p, cell.get(out), ir::Guard::True) })) - .chain(enable_assignments.drain(..)) .collect() } -/// Compiles [`ir::Invoke`](calyx_ir::Invoke) statements into an [`ir::Enable`](calyx_ir::Enable) -/// that runs the invoked component. #[derive(Default)] -pub struct CompileInvoke; +/// Map for storing added ports for each ref cell +/// level of Hashmap represents: +/// HashMap<-component name-, Hashmap<(-ref cell name-,-port name-), port>>; +struct RefPortMap(HashMap>>); + +impl RefPortMap { + fn insert( + &mut self, + comp_name: ir::Id, + ports: HashMap>, + ) { + self.0.insert(comp_name, ports); + } + + fn get( + &self, + comp_name: &ir::Id, + ) -> Option<&HashMap>> { + self.0.get(comp_name) + } + + /// Get all of the newly added ports associated with a component that had + /// ref cells + fn get_ports(&self, comp_name: &ir::Id) -> Option>> { + self.0 + .get(comp_name) + .map(|map| map.values().cloned().collect()) + } +} + +/// Compiles [`ir::Invoke`] statements into an [`ir::Enable`] that runs the +/// invoked component. +pub struct CompileInvoke { + /// Mapping from component to the canonical port name of ref cell o + port_names: RefPortMap, + /// Mapping from the ports of cells that were removed to the new port on the + /// component signature. + removed: HashMap>, + /// Ref cells in the component. We hold onto these so that our references don't get invalidated + ref_cells: Vec>, +} + +impl ConstructVisitor for CompileInvoke { + fn from(_ctx: &ir::Context) -> CalyxResult + where + Self: Sized, + { + Ok(CompileInvoke { + port_names: RefPortMap::default(), + removed: HashMap::new(), + ref_cells: Vec::new(), + }) + } + + fn clear_data(&mut self) { + self.removed.clear(); + self.ref_cells.clear() + } +} impl Named for CompileInvoke { fn name() -> &'static str { @@ -62,7 +122,157 @@ impl Named for CompileInvoke { } } +impl CompileInvoke { + /// Given `ref_cells` of an invoke, returns `(inputs, outputs)` where + /// inputs are the corresponding inputs to the `invoke` and + /// outputs are the corresponding outputs to the `invoke`. + /// + /// Since this pass eliminates all ref cells in post order, we expect that + /// invoked component already had all of its ref cells removed. + fn ref_cells_to_ports( + &mut self, + inv_cell: RRC, + ref_cells: impl Iterator)>, + ) -> Vec> { + let inv_comp = inv_cell.borrow().type_name().unwrap(); + let mut assigns = Vec::new(); + for (ref_cell_name, cell) in ref_cells { + log::debug!( + "Removing ref cell `{}` with {} ports", + ref_cell_name, + cell.borrow().ports.len() + ); + + // Mapping from canonical names of the ports of the ref cell to the + // new port defined on the signature of the component + let Some(comp_ports) = self.port_names.get(&inv_comp) else { + unreachable!("component `{}` invoked but not already visited by the pass", inv_comp) + }; + + // The type of the cell is the same as the ref cell so we can + // iterate over its ports and generate bindings for the ref cell. + for pr in &cell.borrow().ports { + let port = pr.borrow(); + if port.has_attribute(ir::BoolAttr::Clk) + || port.has_attribute(ir::BoolAttr::Reset) + { + continue; + } + + let canon = ir::Canonical(ref_cell_name, port.name); + let Some(comp_port) = comp_ports.get(&canon) else { + unreachable!("port `{}` not found in the signature of {}. Known ports are: {}", + canon, + inv_comp, + comp_ports.keys().map(|c| c.1.as_ref()).collect_vec().join(", ") + ) + }; + // Get the port on the new cell with the same name as ref_port + let ref_port = inv_cell.borrow().get(comp_port.borrow().name); + log::debug!("Port `{}` -> `{}`", canon, ref_port.borrow().name); + + let old_port = pr.borrow().canonical(); + // If the port has been removed already, get the new port from the component's signature + let arg_port = if let Some(sig_pr) = self.removed.get(&old_port) + { + log::debug!( + "Port `{}` has been removed. Using `{}`", + old_port, + sig_pr.borrow().name + ); + Rc::clone(sig_pr) + } else { + Rc::clone(pr) + }; + + match port.direction { + ir::Direction::Output => { + log::debug!( + "constructing: {} = {}", + ref_port.borrow().canonical(), + arg_port.borrow().canonical() + ); + assigns.push(ir::Assignment::new( + ref_port.clone(), + arg_port, + )); + } + ir::Direction::Input => { + log::debug!( + "constructing: {} = {}", + arg_port.borrow().canonical(), + ref_port.borrow().canonical(), + ); + assigns.push(ir::Assignment::new( + arg_port, + ref_port.clone(), + )); + } + _ => { + unreachable!("Cell should have inout ports"); + } + } + } + } + assigns + } +} + impl Visitor for CompileInvoke { + fn iteration_order() -> crate::traversal::Order + where + Self: Sized, + { + traversal::Order::Post + } + + fn start( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + log::debug!("Visiting `{}`", comp.name); + // For all subcomponents that had a `ref` cell in them, we need to + // update their cell to have the new ports added from inlining the + // signatures of all the ref cells. + for cell in comp.cells.iter() { + let mut new_ports: Vec> = Vec::new(); + if let Some(name) = cell.borrow().type_name() { + if let Some(vec) = self.port_names.get_ports(&name) { + log::debug!( + "Updating ports of cell `{}' (type `{name}')", + cell.borrow().name() + ); + for p in vec.iter() { + let new_port = Rc::new(RefCell::new(ir::Port { + name: p.borrow().name, + width: p.borrow().width, + direction: p.borrow().direction.reverse(), + parent: ir::PortParent::Cell(WRC::from(cell)), + attributes: Attributes::default(), + })); + new_ports.push(new_port); + } + } + } + cell.borrow_mut().ports.extend(new_ports); + } + + let dump_ports::DumpResults { cells, rewrites } = + dump_ports::dump_ports_to_signature( + comp, + |cell| cell.borrow().is_reference(), + true, + ); + + // Hold onto the cells so they don't get dropped. + self.ref_cells = cells; + self.removed = rewrites; + + Ok(Action::Continue) + } + fn invoke( &mut self, s: &mut ir::Invoke, @@ -71,36 +281,20 @@ impl Visitor for CompileInvoke { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, ctx); - let invoke_group = builder.add_group("invoke"); - - if !s.ref_cells.is_empty() { - return Err(Error::malformed_structure(format!( - "Invoke statement contains ref cell. Run {} before this pass", - super::CompileRef::name() - ))); - } + // Assigns representing the ref cell connections + invoke_group.borrow_mut().assignments.extend( + self.ref_cells_to_ports(Rc::clone(&s.comp), s.ref_cells.drain(..)), + ); // comp.go = 1'd1; // invoke[done] = comp.done; structure!(builder; let one = constant(1, 1); ); - let cell = s.comp.borrow(); - let name = cell.name(); - - // Get the go port let go_port = get_go_port(Rc::clone(&s.comp))?; - - // Get the done ports - let mut done_ports = - cell.find_all_with_attr(ir::NumAttr::Done).collect_vec(); - if done_ports.len() > 1 { - return Err(Error::malformed_control(format!("Invoked component `{name}` defines multiple @done signals. Cannot compile the invoke"))); - } else if done_ports.is_empty() { - return Err(Error::malformed_control(format!("Invoked component `{name}` does not define a @done signal. Cannot compile the invoke"))); - } + let done_port = cell.find_unique_with_attr(ir::NumAttr::Done)?.unwrap(); // Build assignemnts let go_assign = builder.build_assignment( @@ -110,21 +304,24 @@ impl Visitor for CompileInvoke { ); let done_assign = builder.build_assignment( invoke_group.borrow().get("done"), - done_ports.pop().unwrap(), + done_port, ir::Guard::True, ); - let enable_assignments = vec![go_assign, done_assign]; + + invoke_group + .borrow_mut() + .assignments + .extend(vec![go_assign, done_assign]); // Generate argument assignments let cell = &*s.comp.borrow(); let assigns = build_assignments( &mut s.inputs, &mut s.outputs, - enable_assignments, &mut builder, cell, ); - invoke_group.borrow_mut().assignments = assigns; + invoke_group.borrow_mut().assignments.extend(assigns); // Add assignments from the attached combinational group if let Some(cgr) = &s.comb_group { @@ -165,13 +362,6 @@ impl Visitor for CompileInvoke { let invoke_group = builder.add_static_group("static_invoke", s.latency); - if !s.ref_cells.is_empty() { - return Err(Error::malformed_structure(format!( - "Invoke statement contains ref cell. Run {} before this pass", - super::CompileRef::name() - ))); - } - // comp.go = 1'd1; structure!(builder; let one = constant(1, 1); @@ -181,24 +371,23 @@ impl Visitor for CompileInvoke { let go_port = get_go_port(Rc::clone(&s.comp))?; // Build assignemnts - let go_assign = builder.build_assignment( - go_port, - one.borrow().get("out"), - ir::Guard::True, - ); - - let enable_assignments = vec![go_assign]; + let go_assign: ir::Assignment = builder + .build_assignment( + go_port, + one.borrow().get("out"), + ir::Guard::True, + ); + invoke_group.borrow_mut().assignments.push(go_assign); // Generate argument assignments let cell = &*s.comp.borrow(); let assigns = build_assignments( &mut s.inputs, &mut s.outputs, - enable_assignments, &mut builder, cell, ); - invoke_group.borrow_mut().assignments = assigns; + invoke_group.borrow_mut().assignments.extend(assigns); let en = ir::StaticEnable { group: invoke_group, @@ -209,4 +398,22 @@ impl Visitor for CompileInvoke { en, )))) } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + let port_map = std::mem::take(&mut self.removed); + // Add the newly added port to the global port map + // Rewrite all of the ref cell ports + let rw = ir::Rewriter { + port_map, + ..Default::default() + }; + rw.rewrite(comp); + self.port_names.insert(comp.name, rw.port_map); + Ok(Action::Continue) + } } diff --git a/calyx-opt/src/passes/compile_ref.rs b/calyx-opt/src/passes/compile_ref.rs deleted file mode 100644 index 5eb35c5ff..000000000 --- a/calyx-opt/src/passes/compile_ref.rs +++ /dev/null @@ -1,253 +0,0 @@ -use super::dump_ports; -use crate::traversal::{ - Action, ConstructVisitor, Named, Order, VisResult, Visitor, -}; -use calyx_ir::{self as ir, Attributes, LibrarySignatures, RRC, WRC}; -use calyx_utils::CalyxResult; -use itertools::Itertools; -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; - -type PortMap = Vec<(ir::Id, ir::RRC)>; - -/// Map for storing added ports for each ref cell -/// level of Hashmap represents: -/// HashMap<-component name-, Hashmap<(-ref cell name-,-port name-), port>>; -pub(super) type RefPortMap = - HashMap>>; - -trait GetPorts { - fn get_ports(&self, comp_name: &ir::Id) -> Option>>; -} - -impl GetPorts for RefPortMap { - fn get_ports(&self, comp_name: &ir::Id) -> Option>> { - if self.contains_key(comp_name) { - let mut ret = Vec::new(); - for (_, p) in self[comp_name].iter() { - ret.push(Rc::clone(p)); - } - Some(ret) - } else { - None - } - } -} - -/// Pass to eliminate `ref` cells from the program. -/// 1. Remove all the cells marked with the 'ref' keyword -/// 2. Inline all the ports of the ref cells to the component signature -/// 3. Remove all the ref cell mappings from the invoke statement -/// 4. Inline all the mappings of ports to the invoke signature -pub struct CompileRef { - port_names: RefPortMap, - /// Mapping from the ports of cells that were removed to the new port on the - /// component signature. - removed: HashMap>, - /// Ref cells in the component. We hold onto these so that our references don't get invalidated - ref_cells: Vec>, -} - -impl ConstructVisitor for CompileRef { - fn from(_ctx: &ir::Context) -> CalyxResult - where - Self: Sized, - { - Ok(CompileRef { - port_names: HashMap::new(), - removed: HashMap::new(), - ref_cells: Vec::new(), - }) - } - - fn clear_data(&mut self) { - self.removed.clear(); - self.ref_cells.clear() - } -} - -fn is_external_cell(cr: &RRC) -> bool { - cr.borrow().is_reference() -} - -impl Named for CompileRef { - fn name() -> &'static str { - "compile-ref" - } - - fn description() -> &'static str { - "Inline the ports of reference cells to component signature and the invoke signature" - } -} - -impl CompileRef { - /// Given `ref_cells` of an invoke, returns `(inputs, outputs)` where - /// inputs are the corresponding inputs to the `invoke` and - /// outputs are the corresponding outputs to the `invoke`. - /// - /// Since this pass eliminates all ref cells in post order, we expect that - /// invoked component already had all of its ref cells removed. - fn ref_cells_to_ports( - &mut self, - inv_comp: ir::Id, - ref_cells: Vec<(ir::Id, ir::RRC)>, - ) -> (PortMap, PortMap) { - let mut inputs = Vec::new(); - let mut outputs = Vec::new(); - for (ref_cell_name, cell) in ref_cells { - log::debug!( - "Removing ref cell `{}` with {} ports", - ref_cell_name, - cell.borrow().ports.len() - ); - let Some(comp_ports) = self.port_names.get(&inv_comp) else { - unreachable!("component `{}` invoked but not already visited by the pass", inv_comp) - }; - // The type of the cell is the same as the ref cell so we can - // iterate over its ports and generate bindings for the ref cell. - for pr in &cell.borrow().ports { - let port = pr.borrow(); - if !port.attributes.has(ir::BoolAttr::Clk) - && !port.attributes.has(ir::BoolAttr::Reset) - { - log::debug!("Adding port `{}`", port.name); - let canon = ir::Canonical(ref_cell_name, port.name); - let Some(ref_port) = comp_ports.get(&canon) else { - unreachable!("port `{}` not found. Known ports are: {}", - canon, - comp_ports.keys().map(|c| c.1.as_ref()).collect_vec().join(", ") - ) - }; - let port_name = ref_port.borrow().name; - let old_port = pr.borrow().canonical(); - // If the port has been removed already, get the new port from the component's signature - let port_bind = - if let Some(sig_pr) = self.removed.get(&old_port) { - log::debug!( - "Port `{}` has been removed. Using `{}`", - old_port, - sig_pr.borrow().name - ); - (port_name, Rc::clone(sig_pr)) - } else { - (port_name, Rc::clone(pr)) - }; - - match port.direction { - ir::Direction::Input => { - outputs.push(port_bind); - } - ir::Direction::Output => { - inputs.push(port_bind); - } - _ => { - unreachable!("Cell should have inout ports"); - } - } - } - } - } - (inputs, outputs) - } -} - -impl Visitor for CompileRef { - fn iteration_order() -> Order { - Order::Post - } - - fn start( - &mut self, - comp: &mut ir::Component, - _ctx: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - log::debug!("compile-ref: {}", comp.name); - let dump_ports::DumpResults { cells, rewrites } = - dump_ports::dump_ports_to_signature(comp, is_external_cell, true); - self.removed.extend(rewrites.clone()); - self.port_names.insert(comp.name, rewrites); - self.ref_cells = cells; - - // For all subcomponents that had a `ref` cell in them, we need to - // update their cell to have the new ports added from inlining the - // signatures of all the ref cells. - for cell in comp.cells.iter() { - let mut new_ports: Vec> = Vec::new(); - if let Some(name) = cell.borrow().type_name() { - if let Some(vec) = self.port_names.get_ports(&name) { - log::debug!( - "Updating ports of cell `{}' (type `{name}')", - cell.borrow().name() - ); - for p in vec.iter() { - let new_port = Rc::new(RefCell::new(ir::Port { - name: p.borrow().name, - width: p.borrow().width, - direction: p.borrow().direction.reverse(), - parent: ir::PortParent::Cell(WRC::from(cell)), - attributes: Attributes::default(), - })); - new_ports.push(new_port); - } - } - } - cell.borrow_mut().ports.extend(new_ports); - } - Ok(Action::Continue) - } - - fn invoke( - &mut self, - s: &mut ir::Invoke, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let comp_name = s.comp.borrow().type_name().unwrap(); - let ref_cells = std::mem::take(&mut s.ref_cells); - let (mut inputs, mut outputs) = - self.ref_cells_to_ports(comp_name, ref_cells); - s.inputs.append(&mut inputs); - s.outputs.append(&mut outputs); - Ok(Action::Continue) - } - fn static_invoke( - &mut self, - s: &mut ir::StaticInvoke, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let comp_name = s.comp.borrow().type_name().unwrap(); - let ref_cells = std::mem::take(&mut s.ref_cells); - let (mut inputs, mut outputs) = - self.ref_cells_to_ports(comp_name, ref_cells); - s.inputs.append(&mut inputs); - s.outputs.append(&mut outputs); - Ok(Action::Continue) - } - - fn finish( - &mut self, - comp: &mut ir::Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let port_map = std::mem::take(&mut self.removed); - // Rewrite all of the ref cell ports - let rw = ir::Rewriter { - port_map, - ..Default::default() - }; - comp.for_each_assignment(|assign| { - rw.rewrite_assign(assign); - }); - comp.for_each_static_assignment(|assign| { - rw.rewrite_assign(assign); - }); - rw.rewrite_control(&mut comp.control.borrow_mut()); - Ok(Action::Continue) - } -} diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index 532e1ab5d..ce0ab87a0 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -39,7 +39,7 @@ where for cell_ref in &ext_cells { let cell = cell_ref.borrow(); - log::debug!("`{}' is matches predictate", cell.name()); + log::debug!("cell `{}' removed", cell.name()); // If we do not eliminate the @clk and @reset ports, we may // get signals conflicting the original @clk and @reset signals of diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index 781dc0a70..a12982c38 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -7,7 +7,6 @@ mod collapse_control; mod comb_prop; mod compile_empty; mod compile_invoke; -mod compile_ref; mod compile_repeat; mod compile_static; mod component_iniliner; @@ -53,7 +52,6 @@ pub use collapse_control::CollapseControl; pub use comb_prop::CombProp; pub use compile_empty::CompileEmpty; pub use compile_invoke::CompileInvoke; -pub use compile_ref::CompileRef; pub use compile_repeat::CompileRepeat; pub use compile_static::CompileStatic; pub use component_iniliner::ComponentInliner; diff --git a/tests/correctness/ref-cells/higher-order.expect b/tests/correctness/ref-cells/higher-order.expect new file mode 100644 index 000000000..159b8bc1a --- /dev/null +++ b/tests/correctness/ref-cells/higher-order.expect @@ -0,0 +1,42 @@ +{ + "A": [ + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ], + "B": [ + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ], + "C": [ + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40 + ], + "stats": [ + 20, + 10 + ] +} diff --git a/tests/correctness/ref-cells/higher-order.futil b/tests/correctness/ref-cells/higher-order.futil new file mode 100644 index 000000000..4d9caf43a --- /dev/null +++ b/tests/correctness/ref-cells/higher-order.futil @@ -0,0 +1,137 @@ +import "primitives/core.futil"; +import "primitives/memories.futil"; + +/// The function we can map over the array. +/// This function increments in input by 10 and tracks the number of elements +/// its processed. +component func() -> (@stable processed: 32) { + cells { + ref in = std_reg(32); + acc_r = std_reg(32); + incr = std_add(32); + add = std_add(32); + } + wires { + group apply { + incr.left = in.out; + incr.right = 32'd10; + in.in = incr.out; + in.write_en = 1'd1; + apply[done] = in.done; + } + group bump_proc { + add.left = acc_r.out; + add.right = 32'd1; + acc_r.in = add.out; + acc_r.write_en = 1'd1; + bump_proc[done] = acc_r.done; + } + processed = acc_r.out; + } + control { + seq { apply; bump_proc; } + } +} + +// A component that takes an array and a function and applies the function to +// each element, returning the result. +component map_f() -> () { + cells { + // We have to pre-commit to the function we'll call which means this is + // not really a higher-order map. However, we can certainly pass in + // different inputs for the function. + // In Rust-terms, this is a FnMut since it updates its own state. + ref func = func(); + // We apply the function and store the result in the output array. + ref in = seq_mem_d1(32, 10, 4); + ref out = seq_mem_d1(32, 10, 4); + idx = std_reg(4); + lt = std_lt(4); + add = std_add(4); + r = std_reg(32); + } + wires { + comb group cmp { + lt.left = idx.out; + lt.right = 4'd10; + } + group init { + idx.write_en = 1'd1; + idx.in = 4'd0; + init[done] = idx.done; + } + group incr { + add.left = idx.out; + add.right = 4'd1; + idx.in = add.out; + idx.write_en = 1'd1; + incr[done] = idx.done; + } + group read_in { + in.read_en = 1'd1; + in.addr0 = idx.out; + read_in[done] = in.read_done; + } + group write_r { + r.write_en = 1'd1; + r.in = in.read_data; + write_r[done] = r.done; + } + group write_out { + out.write_en = 1'd1; + out.addr0 = idx.out; + out.write_data = r.out; + write_out[done] = out.write_done; + } + } + control { + seq { + init; + while lt.out with cmp { + read_in; + write_r; + invoke func[in=r]()(); + write_out; incr; + } + } + } +} + +component main() -> () { + cells { + @external A = seq_mem_d1(32, 10, 4); + @external B = seq_mem_d1(32, 10, 4); + @external C = seq_mem_d1(32, 10, 4); + @external stats = seq_mem_d1(32, 2, 2); + f1 = func(); + f2 = func(); + map = map_f(); + } + wires { + group f1_stats { + stats.addr0 = 2'd0; + stats.write_data = f1.processed; + stats.write_en = 1'd1; + f1_stats[done] = stats.write_done; + } + group f2_stats { + stats.addr0 = 2'd1; + stats.write_data = f2.processed; + stats.write_en = 1'd1; + f2_stats[done] = stats.write_done; + } + } + control { + // The same map can be used with different memories. + invoke map[in=A, func=f1, out=B]()(); + invoke map[in=B, func=f1, out=A]()(); + + // The same map can be used with different functions + invoke map[in=A, func=f2, out=C]()(); + + // Write the statistics computed by the functions + f1_stats; + f2_stats; + } + +} \ No newline at end of file diff --git a/tests/correctness/ref-cells/higher-order.futil.data b/tests/correctness/ref-cells/higher-order.futil.data new file mode 100644 index 000000000..dc21fbff4 --- /dev/null +++ b/tests/correctness/ref-cells/higher-order.futil.data @@ -0,0 +1,70 @@ +{ + "A": { + "data": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "B": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "C": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "stats": { + "data": [ + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/passes/compile-invoke/compile-invoke.expect b/tests/passes/compile-invoke/compile-invoke.expect index 24a920c7d..c7b74e24d 100644 --- a/tests/passes/compile-invoke/compile-invoke.expect +++ b/tests/passes/compile-invoke/compile-invoke.expect @@ -21,16 +21,16 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { group invoke0<"static"=4> { - exp0.base = r.out; - exp0.exp = 4'd3; exp0.go = 1'd1; invoke0[done] = exp0.done; + exp0.base = r.out; + exp0.exp = 4'd3; } group invoke1<"static"=4> { - exp0.base = w.out; - exp0.exp = 4'd3; exp0.go = 1'd1; invoke1[done] = exp0.done; + exp0.base = w.out; + exp0.exp = 4'd3; w.in = 32'd10; } } diff --git a/tests/passes/compile-invoke/compile-static-invoke.expect b/tests/passes/compile-invoke/compile-static-invoke.expect index add955da3..b78e25044 100644 --- a/tests/passes/compile-invoke/compile-static-invoke.expect +++ b/tests/passes/compile-invoke/compile-static-invoke.expect @@ -20,9 +20,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<4> group static_invoke { + exp0.go = 1'd1; exp0.base = r.out; exp0.exp = 4'd3; - exp0.go = 1'd1; } } control { diff --git a/tests/passes/compile-invoke/invoke-ref.expect b/tests/passes/compile-invoke/invoke-ref.expect new file mode 100644 index 000000000..dadf22555 --- /dev/null +++ b/tests/passes/compile-invoke/invoke-ref.expect @@ -0,0 +1,34 @@ +import "primitives/compile.futil"; +component foo(@go go: 1, @clk clk: 1, @reset reset: 1, r_out: 32, r_done: 1) -> (@done done: 1, r_in: 32, r_write_en: 1) { + cells { + } + wires { + group invoke0 { + r_write_en = 1'd1; + invoke0[done] = r_done; + r_in = 32'd10; + } + } + control { + invoke0; + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r0 = std_reg(32); + f = foo(); + } + wires { + group invoke0 { + r0.in = f.r_in; + r0.write_en = f.r_write_en; + f.r_out = r0.out; + f.r_done = r0.done; + f.go = 1'd1; + invoke0[done] = f.done; + } + } + control { + invoke0; + } +} diff --git a/tests/passes/compile-invoke/invoke-ref.futil b/tests/passes/compile-invoke/invoke-ref.futil new file mode 100644 index 000000000..78e3fe79f --- /dev/null +++ b/tests/passes/compile-invoke/invoke-ref.futil @@ -0,0 +1,23 @@ +// -p validate -p compile-invoke +import "primitives/compile.futil"; + +component foo() -> () { + cells { + ref r = std_reg(32); + } + wires {} + control { + invoke r(in = 32'd10)(); + } +} + +component main() -> () { + cells { + r0 = std_reg(32); + f = foo(); + } + wires {} + control { + invoke f[r=r0]()(); + } +} \ No newline at end of file diff --git a/tests/passes/compile-ref/ref-chain.expect b/tests/passes/compile-invoke/ref-chain.expect similarity index 64% rename from tests/passes/compile-ref/ref-chain.expect rename to tests/passes/compile-invoke/ref-chain.expect index 7c7e28dea..6c7460fe4 100644 --- a/tests/passes/compile-ref/ref-chain.expect +++ b/tests/passes/compile-invoke/ref-chain.expect @@ -4,16 +4,19 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { i = incr(); value = std_reg(32); } - wires {} + wires { + group invoke0 { + value.in = i.value_in; + value.write_en = i.value_write_en; + i.value_out = value.out; + i.value_done = value.done; + i.go = 1'd1; + invoke0[done] = i.done; + } + } control { seq { - invoke i( - value_out = value.out, - value_done = value.done - )( - value_in = value.in, - value_write_en = value.write_en - ); + invoke0; } } } @@ -21,16 +24,19 @@ component incr(@go go: 1, @clk clk: 1, @reset reset: 1, value_out: 32, value_don cells { ih = incr_helper(); } - wires {} + wires { + group invoke0 { + value_in = ih.value_in; + value_write_en = ih.value_write_en; + ih.value_out = value_out; + ih.value_done = value_done; + ih.go = 1'd1; + invoke0[done] = ih.done; + } + } control { seq { - invoke ih( - value_out = value_out, - value_done = value_done - )( - value_in = value_in, - value_write_en = value_write_en - ); + invoke0; } } } diff --git a/tests/passes/compile-ref/ref-chain.futil b/tests/passes/compile-invoke/ref-chain.futil similarity index 95% rename from tests/passes/compile-ref/ref-chain.futil rename to tests/passes/compile-invoke/ref-chain.futil index a1281b943..996b1245d 100644 --- a/tests/passes/compile-ref/ref-chain.futil +++ b/tests/passes/compile-invoke/ref-chain.futil @@ -1,5 +1,6 @@ -// -p validate -p compile-ref +// -p validate -p compile-invoke import "primitives/compile.futil"; + component main() -> () { cells { i = incr(); diff --git a/tests/passes/compile-ref/ref-invoke.expect b/tests/passes/compile-invoke/ref-invoke.expect similarity index 52% rename from tests/passes/compile-ref/ref-invoke.expect rename to tests/passes/compile-invoke/ref-invoke.expect index 6d60fd818..fed3a9b24 100644 --- a/tests/passes/compile-ref/ref-invoke.expect +++ b/tests/passes/compile-invoke/ref-invoke.expect @@ -1,5 +1,4 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; +import "primitives/compile.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1, m_out: 32, m_done: 1) -> (@done done: 1, m_in: 32, m_write_en: 1) { cells { r = std_reg(32); @@ -21,23 +20,28 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { k1 = std_reg(32); k2 = std_reg(32); } - wires {} + wires { + group invoke0 { + k1.in = f.m_in; + k1.write_en = f.m_write_en; + f.m_out = k1.out; + f.m_done = k1.done; + f.go = 1'd1; + invoke0[done] = f.done; + } + group invoke1 { + k2.in = f.m_in; + k2.write_en = f.m_write_en; + f.m_out = k2.out; + f.m_done = k2.done; + f.go = 1'd1; + invoke1[done] = f.done; + } + } control { seq { - invoke f( - m_out = k1.out, - m_done = k1.done - )( - m_in = k1.in, - m_write_en = k1.write_en - ); - invoke f( - m_out = k2.out, - m_done = k2.done - )( - m_in = k2.in, - m_write_en = k2.write_en - ); + invoke0; + invoke1; } } } diff --git a/tests/passes/compile-ref/ref-invoke.futil b/tests/passes/compile-invoke/ref-invoke.futil similarity index 85% rename from tests/passes/compile-ref/ref-invoke.futil rename to tests/passes/compile-invoke/ref-invoke.futil index a4985b9cb..27574d340 100644 --- a/tests/passes/compile-ref/ref-invoke.futil +++ b/tests/passes/compile-invoke/ref-invoke.futil @@ -1,6 +1,5 @@ -// -p compile-ref -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; +// -p compile-invoke +import "primitives/compile.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/compile-invoke/ref.expect b/tests/passes/compile-invoke/ref.expect new file mode 100644 index 000000000..20274fc71 --- /dev/null +++ b/tests/passes/compile-invoke/ref.expect @@ -0,0 +1,38 @@ +import "primitives/compile.futil"; +component foo(@go go: 1, @clk clk: 1, @reset reset: 1, r_out: 32, r_done: 1) -> (@done done: 1, r_in: 32, r_write_en: 1) { + cells { + } + wires { + group reg_to_mem { + r_in = 32'd10; + r_write_en = 1'd1; + reg_to_mem[done] = r_done; + } + } + control { + seq { + if r_out { + reg_to_mem; + } + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = foo(); + r0 = std_reg(32); + } + wires { + group invoke0 { + r0.in = f.r_in; + r0.write_en = f.r_write_en; + f.r_out = r0.out; + f.r_done = r0.done; + f.go = 1'd1; + invoke0[done] = f.done; + } + } + control { + invoke0; + } +} diff --git a/tests/passes/compile-invoke/ref.futil b/tests/passes/compile-invoke/ref.futil new file mode 100644 index 000000000..3e2711b8d --- /dev/null +++ b/tests/passes/compile-invoke/ref.futil @@ -0,0 +1,35 @@ +// -p well-formed -p compile-invoke +import "primitives/compile.futil"; + +component foo() -> () { + cells { + ref r = std_reg(32); + } + + wires { + group reg_to_mem { + r.in = 32'd10; + r.write_en = 1'd1; + reg_to_mem[done] = r.done; + } + } + + control { + seq { + if r.out { + reg_to_mem; + } + } + } +} + +component main() -> () { + cells { + f = foo(); + r0 = std_reg(32); + } + wires {} + control { + invoke f[r = r0]()(); + } +} \ No newline at end of file diff --git a/tests/passes/compile-ref/static-ref.expect b/tests/passes/compile-invoke/static-ref.expect similarity index 81% rename from tests/passes/compile-ref/static-ref.expect rename to tests/passes/compile-invoke/static-ref.expect index 2109ed306..a21e4a6bf 100644 --- a/tests/passes/compile-ref/static-ref.expect +++ b/tests/passes/compile-invoke/static-ref.expect @@ -1,5 +1,4 @@ import "primitives/core.futil"; -import "primitives/binary_operators.futil"; static<2> component add_one(@go go: 1, @clk clk: 1, @reset reset: 1, out_read_data: 32, out_done: 1) -> (@done done: 1, out_addr0: 1, out_write_data: 32, out_write_en: 1) { cells { add = std_add(32); @@ -47,17 +46,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { mem.write_en = 1'd1; reg_to_mem[done] = mem.done; } + static<2> group static_invoke { + adder.go = 1'd1; + } } control { seq { - static<2> invoke adder( - out_read_data = mem.read_data, - out_done = mem.done - )( - out_addr0 = mem.addr0, - out_write_data = mem.write_data, - out_write_en = mem.write_en - ); + static_invoke; add_1; reg_to_mem; } diff --git a/tests/passes/compile-ref/static-ref.futil b/tests/passes/compile-invoke/static-ref.futil similarity index 93% rename from tests/passes/compile-ref/static-ref.futil rename to tests/passes/compile-invoke/static-ref.futil index dfce0b4c5..e81531852 100644 --- a/tests/passes/compile-ref/static-ref.futil +++ b/tests/passes/compile-invoke/static-ref.futil @@ -1,6 +1,5 @@ -// -p well-formed -p compile-ref +// -p well-formed -p compile-invoke import "primitives/core.futil"; -import "primitives/binary_operators.futil"; static<2> component add_one() -> () { cells { diff --git a/tests/passes/compile-ref/ref.expect b/tests/passes/compile-ref/ref.expect deleted file mode 100644 index 435b713fd..000000000 --- a/tests/passes/compile-ref/ref.expect +++ /dev/null @@ -1,67 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -component add_one(@go go: 1, @clk clk: 1, @reset reset: 1, out_read_data: 32, out_done: 1) -> (@done done: 1, out_addr0: 1, out_write_data: 32, out_write_en: 1) { - cells { - add = std_add(32); - r = std_reg(32); - } - wires { - group add_1 { - add.left = 32'd1; - add.right = 32'd1; - r.in = add.out; - r.write_en = 1'd1; - add_1[done] = r.done; - } - group reg_to_mem { - out_write_data = r.out; - out_addr0 = 1'd0; - out_write_en = 1'd1; - reg_to_mem[done] = out_done; - } - } - control { - seq { - add_1; - reg_to_mem; - } - } -} -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - adder = add_one(); - @external mem = std_mem_d1(32, 1, 1); - add = std_add(32); - r = std_reg(32); - } - wires { - group add_1 { - add.left = mem.read_data; - mem.addr0 = 1'd0; - add.right = 32'd1; - r.in = add.out; - r.write_en = 1'd1; - add_1[done] = r.done; - } - group reg_to_mem { - mem.addr0 = 1'd0; - mem.write_data = r.out; - mem.write_en = 1'd1; - reg_to_mem[done] = mem.done; - } - } - control { - seq { - invoke adder( - out_read_data = mem.read_data, - out_done = mem.done - )( - out_addr0 = mem.addr0, - out_write_data = mem.write_data, - out_write_en = mem.write_en - ); - add_1; - reg_to_mem; - } - } -} diff --git a/tests/passes/compile-ref/ref.futil b/tests/passes/compile-ref/ref.futil deleted file mode 100644 index 91b8e2893..000000000 --- a/tests/passes/compile-ref/ref.futil +++ /dev/null @@ -1,69 +0,0 @@ -// -p well-formed -p compile-ref -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; - -component add_one() -> () { - cells { - add = std_add(32); - r = std_reg(32); - ref out = std_mem_d1(32, 1, 1); - } - - wires { - group add_1 { - add.left = 32'd1; - add.right = 32'd1; - r.in = add.out; - r.write_en = 1'd1; - add_1[done] = r.done; - } - group reg_to_mem { - out.write_data = r.out; - out.addr0 = 1'd0; - out.write_en = 1'd1; - reg_to_mem[done] = out.done; - } - } - - control { - seq { - add_1; - reg_to_mem; - } - } -} - -component main() -> () { - cells { - adder = add_one(); - @external mem = std_mem_d1(32, 1, 1); - add = std_add(32); - r = std_reg(32); - } - - wires { - group add_1 { - add.left = mem.read_data; - mem.addr0 = 1'd0; - add.right = 32'd1; - r.in = add.out; - r.write_en = 1'd1; - add_1[done] = r.done; - } - - group reg_to_mem { - mem.addr0 = 1'd0; - mem.write_data = r.out; - mem.write_en = 1'd1; - reg_to_mem[done] = mem.done; - } - } - - control { - seq { - invoke adder[out = mem]()(); - add_1; - reg_to_mem; - } - } -} \ No newline at end of file From 691bd5506fbe8f64b84c1da3e87dc02a3f467d95 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Fri, 25 Aug 2023 14:35:35 -0400 Subject: [PATCH 051/189] [Cider] Patch ref-cell bug (#1695) * tiny fix * remove the debug print * remove the space to shrink the diff --- interp/runt.toml | 14 ++++++++++++++ interp/src/interpreter/component_interpreter.rs | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/interp/runt.toml b/interp/runt.toml index 0fe86c28b..f877575d7 100644 --- a/interp/runt.toml +++ b/interp/runt.toml @@ -104,6 +104,20 @@ fud exec --from calyx --to jq \ {} -q """ +[[tests]] +name = "correctness ref cells" +paths = ["../tests/correctness/ref-cells/*.futil"] +cmd = """ +fud exec --from calyx --to jq \ + --through interpreter-out \ + -s calyx.flags "-p compile-invoke" \ + -s verilog.data {}.data \ + -s interpreter.flags " --raw" \ + -s jq.expr ".main" \ + -s jq.flags "--sort-keys " \ + {} -q +""" + [[tests]] name = "numeric types correctness and parsing" paths = [ diff --git a/interp/src/interpreter/component_interpreter.rs b/interp/src/interpreter/component_interpreter.rs index 5e0d4e875..778500df5 100644 --- a/interp/src/interpreter/component_interpreter.rs +++ b/interp/src/interpreter/component_interpreter.rs @@ -421,9 +421,13 @@ impl Primitive for ComponentInterpreter { _inputs: &[(ir::Id, &crate::values::Value)], ) -> InterpreterResult> { if self.interp.is_control() { + if !self.is_done() && !self.go_is_high() { + return Ok(self.look_up_outputs()); + } assert!( self.is_done(), - "Component interpreter reset before finishing" + "Component {} interpreter reset before finishing", + self.full_name_clone ); } From 00227416b55fde57445384c9297ba28a63ffa599 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 30 Aug 2023 11:49:00 +0530 Subject: [PATCH 052/189] generate `calyx.undefined` for `undef` ops (#1704) --- src/backend/mlir.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/backend/mlir.rs b/src/backend/mlir.rs index 20c76f4d8..183306009 100644 --- a/src/backend/mlir.rs +++ b/src/backend/mlir.rs @@ -153,21 +153,22 @@ impl MlirBackend { .map(|(k, v)| (k.as_ref(), *v)) .collect(); match name.as_ref() { + "undef" => { + write!(f, "calyx.undefined @{cell_name}")? + } "std_reg" => { - write!(f, "calyx.register @{}", cell_name)? + write!(f, "calyx.register @{cell_name}")? } "std_mem_d1" => write!( f, - "calyx.memory @{} <[{}] x {}> [{}]", - cell_name, + "calyx.memory @{cell_name} <[{}] x {}> [{}]", bind["SIZE"], bind["WIDTH"], bind["IDX_SIZE"] )?, "std_mem_d2" => write!( f, - "calyx.memory @{} <[{}, {}] x {}> [{}, {}]", - cell_name, + "calyx.memory @{cell_name} <[{}, {}] x {}> [{}, {}]", bind["D0_SIZE"], bind["D1_SIZE"], bind["WIDTH"], @@ -176,8 +177,7 @@ impl MlirBackend { )?, "std_mem_d3" => write!( f, - "calyx.memory @{} <[{}, {}, {}] x {}> [{}, {}, {}]", - cell_name, + "calyx.memory @{cell_name} <[{}, {}, {}] x {}> [{}, {}, {}]", bind["D0_SIZE"], bind["D1_SIZE"], bind["D2_SIZE"], @@ -188,8 +188,7 @@ impl MlirBackend { )?, "std_mem_d4" => write!( f, - "calyx.memory @{} <[{}, {}, {}, {}] x {}> [{}, {}, {}, {}]", - cell_name, + "calyx.memory @{cell_name} <[{}, {}, {}, {}] x {}> [{}, {}, {}, {}]", bind["D0_SIZE"], bind["D1_SIZE"], bind["D2_SIZE"], @@ -200,14 +199,14 @@ impl MlirBackend { bind["D2_IDX_SIZE"], bind["D3_IDX_SIZE"] )?, - prim => write!(f, "calyx.{} @{}", prim, cell_name)?, + prim => write!(f, "calyx.{prim} @{cell_name}")?, } } ir::CellType::Component { name } => { - write!(f, "calyx.instance @{} of @{}", cell_name, name)?; + write!(f, "calyx.instance @{cell_name} of @{name}")?; } ir::CellType::Constant { val, .. } => { - write!(f, "hw.constant {}", val)?; + write!(f, "hw.constant {val}")?; return Ok(false); } _ => (), From 52b85b5640f303ab8b75bb68d247bd0192690c2e Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 30 Aug 2023 11:52:04 +0530 Subject: [PATCH 053/189] allow trailing comma in attribute list (#1703) --- calyx-frontend/src/syntax.pest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx-frontend/src/syntax.pest b/calyx-frontend/src/syntax.pest index b3fe55b56..bbf99dec5 100644 --- a/calyx-frontend/src/syntax.pest +++ b/calyx-frontend/src/syntax.pest @@ -247,7 +247,7 @@ latency_annotation = { "<" ~ bitwidth ~ ">" } attributes = { - "<" ~ (attribute ~ ("," ~ attribute)*) ~ ">" + "<" ~ (attribute ~ ("," ~ attribute)*) ~ ","? ~ ">" } name_with_attribute = { identifier ~ attributes? From 181cd7a3b9d65bf3b33b619403d7d3d65973d7fa Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 30 Aug 2023 12:07:25 +0530 Subject: [PATCH 054/189] add version information for the compiler (#1705) --- src/cmdline.rs | 4 ++++ src/driver.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/cmdline.rs b/src/cmdline.rs index b5da25720..db7f627d6 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -75,6 +75,10 @@ pub struct Opts { #[argh(switch, long = "dump-ir")] /// print out the IR after every pass pub dump_ir: bool, + + #[argh(switch, long = "version")] + /// print out the version information + pub version: bool, } fn read_path(path: &str) -> Result { diff --git a/src/driver.rs b/src/driver.rs index a021c88e9..0a517301a 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -11,6 +11,16 @@ pub fn run_compiler() -> CalyxResult<()> { // parse the command line arguments into Opts struct let mut opts = Opts::get_opts()?; + // Return the version and the git commit this was built on + if opts.version { + println!("Calyx compiler version {}", env!("CARGO_PKG_VERSION")); + println!( + "Library location: {}", + option_env!("CALYX_PRIMITIVES_DIR").unwrap_or(".") + ); + return Ok(()); + } + // enable tracing env_logger::Builder::new() .format_timestamp(None) From 47211699e4a78f5179aeb351e0f5ee5a3783f150 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 30 Aug 2023 19:17:54 +0530 Subject: [PATCH 055/189] move backend code into separate dir (#1706) --- .github/workflows/format.yml | 2 +- Cargo.lock | 345 +++++++++--------- Cargo.toml | 15 +- calyx-backend/Cargo.toml | 43 +++ calyx-backend/src/backend_opt.rs | 75 ++++ calyx-backend/src/lib.rs | 26 ++ {src/backend => calyx-backend/src}/mlir.rs | 1 + .../src}/resources.rs | 2 +- {src/backend => calyx-backend/src}/sexp.rs | 10 +- {src/backend => calyx-backend/src}/traits.rs | 0 {src/backend => calyx-backend/src}/verilog.rs | 2 +- .../src}/xilinx/axi.rs | 0 .../src}/xilinx/axi_address_space.rs | 0 .../src}/xilinx/control_axi.rs | 0 .../src}/xilinx/fsm.rs | 0 .../src}/xilinx/memory_axi.rs | 0 .../src}/xilinx/mod.rs | 0 .../src}/xilinx/toplevel.rs | 2 +- .../src}/xilinx/utils.rs | 0 .../src}/xilinx/xml.rs | 2 +- calyx-opt/src/analysis/compute_static.rs | 16 +- .../src/passes/dead_assignment_removal.rs | 3 +- calyx-opt/src/passes/discover_external.rs | 3 +- calyx-opt/src/passes/group_to_invoke.rs | 6 +- calyx-opt/src/passes/hole_inliner.rs | 2 +- calyx-opt/src/passes/papercut.rs | 2 +- .../src/passes/top_down_compile_control.rs | 4 +- interp/src/flatten/primitives/mod.rs | 2 +- interp/src/primitives/stateful/math.rs | 5 +- src/backend/mod.rs | 7 - src/cmdline.rs | 97 +---- src/driver.rs | 78 ---- src/lib.rs | 9 +- src/main.rs | 75 +++- 34 files changed, 449 insertions(+), 385 deletions(-) create mode 100644 calyx-backend/Cargo.toml create mode 100644 calyx-backend/src/backend_opt.rs create mode 100644 calyx-backend/src/lib.rs rename {src/backend => calyx-backend/src}/mlir.rs (99%) rename {src/backend => calyx-backend/src}/resources.rs (99%) rename {src/backend => calyx-backend/src}/sexp.rs (66%) rename {src/backend => calyx-backend/src}/traits.rs (100%) rename {src/backend => calyx-backend/src}/verilog.rs (99%) rename {src/backend => calyx-backend/src}/xilinx/axi.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/axi_address_space.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/control_axi.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/fsm.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/memory_axi.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/mod.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/toplevel.rs (99%) rename {src/backend => calyx-backend/src}/xilinx/utils.rs (100%) rename {src/backend => calyx-backend/src}/xilinx/xml.rs (99%) delete mode 100644 src/backend/mod.rs delete mode 100644 src/driver.rs diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 2c53a2ff7..b4c1bcc6e 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -12,7 +12,7 @@ jobs: - name: Install stable uses: actions-rs/toolchain@v1 with: - toolchain: 1.66.0 + toolchain: 1.69.0 override: true components: rustfmt, clippy - name: Check formatting diff --git a/Cargo.lock b/Cargo.lock index f5aa4e361..706f82a0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,9 +27,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "argh" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e" +checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219" dependencies = [ "argh_derive", "argh_shared", @@ -61,21 +61,24 @@ dependencies = [ [[package]] name = "argh_derive" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6" +checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a" dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.29", ] [[package]] name = "argh_shared" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f" +checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531" +dependencies = [ + "serde", +] [[package]] name = "arrayvec" @@ -108,9 +111,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" [[package]] name = "bit-set" @@ -135,9 +138,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -188,20 +191,39 @@ version = "0.5.1" dependencies = [ "argh", "atty", + "calyx-backend", "calyx-frontend", "calyx-ir", "calyx-opt", "calyx-stdlib", "calyx-utils", "criterion", - "csv", "env_logger", "itertools 0.10.5", "log", + "serde", + "serde_sexpr", + "serde_with 3.3.0", +] + +[[package]] +name = "calyx-backend" +version = "0.5.0" +dependencies = [ + "calyx-frontend", + "calyx-ir", + "calyx-utils", + "csv", + "itertools 0.10.5", + "linked-hash-map", + "log", + "petgraph", "quick-xml", "serde", "serde_sexpr", - "serde_with 3.1.0", + "serde_with 3.3.0", + "smallvec", + "string-interner", "vast", ] @@ -219,7 +241,7 @@ dependencies = [ "pest_consume", "pest_derive", "serde", - "serde_with 3.1.0", + "serde_with 3.3.0", "smallvec", "strum", "strum_macros", @@ -236,7 +258,7 @@ dependencies = [ "log", "petgraph", "serde", - "serde_with 3.1.0", + "serde_with 3.3.0", "smallvec", "string-interner", ] @@ -297,9 +319,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -309,15 +334,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "f56b4c72906975ca04becb8a30e102dfecddd0c06181e3e95ddc444be28881f8" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "winapi", + "windows-targets", ] [[package]] @@ -544,7 +569,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] @@ -566,7 +591,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] @@ -584,6 +609,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "deranged" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +dependencies = [ + "serde", +] + [[package]] name = "digest" version = "0.10.7" @@ -617,9 +651,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "endian-type" @@ -638,11 +672,17 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -671,12 +711,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "fd-lock" @@ -685,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix 0.38.3", + "rustix", "windows-sys", ] @@ -764,6 +801,12 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.4.1" @@ -845,12 +888,14 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown 0.14.0", + "serde", ] [[package]] @@ -887,17 +932,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.2", - "libc", - "windows-sys", -] - [[package]] name = "itertools" version = "0.9.0" @@ -918,9 +952,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -957,27 +991,21 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" [[package]] name = "memoffset" @@ -1034,9 +1062,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -1046,9 +1074,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ "num-traits", "serde", @@ -1137,9 +1165,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "pest" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ "thiserror", "ucd-trie", @@ -1169,9 +1197,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -1179,22 +1207,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] name = "pest_meta" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", @@ -1203,12 +1231,12 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 2.0.0", ] [[package]] @@ -1259,9 +1287,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -1294,9 +1322,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.28.2" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" dependencies = [ "memchr", "serde", @@ -1304,9 +1332,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1419,25 +1447,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -1448,42 +1476,28 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" - -[[package]] -name = "rustix" -version = "0.37.23" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys", -] +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rustix" -version = "0.38.3" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "rusty-fork" @@ -1522,9 +1536,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -1543,9 +1557,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.171" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1562,20 +1576,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -1604,17 +1618,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e47d95bc83ed33b2ecf84f4187ad1ab9685d18ff28db000c99deac8ce180e3" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" dependencies = [ - "base64 0.21.2", + "base64 0.21.3", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", + "indexmap 2.0.0", "serde", "serde_json", - "serde_with_macros 3.1.0", + "serde_with_macros 3.3.0", "time", ] @@ -1632,14 +1647,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3cee93715c2e266b9338b7544da68a9f24e227722ba482bd1c024367c77c65" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] @@ -1661,9 +1676,9 @@ checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" [[package]] name = "slog-async" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "766c59b252e62a34651412870ff55d8c4e6d04df19b43eecb2703e417b097ffe" +checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" dependencies = [ "crossbeam-channel", "slog", @@ -1765,9 +1780,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -1788,15 +1803,14 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix", "windows-sys", ] @@ -1831,22 +1845,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.29", ] [[package]] @@ -1861,10 +1875,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ + "deranged", "itoa", "libc", "num_threads", @@ -1881,9 +1896,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -1924,9 +1939,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-segmentation" @@ -2110,9 +2125,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2125,45 +2140,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "wyz" diff --git a/Cargo.toml b/Cargo.toml index d7f1905bf..43b96da2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "calyx-opt", "calyx-frontend", "calyx-stdlib", + "calyx-backend", "interp", "web/rust", "tools/data_gen", @@ -24,7 +25,7 @@ categories = ["compilers"] homepage = "https://calyxir.org" edition = "2021" version = "0.5.0" -rust-version = "1.66" +rust-version = "1.67" [workspace.dependencies] itertools = "0.10" @@ -45,6 +46,7 @@ calyx-utils = { path = "calyx-utils", version = "0.5.0" } calyx-ir = { path = "calyx-ir", version = "0.5.0" } calyx-frontend = { path = "calyx-frontend", version = "0.5.0" } calyx-opt = { path = "calyx-opt", version = "0.5.0" } +calyx-backend = { path = "calyx-backend", version = "0.5.0" } [workspace.dependencies.petgraph] version = "0.6" @@ -77,8 +79,8 @@ path = "src/main.rs" default = [] serialize = [ "dep:serde_with", - "calyx-ir/serialize", "dep:serde_sexpr", + "calyx-ir/serialize", "serde/rc", ] @@ -93,18 +95,15 @@ serde.workspace = true serde_with = { workspace = true, optional = true } serde_sexpr = { workspace = true, optional = true } argh.workspace = true -csv = "1.1" -vast = "0.3.1" calyx-utils.workspace = true calyx-ir.workspace = true calyx-frontend.workspace = true calyx-opt.workspace = true -[dependencies.quick-xml] -version = "0.28" -default-features = false -features = ["serialize"] +[dependencies.calyx-backend] +workspace = true +features = ["mlir", "resources", "xilinx", "sexp"] [dependencies.env_logger] version = "0.9.0" diff --git a/calyx-backend/Cargo.toml b/calyx-backend/Cargo.toml new file mode 100644 index 000000000..dfe6c4b91 --- /dev/null +++ b/calyx-backend/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "calyx-backend" +version.workspace = true +edition.workspace = true +description.workspace = true +authors.workspace = true +license-file.workspace = true +keywords.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +readme.workspace = true + +[dependencies] +log.workspace = true +petgraph.workspace = true +string-interner.workspace = true +itertools.workspace = true +linked-hash-map.workspace = true +serde = { workspace = true } +serde_with = { workspace = true, optional = true } +serde_sexpr = { workspace = true, optional = true } +smallvec.workspace = true + +calyx-utils.workspace = true +calyx-frontend.workspace = true +calyx-ir.workspace = true + +csv = { version = "1.1", optional = true } +vast = "0.3.1" + +[dependencies.quick-xml] +version = "0.30" +features = ["serialize"] +default-features = false +optional = true + +[features] +default = [] +mlir = [] +xilinx = ["dep:quick-xml"] +resources = ["dep:csv"] +sexp = ["dep:serde_with", "dep:serde_sexpr", "serde/rc", "calyx-ir/serialize"] diff --git a/calyx-backend/src/backend_opt.rs b/calyx-backend/src/backend_opt.rs new file mode 100644 index 000000000..fec1144cf --- /dev/null +++ b/calyx-backend/src/backend_opt.rs @@ -0,0 +1,75 @@ +use itertools::Itertools; +use std::str::FromStr; + +/// Enumeration of valid backends +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub enum BackendOpt { + #[default] + Calyx, + Verilog, + Xilinx, + XilinxXml, + Mlir, + Resources, + Sexp, + None, +} + +/// Return a vector that maps strings to Backends. +#[inline(always)] +fn backends() -> Vec<(&'static str, BackendOpt)> { + vec![ + ("verilog", BackendOpt::Verilog), + ("xilinx", BackendOpt::Xilinx), + ("xilinx-xml", BackendOpt::XilinxXml), + ("calyx", BackendOpt::Calyx), + ("mlir", BackendOpt::Mlir), + ("resources", BackendOpt::Resources), + ("sexp", BackendOpt::Sexp), + ("none", BackendOpt::None), + ] +} + +/// Command line parsing for the Backend enum +impl FromStr for BackendOpt { + type Err = String; + fn from_str(input: &str) -> Result { + // allocate a vector for the list of backends + let backends = backends(); + // see if there is a backend for the string that we receive + let found_backend = backends + .iter() + .find(|(backend_name, _)| &input == backend_name); + if let Some((_, opt)) = found_backend { + // return the BackendOpt if we found one + Ok(opt.clone()) + } else { + // build list of backends for error message + let backend_str = backends + .iter() + .map(|(name, _)| (*name).to_string()) + .join(", "); + Err(format!( + "`{}` is not a valid backend.\nValid backends: {}", + input, backend_str + )) + } + } +} + +/// Convert `BackendOpt` to a string +impl ToString for BackendOpt { + fn to_string(&self) -> String { + match self { + Self::Mlir => "mlir", + Self::Resources => "resources", + Self::Sexp => "sexp", + Self::Verilog => "verilog", + Self::Xilinx => "xilinx", + Self::XilinxXml => "xilinx-xml", + Self::Calyx => "calyx", + Self::None => "none", + } + .to_string() + } +} diff --git a/calyx-backend/src/lib.rs b/calyx-backend/src/lib.rs new file mode 100644 index 000000000..04efe3577 --- /dev/null +++ b/calyx-backend/src/lib.rs @@ -0,0 +1,26 @@ +//! Backends for the Calyx compiler. +mod backend_opt; +mod traits; +mod verilog; + +pub use backend_opt::BackendOpt; +pub use traits::Backend; +pub use verilog::VerilogBackend; + +#[cfg(feature = "mlir")] +mod mlir; +#[cfg(feature = "mlir")] +pub use mlir::MlirBackend; + +#[cfg(feature = "resources")] +mod resources; +#[cfg(feature = "resources")] +pub use resources::ResourcesBackend; + +#[cfg(feature = "sexp")] +mod sexp; +#[cfg(feature = "sexp")] +pub use sexp::SexpBackend; + +#[cfg(feature = "xilinx")] +pub mod xilinx; diff --git a/src/backend/mlir.rs b/calyx-backend/src/mlir.rs similarity index 99% rename from src/backend/mlir.rs rename to calyx-backend/src/mlir.rs index 183306009..baca083af 100644 --- a/src/backend/mlir.rs +++ b/calyx-backend/src/mlir.rs @@ -1,3 +1,4 @@ +//! Generation for the MLIR backend of the Calyx compiler use super::traits::Backend; use calyx_frontend::GetAttributes; use calyx_ir::{self as ir, RRC}; diff --git a/src/backend/resources.rs b/calyx-backend/src/resources.rs similarity index 99% rename from src/backend/resources.rs rename to calyx-backend/src/resources.rs index e770b8b5b..c774120c1 100644 --- a/src/backend/resources.rs +++ b/calyx-backend/src/resources.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use std::fmt::Write; use std::vec; -use crate::backend::traits::Backend; +use crate::traits::Backend; use calyx_ir as ir; use calyx_utils::{CalyxResult, OutputFile}; diff --git a/src/backend/sexp.rs b/calyx-backend/src/sexp.rs similarity index 66% rename from src/backend/sexp.rs rename to calyx-backend/src/sexp.rs index d16cd0666..7670edcea 100644 --- a/src/backend/sexp.rs +++ b/calyx-backend/src/sexp.rs @@ -1,7 +1,7 @@ //! Pretty-printer for Calyx syntax. //! Outputs s-expressions. -use crate::backend::traits::Backend; +use crate::traits::Backend; use calyx_ir as ir; use calyx_utils::{CalyxResult, OutputFile}; @@ -26,18 +26,10 @@ impl Backend for SexpBackend { Ok(()) } - #[cfg(feature = "serialize")] fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { let out = &mut file.get_write(); writeln!(out, "{}", serde_sexpr::to_string(ctx).unwrap())?; Ok(()) } - - #[cfg(not(feature = "serialize"))] - fn emit(_ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { - let out = &mut file.get_write(); - writeln!(out, "The serialize feature is not enabled. To compile Calyx with the serialize feature, run `cargo build --features serialize`")?; - Ok(()) - } } diff --git a/src/backend/traits.rs b/calyx-backend/src/traits.rs similarity index 100% rename from src/backend/traits.rs rename to calyx-backend/src/traits.rs diff --git a/src/backend/verilog.rs b/calyx-backend/src/verilog.rs similarity index 99% rename from src/backend/verilog.rs rename to calyx-backend/src/verilog.rs index 354657414..2b330c738 100644 --- a/src/backend/verilog.rs +++ b/calyx-backend/src/verilog.rs @@ -3,7 +3,7 @@ //! Transforms an [`ir::Context`](crate::ir::Context) into a formatted string that represents a //! valid SystemVerilog program. -use crate::backend::traits::Backend; +use crate::traits::Backend; use calyx_ir::{self as ir, Control, FlatGuard, Group, Guard, GuardRef, RRC}; use calyx_utils::{CalyxResult, Error, OutputFile}; use ir::Nothing; diff --git a/src/backend/xilinx/axi.rs b/calyx-backend/src/xilinx/axi.rs similarity index 100% rename from src/backend/xilinx/axi.rs rename to calyx-backend/src/xilinx/axi.rs diff --git a/src/backend/xilinx/axi_address_space.rs b/calyx-backend/src/xilinx/axi_address_space.rs similarity index 100% rename from src/backend/xilinx/axi_address_space.rs rename to calyx-backend/src/xilinx/axi_address_space.rs diff --git a/src/backend/xilinx/control_axi.rs b/calyx-backend/src/xilinx/control_axi.rs similarity index 100% rename from src/backend/xilinx/control_axi.rs rename to calyx-backend/src/xilinx/control_axi.rs diff --git a/src/backend/xilinx/fsm.rs b/calyx-backend/src/xilinx/fsm.rs similarity index 100% rename from src/backend/xilinx/fsm.rs rename to calyx-backend/src/xilinx/fsm.rs diff --git a/src/backend/xilinx/memory_axi.rs b/calyx-backend/src/xilinx/memory_axi.rs similarity index 100% rename from src/backend/xilinx/memory_axi.rs rename to calyx-backend/src/xilinx/memory_axi.rs diff --git a/src/backend/xilinx/mod.rs b/calyx-backend/src/xilinx/mod.rs similarity index 100% rename from src/backend/xilinx/mod.rs rename to calyx-backend/src/xilinx/mod.rs diff --git a/src/backend/xilinx/toplevel.rs b/calyx-backend/src/xilinx/toplevel.rs similarity index 99% rename from src/backend/xilinx/toplevel.rs rename to calyx-backend/src/xilinx/toplevel.rs index b5d814f91..543754123 100644 --- a/src/backend/xilinx/toplevel.rs +++ b/calyx-backend/src/xilinx/toplevel.rs @@ -2,7 +2,7 @@ use super::{ axi, control_axi::ControlInterface, fsm, memory_axi::bram, memory_axi::MemoryInterface, utils, }; -use crate::backend::traits::Backend; +use crate::traits::Backend; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error}; use vast::v05::ast as v; diff --git a/src/backend/xilinx/utils.rs b/calyx-backend/src/xilinx/utils.rs similarity index 100% rename from src/backend/xilinx/utils.rs rename to calyx-backend/src/xilinx/utils.rs diff --git a/src/backend/xilinx/xml.rs b/calyx-backend/src/xilinx/xml.rs similarity index 99% rename from src/backend/xilinx/xml.rs rename to calyx-backend/src/xilinx/xml.rs index 336c7f156..2c0759382 100644 --- a/src/backend/xilinx/xml.rs +++ b/calyx-backend/src/xilinx/xml.rs @@ -1,4 +1,4 @@ -use crate::backend::traits::Backend; +use crate::traits::Backend; use calyx_ir as ir; use calyx_utils::CalyxResult; use serde::Serialize; diff --git a/calyx-opt/src/analysis/compute_static.rs b/calyx-opt/src/analysis/compute_static.rs index bb0e3d4c0..67102da2a 100644 --- a/calyx-opt/src/analysis/compute_static.rs +++ b/calyx-opt/src/analysis/compute_static.rs @@ -163,7 +163,9 @@ impl IntoStatic for ir::Seq { } for stmt in self.stmts.drain(..) { - let ir::Control::Static(sc) = stmt else {unreachable!("We have already checked that all control statements are static")}; + let ir::Control::Static(sc) = stmt else { + unreachable!("We have already checked that all control statements are static") + }; latency += sc.get_latency(); static_stmts.push(sc); } @@ -188,7 +190,9 @@ impl IntoStatic for ir::Par { } for stmt in self.stmts.drain(..) { - let ir::Control::Static(sc) = stmt else {unreachable!("We have already checked that all control statements are static")}; + let ir::Control::Static(sc) = stmt else { + unreachable!("We have already checked that all control statements are static") + }; latency = std::cmp::max(latency, sc.get_latency()); static_stmts.push(sc); } @@ -209,11 +213,11 @@ impl IntoStatic for ir::If { let tb = std::mem::replace(&mut *self.tbranch, ir::Control::empty()); let fb = std::mem::replace(&mut *self.fbranch, ir::Control::empty()); let ir::Control::Static(sc_t) = tb else { - unreachable!("we have already checked tbranch to be static") - }; + unreachable!("we have already checked tbranch to be static") + }; let ir::Control::Static(sc_f) = fb else { - unreachable!("we have already checker fbranch to be static") - }; + unreachable!("we have already checker fbranch to be static") + }; let latency = std::cmp::max(sc_t.get_latency(), sc_f.get_latency()); Some(ir::StaticIf { tbranch: Box::new(sc_t), diff --git a/calyx-opt/src/passes/dead_assignment_removal.rs b/calyx-opt/src/passes/dead_assignment_removal.rs index a28fa71d5..51953ba07 100644 --- a/calyx-opt/src/passes/dead_assignment_removal.rs +++ b/calyx-opt/src/passes/dead_assignment_removal.rs @@ -85,8 +85,7 @@ fn saturate_dep_maps( let mut used_combs = HashSet::new(); // while loop is bound by size of comb_dependence_map, which is bound // in size by number of ports in the group's assignments - while !(non_comb_writes.is_empty()) { - let used = non_comb_writes.pop().unwrap(); + while let Some(used) = non_comb_writes.pop() { // add all writes to used to non_comb_writes if let Some(write_to_used) = comb_dep_map.remove(&used) { for write in write_to_used { diff --git a/calyx-opt/src/passes/discover_external.rs b/calyx-opt/src/passes/discover_external.rs index 1067b75f1..467d2428e 100644 --- a/calyx-opt/src/passes/discover_external.rs +++ b/calyx-opt/src/passes/discover_external.rs @@ -52,7 +52,8 @@ impl ConstructVisitor for DiscoverExternal { let spl = splits.next(); // Search for the "default=" option if spl == Some("default") { - let Some(val) = splits.next().and_then(|v| v.parse().ok()) else { + let Some(val) = splits.next().and_then(|v| v.parse().ok()) + else { log::warn!("Failed to parse default value. Please specify using -x {}:default=", n); continue; }; diff --git a/calyx-opt/src/passes/group_to_invoke.rs b/calyx-opt/src/passes/group_to_invoke.rs index 441d847a3..3764ad0ab 100644 --- a/calyx-opt/src/passes/group_to_invoke.rs +++ b/calyx-opt/src/passes/group_to_invoke.rs @@ -266,10 +266,12 @@ impl GroupToInvoke { } // Component must define exactly one @go/@done interface - let Ok(Some(go_port)) = cell.find_unique_with_attr(ir::NumAttr::Go) else { + let Ok(Some(go_port)) = cell.find_unique_with_attr(ir::NumAttr::Go) + else { return; }; - let Ok(Some(done_port)) = cell.find_unique_with_attr(ir::NumAttr::Done) else { + let Ok(Some(done_port)) = cell.find_unique_with_attr(ir::NumAttr::Done) + else { return; }; diff --git a/calyx-opt/src/passes/hole_inliner.rs b/calyx-opt/src/passes/hole_inliner.rs index b453cd2ba..dc462d801 100644 --- a/calyx-opt/src/passes/hole_inliner.rs +++ b/calyx-opt/src/passes/hole_inliner.rs @@ -199,7 +199,7 @@ impl Visitor for HoleInliner { builder; let signal_on = constant(1, 1); ); - assignments.iter_mut().for_each(|mut asgn| { + assignments.iter_mut().for_each(|asgn| { if asgn.src.borrow().is_hole() { let and_guard = ir::Guard::port(Rc::clone(&asgn.src)); *asgn.guard &= and_guard; diff --git a/calyx-opt/src/passes/papercut.rs b/calyx-opt/src/passes/papercut.rs index 3675592ee..895e0faee 100644 --- a/calyx-opt/src/passes/papercut.rs +++ b/calyx-opt/src/passes/papercut.rs @@ -215,7 +215,7 @@ impl Papercut { all_writes.get(&(inst, comp_type)).unwrap_or(&empty); for (read, required) in spec { if reads.contains(read) - && matches!(required.difference(writes).next(), Some(_)) + && required.difference(writes).next().is_some() { let missing = required .difference(writes) diff --git a/calyx-opt/src/passes/top_down_compile_control.rs b/calyx-opt/src/passes/top_down_compile_control.rs index d4f1ef2de..6112c359a 100644 --- a/calyx-opt/src/passes/top_down_compile_control.rs +++ b/calyx-opt/src/passes/top_down_compile_control.rs @@ -526,7 +526,7 @@ impl Schedule<'_, '_> { )? }; - let prevs = tru_prev.into_iter().chain(fal_prev.into_iter()).collect(); + let prevs = tru_prev.into_iter().chain(fal_prev).collect(); Ok(prevs) } @@ -573,7 +573,7 @@ impl Schedule<'_, '_> { let not_port_guard = !port_guard; let all_prevs = preds .into_iter() - .chain(prevs.into_iter()) + .chain(prevs) .map(|(st, guard)| (st, guard & not_port_guard.clone())) .collect(); diff --git a/interp/src/flatten/primitives/mod.rs b/interp/src/flatten/primitives/mod.rs index f52d85984..da89eeb01 100644 --- a/interp/src/flatten/primitives/mod.rs +++ b/interp/src/flatten/primitives/mod.rs @@ -7,4 +7,4 @@ pub mod stateful; pub(crate) use builder::build_primitive; pub use prim_trait::Primitive; -pub(self) use macros::*; +use macros::*; diff --git a/interp/src/primitives/stateful/math.rs b/interp/src/primitives/stateful/math.rs index 552117f3a..c9bf0bc13 100644 --- a/interp/src/primitives/stateful/math.rs +++ b/interp/src/primitives/stateful/math.rs @@ -205,7 +205,7 @@ impl Primitive fn serialize(&self, signed: Option) -> Serializable { let code = signed.unwrap_or_default(); Serializable::Array( - vec![self.product.clone()] + [self.product.clone()] .iter() .map(|x| Entry::from_val_code(x, &code)) .collect(), @@ -415,8 +415,7 @@ impl Primitive for StdDivPipe { fn serialize(&self, signed: Option) -> Serializable { let code = signed.unwrap_or_default(); Serializable::Array( - //vec![self.left.clone(), self.right.clone(), self.product.clone()] - vec![self.quotient.clone(), self.remainder.clone()] + [self.quotient.clone(), self.remainder.clone()] .iter() .map(|x| Entry::from_val_code(x, &code)) .collect(), diff --git a/src/backend/mod.rs b/src/backend/mod.rs deleted file mode 100644 index 4112af634..000000000 --- a/src/backend/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Backends for the Calyx compiler. -pub mod mlir; -pub mod resources; -pub mod sexp; -pub mod traits; -pub mod verilog; -pub mod xilinx; diff --git a/src/cmdline.rs b/src/cmdline.rs index db7f627d6..9cc49b694 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -1,14 +1,12 @@ //! Command line parsing for the Calyx compiler. -use crate::backend::traits::Backend; -use crate::backend::{ - mlir::MlirBackend, resources::ResourcesBackend, sexp::SexpBackend, - verilog::VerilogBackend, xilinx::XilinxInterfaceBackend, - xilinx::XilinxXmlBackend, -}; use argh::FromArgs; +use calyx_backend::{ + xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, + Backend, BackendOpt, MlirBackend, ResourcesBackend, SexpBackend, + VerilogBackend, +}; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; -use itertools::Itertools; use std::path::Path; use std::path::PathBuf; use std::str::FromStr; @@ -109,105 +107,32 @@ impl FromStr for CompileMode { // ================== Backend Variant and Parsing ===================== // -/// Enumeration of valid backends -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub enum BackendOpt { - #[default] - Calyx, - Verilog, - Xilinx, - XilinxXml, - Mlir, - Resources, - Sexp, - None, -} - -/// Return a vector that maps strings to Backends. -#[inline(always)] -fn backends() -> Vec<(&'static str, BackendOpt)> { - vec![ - ("verilog", BackendOpt::Verilog), - ("xilinx", BackendOpt::Xilinx), - ("xilinx-xml", BackendOpt::XilinxXml), - ("calyx", BackendOpt::Calyx), - ("mlir", BackendOpt::Mlir), - ("resources", BackendOpt::Resources), - ("sexp", BackendOpt::Sexp), - ("none", BackendOpt::None), - ] -} - -/// Command line parsing for the Backend enum -impl FromStr for BackendOpt { - type Err = String; - fn from_str(input: &str) -> Result { - // allocate a vector for the list of backends - let backends = backends(); - // see if there is a backend for the string that we receive - let found_backend = backends - .iter() - .find(|(backend_name, _)| &input == backend_name); - if let Some((_, opt)) = found_backend { - // return the BackendOpt if we found one - Ok(opt.clone()) - } else { - // build list of backends for error message - let backend_str = backends - .iter() - .map(|(name, _)| (*name).to_string()) - .join(", "); - Err(format!( - "`{}` is not a valid backend.\nValid backends: {}", - input, backend_str - )) - } - } -} - -/// Convert `BackendOpt` to a string -impl ToString for BackendOpt { - fn to_string(&self) -> String { - match self { - Self::Mlir => "mlir", - Self::Resources => "resources", - Self::Sexp => "sexp", - Self::Verilog => "verilog", - Self::Xilinx => "xilinx", - Self::XilinxXml => "xilinx-xml", - Self::Calyx => "calyx", - Self::None => "none", - } - .to_string() - } -} - impl Opts { /// Given a context, calls the backend corresponding to the `BackendOpt` variant pub fn run_backend(self, context: ir::Context) -> CalyxResult<()> { match self.backend { BackendOpt::Mlir => { - let backend = MlirBackend::default(); + let backend = MlirBackend; backend.run(context, self.output) } BackendOpt::Resources => { - let backend = ResourcesBackend::default(); + let backend = ResourcesBackend; backend.run(context, self.output) } BackendOpt::Sexp => { - let backend = SexpBackend::default(); + let backend = SexpBackend; backend.run(context, self.output) } BackendOpt::Verilog => { - let backend = VerilogBackend::default(); + let backend = VerilogBackend; backend.run(context, self.output) } BackendOpt::Xilinx => { - let backend = XilinxInterfaceBackend::default(); + let backend = XilinxInterfaceBackend; backend.run(context, self.output) } BackendOpt::XilinxXml => { - let backend = XilinxXmlBackend::default(); + let backend = XilinxXmlBackend; backend.run(context, self.output) } BackendOpt::Calyx => { diff --git a/src/driver.rs b/src/driver.rs deleted file mode 100644 index 0a517301a..000000000 --- a/src/driver.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Driver for the Calyx compiler. -use crate::cmdline::{BackendOpt, CompileMode, Opts}; -use calyx_frontend as frontend; -use calyx_ir as ir; -use calyx_opt::pass_manager::PassManager; -use calyx_utils::CalyxResult; -use itertools::Itertools; - -/// Run the compiler from the command line. -pub fn run_compiler() -> CalyxResult<()> { - // parse the command line arguments into Opts struct - let mut opts = Opts::get_opts()?; - - // Return the version and the git commit this was built on - if opts.version { - println!("Calyx compiler version {}", env!("CARGO_PKG_VERSION")); - println!( - "Library location: {}", - option_env!("CALYX_PRIMITIVES_DIR").unwrap_or(".") - ); - return Ok(()); - } - - // enable tracing - env_logger::Builder::new() - .format_timestamp(None) - .filter_level(opts.log_level) - .target(env_logger::Target::Stderr) - .init(); - - let pm = PassManager::default_passes()?; - - // list all the avaliable pass options when flag --list-passes is enabled - if opts.list_passes { - println!("{}", pm.show_names()); - return Ok(()); - } - - // Construct the namespace. - let mut ws = frontend::Workspace::construct(&opts.file, &opts.lib_path)?; - - let imports = ws.original_imports.drain(..).collect_vec(); - - // Build the IR representation - let mut ctx = ir::from_ast::ast_to_ir(ws)?; - // Configuration for the backend - ctx.bc = ir::BackendConf { - synthesis_mode: opts.enable_synthesis, - enable_verification: !opts.disable_verify, - flat_assign: !opts.nested_assign, - }; - // Extra options for the passes - ctx.extra_opts = opts.extra_opts.drain(..).collect(); - - // Run all passes specified by the command line - pm.execute_plan(&mut ctx, &opts.pass, &opts.disable_pass, opts.dump_ir)?; - - // Print out the Calyx program after transformation. - if opts.backend == BackendOpt::Calyx { - let out = &mut opts.output.get_write(); - - // Print out the original imports for this file. - if opts.compile_mode == CompileMode::File { - for import in imports { - writeln!(out, "import \"{}\";", import)?; - } - } - ir::Printer::write_context( - &ctx, - opts.compile_mode == CompileMode::File, - out, - )?; - - Ok(()) - } else { - opts.run_backend(ctx) - } -} diff --git a/src/lib.rs b/src/lib.rs index abd17e5cf..68b856f5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,7 @@ -//! # The Calyx Compiler Driver +//! # The Calyx Compiler //! //! This crate plumbs together the Calyx compiler crates and provides a command-line interface for the Calyx compiler. //! What `clang` it to `llvm`, this crate is to the Calyx IL. -//! -//! For the most part, you don't want to directly rely on this crate and instead use the [`calyx_ir`] or the [`calyx_opt`] crates. -//! However, the [driver::run_compiler] function's is a good example for how to use the Calyx compiler crates. -pub mod backend; +//! You SHOULD NOT depend on this crate since does things like installing the primitives library in a global location. +//! Instead, depend on the crates that this crate depends: [`calyx_frontend`], [`calyx_ir`], [`calyx_opt`]. pub mod cmdline; -pub mod driver; diff --git a/src/main.rs b/src/main.rs index 331751d37..88fa7cbc5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,77 @@ -use calyx::driver; +use calyx::cmdline::{CompileMode, Opts}; +use calyx_backend::BackendOpt; +use calyx_frontend as frontend; +use calyx_ir as ir; +use calyx_opt::pass_manager::PassManager; use calyx_utils::CalyxResult; +use itertools::Itertools; fn main() -> CalyxResult<()> { - driver::run_compiler() + // parse the command line arguments into Opts struct + let mut opts = Opts::get_opts()?; + + // Return the version and the git commit this was built on + if opts.version { + println!("Calyx compiler version {}", env!("CARGO_PKG_VERSION")); + println!( + "Library location: {}", + option_env!("CALYX_PRIMITIVES_DIR").unwrap_or(".") + ); + return Ok(()); + } + + // enable tracing + env_logger::Builder::new() + .format_timestamp(None) + .filter_level(opts.log_level) + .target(env_logger::Target::Stderr) + .init(); + + let pm = PassManager::default_passes()?; + + // list all the avaliable pass options when flag --list-passes is enabled + if opts.list_passes { + println!("{}", pm.show_names()); + return Ok(()); + } + + // Construct the namespace. + let mut ws = frontend::Workspace::construct(&opts.file, &opts.lib_path)?; + + let imports = ws.original_imports.drain(..).collect_vec(); + + // Build the IR representation + let mut ctx = ir::from_ast::ast_to_ir(ws)?; + // Configuration for the backend + ctx.bc = ir::BackendConf { + synthesis_mode: opts.enable_synthesis, + enable_verification: !opts.disable_verify, + flat_assign: !opts.nested_assign, + }; + // Extra options for the passes + ctx.extra_opts = opts.extra_opts.drain(..).collect(); + + // Run all passes specified by the command line + pm.execute_plan(&mut ctx, &opts.pass, &opts.disable_pass, opts.dump_ir)?; + + // Print out the Calyx program after transformation. + if opts.backend == BackendOpt::Calyx { + let out = &mut opts.output.get_write(); + + // Print out the original imports for this file. + if opts.compile_mode == CompileMode::File { + for import in imports { + writeln!(out, "import \"{}\";", import)?; + } + } + ir::Printer::write_context( + &ctx, + opts.compile_mode == CompileMode::File, + out, + )?; + + Ok(()) + } else { + opts.run_backend(ctx) + } } From 0330cb3eb3dbb6d4ac89843682aa8304ec1fa2c8 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 14:32:15 +0530 Subject: [PATCH 056/189] Bump dependent crates (#1707) * move backend code into separate dir * bump dependent crates * disable serialize backend by default --- Cargo.lock | 45 ++++++++++++++------------------------- Cargo.toml | 21 ++++++------------ calyx-frontend/Cargo.toml | 4 ++-- calyx-opt/Cargo.toml | 3 +-- calyx-utils/src/errors.rs | 28 ++++++++++++------------ src/cmdline.rs | 18 ++++++++++++---- 6 files changed, 54 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 706f82a0e..8998552dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,16 +163,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "boolean_expression" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae1ed5495f7bb2450decd75a8f0a4580a4c81f0ee7dcc698d3712c9f15eded2" -dependencies = [ - "itertools 0.9.0", - "smallvec", -] - [[package]] name = "bumpalo" version = "3.13.0" @@ -199,11 +189,9 @@ dependencies = [ "calyx-utils", "criterion", "env_logger", - "itertools 0.10.5", + "itertools 0.11.0", "log", "serde", - "serde_sexpr", - "serde_with 3.3.0", ] [[package]] @@ -214,7 +202,7 @@ dependencies = [ "calyx-ir", "calyx-utils", "csv", - "itertools 0.10.5", + "itertools 0.11.0", "linked-hash-map", "log", "petgraph", @@ -233,7 +221,7 @@ version = "0.5.0" dependencies = [ "atty", "calyx-utils", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "linked-hash-map", "log", @@ -253,7 +241,7 @@ version = "0.5.0" dependencies = [ "calyx-frontend", "calyx-utils", - "itertools 0.10.5", + "itertools 0.11.0", "linked-hash-map", "log", "petgraph", @@ -267,10 +255,9 @@ dependencies = [ name = "calyx-opt" version = "0.5.0" dependencies = [ - "boolean_expression", "calyx-ir", "calyx-utils", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "linked-hash-map", "log", @@ -289,7 +276,7 @@ name = "calyx-utils" version = "0.5.0" dependencies = [ "atty", - "itertools 0.10.5", + "itertools 0.11.0", "petgraph", "serde", "string-interner", @@ -912,7 +899,7 @@ dependencies = [ "calyx-utils", "fraction", "ibig", - "itertools 0.10.5", + "itertools 0.11.0", "lazy_static", "once_cell", "owo-colors", @@ -934,18 +921,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.9.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -1739,21 +1726,21 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.29", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 43b96da2b..25a209f07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,17 +28,17 @@ version = "0.5.0" rust-version = "1.67" [workspace.dependencies] -itertools = "0.10" -atty = "0.2.14" -log = "0.4.14" +itertools = "0.11" +atty = "0.2" +log = "0.4" string-interner = "0.14.0" lazy_static = "1" linked-hash-map = "0.5" smallvec = "1" serde = { version = "1.0", features = ["derive"] } serde_sexpr = "0.1.0" -serde_with = "3.0.0" -pest = "2.0" +serde_with = "3" +pest = "2" pest_derive = "2" pest_consume = "1" argh = "0.1" @@ -77,12 +77,7 @@ path = "src/main.rs" [features] default = [] -serialize = [ - "dep:serde_with", - "dep:serde_sexpr", - "calyx-ir/serialize", - "serde/rc", -] +serialize = ["calyx-ir/serialize", "serde/rc", "calyx-backend/sexp"] [build-dependencies] calyx-stdlib = { path = "calyx-stdlib", version = "0.5.0" } @@ -92,8 +87,6 @@ atty.workspace = true itertools.workspace = true log.workspace = true serde.workspace = true -serde_with = { workspace = true, optional = true } -serde_sexpr = { workspace = true, optional = true } argh.workspace = true calyx-utils.workspace = true @@ -103,7 +96,7 @@ calyx-opt.workspace = true [dependencies.calyx-backend] workspace = true -features = ["mlir", "resources", "xilinx", "sexp"] +features = ["mlir", "resources", "xilinx"] [dependencies.env_logger] version = "0.9.0" diff --git a/calyx-frontend/Cargo.toml b/calyx-frontend/Cargo.toml index 7870742a5..d6a3d9503 100644 --- a/calyx-frontend/Cargo.toml +++ b/calyx-frontend/Cargo.toml @@ -32,5 +32,5 @@ itertools.workspace = true calyx-utils.workspace = true -strum_macros = "0.24.3" -strum = "0.24.1" \ No newline at end of file +strum_macros = "0.25" +strum = "0.25" diff --git a/calyx-opt/Cargo.toml b/calyx-opt/Cargo.toml index 84e706eed..de4c79ace 100644 --- a/calyx-opt/Cargo.toml +++ b/calyx-opt/Cargo.toml @@ -23,8 +23,7 @@ lazy_static.workspace = true smallvec.workspace = true serde.workspace = true -boolean_expression = "=0.4.1" serde_json = "1.0.79" calyx-ir.workspace = true -calyx-utils.workspace = true \ No newline at end of file +calyx-utils.workspace = true diff --git a/calyx-utils/src/errors.rs b/calyx-utils/src/errors.rs index 31405ba52..86a5948b7 100644 --- a/calyx-utils/src/errors.rs +++ b/calyx-utils/src/errors.rs @@ -43,9 +43,9 @@ impl Error { post_msg: None, } } - pub fn malformed_control(msg: String) -> Self { + pub fn malformed_control(msg: S) -> Self { Self { - kind: Box::new(ErrorKind::MalformedControl(msg)), + kind: Box::new(ErrorKind::MalformedControl(msg.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } @@ -67,16 +67,16 @@ impl Error { post_msg: None, } } - pub fn undefined(name: Id, typ: String) -> Self { + pub fn undefined(name: Id, typ: S) -> Self { Self { - kind: Box::new(ErrorKind::Undefined(name, typ)), + kind: Box::new(ErrorKind::Undefined(name, typ.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } } - pub fn already_bound(name: Id, typ: String) -> Self { + pub fn already_bound(name: Id, typ: S) -> Self { Self { - kind: Box::new(ErrorKind::AlreadyBound(name, typ)), + kind: Box::new(ErrorKind::AlreadyBound(name, typ.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } @@ -88,30 +88,30 @@ impl Error { post_msg: None, } } - pub fn papercut(msg: String) -> Self { + pub fn papercut(msg: S) -> Self { Self { - kind: Box::new(ErrorKind::Papercut(msg)), + kind: Box::new(ErrorKind::Papercut(msg.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } } - pub fn misc(msg: String) -> Self { + pub fn misc(msg: S) -> Self { Self { - kind: Box::new(ErrorKind::Misc(msg)), + kind: Box::new(ErrorKind::Misc(msg.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } } - pub fn invalid_file(msg: String) -> Self { + pub fn invalid_file(msg: S) -> Self { Self { - kind: Box::new(ErrorKind::InvalidFile(msg)), + kind: Box::new(ErrorKind::InvalidFile(msg.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } } - pub fn write_error(msg: String) -> Self { + pub fn write_error(msg: S) -> Self { Self { - kind: Box::new(ErrorKind::WriteError(msg)), + kind: Box::new(ErrorKind::WriteError(msg.to_string())), pos: GPosIdx::UNKNOWN, post_msg: None, } diff --git a/src/cmdline.rs b/src/cmdline.rs index 9cc49b694..067f321b4 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -1,9 +1,10 @@ //! Command line parsing for the Calyx compiler. use argh::FromArgs; +#[cfg(feature = "serialize")] +use calyx_backend::SexpBackend; use calyx_backend::{ xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, - Backend, BackendOpt, MlirBackend, ResourcesBackend, SexpBackend, - VerilogBackend, + Backend, BackendOpt, MlirBackend, ResourcesBackend, VerilogBackend, }; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; @@ -120,8 +121,17 @@ impl Opts { backend.run(context, self.output) } BackendOpt::Sexp => { - let backend = SexpBackend; - backend.run(context, self.output) + #[cfg(feature = "serialize")] + { + let backend = SexpBackend; + backend.run(context, self.output) + } + #[cfg(not(feature = "serialize"))] + { + Err(Error::misc( + "Sexp backend requires the `serialize` feature to be enabled", + )) + } } BackendOpt::Verilog => { let backend = VerilogBackend; From 437ecdc2187f7bc7b138dcd43126358198537f6c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 14:39:00 +0530 Subject: [PATCH 057/189] bump runt version (#1708) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c7a6cfd12..6c14b4b2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,7 +58,7 @@ ADD . calyx WORKDIR /home/calyx RUN cargo build --all && \ cargo install vcdump && \ - cargo install runt --version $(grep ^ver runt.toml | awk '{print $3}' | tr -d '"') + cargo install runt --version 0.4.1 # Install fud WORKDIR /home/calyx/fud From 5b210a81088bda4b0fb31727268ad116f4451b84 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 16:45:46 +0530 Subject: [PATCH 058/189] more expressive `guard!` macro (#1709) * more expressive `guard!` macro * use new `guard!` macro capabilities * update changelog --- CHANGELOG.md | 1 + calyx-ir/src/guard.rs | 47 +++++++++++----- calyx-ir/src/macros.rs | 55 ++++++++++++++++++- calyx-opt/src/passes/compile_repeat.rs | 2 +- calyx-opt/src/passes/compile_static.rs | 24 ++++---- .../src/passes/top_down_compile_control.rs | 9 ++- .../top_down_static_timing/compute_states.rs | 2 +- .../src/passes/top_down_static_timing/tdst.rs | 28 ++++------ 8 files changed, 116 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d904b5d4a..5661d3337 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - BREAKING: Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. - BREAKING: Redesign the `ir::Rewriter` interface to take all the rewrite maps when constructing the `ir::Rewriter` struct. - Merge the logic of `compile-ref` pass into `compile-invoke` so that `ref` cells can be invoked. +- The `guard!` macro supports parsing complex guard expressions that use logical connectives and comparison operators. ## 0.5.1 - Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. diff --git a/calyx-ir/src/guard.rs b/calyx-ir/src/guard.rs index 2159648fe..287adbd22 100644 --- a/calyx-ir/src/guard.rs +++ b/calyx-ir/src/guard.rs @@ -1,3 +1,5 @@ +use crate::Printer; + use super::{NumAttr, Port, RRC}; use calyx_utils::Error; use std::fmt::Debug; @@ -257,21 +259,25 @@ impl Guard { pub fn eq(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { Guard::CompOp(PortComp::Eq, l, r) } (l, r) => { - unreachable!("Cannot build Guard::Eq using {:?} and {:?}", l, r) + unreachable!( + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), + ) } } } pub fn neq(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { @@ -279,8 +285,9 @@ impl Guard { } (l, r) => { unreachable!( - "Cannot build Guard::Neq using {:?} and {:?}", - l, r + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), ) } } @@ -288,7 +295,7 @@ impl Guard { pub fn le(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { @@ -296,8 +303,9 @@ impl Guard { } (l, r) => { unreachable!( - "Cannot build Guard::Leq using {:?} and {:?}", - l, r + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), ) } } @@ -305,21 +313,25 @@ impl Guard { pub fn lt(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { Guard::CompOp(PortComp::Lt, l, r) } (l, r) => { - unreachable!("Cannot build Guard::Lt using {:?} and {:?}", l, r) + unreachable!( + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), + ) } } } pub fn ge(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { @@ -327,8 +339,9 @@ impl Guard { } (l, r) => { unreachable!( - "Cannot build Guard::Geq using {:?} and {:?}", - l, r + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), ) } } @@ -336,14 +349,18 @@ impl Guard { pub fn gt(self, other: Guard) -> Self where - T: Debug, + T: Debug + Eq + ToString, { match (self, other) { (Guard::Port(l), Guard::Port(r)) => { Guard::CompOp(PortComp::Gt, l, r) } (l, r) => { - unreachable!("Cannot build Guard::Gt using {:?} and {:?}", l, r) + unreachable!( + "Cannot build Guard::Eq using `{}' and `{}'", + Printer::guard_str(&l), + Printer::guard_str(&r), + ) } } } diff --git a/calyx-ir/src/macros.rs b/calyx-ir/src/macros.rs index d2e621330..c67429629 100644 --- a/calyx-ir/src/macros.rs +++ b/calyx-ir/src/macros.rs @@ -1,16 +1,67 @@ -/// Convinience macro to get a port and turn it into an [`ir::Guard`](crate::Guard). +/// Parse guard expression into [`ir::Guard`](crate::Guard). /// /// The identifier should either be a [`ir::Group`](crate::Group) or an /// [`ir::Cell`](crate::Cell). /// Example: /// ``` -/// let fsm_out = guard!(fsm["out"]); +/// let fsm_out = guard!(fsm["out"] == lb["out"] & g); /// ``` +/// +/// The macro supports constructing guards using the following operators: +/// - Port access: `node[port]` +/// - Comparison operators: `==`, `>=`, `<=`, `>`, `<` +/// - Logical operators: `&`, `|` +/// - Parentheses: `()` #[macro_export] macro_rules! guard { + // Base + // Port access ($node:ident[$port:expr]) => { $crate::Guard::from($node.borrow().get($port)) }; + // Parentheses + ( ( $($head:tt)* ) ) => { + guard!($($head)*) + }; + // A bare name + ($e:ident) => { $e }; + + // Comparison operators + ($node:ident[$port:expr] >= $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).ge(guard!($($tail)*)) + }; + ($node:ident[$port:expr] <= $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).le(guard!($($tail)*)) + }; + ($node:ident[$port:expr] < $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).lt(guard!($($tail)*)) + }; + ($node:ident[$port:expr] > $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).gt(guard!($($tail)*)) + }; + ($node:ident[$port:expr] == $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).eq(guard!($($tail)*)) + }; + ($node:ident[$port:expr] != $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)).neq(guard!($($tail)*)) + }; + + // Logical operators + // AND + ($node:ident[$port:expr] & $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)) & guard!($($tail)*) + }; + ( ( $($head:tt)* ) & $($tail:tt)*) => { + guard!($($head)*) & guard!($($tail)*) + }; + + // OR + ($node:ident[$port:expr] | $($tail:tt)*) => { + $crate::Guard::from($node.borrow().get($port)) | guard!($($tail)*) + }; + ( ( $($head:tt)* ) | $($tail:tt)*) => { + guard!($($head)*) | guard!($($tail)*) + }; } /// Add primitives and constants to the component and `let`-bind the diff --git a/calyx-opt/src/passes/compile_repeat.rs b/calyx-opt/src/passes/compile_repeat.rs index ccbde283f..ffe707ea9 100644 --- a/calyx-opt/src/passes/compile_repeat.rs +++ b/calyx-opt/src/passes/compile_repeat.rs @@ -52,7 +52,7 @@ impl Visitor for CompileRepeat { ); // regs_done is `cond_reg.done & idx.done` let regs_done: ir::Guard = - guard!(cond_reg["done"]).and(guard!(idx["done"])); + guard!(cond_reg["done"] & idx["done"]); // init_group sets cond_reg to 1 and idx to 0 let init_group = builder.add_group("init_repeat"); let init_assigns = build_assignments!( diff --git a/calyx-opt/src/passes/compile_static.rs b/calyx-opt/src/passes/compile_static.rs index a103c6d39..23a0cf32b 100644 --- a/calyx-opt/src/passes/compile_static.rs +++ b/calyx-opt/src/passes/compile_static.rs @@ -65,22 +65,22 @@ fn make_guard_dyn( if beg + 1 == end { // if beg + 1 == end then we only need to check if fsm == beg let interval_const = builder.add_constant(beg, fsm_size); - let g = guard!(fsm["out"]).eq(guard!(interval_const["out"])); + let g = guard!(fsm["out"] == interval_const["out"]); Box::new(g) } else if beg == 0 { // if beg == 0, then we only need to check if fsm < end let end_const = builder.add_constant(end, fsm_size); let lt: ir::Guard = - guard!(fsm["out"]).lt(guard!(end_const["out"])); + guard!(fsm["out"] < end_const["out"]); Box::new(lt) } else { // otherwise, check if fsm >= beg & fsm < end let beg_const = builder.add_constant(beg, fsm_size); let end_const = builder.add_constant(end, fsm_size); let beg_guard: ir::Guard = - guard!(fsm["out"]).ge(guard!(beg_const["out"])); + guard!(fsm["out"] >= beg_const["out"]); let end_guard: ir::Guard = - guard!(fsm["out"]).lt(guard!(end_const["out"])); + guard!(fsm["out"] < end_const["out"]); Box::new(ir::Guard::And( Box::new(beg_guard), Box::new(end_guard), @@ -181,9 +181,9 @@ impl CompileStatic { .collect_vec(); // assignments to increment the fsm let not_penultimate_state_guard: ir::Guard = - guard!(fsm["out"]).neq(guard!(penultimate_state["out"])); + guard!(fsm["out"] != penultimate_state["out"]); let penultimate_state_guard: ir::Guard = - guard!(fsm["out"]).eq(guard!(penultimate_state["out"])); + guard!(fsm["out"] == penultimate_state["out"]); let fsm_incr_assigns = build_assignments!( builder; // increments the fsm @@ -244,16 +244,16 @@ impl CompileStatic { // make guards // fsm.out == 0 ? let first_state: ir::Guard = - guard!(early_reset_fsm["out"]).eq(guard!(state_zero["out"])); + guard!(early_reset_fsm["out"] == state_zero["out"]); // signal_reg.out ? let signal_reg_guard: ir::Guard = guard!(signal_reg["out"]); // !signal_reg.out ? let not_signal_reg = signal_reg_guard.clone().not(); // fsm.out == 0 & signal_reg.out ? - let first_state_and_signal = first_state.clone().and(signal_reg_guard); + let first_state_and_signal = first_state.clone() & signal_reg_guard; // fsm.out == 0 & ! signal_reg.out ? - let first_state_and_not_signal = first_state.and(not_signal_reg); + let first_state_and_not_signal = first_state & not_signal_reg; // create the wrapper group for early_reset_group let mut wrapper_name = group_name.clone().to_string(); wrapper_name.insert_str(0, "wrapper_"); @@ -351,8 +351,8 @@ impl CompileStatic { let port_parent = port.borrow().cell_parent(); let port_name = port.borrow().name; - let done_guard = (!guard!(port_parent[port_name])) - & guard!(early_reset_fsm["out"]).eq(guard!(time_0["out"])); + let done_guard = guard!(port_parent[port_name]).not() + & guard!(early_reset_fsm["out"] == time_0["out"]); let assignments = build_assignments!( builder; @@ -535,7 +535,7 @@ impl CompileStatic { vec_color_to_groups .sort_by(|(color1, _), (color2, _)| color1.cmp(color2)); vec_color_to_groups.into_iter().map(|(color, group_names)| { - // For each color, build an FSM that has the number of bits required + // For each color, build an FSM that has the number of bits required // for the largest latency in `group_names` let max_latency = group_names .iter() diff --git a/calyx-opt/src/passes/top_down_compile_control.rs b/calyx-opt/src/passes/top_down_compile_control.rs index 6112c359a..8a72426cc 100644 --- a/calyx-opt/src/passes/top_down_compile_control.rs +++ b/calyx-opt/src/passes/top_down_compile_control.rs @@ -308,8 +308,7 @@ impl<'b, 'a> Schedule<'b, 'a> { .flat_map(|(state, mut assigns)| { let state_const = self.builder.add_constant(state, fsm_size); - let state_guard = - guard!(fsm["out"]).eq(guard!(state_const["out"])); + let state_guard = guard!(fsm["out"] == state_const["out"]); assigns.iter_mut().for_each(|asgn| { asgn.guard.update(|g| g.and(state_guard.clone())) }); @@ -326,7 +325,7 @@ impl<'b, 'a> Schedule<'b, 'a> { ); let ec_borrow = end_const.borrow(); let trans_guard = - guard!(fsm["out"]).eq(guard!(start_const["out"])) & guard; + guard!((fsm["out"] == start_const["out"]) & guard); vec![ self.builder.build_assignment( @@ -344,7 +343,7 @@ impl<'b, 'a> Schedule<'b, 'a> { ); // Done condition for group - let last_guard = guard!(fsm["out"]).eq(guard!(last_state["out"])); + let last_guard = guard!(fsm["out"] == last_state["out"]); let done_assign = self.builder.build_assignment( group.borrow().get("done"), signal_on.borrow().get("out"), @@ -952,7 +951,7 @@ impl Visitor for TopDownCompileControl { structure!(builder; let pd = prim std_reg(1); ); - let group_go = !(guard!(pd["out"]) | guard!(group["done"])); + let group_go = !(guard!(pd["out"] | group["done"])); let group_done = guard!(group["done"]); // Save the done condition in a register. diff --git a/calyx-opt/src/passes/top_down_static_timing/compute_states.rs b/calyx-opt/src/passes/top_down_static_timing/compute_states.rs index 667f4a316..f6d309fe1 100644 --- a/calyx-opt/src/passes/top_down_static_timing/compute_states.rs +++ b/calyx-opt/src/passes/top_down_static_timing/compute_states.rs @@ -155,7 +155,7 @@ impl ComputeStates { // Guard the exit edges for the body with the loop exit condition let (idx, bound) = self.loop_bounds(wh, builder); - let guard = guard!(idx["out"]).eq(guard!(bound["out"])); + let guard = guard!(idx["out"] == bound["out"]); exits.extend( loop_exits .into_iter() diff --git a/calyx-opt/src/passes/top_down_static_timing/tdst.rs b/calyx-opt/src/passes/top_down_static_timing/tdst.rs index 6d9f179bf..0ff533d80 100644 --- a/calyx-opt/src/passes/top_down_static_timing/tdst.rs +++ b/calyx-opt/src/passes/top_down_static_timing/tdst.rs @@ -182,19 +182,17 @@ impl Schedule<'_, '_> { fsm: &RRC, ) -> ir::Guard { structure!(builder; - let lb_const = constant(s, fsm_size); - let ub_const = constant(e, fsm_size); + let lb = constant(s, fsm_size); + let ub = constant(e, fsm_size); ); if s == 0 { - guard!(fsm["out"]).lt(guard!(ub_const["out"])) + guard!(fsm["out"] < ub["out"]) } else if e == s + 1 { - guard!(fsm["out"]).eq(guard!(lb_const["out"])) + guard!(fsm["out"] == lb["out"]) } else if e == 1 << fsm_size { - guard!(fsm["out"]).ge(guard!(lb_const["out"])) + guard!(fsm["out"] >= lb["out"]) } else { - guard!(fsm["out"]) - .ge(guard!(lb_const["out"])) - .and(guard!(fsm["out"]).lt(guard!(ub_const["out"]))) + guard!((fsm["out"] >= lb["out"]) & (fsm["out"] < ub["out"])) } } @@ -254,9 +252,7 @@ impl Schedule<'_, '_> { let end_const = constant(end, fsm_size); ); - let transition_guard = guard!(st_fsm["out"]) - .eq(guard!(start_const["out"])) - .and(guard); + let transition_guard = guard!((st_fsm["out"] == start_const["out"]) & guard); let assigns = build_assignments!(builder; st_fsm["in"] = transition_guard ? end_const["out"]; @@ -291,11 +287,11 @@ impl Schedule<'_, '_> { // Done condition for group. let (st, g) = out_edges.pop().expect("No outgoing edges"); let c = builder.add_constant(st, fsm_size); - let mut done_guard = guard!(st_fsm["out"]).eq(guard!(c["out"])) & g; + let mut done_guard = guard!((st_fsm["out"] == c["out"]) & g); for (st, g) in out_edges { let stc = builder.add_constant(st, fsm_size); - let st_guard = guard!(st_fsm["out"]).eq(guard!(stc["out"])); - done_guard |= st_guard & g; + let st_guard = guard!((st_fsm["out"] == stc["out"]) & g); + done_guard |= st_guard; } let done_assign = build_assignments!(builder; group["done"] = done_guard ? signal_on["out"]; @@ -642,7 +638,7 @@ impl Schedule<'_, '_> { let on = constant(1, 1); ); // Add back edges - let enter_guard = guard!(idx["out"]).lt(guard!(total["out"])); + let enter_guard = guard!(idx["out"] < total["out"]); let mut exits = vec![]; self.states .control_exits(&wh.body, self.builder, &mut exits); @@ -681,7 +677,7 @@ impl Schedule<'_, '_> { } // Reset the index when exiting the loop - let exit = guard!(idx["out"]).eq(guard!(total["out"])); + let exit = guard!(idx["out"] == total["out"]); let reset_group = self.reset_group(&idx); let reset_activate = self.builder.build_assignment( reset_group.borrow().get("go"), From 3701a539e82c74ac07069188204eda6d6e40b56b Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 16:51:37 +0530 Subject: [PATCH 059/189] Rename `interp` to `cider` (#1686) * remove-futil * rename `interp` to `cider` * fix runt def --- .github/workflows/rust.yml | 4 ++++ .vscode/launch.json | 8 ++++---- Dockerfile | 2 +- fud/fud/config.py | 2 +- interp/Cargo.toml | 6 +++++- interp/runt.toml | 16 ++++++++-------- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7e1e5ce65..6b0bba593 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -37,6 +37,10 @@ jobs: command: build args: --all --manifest-path /home/calyx/interp/Cargo.toml + - name: Set location of cider binary + run: | + fud c stages.interpreter.exec /home/calyx/target/debug/cider + - name: Runt tests working-directory: /home/calyx run: | diff --git a/.vscode/launch.json b/.vscode/launch.json index 9e20f454f..4b303a6e4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -53,9 +53,9 @@ "-l", "${workspaceFolder}" ], - "program": "${workspaceFolder}/target/debug/interp", + "program": "${workspaceFolder}/target/debug/cider", "windows": { - "program": "${workspaceFolder}/target/debug/interp.exe" + "program": "${workspaceFolder}/target/debug/cider.exe" }, "cwd": "${workspaceFolder}", "stopOnEntry": false, @@ -72,9 +72,9 @@ "-l", "${workspaceFolder}" ], - "program": "${workspaceFolder}/target/debug/interp", + "program": "${workspaceFolder}/target/debug/cider", "windows": { - "program": "${workspaceFolder}/target/debug/interp.exe" + "program": "${workspaceFolder}/target/debug/cider.exe" }, "cwd": "${workspaceFolder}", "stopOnEntry": false, diff --git a/Dockerfile b/Dockerfile index 6c14b4b2b..9626465d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,7 +71,7 @@ ENV PYTHONPATH=/root/.local/lib/python3.9/site-packages:$PYTHONPATH RUN fud config --create global.root /home/calyx && \ fud config stages.dahlia.exec '/home/dahlia/fuse' && \ fud config stages.calyx.exec '/home/calyx/target/debug/calyx' && \ - fud config stages.interpreter.exec '/home/calyx/target/debug/interp' && \ + fud config stages.interpreter.exec '/home/calyx/target/debug/cider' && \ fud register ntt -p '/home/calyx/frontends/ntt-pipeline/fud/ntt.py' && \ fud register mrxl -p '/home/calyx/frontends/mrxl/fud/mrxl.py' && \ fud register icarus-verilog -p '/home/calyx/fud/icarus/icarus.py' diff --git a/fud/fud/config.py b/fud/fud/config.py index 974741fac..3c7e5645f 100644 --- a/fud/fud/config.py +++ b/fud/fud/config.py @@ -32,7 +32,7 @@ "flags": None, }, "interpreter": { - "exec": "./target/debug/interp", + "exec": "./target/debug/cider", "flags": "--raw ", "data": None, "round_float_to_fixed": True, diff --git a/interp/Cargo.toml b/interp/Cargo.toml index abccd09d5..dbe272b62 100644 --- a/interp/Cargo.toml +++ b/interp/Cargo.toml @@ -8,6 +8,10 @@ rust-version.workspace = true [lib] doctest = false # Don't run doc tests +[[bin]] +name = "cider" +path = "src/main.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] @@ -48,4 +52,4 @@ calyx-frontend = { path = "../calyx-frontend" } proptest = "1.0.0" [dependencies.serde_with] -version = "1.6.4" \ No newline at end of file +version = "1.6.4" diff --git a/interp/runt.toml b/interp/runt.toml index f877575d7..8477749a6 100644 --- a/interp/runt.toml +++ b/interp/runt.toml @@ -5,7 +5,7 @@ ver = "0.4.0" name = "unit" paths = ["tests/unit/*.futil"] cmd = """ - ../target/debug/interp {} | jq .memories --sort-keys + ../target/debug/cider {} | jq .memories --sort-keys """ timeout = 3 @@ -14,7 +14,7 @@ name = "errors" paths = ["tests/errors/*.futil"] cmd = """ -../target/debug/interp {} +../target/debug/cider {} """ timeout = 3 @@ -23,7 +23,7 @@ name = "complex" paths = ["tests/complex/*.futil"] cmd = """ -../target/debug/interp {} | jq . --sort-keys +../target/debug/cider {} | jq . --sort-keys """ timeout = 3 @@ -31,7 +31,7 @@ timeout = 3 name = "primitives" paths = ["tests/primitives/*.futil"] cmd = """ -../target/debug/interp {} -q | jq .memories --sort-keys +../target/debug/cider {} -q | jq .memories --sort-keys """ timeout = 3 @@ -39,7 +39,7 @@ timeout = 3 name = "par to seq" paths = ["tests/control/par_reg.futil", "tests/control/par_mem.futil"] cmd = """ -../target/debug/calyx {} -p par-to-seq -l ../ | ../target/debug/interp | jq .memories --sort-keys +../target/debug/calyx {} -p par-to-seq -l ../ | ../target/debug/cider | jq .memories --sort-keys """ timeout = 3 @@ -51,7 +51,7 @@ paths = [ "tests/control/static/*.futil", ] cmd = """ -../target/debug/interp {} -q | jq .memories --sort-keys +../target/debug/cider {} -q | jq .memories --sort-keys """ timeout = 3 @@ -77,7 +77,7 @@ paths = [ # "tests/control/iteration/*.futil" ] cmd = """ -../target/debug/calyx {} -d pre-opt -d post-opt -p simplify-with-control -l ../ | ../target/debug/interp | jq .memories --sort-keys +../target/debug/calyx {} -d pre-opt -d post-opt -p simplify-with-control -l ../ | ../target/debug/cider | jq .memories --sort-keys """ expect_dir = "tests/lowered/" timeout = 3 @@ -86,7 +86,7 @@ timeout = 3 name = "fully structural static" paths = ["tests/control/static*.futil"] cmd = """ -../target/debug/calyx {} -d pre-opt -d post-opt -l ../ | ../target/debug/interp | jq .memories --sort-keys +../target/debug/calyx {} -d pre-opt -d post-opt -l ../ | ../target/debug/cider | jq .memories --sort-keys """ expect_dir = "tests/lowered/" timeout = 3 From 5b4379f2e513edf373fe075a1aac61c8c7d4d833 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 16:59:26 +0530 Subject: [PATCH 060/189] Remove calyx lib.rs so it does not expose any thing (#1711) --- src/lib.rs | 7 ------- src/main.rs | 10 +++++++++- 2 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 src/lib.rs diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 68b856f5e..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! # The Calyx Compiler -//! -//! This crate plumbs together the Calyx compiler crates and provides a command-line interface for the Calyx compiler. -//! What `clang` it to `llvm`, this crate is to the Calyx IL. -//! You SHOULD NOT depend on this crate since does things like installing the primitives library in a global location. -//! Instead, depend on the crates that this crate depends: [`calyx_frontend`], [`calyx_ir`], [`calyx_opt`]. -pub mod cmdline; diff --git a/src/main.rs b/src/main.rs index 88fa7cbc5..0919959f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,17 @@ -use calyx::cmdline::{CompileMode, Opts}; +//! # The Calyx Compiler +//! +//! This crate plumbs together the Calyx compiler crates and provides a command-line interface for the Calyx compiler. +//! What `clang` it to `llvm`, this crate is to the Calyx IL. +//! You SHOULD NOT depend on this crate since does things like installing the primitives library in a global location. +//! Instead, depend on the crates that this crate depends: [`calyx_frontend`], [`calyx_ir`], [`calyx_opt`]. + +mod cmdline; use calyx_backend::BackendOpt; use calyx_frontend as frontend; use calyx_ir as ir; use calyx_opt::pass_manager::PassManager; use calyx_utils::CalyxResult; +use cmdline::{CompileMode, Opts}; use itertools::Itertools; fn main() -> CalyxResult<()> { From c64cbed81370ec1a6e3ba106b4cac3b6b53fa524 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 17:00:15 +0530 Subject: [PATCH 061/189] define `ir::rrc` to build RRCs (#1710) --- calyx-ir/src/builder.rs | 23 +++++++++---------- calyx-ir/src/common.rs | 5 ++++ calyx-ir/src/component.rs | 3 +-- calyx-ir/src/from_ast.rs | 8 ++----- calyx-ir/src/lib.rs | 2 +- calyx-opt/src/passes/compile_invoke.rs | 5 ++-- calyx-opt/src/passes/dump_ports.rs | 6 ++--- .../src/passes/top_down_static_timing/tdst.rs | 3 +-- interp/src/structures/environment.rs | 3 +-- interp/src/structures/values.rs | 10 ++++---- tests/errors/insufficient-params.expect | 2 +- 11 files changed, 34 insertions(+), 36 deletions(-) diff --git a/calyx-ir/src/builder.rs b/calyx-ir/src/builder.rs index 14e928439..78aa36968 100644 --- a/calyx-ir/src/builder.rs +++ b/calyx-ir/src/builder.rs @@ -2,7 +2,6 @@ //! representation. use crate::{self as ir, LibrarySignatures, Nothing, RRC, WRC}; use calyx_frontend::BoolAttr; -use std::cell::RefCell; use std::rc::Rc; use super::{CellType, PortDef}; @@ -75,17 +74,17 @@ impl<'a> Builder<'a> { let name = self.component.generate_name(prefix); // Check if there is a group with the same name. - let group = Rc::new(RefCell::new(ir::Group::new(name))); + let group = ir::rrc(ir::Group::new(name)); // Add default holes to the group. for (name, width) in &[("go", 1), ("done", 1)] { - let hole = Rc::new(RefCell::new(ir::Port { + let hole = ir::rrc(ir::Port { name: ir::Id::from(*name), width: *width, direction: ir::Direction::Inout, parent: ir::PortParent::Group(WRC::from(&group)), attributes: ir::Attributes::default(), - })); + }); group.borrow_mut().holes.push(hole); } @@ -114,19 +113,19 @@ impl<'a> Builder<'a> { let name = self.component.generate_name(prefix); // Check if there is a group with the same name. - let group = Rc::new(RefCell::new(ir::StaticGroup::new(name, latency))); + let group = ir::rrc(ir::StaticGroup::new(name, latency)); // Add default holes to the group. // Static Groups don't need a done hole. // May be beneficial to have a go hole, though (although maybe not) let (name, width) = ("go", 1); - let hole = Rc::new(RefCell::new(ir::Port { + let hole = ir::rrc(ir::Port { name: ir::Id::from(name), width, direction: ir::Direction::Inout, parent: ir::PortParent::StaticGroup(WRC::from(&group)), attributes: ir::Attributes::default(), - })); + }); group.borrow_mut().holes.push(hole); // Add the group to the component. @@ -145,11 +144,11 @@ impl<'a> Builder<'a> { let name = self.component.generate_name(prefix); // Check if there is a group with the same name. - let group = Rc::new(RefCell::new(ir::CombGroup { + let group = ir::rrc(ir::CombGroup { name, attributes: ir::Attributes::default(), assignments: vec![], - })); + }); // Add the group to the component. self.component.comb_groups.add(Rc::clone(&group)); @@ -346,15 +345,15 @@ impl<'a> Builder<'a> { typ: ir::CellType, ports: Vec>, ) -> RRC { - let cell = Rc::new(RefCell::new(ir::Cell::new(name, typ))); + let cell = ir::rrc(ir::Cell::new(name, typ)); ports.into_iter().for_each(|pd| { - let port = Rc::new(RefCell::new(ir::Port { + let port = ir::rrc(ir::Port { name: pd.name(), width: pd.width, direction: pd.direction, parent: ir::PortParent::Cell(WRC::from(&cell)), attributes: pd.attributes, - })); + }); cell.borrow_mut().ports.push(port); }); cell diff --git a/calyx-ir/src/common.rs b/calyx-ir/src/common.rs index f84bd270c..139c16e70 100644 --- a/calyx-ir/src/common.rs +++ b/calyx-ir/src/common.rs @@ -8,6 +8,11 @@ use std::rc::{Rc, Weak}; #[allow(clippy::upper_case_acronyms)] pub type RRC = Rc>; +/// Construct a new RRC. +pub fn rrc(t: T) -> RRC { + Rc::new(RefCell::new(t)) +} + /// A Wrapper for a weak RefCell pointer. /// Used by parent pointers in the internal representation. #[allow(clippy::upper_case_acronyms)] diff --git a/calyx-ir/src/component.rs b/calyx-ir/src/component.rs index a0018a2b7..b0923f5fc 100644 --- a/calyx-ir/src/component.rs +++ b/calyx-ir/src/component.rs @@ -8,7 +8,6 @@ use crate::Nothing; use calyx_utils::NameGenerator; use itertools::Itertools; use linked_hash_map::LinkedHashMap; -use std::cell::RefCell; use std::collections::HashSet; use std::iter::Extend; use std::num::NonZeroU64; @@ -135,7 +134,7 @@ impl Component { static_groups: IdList::default(), comb_groups: IdList::default(), continuous_assignments: vec![], - control: Rc::new(RefCell::new(Control::empty())), + control: super::rrc(Control::empty()), namegen: NameGenerator::with_prev_defined_names(prev_names), attributes: Attributes::default(), is_comb, diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index d125faf9c..0a4ab9da7 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -8,7 +8,6 @@ use crate::{Nothing, PortComp, StaticTiming}; use calyx_frontend::{ast, ast::Atom, BoolAttr, Workspace}; use calyx_utils::{CalyxResult, Error, GPosIdx, WithPos}; use itertools::Itertools; -use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::num::NonZeroU64; @@ -287,11 +286,8 @@ fn build_component( builder.component.continuous_assignments = continuous_assignments; // Build the Control ast using ast::Control. - let control = Rc::new(RefCell::new(build_control( - comp.control, - sig_ctx, - &mut builder, - )?)); + let control = + super::rrc(build_control(comp.control, sig_ctx, &mut builder)?); builder.component.control = control; diff --git a/calyx-ir/src/lib.rs b/calyx-ir/src/lib.rs index be405c992..265d7a02c 100644 --- a/calyx-ir/src/lib.rs +++ b/calyx-ir/src/lib.rs @@ -24,7 +24,7 @@ pub mod rewriter; // Re-export types at the module level. pub use builder::Builder; pub use calyx_utils::{GetName, Id}; -pub use common::{RRC, WRC}; +pub use common::{rrc, RRC, WRC}; pub use component::{Component, IdList}; pub use context::{BackendConf, Context}; pub use control::{ diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 8e0458e5b..3458ce344 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -6,7 +6,6 @@ use calyx_ir::{self as ir, Attributes, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; use ir::{RRC, WRC}; use itertools::Itertools; -use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; @@ -245,13 +244,13 @@ impl Visitor for CompileInvoke { cell.borrow().name() ); for p in vec.iter() { - let new_port = Rc::new(RefCell::new(ir::Port { + let new_port = ir::rrc(ir::Port { name: p.borrow().name, width: p.borrow().width, direction: p.borrow().direction.reverse(), parent: ir::PortParent::Cell(WRC::from(cell)), attributes: Attributes::default(), - })); + }); new_ports.push(new_port); } } diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index ce0ab87a0..afe6a5b98 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -1,7 +1,7 @@ use calyx_ir::{self as ir, RRC, WRC}; use ir::rewriter; use itertools::Itertools; -use std::{cell::RefCell, rc::Rc}; +use std::rc::Rc; #[derive(Default)] /// Results generated from the process of dumping out ports. @@ -62,13 +62,13 @@ where for port_ref in ports_inline { let canon = port_ref.borrow().canonical(); let port = port_ref.borrow(); - let new_port = Rc::new(RefCell::new(ir::Port { + let new_port = ir::rrc(ir::Port { name: component.generate_name(format_port_name(&canon)), width: port.width, direction: port.direction.clone(), parent: ir::PortParent::Cell(WRC::from(&component.signature)), attributes: ir::Attributes::default(), - })); + }); component .signature .borrow_mut() diff --git a/calyx-opt/src/passes/top_down_static_timing/tdst.rs b/calyx-opt/src/passes/top_down_static_timing/tdst.rs index 0ff533d80..c5295771d 100644 --- a/calyx-opt/src/passes/top_down_static_timing/tdst.rs +++ b/calyx-opt/src/passes/top_down_static_timing/tdst.rs @@ -10,7 +10,6 @@ use calyx_ir::{ use calyx_utils::{CalyxResult, Error}; use ir::Nothing; use itertools::Itertools; -use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::io::Write; use std::iter; @@ -910,7 +909,7 @@ impl Visitor for TopDownStaticTiming { Self::compile_sub_programs(&mut con, &mut builder, self.dump_fsm)?; // Add the control program back. - comp.control = Rc::new(RefCell::new(con)); + comp.control = ir::rrc(con); // If the force flag is set, make sure that we only have one group remaining if self.force diff --git a/interp/src/structures/environment.rs b/interp/src/structures/environment.rs index 262c9a382..fda7aa741 100644 --- a/interp/src/structures/environment.rs +++ b/interp/src/structures/environment.rs @@ -17,7 +17,6 @@ use crate::{ values::Value, }; use calyx_ir::{self as ir, RRC}; -use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::iter::once; use std::rc::Rc; @@ -488,7 +487,7 @@ impl InterpreterState { _ => {} } } - Ok((Rc::new(RefCell::new(map)), set)) + Ok((ir::rrc(map), set)) } /// A helper meathod which constructs the initial environment map from ports diff --git a/interp/src/structures/values.rs b/interp/src/structures/values.rs index 84153c71d..bcebcc46f 100644 --- a/interp/src/structures/values.rs +++ b/interp/src/structures/values.rs @@ -9,6 +9,8 @@ use itertools::Itertools; use serde::de::{self, Deserialize, Visitor}; use serde::Serialize; +use calyx_ir as ir; + pub type BitString = BitVec; /// Retrieves the unsigned fixed point representation of `v`. This splits the representation into @@ -333,8 +335,8 @@ impl Value { let input_num: InputNumber = bitwidth.into(); Value { vec: Rc::new(bitvec![usize, Lsb0; 0; input_num.as_usize()]), - unsigned: Rc::new(RefCell::new(Some(0_u8.into()))), - signed: Rc::new(RefCell::new(Some(0.into()))), + unsigned: ir::rrc(Some(0_u8.into())), + signed: ir::rrc(Some(0.into())), } } @@ -383,8 +385,8 @@ impl Value { ( Value { vec: Rc::new(bv), - signed: Rc::new(RefCell::new(None)), - unsigned: Rc::new(RefCell::new(None)), + signed: ir::rrc(None), + unsigned: ir::rrc(None), }, flag, ) diff --git a/tests/errors/insufficient-params.expect b/tests/errors/insufficient-params.expect index 162804fe1..25f8b07e8 100644 --- a/tests/errors/insufficient-params.expect +++ b/tests/errors/insufficient-params.expect @@ -1,5 +1,5 @@ ---CODE--- 101 ---STDERR--- -thread 'main' panicked at 'Failed to add primitive.: Malformed Structure: Invalid parameter binding for primitive `std_fp_div_pipe`. Requires 3 parameters but provided with 1.', calyx-ir/src/builder.rs:220:14 +thread 'main' panicked at 'Failed to add primitive.: Malformed Structure: Invalid parameter binding for primitive `std_fp_div_pipe`. Requires 3 parameters but provided with 1.', calyx-ir/src/builder.rs:219:14 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 3339f514d0238ab7250a73904f18f0b0bf3164e9 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 31 Aug 2023 17:48:58 +0530 Subject: [PATCH 062/189] version 0.6.0 --- CHANGELOG.md | 3 ++- Cargo.lock | 14 +++++++------- Cargo.toml | 16 ++++++++-------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5661d3337..e072263c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ -## Unreleased +## 0.6.0 - BREAKING: Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. - BREAKING: Redesign the `ir::Rewriter` interface to take all the rewrite maps when constructing the `ir::Rewriter` struct. - Merge the logic of `compile-ref` pass into `compile-invoke` so that `ref` cells can be invoked. - The `guard!` macro supports parsing complex guard expressions that use logical connectives and comparison operators. +- The `calyx` library no longer exposes any methods and should not be depended upon. Instead, the new `calyx-backend` crate provides the code needed to emit Verilog from Calyx. ## 0.5.1 - Change the `calyx` build script to use the `CALYX_PRIMITIVES_DIR` env variable to install primitive libraries. If unset, use `$HOME/.calyx`. diff --git a/Cargo.lock b/Cargo.lock index 8998552dd..3b80102a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "calyx" -version = "0.5.1" +version = "0.6.0" dependencies = [ "argh", "atty", @@ -196,7 +196,7 @@ dependencies = [ [[package]] name = "calyx-backend" -version = "0.5.0" +version = "0.6.0" dependencies = [ "calyx-frontend", "calyx-ir", @@ -217,7 +217,7 @@ dependencies = [ [[package]] name = "calyx-frontend" -version = "0.5.0" +version = "0.6.0" dependencies = [ "atty", "calyx-utils", @@ -237,7 +237,7 @@ dependencies = [ [[package]] name = "calyx-ir" -version = "0.5.0" +version = "0.6.0" dependencies = [ "calyx-frontend", "calyx-utils", @@ -253,7 +253,7 @@ dependencies = [ [[package]] name = "calyx-opt" -version = "0.5.0" +version = "0.6.0" dependencies = [ "calyx-ir", "calyx-utils", @@ -269,11 +269,11 @@ dependencies = [ [[package]] name = "calyx-stdlib" -version = "0.5.0" +version = "0.6.0" [[package]] name = "calyx-utils" -version = "0.5.0" +version = "0.6.0" dependencies = [ "atty", "itertools 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 25a209f07..b4fbd9044 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ description = "Compiler Infrastructure for Hardware Accelerator Generation" categories = ["compilers"] homepage = "https://calyxir.org" edition = "2021" -version = "0.5.0" +version = "0.6.0" rust-version = "1.67" [workspace.dependencies] @@ -42,11 +42,11 @@ pest = "2" pest_derive = "2" pest_consume = "1" argh = "0.1" -calyx-utils = { path = "calyx-utils", version = "0.5.0" } -calyx-ir = { path = "calyx-ir", version = "0.5.0" } -calyx-frontend = { path = "calyx-frontend", version = "0.5.0" } -calyx-opt = { path = "calyx-opt", version = "0.5.0" } -calyx-backend = { path = "calyx-backend", version = "0.5.0" } +calyx-utils = { path = "calyx-utils", version = "0.6.0" } +calyx-ir = { path = "calyx-ir", version = "0.6.0" } +calyx-frontend = { path = "calyx-frontend", version = "0.6.0" } +calyx-opt = { path = "calyx-opt", version = "0.6.0" } +calyx-backend = { path = "calyx-backend", version = "0.6.0" } [workspace.dependencies.petgraph] version = "0.6" @@ -58,7 +58,7 @@ features = ["matrix_graph"] [package] name = "calyx" default-run = "calyx" -version = "0.5.1" +version.workspace = true edition.workspace = true description.workspace = true authors.workspace = true @@ -80,7 +80,7 @@ default = [] serialize = ["calyx-ir/serialize", "serde/rc", "calyx-backend/sexp"] [build-dependencies] -calyx-stdlib = { path = "calyx-stdlib", version = "0.5.0" } +calyx-stdlib = { path = "calyx-stdlib", version = "0.6.0" } [dependencies] atty.workspace = true From 67e11311a7e156bed74163af91f98b193f06cd40 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:21:51 -0400 Subject: [PATCH 063/189] Systolic Array MM and Post Op Separated into Separate Components (#1702) * working separated relu * correct implementation of separate relu unit * removed unnecessary file * python lint * some progress on refactoring * some progress on leaky relu * working leaky relu post op * deleted unnec file * cleaner code * modified gen-systolic * small changes * python formatting * rewrote tests * simplified gen-systolic * simplified code + design * py format * rewrote tests * documentation * some code cleaning * code cleaning --- calyx-py/calyx/builder.py | 32 + frontends/systolic-lang/check-output.py | 34 +- frontends/systolic-lang/convert-mems.py | 50 + frontends/systolic-lang/gen-systolic.py | 1105 ++--------------- .../systolic-lang/gen_array_component.py | 711 +++++++++++ frontends/systolic-lang/gen_pe.py | 38 + frontends/systolic-lang/gen_post_op.py | 331 +++++ fud/fud/stages/verilator/numeric_types.py | 19 +- fud/icarus/icarus.py | 6 +- .../systolic/leaky-relu/array-2-3-4.expect | 2 +- .../systolic/leaky-relu/array-8.expect | 2 +- .../systolic/output/array-2-3-4.expect | 54 +- .../systolic/output/array-2-3-4.systolic.data | 92 +- .../systolic/output/array-8.expect | 386 +++--- .../systolic/output/array-8.systolic.data | 504 ++++---- tests/correctness/systolic/pe/array-1.expect | 8 +- .../systolic/pe/array-1.systolic.data | 31 +- .../systolic/pe/array-1.systolic.jq | 2 +- tests/correctness/systolic/pe/array-2.expect | 26 +- .../systolic/pe/array-2.systolic.data | 45 +- .../systolic/pe/array-2.systolic.jq | 2 +- tests/correctness/systolic/pe/array-3.expect | 56 +- .../systolic/pe/array-3.systolic.data | 76 +- .../systolic/pe/array-3.systolic.jq | 2 +- tests/frontend/systolic/array-1.expect | 101 +- tests/frontend/systolic/array-2.expect | 658 ---------- tests/frontend/systolic/array-2.systolic | 6 - tests/frontend/systolic/array-3.expect | 1065 ---------------- tests/frontend/systolic/array-3.systolic | 6 - 29 files changed, 2064 insertions(+), 3386 deletions(-) create mode 100644 frontends/systolic-lang/convert-mems.py create mode 100644 frontends/systolic-lang/gen_array_component.py create mode 100644 frontends/systolic-lang/gen_pe.py create mode 100644 frontends/systolic-lang/gen_post_op.py delete mode 100644 tests/frontend/systolic/array-2.expect delete mode 100644 tests/frontend/systolic/array-2.systolic delete mode 100644 tests/frontend/systolic/array-3.expect delete mode 100644 tests/frontend/systolic/array-3.systolic diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index b55aa4516..e33f9ac81 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -172,6 +172,14 @@ def get_group(self, name: str) -> GroupBuilder: f"Group `{name}' not found in component {self.component.name}" ) + def try_get_group(self, name: str) -> GroupBuilder: + """Tries to get a group builder by name. If cannot find it, return None""" + out = self.index.get(name) + if out and isinstance(out, GroupBuilder): + return out + else: + return None + def group(self, name: str, static_delay: Optional[int] = None) -> GroupBuilder: """Create a new group with the given name and (optional) static delay.""" group = ast.Group(ast.CompVar(name), connections=[], static_delay=static_delay) @@ -1176,3 +1184,27 @@ def seq(*args) -> ast.SeqComp: {a; b; c;}`. """ return ast.SeqComp([as_control(x) for x in args]) + + +def build_connections( + cell1: Union[CellBuilder, ThisBuilder], + cell2: Union[CellBuilder, ThisBuilder], + root1: str, + root2: str, + forward_ports: List, + reverse_ports: List, +): + """ + Intended for wiring together two cells whose ports have similar names. + For each `name` in `forward_port_names`, adds the following connection: + `(cell1.root1_name,cell2.root2_name)` + For `backwards_port_names`, adds the following connection: + `(cell2.root2_name,cell1.root1_name)` + Returns a list of the resulting connections. + """ + res = [] + for port in forward_ports: + res.append((cell1.port(root1 + port), cell2.port(root2 + port))) + for port in reverse_ports: + res.append((cell2.port(root2 + port), cell1.port(root1 + port))) + return res diff --git a/frontends/systolic-lang/check-output.py b/frontends/systolic-lang/check-output.py index 677c46a8f..6548b39f3 100644 --- a/frontends/systolic-lang/check-output.py +++ b/frontends/systolic-lang/check-output.py @@ -36,12 +36,8 @@ assert td == ld, f"Cannot multiply matrices: " f"{tl}x{td} and {ld}x{ll}" - if relu: - dtype = "f" - else: - dtype = "i" - left = np.zeros((ll, ld), dtype) - top = np.zeros((td, tl), dtype) + left = np.zeros((ll, ld), "f") + top = np.zeros((td, tl), "f") json_data = json.load(open(json_file))["memories"] for r in range(ll): @@ -58,26 +54,14 @@ res = [] for r in range(ll): - if relu: - res.append(list(map(float, json_data[f"out_mem_{r}"]))) - else: - res.append(json_data[f"out_mem_{r}"]) + res.append(list(map(float, json_data[f"out_mem_{r}"]))) json_result = np.array(res) - if relu: - if np.isclose(matmul_result, json_result, atol=1e-3).all(): - print("Correct") - else: - print("Incorrect\n. Should have been:\n") - print(matmul_result) - print("\nBut got:\n") - print(json_result) + if np.isclose(matmul_result, json_result, atol=1e-3).all(): + print("Correct") else: - if np.equal(json_result, matmul_result): - print("Correct") - else: - print("Incorrect\n. Should have been:\n") - print(matmul_result) - print("\nBut got:\n") - print(json_result) + print("Incorrect\n. Should have been:\n") + print(matmul_result) + print("\nBut got:\n") + print(json_result) diff --git a/frontends/systolic-lang/convert-mems.py b/frontends/systolic-lang/convert-mems.py new file mode 100644 index 000000000..22af8aaf4 --- /dev/null +++ b/frontends/systolic-lang/convert-mems.py @@ -0,0 +1,50 @@ +import argparse +import json +from fud.stages.verilator import numeric_types + + +if __name__ == "__main__": + """ + This is a script to help you know whether the Calyx's systolic array + generator is giving you the correct answers. + + How to use this script: run Calyx's systolic array generator and get an + output json. Then run this script on the output json, and this script + will check the answers against numpy's matrix multiplication implementation. + + Command line arguments are (no json support yet): + -tl -td -ll -ld are the same as the systolic array arguments. + -j which is the path to the json you want to check + """ + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument("-iw", "--int-width", type=int) + parser.add_argument("-fw", "--frac-width", type=int) + parser.add_argument("-bw", "--bit-width", type=int) + parser.add_argument("-s", "--signed", action="store_true") + parser.add_argument("-j", "--json_file", type=str) + + args = parser.parse_args() + + int_width = args.int_width + frac_width = args.frac_width + bit_width = args.bit_width + signed = args.signed + json_file = args.json_file + + assert ( + bit_width == frac_width + int_width + ), f"Bitwidth {bit_width} should equal: frac_width {frac_width} \ + + int_width {int_width}" + + json_data = json.load(open(json_file)) + + for key, value in json_data.items(): + if key != "cycles": + new_values = [ + numeric_types.bitnum_to_fixed( + numeric_types.Bitnum(str(x), is_signed=signed, width=bit_width), + int_width=int_width, + ).string_repr + for x in value + ] + print(new_values) diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 8665f3a00..7c67e1292 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -1,1020 +1,132 @@ #!/usr/bin/env python3 - -import numpy as np import calyx.builder as cb +from gen_array_component import ( + create_systolic_array, + BITWIDTH, + SYSTOLIC_ARRAY_COMP, + NAME_SCHEME, +) +from gen_post_op import ( + default_post_op, + leaky_relu_post_op, + OUT_MEM, + DEFAULT_POST_OP, + LEAKY_RELU_POST_OP, +) from calyx import py_ast -from calyx.utils import bits_needed -from fud.stages.verilator import numeric_types -from calyx.utils import float_to_fixed_point - -# Global constant for the current bitwidth. -BITWIDTH = 32 -INTWIDTH = 16 -FRACWIDTH = 16 -# Name of the ouput array -OUT_MEM = "out_mem" -PE_NAME = "mac_pe" -DEPTH = "depth" - - -class CalyxAdd: - """ - A class that represents addition in Calyx between a port and a constant - """ - - def __init__(self, port, const): - self.port = port - self.const = const - - def __eq__(self, other): - if type(other) != CalyxAdd: - return False - return ( - cb.ExprBuilder.unwrap(self.port) == cb.ExprBuilder.unwrap(other.port) - and self.const == other.const - ) - - def __hash__(self): - return hash(self.const) - - def __repr__(self): - return ( - str(cb.ExprBuilder.unwrap(self.port).item.id.name) - + "_plus_" - + str(self.const) - ) - - def __str__(self): - return ( - str(cb.ExprBuilder.unwrap(self.port).item.id.name) - + "_plus_" - + str(self.const) - ) - - -def pe(prog: cb.Builder, leaky_relu): - comp = prog.component(name=PE_NAME, latency=1) - comp.input("top", BITWIDTH) - comp.input("left", BITWIDTH) - comp.input("mul_ready", 1) - comp.output("out", BITWIDTH) - acc = comp.reg("acc", BITWIDTH) - # Leaky relu means 32 bit signed fixed point operations. - if leaky_relu: - add = comp.fp_sop("adder", "add", BITWIDTH, INTWIDTH, FRACWIDTH) - mul = comp.pipelined_fp_smult("mul", BITWIDTH, INTWIDTH, FRACWIDTH) - # No leaky relu means integer operations - else: - add = comp.add(BITWIDTH, "add") - # XXX: pipelined mult assumes 32 bit multiplication - mul = comp.pipelined_mult("mul") - - this = comp.this() - with comp.static_group("do_add", 1): - add.left = acc.out - add.right = mul.out - acc.in_ = add.out - acc.write_en = this.mul_ready - - with comp.static_group("do_mul", 1): - mul.left = this.top - mul.right = this.left - - par = py_ast.StaticParComp([py_ast.Enable("do_add"), py_ast.Enable("do_mul")]) - - with comp.continuous: - this.out = acc.out - - comp.control += par - - -# Naming scheme for generated groups. Used to keep group names consistent -# across structure and control. -NAME_SCHEME = { - # Indexing into the memory - "index name": "{prefix}_idx", - "index init": "{prefix}_idx_init", - "index update": "{prefix}_idx_update", - # Move data from main memories - "memory move": "{prefix}_move", - "out mem move": "{pe}_out_write", - # Move data between internal registers - "register move down": "{pe}_down_move", - "register move right": "{pe}_right_move", -} - - -def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuilder: - """ - Instantiate an indexor for accessing memory with name `prefix`. - Generates structure to initialize and update the indexor. - - The initializor starts sets the memories to their maximum value - because we expect all indices to be incremented once before - being used. - - Returns (cells, structure) - """ - name = NAME_SCHEME["index name"].format(prefix=prefix) - - reg = comp.reg(name, width) - add = comp.add(width, f"{prefix}_add") - - init_name = NAME_SCHEME["index init"].format(prefix=prefix) - with comp.static_group(init_name, 1): - # Initialize the indexor to 0 - reg.in_ = 0 - reg.write_en = 1 - - upd_name = NAME_SCHEME["index update"].format(prefix=prefix) - with comp.static_group(upd_name, 1): - # Increment the indexor. - add.left = 1 - add.right = reg.out - reg.in_ = add.out - reg.write_en = 1 - - return reg - - -def add_read_mem_argument(comp: cb.ComponentBuilder, name, addr_width): - """ - Add arguments to component `comp` if we want to read from a mem named `name` with - width of `addr_width` - """ - comp.input(f"{name}_read_data", BITWIDTH) - comp.output(f"{name}_addr0", addr_width) - - -def add_write_mem_argument(comp: cb.ComponentBuilder, name, addr_width): - """ - Add arguments to component `comp` if we want to write to a mem named `name` with - width of `addr_width` inside `comp.` - """ - comp.output(f"{name}_addr0", addr_width) - comp.output(f"{name}_write_data", BITWIDTH) - comp.output(f"{name}_write_en", 1) - - -def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): - """ - Instantiates: - - top memory - - structure to move data from memory to read registers. - - Returns (cells, structure) tuple. - """ - if top_or_left == "top": - name = f"t{idx}" - target_reg = f"top_0_{idx}" - elif top_or_left == "left": - name = f"l{idx}" - target_reg = f"left_{idx}_0" - else: - raise Exception(f"Invalid top_or_left: {top_or_left}") - idx_width = bits_needed(size) - # Instantiate the memory - add_read_mem_argument(comp, name, idx_width) - this = comp.this() - addr0_port = cb.ExprBuilder.unwrap(this.port(name + "_addr0")) - read_data_port = this.port(name + "_read_data") - # Instantiate the indexing register - idx = instantiate_indexor(comp, name, idx_width) - # Register to save the value from the memory. Defined by [[instantiate_pe]]. - target = comp.get_cell(target_reg) - group_name = NAME_SCHEME["memory move"].format(prefix=name) - with comp.static_group(group_name, 1) as g: - g.asgn(addr0_port, idx.out) - target.in_ = read_data_port - target.write_en = 1 - -def instantiate_pe(comp: cb.ComponentBuilder, row: int, col: int): - """ - Instantiate the PE and all the registers connected to it. - """ - # Add all the required cells. - comp.cell(f"pe_{row}_{col}", py_ast.CompInst(PE_NAME, [])) - comp.reg(f"top_{row}_{col}", BITWIDTH) - comp.reg(f"left_{row}_{col}", BITWIDTH) - - -def instantiate_data_move( - comp: cb.ComponentBuilder, row: int, col: int, right_edge: bool, down_edge: bool +def create_mem_connections( + main: cb.ComponentBuilder, + component_builder: cb.ComponentBuilder, + mem_name: str, + mem_size: int, + read_mem: bool, ): """ - Generates groups for "data movers" which are groups that move data - from the `write` register of the PE at (row, col) to the read register - of the PEs at (row+1, col) and (row, col+1) - """ - name = f"pe_{row}_{col}" - - if not right_edge: - group_name = NAME_SCHEME["register move right"].format(pe=name) - src_reg = comp.get_cell(f"left_{row}_{col}") - dst_reg = comp.get_cell(f"left_{row}_{col + 1}") - with comp.static_group(group_name, 1): - dst_reg.in_ = src_reg.out - dst_reg.write_en = 1 - - if not down_edge: - group_name = NAME_SCHEME["register move down"].format(pe=name) - src_reg = comp.get_cell(f"top_{row}_{col}") - dst_reg = comp.get_cell(f"top_{row + 1}_{col}") - with comp.static_group(group_name, 1): - dst_reg.in_ = src_reg.out - dst_reg.write_en = 1 - - -def instantiate_output_move(comp: cb.ComponentBuilder, row, col, cols): - """ - Generates groups to move the final value from a PE into the output array. - """ - group_name = NAME_SCHEME["out mem move"].format(pe=f"pe_{row}_{col}") - pe = comp.get_cell(f"pe_{row}_{col}") - this = comp.this() - mem_name = OUT_MEM + f"_{row}" - addr0_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_addr0")) - write_data_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_data")) - write_en_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_en")) - with comp.static_group(group_name, 1) as g: - g.asgn(addr0_port, col) - g.asgn(write_data_port, pe.out) - g.asgn(write_en_port, 1) - - -def instantiate_relu_cond_reg( - comp: cb.ComponentBuilder, - num_rows, -): - """ - Writes into `cond_reg`, the condition register for the while loop. - `cond_reg` basically checks whether the relu operation has finished yet - for all rows of the array. If so, it sets `cond_reg` to lo. Otherwise it - sets it to high. - """ - cond_reg = comp.get_cell("cond_reg") - cond_wire = comp.wire("cond_wire", 1) - for r in range(num_rows): - if r == 0: - guard = comp.get_cell(f"relu_finished_reg_r{r}").port("out") - else: - guard = guard & comp.get_cell(f"relu_finished_reg_r{r}").port("out") - with comp.static_group("write_cond_reg", 1): - cond_wire.in_ = guard @ 1 - cond_reg.in_ = ~cond_wire.out @ 1 - cond_reg.in_ = cond_wire.out @ 0 - cond_reg.write_en = 1 - - -def gen_schedules( - top_length, - top_depth, - left_length, - left_depth, - leaky_relu, - comp: cb.ComponentBuilder, -): - """ - Generates 5 arrays that are the same size as the output (systolic) array - Each entry in the array has tuple [start, end) that indicates the cycles that - they are active - `update_sched` contains when to update the indices of the input memories and feed - them into the systolic array - `pe_fill_sched` contains when to invoke PE but not accumulate (bc the multipliers - are not ready with an output yet) - `pe_accum_sched` contains when to invoke PE and accumulate (bc the multipliers - are ready with an output) - `pe_move_sched` contains when to "move" the PE (i.e., pass data) - `pe_write_sched` contains when to "write" the PE value into memory (i.e., when - the PE is "finished") - `relu_sched` replaces `pe_write_sched` for Leaky Relu, and contains when to - start the relu operation for a given row. - """ - depth_port = comp.this().depth - min_depth_4_port = comp.get_cell("min_depth_4").port("out") - schedules = {} - update_sched = np.zeros((left_length, top_length), dtype=object) - pe_fill_sched = np.zeros((left_length, top_length), dtype=object) - pe_accum_sched = np.zeros((left_length, top_length), dtype=object) - pe_move_sched = np.zeros((left_length, top_length), dtype=object) - # will only actually use one of the following two schedules - pe_write_sched = np.zeros((left_length, top_length), dtype=object) - relu_sched = np.zeros((left_length), dtype=object) - for row in range(0, left_length): - relu_sched[row] = ( - CalyxAdd(depth_port, row + 5), - None, - ) - for col in range(0, top_length): - pos = row + col - update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) - pe_fill_sched[row][col] = (pos + 1, CalyxAdd(min_depth_4_port, pos + 1)) - pe_accum_sched[row][col] = (pos + 5, CalyxAdd(depth_port, pos + 5)) - pe_move_sched[row][col] = (pos + 1, CalyxAdd(depth_port, pos + 1)) - pe_write_sched[row][col] = ( - CalyxAdd(depth_port, pos + 5), - CalyxAdd(depth_port, pos + 6), - ) - schedules["update_sched"] = update_sched - schedules["fill_sched"] = pe_fill_sched - schedules["accum_sched"] = pe_accum_sched - schedules["move_sched"] = pe_move_sched - # Only need one of relu_sched and write_sched - if leaky_relu: - schedules["relu_sched"] = relu_sched - else: - schedules["write_sched"] = pe_write_sched - return schedules - - -def accum_nec_ranges(nec_ranges, schedule): - """ - Essentially creates a set that contains all of the idx ranges that - we need to check for (e.g., [1,3) [2,4)] in order to realize - the schedule - - nec_ranges is a set of tuples. - schedule is either a 2d array or 1d array with tuple (start,end) entries. - Adds all intervals (start,end) in schedule to nec_ranges if the it's - not already in nec_ranges. - """ - if schedule.ndim == 1: - for r in schedule: - nec_ranges.add(r) - elif schedule.ndim == 2: - for r in schedule: - for c in r: - nec_ranges.add(c) - else: - raise Exception("accum_nec_ranges expects only 1d or 2d arrays") - return nec_ranges - - -def try_build_calyx_add(comp, obj): - """ - Attempts to build an adder for obj, with name str(obj) and group name - str(obj) + "_group" that adds obj.port and obj.const - Returns true if we actually build it - Returns false otherwise - """ - if type(obj) == CalyxAdd: - add_str = str(obj) - if comp.try_get_cell(add_str) is None: - add = comp.add(BITWIDTH, add_str) - with comp.static_group(add_str + "_group", 1): - add.left = obj.port - add.right = obj.const - return True - return False - - -def instantiate_calyx_adds(comp, nec_ranges): - """ - Instantiates the CalyxAdds objects to adders and actual groups that add things - """ - depth_adders = [] - for lo, hi in nec_ranges: - if try_build_calyx_add(comp, lo): - depth_adders.append(str(lo) + "_group") - if try_build_calyx_add(comp, hi): - depth_adders.append(str(hi) + "_group") - return depth_adders - - -def instantiate_idx_cond_groups(comp: cb.ComponentBuilder, leaky_relu): - """ - Builds groups that instantiate idx to 0 and increment idx - Also builds groups that set cond_reg to 1 (runs before the while loop) - and that sets cond_reg to idx + 1 < iter_limit - """ - idx = comp.reg("idx", BITWIDTH) - add = comp.add(BITWIDTH, "idx_add") - cond_reg = comp.reg("cond_reg", 1) - with comp.static_group("init_idx", 1): - idx.in_ = 0 - idx.write_en = 1 - with comp.static_group("incr_idx", 1): - add.left = idx.out - add.right = 1 - idx.in_ = add.out - idx.write_en = 1 - with comp.static_group("init_cond_reg", 1): - cond_reg.in_ = 1 - cond_reg.write_en = 1 - # Only check iter_limit if not leaky_relu. - # For leaky_relu we don't check iterations, we check if the relu - # operations are finished yet - if not leaky_relu: - iter_limit = comp.get_cell("iter_limit") - lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") - with comp.static_group("lt_iter_limit_group", 1): - lt_iter_limit.left = add.out - lt_iter_limit.right = iter_limit.out - cond_reg.in_ = lt_iter_limit.out - cond_reg.write_en = 1 - - -def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, rem_iter_limit, leaky_relu): - """ - Builds group that instantiates the dynamic/runtime values for the systolic - array: its depth and iteration limit/count (since its iteration limit depends on - its depth). - If leaky_relu, we do not need to check iteration limit. - """ - min_depth_4 = comp.reg("min_depth_4", BITWIDTH) - lt_depth_4 = comp.lt(BITWIDTH, "lt_depth_4") - with comp.static_group("init_min_depth", 1): - lt_depth_4.left = depth_port - lt_depth_4.right = 4 - min_depth_4.in_ = lt_depth_4.out @ depth_port - min_depth_4.in_ = ~lt_depth_4.out @ 4 - min_depth_4.write_en = 1 - if not leaky_relu: - iter_limit = comp.reg("iter_limit", BITWIDTH) - iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") - with comp.static_group("init_iter_limit", 1): - iter_limit_add.left = rem_iter_limit - iter_limit_add.right = depth_port - iter_limit.in_ = iter_limit_add.out - iter_limit.write_en = 1 - - -def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: - """ - Instantiates a static group and register called "idx_between_{lo}_{hi}_reg/group" - that should output whether idx is between [lo, hi). That is, whether lo <= idx < hi. - - Note: If you're trying to understand why this works, we are checking `idx_add` which - is one higher than idx. This offsets the cycle it takes to update the register. + Instantiates 1d memory named mem_name with idx widths of idx_width. + Also connects the memory ports to `component_builder` + If `read_mem` == True, then connects memory ports such that + `component_builder` can read from memory. + If `read_mem` == False, then connects memory ports such that + `component_builder` can write to memory. """ - if type(hi) == CalyxAdd: - hi_value = comp.get_cell(str(hi)).port("out") - else: - hi_value = hi - if type(lo) == CalyxAdd: - lo_value = comp.get_cell(str(lo)).port("out") - else: - lo_value = lo - idx_add = comp.get_cell("idx_add") - reg_str = f"idx_between_{lo}_{hi}_reg" - comb_str = f"idx_between_{lo}_{hi}_comb" - group_str = f"idx_between_{lo}_{hi}_group" - index_lt = f"index_lt_{str(hi)}" - index_ge = f"index_ge_{str(lo)}" - assert ( - not type(lo) is None - ), "None Type Lower Bound not supported in instantiate_idx_between" - # If no upper bound, then only need to check reg >= lo - if hi is None: - ge = ( - comp.get_cell(index_ge) - if comp.try_get_cell(index_ge) is not None - else comp.ge(BITWIDTH, index_ge) - ) - with comp.static_group(group_str, 1): - ge.left = idx_add.out - ge.right = lo_value - else: - reg = comp.reg(reg_str, 1) - lt = ( - comp.get_cell(index_lt) - if comp.try_get_cell(index_lt) is not None - else comp.lt(BITWIDTH, index_lt) - ) - # if lo == 0, then only need to check if reg < hi - if type(lo) == int and lo == 0: - with comp.static_group(group_str, 1): - lt.left = idx_add.out - lt.right = hi_value - reg.in_ = lt.out - reg.write_en = 1 - # need to check if reg >= lo and reg < hi - else: - ge = ( - comp.get_cell(index_ge) - if comp.try_get_cell(index_ge) is not None - else comp.ge(BITWIDTH, index_ge) - ) - and_ = comp.and_(1, comb_str) - with comp.static_group(group_str, 1): - ge.left = idx_add.out - ge.right = lo_value - lt.left = idx_add.out - lt.right = hi_value - and_.left = ge.out - and_.right = lt.out - reg.in_ = and_.out - reg.write_en = 1 - - -def instantiate_init_group(comp: cb.ComponentBuilder, lo, hi): - """ - Builds a group to set initial state for register idx_between_{lo}_{hi}_reg. - """ - # if lo == 0, then the idx will initially be in between the interval, so - # need to set idx_between to high - start_hi = 1 if lo == 0 else 0 - # XXX(Caleb): assumed hi=None is used for a Relu computation, and therefore - # idx_between_reg is not necessary. - if hi is None: - return - idx_between = comp.get_cell(f"idx_between_{lo}_{hi}_reg") - with comp.static_group(f"init_idx_between_{lo}_{hi}", 1): - idx_between.in_ = start_hi - idx_between.write_en = 1 - - -def instantiate_relu_groups(comp: cb.ComponentBuilder, row, top_length): - """ - Instantiates leaky relu groups that performs leaky relu on `row`. - """ - - # Helper function adds assignment wire.in = reg.out == col ? pe_{row}_{col}_out. - def build_assignment( - comp: cb.ComponentBuilder, group: cb.GroupBuilder, wire, register, row, col - ): - wire_in = wire.port("in") - reg_out = register.port("out") - pe_out = comp.get_cell(f"pe_{row}_{col}").port("out") - group.asgn( - wire_in, - pe_out, - reg_out == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, col)), - ) - - # Current value we are performing relu on. - cur_val = comp.wire(f"relu_r{row}_cur_val", BITWIDTH) - # Current idx within the row for the value we are performing relu on. - idx_reg = comp.reg(f"relu_r{row}_cur_idx", BITWIDTH) - group_assigns = [] - group = comp.static_group(f"relu_r{row}_helper", 1) - # assigning cur_val = value of PE at (row,idx_reg). - for col in range(top_length): - group_assigns.append(build_assignment(comp, group, cur_val, idx_reg, row, col)) - - # Wire that tells us we are finished with relu operation for this row. - relu_finished_wire = comp.wire(f"relu_finished_wire_r{row}", 1) - # Register that holds the value of relu_finished_wire for later cycles. - relu_finished_reg = comp.reg(f"relu_finished_reg_r{row}", 1) - # Checks whether cur_val is > 0. - cur_gt = comp.fp_sop(f"relu_r{row}_val_gt", "gt", BITWIDTH, INTWIDTH, FRACWIDTH) - # Checks whether we should go onto the next entry in the row. This occurs - # either when a) value is positive or b) multiply operation has finished. - go_next = comp.wire(f"relu_r{row}_go_next", BITWIDTH) - # Increments idx_reg. - incr = comp.add(BITWIDTH, f"relu_r{row}_incr") - # Performs multiplication for leaky relu. - fp_mult = comp.fp_sop( - f"relu_r{row}_val_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH - ) - this = comp.this() - mem_name = OUT_MEM + f"_{row}" - addr0_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_addr0")) - write_data_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_data")) - write_en_port = cb.ExprBuilder.unwrap(this.port(mem_name + "_write_en")) - with comp.static_group(f"execute_relu_r{row}", 1) as g: - # Check if the current value is positive or negative. - cur_gt.left = cur_val.out - cur_gt.right = 0 - - # Handle incrementing the idx_reg. - # Increment either when a) multiplication is done or b) cur value is positive - incr.left = idx_reg.out - incr.right = 1 - go_next.in_ = (fp_mult.done | cur_gt.out) @ 1 - idx_reg.in_ = go_next.out @ incr.out - idx_reg.write_en = go_next.out @ 1 - - # Perform the multiplication. - # Get FP approximation of 0.01. - fp_mult.left = numeric_types.FixedPoint( - str(float_to_fixed_point(0.01, FRACWIDTH)), BITWIDTH, INTWIDTH, True - ).unsigned_integer() - fp_mult.right = cur_val.out - fp_mult.go = ~go_next.out @ 1 - - # Write to mem based on whether cur_valu >= 0 - g.asgn(write_en_port, 1, go_next.out) - g.asgn(addr0_port, idx_reg.out) - g.asgn(write_data_port, cur_val.out, cur_gt.out) - g.asgn(write_data_port, fp_mult.out, ~cur_gt.out) - - # While loop logic. relu_finished when idx_reg == top_length - 1 & go_next, - # i.e., when we're at the last index and about to "go to the next value". - relu_finished_wire.in_ = ( - go_next.out - & ( - idx_reg.out - == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, top_length - 1)) - ) - ) @ 1 - relu_finished_reg.in_ = relu_finished_wire.out @ 1 - relu_finished_reg.write_en_ = relu_finished_wire.out @ 1 - - # Start relu when idx_ge row + depth + 5, i.e., when first value in row - # is ready to be computed. - relu_start_port = comp.get_cell(f"index_ge_depth_plus_{5 + row}").port("out") - # relu_cond_wire coordinates when relu_cond_reg should be hi/lo - relu_cond_wire = comp.wire(f"relu_cond_wire_r{row}", 1) - # relu_cond_reg guards when we should perform the relu execution group defined - # above. - relu_cond_reg = comp.reg(f"relu_cond_reg_r{row}", 1) - guard = relu_start_port & (~relu_finished_wire.out) - with comp.static_group(f"check_relu_cond_r{row}", 1): - relu_cond_wire.in_ = guard @ 1 - relu_cond_reg.in_ = relu_cond_wire.out @ 1 - relu_cond_reg.in_ = ~relu_cond_wire.out @ 0 - relu_cond_reg.write_en = ~relu_finished_reg.out @ 1 - - -def get_memory_updates(row, col): - """ - Gets the memory moves and memory idx updates for (row,col) - This is how we coordinate feeding the memories into the systolic array - """ - movers = [] - if col == 0: - movers.append(NAME_SCHEME["memory move"].format(prefix=f"l{row}")) - movers.append(NAME_SCHEME["index update"].format(prefix=f"l{row}")) - if row == 0: - movers.append(NAME_SCHEME["memory move"].format(prefix=f"t{col}")) - movers.append(NAME_SCHEME["index update"].format(prefix=f"t{col}")) - mover_enables = [py_ast.Enable(name) for name in movers] - return mover_enables - - -def get_pe_moves(r, c, top_length, left_length): - """ - Gets the PE moves for the PE at (r,c) - """ - pe_moves = [] - if r < left_length - 1: - pe_moves.append(NAME_SCHEME["register move down"].format(pe=f"pe_{r}_{c}")) - if c < top_length - 1: - pe_moves.append(NAME_SCHEME["register move right"].format(pe=f"pe_{r}_{c}")) - pe_enables = [py_ast.Enable(name) for name in pe_moves] - return pe_enables - - -def get_pe_invoke(r, c, top_length, left_length, mul_ready): - """ - gets the PE invokes for the PE at (r,c). mul_ready signals whether 1 or 0 - should be passed into mul_ready - """ - return py_ast.StaticInvoke( - id=py_ast.CompVar(f"pe_{r}_{c}"), - in_connects=[ - ("top", py_ast.CompPort(py_ast.CompVar(f"top_{r}_{c}"), "out")), - ( - "left", - py_ast.CompPort(py_ast.CompVar(f"left_{r}_{c}"), "out"), - ), - ( - "mul_ready", - py_ast.ConstantPort(1, mul_ready), - ), - ], - out_connects=[], + # XXX(Caleb): should change idx_width to be more precise + idx_width = BITWIDTH + mem = main.mem_d1( + mem_name, + BITWIDTH, + mem_size, + idx_width, + is_external=True, ) - - -def execute_if_between(comp: cb.ComponentBuilder, start, end, body): - """ - body is a list of control stmts - if body is empty, return an empty list - otherwise, builds an if stmt that executes body in parallel if - idx is between start and end - """ - if not body: - return [] - if_cell = comp.get_cell(f"idx_between_{start}_{end}_reg") - return [ - cb.static_if( - if_cell.out, - py_ast.StaticParComp(body), - ) - ] - - -def execute_if_register(comp: cb.ComponentBuilder, register, body): - """ - body is a list of control stmts - if body is empty, return an empty list - otherwise, builds an if stmt that executes body in parallel reg.out is high - """ - if not body: - return [] - return [ - cb.static_if( - register.out, - py_ast.StaticParComp(body), - ) - ] - - -def generate_control( - comp: cb.ComponentBuilder, - top_length, - top_depth, - left_length, - left_depth, - schedules, - depth_adders, - nec_ranges, - leaky_relu, -): - """ - Logically, control performs the following actions: - 1. Initialize all the memory indexors and idx and idx_between - registers at the start - 2. Build a static repeat with a one cycle body that: - a. Updates memory indices if needed/feeds memory into systolic array. - b. Invokes the PEs correctly (mul_ready should only be hi if - the multiplier's values are ready). - c. Move the data needed by each PE - 3. Writes the PE values into external memory - """ - - control = [] - - # Initialize all memories. - init_indices: list[py_ast.Control] = [ - py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"t{idx}")) - for idx in range(top_length) - ] - init_indices.extend( - [ - py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"l{idx}")) - for idx in range(left_length) - ] - + [ - py_ast.Enable("init_idx"), - py_ast.Enable("init_min_depth"), - py_ast.Enable("init_cond_reg"), - ] - + [ - py_ast.Enable(f"init_idx_between_{lo}_{hi}") - for (lo, hi) in filter(lambda x: x[1] is not None, nec_ranges) - ] + input_portname = ["addr0"] if read_mem else ["write_data", "write_en", "addr0"] + output_portnames = ["read_data"] if read_mem else ["done"] + return cb.build_connections( + mem, component_builder, "", f"{mem_name}_", input_portname, output_portnames ) - if not leaky_relu: - init_indices.append(py_ast.Enable("init_iter_limit")) - - control.append(py_ast.StaticParComp(init_indices)) - - # source_pos metadata init - init_tag = 0 - source_map = {} - - def counter(): - nonlocal init_tag - old = init_tag - init_tag += 1 - return old - - # end source pos init - - control_stmts = [] - incr_stmts = [py_ast.Enable("incr_idx")] - if not leaky_relu: - incr_stmts.append(py_ast.Enable("lt_iter_limit_group")) - for r in range(left_length): - for c in range(top_length): - # build 4 if stmts for the 4 schedules that we need to account for - input_mem_updates = execute_if_between( - comp, - schedules["update_sched"][r][c][0], - schedules["update_sched"][r][c][1], - get_memory_updates(r, c), - ) - pe_fills = execute_if_between( - comp, - schedules["fill_sched"][r][c][0], - schedules["fill_sched"][r][c][1], - [get_pe_invoke(r, c, top_length, left_length, 0)], - ) - pe_moves = execute_if_between( - comp, - schedules["move_sched"][r][c][0], - schedules["move_sched"][r][c][1], - get_pe_moves(r, c, top_length, left_length), - ) - pe_accums = execute_if_between( - comp, - schedules["accum_sched"][r][c][0], - schedules["accum_sched"][r][c][1], - [get_pe_invoke(r, c, top_length, left_length, 1)], - ) - if leaky_relu: - pe_writes = [] - else: - pe_writes = execute_if_between( - comp, - schedules["write_sched"][r][c][0], - schedules["write_sched"][r][c][1], - [ - py_ast.Enable( - NAME_SCHEME["out mem move"].format(pe=f"pe_{r}_{c}") - ) - ], - ) - pe_control = input_mem_updates + pe_fills + pe_moves + pe_accums + pe_writes - control_stmts.append(py_ast.StaticParComp(pe_control)) - # providing metadata - tag = counter() - source_map[ - tag - ] = f"pe_{r}_{c} filling: [{schedules['fill_sched'][r][c][0]},\ -{schedules['fill_sched'][r][c][1]}) accumulating: [{schedules['accum_sched'][r][c][0]} \ -{schedules['accum_sched'][r][c][1]})" - - if leaky_relu: - relu_execution = [py_ast.Enable("write_cond_reg")] - for r in range(left_length): - relu_execution += execute_if_register( - comp, - comp.get_cell(f"relu_cond_reg_r{r}"), - [ - py_ast.Enable(f"execute_relu_r{r}"), - py_ast.Enable(f"relu_r{r}_helper"), - ], - ) - relu_execution.append(py_ast.Enable(f"check_relu_cond_r{r}")) - for start, end in nec_ranges: - # build the control stmts that assign correct values to - # idx_between_{start}_{end}_reg, which is what the if stmts above^ rely on - incr_stmts.append(py_ast.Enable(f"idx_between_{start}_{end}_group")) - for depth_adder_group in depth_adders: - incr_stmts.append(py_ast.Enable(depth_adder_group)) - while_ctrl = [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] - if leaky_relu: - while_ctrl.append(py_ast.StaticParComp(relu_execution)) - while_body = py_ast.StaticParComp(while_ctrl) - - # build the while loop with condition cond_reg. - # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 - cond_reg_port = comp.get_cell("cond_reg").port("out") - while_loop = cb.while_(cond_reg_port, while_body) - - control.append(while_loop) - - return py_ast.SeqComp(stmts=control), source_map - - -def create_systolic_array( - prog: cb.Builder, - top_length, - top_depth, - left_length, - left_depth, - leaky_relu, -): +def build_main(prog, post_op_component_name): """ - top_length: Number of PEs in each row. - top_depth: Number of elements processed by each PE in a row. - left_length: Number of PEs in each column. - left_depth: Number of elements processed by each PE in a col. + Build the main component. + It basically connects the ports of the systolic component and post_op component + in a single group so that they run. """ - - assert top_depth == left_depth, ( - f"Cannot multiply matrices: " - f"{top_length}x{top_depth} and {left_depth}x{left_length}" - ) - - computational_unit = prog.component("systolic_array_comp") - depth_port = computational_unit.input("depth", BITWIDTH) - init_dyn_vals( - computational_unit, depth_port, top_length + left_length + 4, leaky_relu - ) - - schedules = gen_schedules( - top_length, top_depth, left_length, left_depth, leaky_relu, computational_unit + main = prog.component("main") + systolic_array = main.cell( + "systolic_array_component", py_ast.CompInst(SYSTOLIC_ARRAY_COMP, []) ) - nec_ranges = set() - for sched in schedules.values(): - accum_nec_ranges(nec_ranges, sched) - depth_adders = instantiate_calyx_adds(computational_unit, nec_ranges) - - for row in range(left_length): - for col in range(top_length): - # Instantiate the PEs and surronding registers - instantiate_pe(computational_unit, row, col) - - # Instantiate all the memories - for r in range(top_length): - instantiate_memory(computational_unit, "top", r, top_depth) - - for col in range(left_length): - instantiate_memory(computational_unit, "left", col, left_depth) - - idx_width = BITWIDTH - # Instantiate output memory - for i in range(left_length): - add_write_mem_argument(computational_unit, OUT_MEM + f"_{i}", idx_width) - - # Instantiate all the PEs - for row in range(left_length): - for col in range(top_length): - # Instantiate the mover fabric - instantiate_data_move( - computational_unit, - row, - col, - col == top_length - 1, - row == left_length - 1, - ) - - # Instantiate output movement structure - # Leaky relu will write into memories using different groups - if not leaky_relu: - instantiate_output_move(computational_unit, row, col, top_length) - - # instantiate groups that handle cond_reg and idx variables - instantiate_idx_cond_groups(computational_unit, leaky_relu) - for start, end in nec_ranges: - # create the groups that create for idx_in_between registers - instantiate_idx_between(computational_unit, start, end) - instantiate_init_group(computational_unit, start, end) - - if leaky_relu: - # Instantiate groups to compute Relu. - for row in range(left_length): - instantiate_relu_groups(computational_unit, row, top_length) - # Write into the cond reg of the while loop. - instantiate_relu_cond_reg(computational_unit, left_length) - - # Generate the control and set the source map - control, source_map = generate_control( - computational_unit, - top_length, - top_depth, - left_length, - left_depth, - schedules, - depth_adders, - nec_ranges, - leaky_relu, + post_op = main.cell( + "post_op_component", py_ast.CompInst(post_op_component_name, []) ) - computational_unit.control = control - prog.program.meta = source_map - - # build the main component - # instantaites the systolic array/computational_unit and the mems, - # and then invokes it - main = prog.component("main") - systolic_array = main.cell("systolic_array", computational_unit) - invoke_args = {} - invoke_args["in_depth"] = py_ast.ConstantPort(BITWIDTH, left_depth) + # Connections contains the RTL-like connections between the ports of + # systolic_array_comp and the post_op. + # Also connects the input memories to the systolic_array_comp and + # output memories to the post_op. + connections = [] + # Connect input memories to systolic_array for r in range(top_length): - name = f"t{r}" - idx_width = bits_needed(top_depth) - mem = main.mem_d1( - name, - BITWIDTH, - top_depth, - idx_width, - is_external=True, + connections += create_mem_connections( + main, systolic_array, f"t{r}", top_depth, read_mem=True ) - invoke_args[f"in_{name}_read_data"] = mem.read_data - invoke_args[f"out_{name}_addr0"] = mem.addr0 - for col in range(left_length): - name = f"l{col}" - idx_width = bits_needed(left_depth) - mem = main.mem_d1( - name, - BITWIDTH, + for c in range(left_length): + connections += create_mem_connections( + # top_depth should = left_depth + main, + systolic_array, + f"l{c}", left_depth, - idx_width, - is_external=True, + read_mem=True, ) - invoke_args[f"in_{name}_read_data"] = mem.read_data - invoke_args[f"out_{name}_addr0"] = mem.addr0 - + # Connect outout memories to post_op, and systolic_array_output to + # post_op inputs. for i in range(left_length): - name = OUT_MEM + f"_{i}" - mem = main.mem_d1( - name, - BITWIDTH, - top_length, - BITWIDTH, - is_external=True, + # connect output memory to post op + connections += create_mem_connections( + main, post_op, OUT_MEM + f"_{i}", top_length, read_mem=False ) - invoke_args[f"out_{name}_addr0"] = mem.addr0 - invoke_args[f"out_{name}_write_data"] = mem.write_data - invoke_args[f"out_{name}_write_en"] = mem.write_en - - invoke = cb.invoke(systolic_array, **invoke_args) - main.control = invoke + # Connect systolic array to post op + connections += cb.build_connections( + post_op, + systolic_array, + "", + "", + [ + NAME_SCHEME["systolic valid signal"].format(row_num=i), + NAME_SCHEME["systolic value signal"].format(row_num=i), + NAME_SCHEME["systolic idx signal"].format(row_num=i), + ], + [], + ) + # Use a wire and register so that we have a signal that tells us when + # systolic array component is done. This way, we don't retrigger systolic_array_comp + # when it has already finished. + systolic_array_done = main.reg("systolic_done", 1) + systolic_done_wire = main.wire("systolic_done_wire", 1) + with main.group("perform_computation") as g: + for i, o in connections: + g.asgn(i, o) + # Use systolic_done_wire to avoid retriggering systolic array after + # it is done. + systolic_array_done.write_en = systolic_array.done @ 1 + systolic_array_done.in_ = systolic_array.done @ 1 + systolic_done_wire.in_ = (systolic_array.done | systolic_array_done.out) @ 1 + systolic_array.go = ~systolic_done_wire.out @ py_ast.ConstantPort(1, 1) + systolic_array.depth = py_ast.ConstantPort(BITWIDTH, left_depth) + + # Triggering post_op component. + post_op.go = py_ast.ConstantPort(1, 1) + g.done = post_op.computation_done + + main.control = py_ast.Enable("perform_computation") if __name__ == "__main__": import argparse import json + # Arg parsing parser = argparse.ArgumentParser(description="Process some integers.") parser.add_argument("file", nargs="?", type=str) parser.add_argument("-tl", "--top-length", type=int) @@ -1055,15 +167,24 @@ def create_systolic_array( "-tl TOP_LENGTH -td TOP_DEPTH -ll LEFT_LENGTH -ld LEFT_DEPTH`" ) + # Building the main component prog = cb.Builder() - pe(prog, leaky_relu) create_systolic_array( prog, top_length=top_length, top_depth=top_depth, left_length=left_length, left_depth=left_depth, - leaky_relu=leaky_relu, ) - + if leaky_relu: + leaky_relu_post_op( + prog, num_rows=left_length, num_cols=top_length, idx_width=BITWIDTH + ) + post_op_component_name = LEAKY_RELU_POST_OP + else: + default_post_op( + prog, num_rows=left_length, num_cols=top_length, idx_width=BITWIDTH + ) + post_op_component_name = DEFAULT_POST_OP + build_main(prog, post_op_component_name) prog.program.emit() diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py new file mode 100644 index 000000000..e7a75ef91 --- /dev/null +++ b/frontends/systolic-lang/gen_array_component.py @@ -0,0 +1,711 @@ +#!/usr/bin/env python3 + +import numpy as np +from gen_pe import pe, PE_NAME, BITWIDTH +import calyx.builder as cb +from calyx import py_ast + +# Global constant for the current bitwidth. +DEPTH = "depth" +SYSTOLIC_ARRAY_COMP = "systolic_array_comp" + +# Naming scheme for generated groups. Used to keep group names consistent +# across structure and control. +NAME_SCHEME = { + # Indexing into the memory + "index name": "{prefix}_idx", + "index init": "{prefix}_idx_init", + "index update": "{prefix}_idx_update", + # Move data from main memories + "memory move": "{prefix}_move", + "out write": "{pe}_out_write", + # Move data between internal registers + "register move down": "{pe}_down_move", + "register move right": "{pe}_right_move", + # Output signals + "systolic valid signal": "r{row_num}_valid", + "systolic value signal": "r{row_num}_value", + "systolic idx signal": "r{row_num}_idx", + # "Index between" registers to help with scheduling + "idx between reg": "idx_between_{lo}_{hi}_reg", + "idx between group": "idx_between_{lo}_{hi}_group", + "idx between init": "init_idx_between_{lo}_{hi}", +} + + +class CalyxAdd: + """ + A class that represents addition in Calyx between a port and a constant + """ + + def __init__(self, port, const): + self.port = port + self.const = const + + def __eq__(self, other): + if type(other) != CalyxAdd: + return False + return ( + cb.ExprBuilder.unwrap(self.port) == cb.ExprBuilder.unwrap(other.port) + and self.const == other.const + ) + + def __hash__(self): + return hash(self.const) + + def __str__(self): + return ( + str(cb.ExprBuilder.unwrap(self.port).item.id.name) + + "_plus_" + + str(self.const) + ) + + def build_group(self, comp: cb.ComponentBuilder) -> str: + """ + Builds a static Calyx group (latency 1) that implements `self` + Note that we avoid creating duplicate groups. + Returns the group name + """ + group_name = str(self) + "_group" + if comp.try_get_group(group_name) is None: + add = comp.add(BITWIDTH, str(self)) + with comp.static_group(group_name, 1): + add.left = self.port + add.right = self.const + return group_name + + +def add_read_mem_arguments(comp: cb.ComponentBuilder, name, addr_width): + """ + Add arguments to component `comp` if we want to read from a mem named `name` with + width of `addr_width` + """ + comp.input(f"{name}_read_data", BITWIDTH) + comp.output(f"{name}_addr0", addr_width) + + +def add_systolic_output_arguments(comp: cb.ComponentBuilder, row_num, addr_width): + """ + Add output arguments to systolic array component `comp` for row `row_num`. + The ouptut arguments alllow the systolic array to expose its outputs for `row_num` + without writing to memory (e.g., r0_valid, r0_value, r0_idx). + """ + comp.output(NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1) + comp.output(NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH) + comp.output(NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width) + + +def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): + """ + Instantiates: + - top memory + - structure to move data from memory to read registers. + + Returns (cells, structure) tuple. + """ + if top_or_left == "top": + name = f"t{idx}" + target_reg = f"top_0_{idx}" + elif top_or_left == "left": + name = f"l{idx}" + target_reg = f"left_{idx}_0" + else: + raise Exception(f"Invalid top_or_left: {top_or_left}") + + # XXX(Caleb): should change to be exact + idx_width = BITWIDTH + # Instantiate the memory + add_read_mem_arguments(comp, name, idx_width) + this = comp.this() + addr0_port = this.port(name + "_addr0") + read_data_port = this.port(name + "_read_data") + # Instantiate the indexing register + idx = instantiate_indexor(comp, name, idx_width) + # Register to save the value from the memory. Defined by [[instantiate_pe]]. + target = comp.get_cell(target_reg) + group_name = NAME_SCHEME["memory move"].format(prefix=name) + with comp.static_group(group_name, 1) as g: + g.asgn(addr0_port, idx.out) + target.in_ = read_data_port + target.write_en = 1 + + +def instantiate_pe(comp: cb.ComponentBuilder, row: int, col: int): + """ + Instantiate the PE and all the registers connected to it. + """ + # Add all the required cells. + comp.cell(f"pe_{row}_{col}", py_ast.CompInst(PE_NAME, [])) + comp.reg(f"top_{row}_{col}", BITWIDTH) + comp.reg(f"left_{row}_{col}", BITWIDTH) + + +def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuilder: + """ + Instantiate an indexor for accessing memory with name `prefix`. + Generates structure to initialize and update the indexor. + + The initializor starts sets the memories to their maximum value + because we expect all indices to be incremented once before + being used. + + Returns (cells, structure) + """ + name = NAME_SCHEME["index name"].format(prefix=prefix) + + reg = comp.reg(name, width) + add = comp.add(width, f"{prefix}_add") + + init_name = NAME_SCHEME["index init"].format(prefix=prefix) + with comp.static_group(init_name, 1): + # Initialize the indexor to 0 + reg.in_ = 0 + reg.write_en = 1 + + upd_name = NAME_SCHEME["index update"].format(prefix=prefix) + with comp.static_group(upd_name, 1): + # Increment the indexor. + add.left = 1 + add.right = reg.out + reg.in_ = add.out + reg.write_en = 1 + + return reg + + +def instantiate_data_move( + comp: cb.ComponentBuilder, row: int, col: int, right_edge: bool, down_edge: bool +): + """ + Generates groups for "data movers" which are groups that move data + from the `write` register of the PE at (row, col) to the read register + of the PEs at (row+1, col) and (row, col+1) + """ + name = f"pe_{row}_{col}" + + if not right_edge: + group_name = NAME_SCHEME["register move right"].format(pe=name) + src_reg = comp.get_cell(f"left_{row}_{col}") + dst_reg = comp.get_cell(f"left_{row}_{col + 1}") + with comp.static_group(group_name, 1): + dst_reg.in_ = src_reg.out + dst_reg.write_en = 1 + + if not down_edge: + group_name = NAME_SCHEME["register move down"].format(pe=name) + src_reg = comp.get_cell(f"top_{row}_{col}") + dst_reg = comp.get_cell(f"top_{row + 1}_{col}") + with comp.static_group(group_name, 1): + dst_reg.in_ = src_reg.out + dst_reg.write_en = 1 + + +def instantiate_output_move(comp: cb.ComponentBuilder, row, col): + """ + Generates groups to move the final value from a PE to the output ports, + e.g., writes the value of the PE to `this.r{row}_value_port` + """ + group_name = NAME_SCHEME["out write"].format(pe=f"pe_{row}_{col}") + pe = comp.get_cell(f"pe_{row}_{col}") + this = comp.this() + valid_port = this.port(NAME_SCHEME["systolic valid signal"].format(row_num=row)) + value_port = this.port(NAME_SCHEME["systolic value signal"].format(row_num=row)) + idx_port = this.port(NAME_SCHEME["systolic idx signal"].format(row_num=row)) + with comp.static_group(group_name, 1) as g: + g.asgn(valid_port, 1) + g.asgn(value_port, pe.out) + g.asgn(idx_port, col) + + +def get_memory_updates(row, col): + """ + Gets the memory moves and memory idx updates for (row,col) + This is how we coordinate feeding the memories into the systolic array + """ + movers = [] + if col == 0: + movers.append(NAME_SCHEME["memory move"].format(prefix=f"l{row}")) + movers.append(NAME_SCHEME["index update"].format(prefix=f"l{row}")) + if row == 0: + movers.append(NAME_SCHEME["memory move"].format(prefix=f"t{col}")) + movers.append(NAME_SCHEME["index update"].format(prefix=f"t{col}")) + mover_enables = [py_ast.Enable(name) for name in movers] + return mover_enables + + +def get_pe_moves(r, c, top_length, left_length): + """ + Gets the PE moves for the PE at (r,c) + """ + pe_moves = [] + if r < left_length - 1: + pe_moves.append(NAME_SCHEME["register move down"].format(pe=f"pe_{r}_{c}")) + if c < top_length - 1: + pe_moves.append(NAME_SCHEME["register move right"].format(pe=f"pe_{r}_{c}")) + pe_enables = [py_ast.Enable(name) for name in pe_moves] + return pe_enables + + +def get_pe_invoke(r, c, mul_ready): + """ + gets the PE invokes for the PE at (r,c). mul_ready signals whether 1 or 0 + should be passed into mul_ready + """ + return py_ast.StaticInvoke( + id=py_ast.CompVar(f"pe_{r}_{c}"), + in_connects=[ + ("top", py_ast.CompPort(py_ast.CompVar(f"top_{r}_{c}"), "out")), + ( + "left", + py_ast.CompPort(py_ast.CompVar(f"left_{r}_{c}"), "out"), + ), + ( + "mul_ready", + py_ast.ConstantPort(1, mul_ready), + ), + ], + out_connects=[], + ) + + +def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): + """ + Builds group that instantiates the dynamic/runtime values for the systolic + array: its depth and iteration limit/count (since its iteration limit depends on + its depth). + iteration limit = depth + partial_iter_limit + """ + min_depth_4 = comp.reg("min_depth_4", BITWIDTH) + lt_depth_4 = comp.lt(BITWIDTH, "lt_depth_4") + iter_limit = comp.reg("iter_limit", BITWIDTH) + iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") + with comp.static_group("init_min_depth", 1): + lt_depth_4.left = depth_port + lt_depth_4.right = 4 + min_depth_4.in_ = lt_depth_4.out @ depth_port + min_depth_4.in_ = ~lt_depth_4.out @ 4 + min_depth_4.write_en = 1 + with comp.static_group("init_iter_limit", 1): + iter_limit_add.left = partial_iter_limit + iter_limit_add.right = depth_port + iter_limit.in_ = iter_limit_add.out + iter_limit.write_en = 1 + + +def instantiate_while_groups(comp: cb.ComponentBuilder): + """ + Builds groups that instantiate idx to 0 and increment idx. + Also builds groups that set cond_reg to 1 (runs before the while loop) + and that sets cond_reg to (idx + 1 < iter_limit). + """ + idx = comp.reg("idx", BITWIDTH) + add = comp.add(BITWIDTH, "idx_add") + cond_reg = comp.reg("cond_reg", 1) + iter_limit = comp.get_cell("iter_limit") + lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") + + with comp.static_group("init_idx", 1): + idx.in_ = 0 + idx.write_en = 1 + with comp.static_group("incr_idx", 1): + add.left = idx.out + add.right = 1 + idx.in_ = add.out + idx.write_en = 1 + with comp.static_group("init_cond_reg", 1): + cond_reg.in_ = 1 + cond_reg.write_en = 1 + with comp.static_group("write_cond_reg", 1): + lt_iter_limit.left = add.out + lt_iter_limit.right = iter_limit.out + cond_reg.in_ = lt_iter_limit.out + cond_reg.write_en = 1 + + +def instantiate_calyx_adds(comp, nec_ranges) -> list: + """ + Instantiates the CalyxAdd objects to adders and actual groups that perform the + specified add. + Returns a list of all the group names that we created. + """ + calyx_add_groups = set() + for lo, hi in nec_ranges: + if type(lo) == CalyxAdd: + group_name = lo.build_group(comp) + calyx_add_groups.add(group_name) + if type(hi) == CalyxAdd: + group_name = hi.build_group(comp) + calyx_add_groups.add(group_name) + group_list = list(calyx_add_groups) + # sort for testing purposes + group_list.sort() + return group_list + + +def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: + """ + Instantiates a static group and register called "idx_between_{lo}_{hi}_reg/group" + that should output whether idx is between [lo, hi). That is, whether lo <= idx < hi. + + Note: If you're trying to understand why this works, we are checking `idx_add` which + is one higher than idx. This offsets the cycle it takes to update the register. + """ + if type(hi) == CalyxAdd: + hi_value = comp.get_cell(str(hi)).port("out") + else: + hi_value = hi + if type(lo) == CalyxAdd: + lo_value = comp.get_cell(str(lo)).port("out") + else: + lo_value = lo + reg_str = NAME_SCHEME["idx between reg"].format(lo=lo, hi=hi) + group_str = NAME_SCHEME["idx between group"].format(lo=lo, hi=hi) + index_lt = f"index_lt_{hi}" + index_ge = f"index_ge_{lo}" + reg = comp.reg(reg_str, 1) + idx_add = comp.get_cell("idx_add") + # If no upper bound, then only need to check reg >= lo + lt = ( + comp.get_cell(index_lt) + if comp.try_get_cell(index_lt) is not None + else comp.lt(BITWIDTH, index_lt) + ) + # if lo == 0, then only need to check if reg < hi + if type(lo) == int and lo == 0: + with comp.static_group(group_str, 1): + lt.left = idx_add.out + lt.right = hi_value + reg.in_ = lt.out + reg.write_en = 1 + # need to check if reg >= lo and reg < hi + else: + ge = ( + comp.get_cell(index_ge) + if comp.try_get_cell(index_ge) is not None + else comp.ge(BITWIDTH, index_ge) + ) + and_ = comp.and_(1, f"idx_between_{lo}_{hi}_comb") + with comp.static_group(group_str, 1): + ge.left = idx_add.out + ge.right = lo_value + lt.left = idx_add.out + lt.right = hi_value + and_.left = ge.out + and_.right = lt.out + reg.in_ = and_.out + reg.write_en = 1 + + +def init_idx_between(comp: cb.ComponentBuilder, lo, hi): + """ + Builds a group to set initial state for register idx_between_{lo}_{hi}_reg. + """ + # if lo == 0, then the idx will initially be in between the interval, so + # need to set idx_between to high + start_hi = 1 if lo == 0 else 0 + idx_between = comp.get_cell(NAME_SCHEME["idx between reg"].format(lo=lo, hi=hi)) + with comp.static_group(NAME_SCHEME["idx between init"].format(lo=lo, hi=hi), 1): + idx_between.in_ = start_hi + idx_between.write_en = 1 + + +def accum_nec_ranges(nec_ranges, schedule): + """ + Essentially creates a set that contains all of the idx ranges that + we need to check for (e.g., [1,3) [2,4)] in order to realize + the schedule + + nec_ranges is a set of tuples. + schedule is either a 2d array or 1d array with tuple (start,end) entries. + Adds all intervals (start,end) in schedule to nec_ranges if the it's + not already in nec_ranges. + """ + if schedule.ndim == 1: + for r in schedule: + nec_ranges.add(r) + elif schedule.ndim == 2: + for r in schedule: + for c in r: + nec_ranges.add(c) + else: + raise Exception("accum_nec_ranges expects only 1d or 2d arrays") + return nec_ranges + + +def gen_schedules( + top_length, + top_depth, + left_length, + left_depth, + comp: cb.ComponentBuilder, +): + """ + Generates 4 arrays that are the same size as the output (systolic) array + Each entry in the array has tuple [start, end) that indicates the cycles that + they are active + `update_sched` contains when to update the indices of the input memories and feed + them into the systolic array + `pe_fill_sched` contains when to invoke PE but not accumulate (bc the multipliers + are not ready with an output yet) + `pe_accum_sched` contains when to invoke PE and accumulate (bc the multipliers + are ready with an output) + `pe_move_sched` contains when to "move" the PE (i.e., pass data) + `pe_write_sched` contains when to "write" the PE value into the output ports + (e.g., this.r0_valid) + """ + depth_port = comp.this().depth + min_depth_4_port = comp.get_cell("min_depth_4").port("out") + schedules = {} + update_sched = np.zeros((left_length, top_length), dtype=object) + pe_fill_sched = np.zeros((left_length, top_length), dtype=object) + pe_accum_sched = np.zeros((left_length, top_length), dtype=object) + pe_move_sched = np.zeros((left_length, top_length), dtype=object) + # will only actually use one of the following two schedules + pe_write_sched = np.zeros((left_length, top_length), dtype=object) + for row in range(0, left_length): + for col in range(0, top_length): + pos = row + col + update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) + pe_fill_sched[row][col] = (pos + 1, CalyxAdd(min_depth_4_port, pos + 1)) + pe_accum_sched[row][col] = (pos + 5, CalyxAdd(depth_port, pos + 5)) + pe_move_sched[row][col] = (pos + 1, CalyxAdd(depth_port, pos + 1)) + pe_write_sched[row][col] = ( + CalyxAdd(depth_port, pos + 5), + CalyxAdd(depth_port, pos + 6), + ) + schedules["update_sched"] = update_sched + schedules["fill_sched"] = pe_fill_sched + schedules["accum_sched"] = pe_accum_sched + schedules["move_sched"] = pe_move_sched + schedules["write_sched"] = pe_write_sched + return schedules + + +def execute_if_between(comp: cb.ComponentBuilder, start, end, body): + """ + body is a list of control stmts + if body is empty, return an empty list + otherwise, builds an if stmt that executes body in parallel if + idx is between start and end + """ + if not body: + return [] + if_cell = comp.get_cell(f"idx_between_{start}_{end}_reg") + return [ + cb.static_if( + if_cell.out, + py_ast.StaticParComp(body), + ) + ] + + +def generate_control( + comp: cb.ComponentBuilder, + top_length, + top_depth, + left_length, + left_depth, + schedules, + calyx_add_groups, + nec_ranges, +): + """ + Logically, control performs the following actions: + 1. Initialize all the memory indexors and idx and idx_between + registers at the start + 2. Build a static repeat with a one cycle body that: + a. Updates memory indices if needed/feeds memory into systolic array. + b. Invokes the PEs correctly (mul_ready should only be hi if + the multiplier's values are ready). + c. Move the data needed by each PE + 3. Writes the PE values into external memory + """ + + control = [] + + # Initialize all memories. + init_indices: list[py_ast.Control] = [ + py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"t{idx}")) + for idx in range(top_length) + ] + init_indices.extend( + [ + py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"l{idx}")) + for idx in range(left_length) + ] + + [ + py_ast.Enable("init_idx"), + py_ast.Enable("init_min_depth"), + py_ast.Enable("init_cond_reg"), + py_ast.Enable("init_iter_limit"), + ] + + [py_ast.Enable(f"init_idx_between_{lo}_{hi}") for (lo, hi) in nec_ranges] + ) + + control.append(py_ast.StaticParComp(init_indices)) + + # source_pos metadata init + init_tag = 0 + source_map = {} + + def counter(): + nonlocal init_tag + old = init_tag + init_tag += 1 + return old + + # end source pos init + + control_stmts = [] + incr_stmts = [py_ast.Enable("incr_idx"), py_ast.Enable("write_cond_reg")] + for r in range(left_length): + for c in range(top_length): + # build 4 if stmts for the 4 schedules that we need to account for + input_mem_updates = execute_if_between( + comp, + schedules["update_sched"][r][c][0], + schedules["update_sched"][r][c][1], + get_memory_updates(r, c), + ) + pe_fills = execute_if_between( + comp, + schedules["fill_sched"][r][c][0], + schedules["fill_sched"][r][c][1], + [get_pe_invoke(r, c, 0)], + ) + pe_moves = execute_if_between( + comp, + schedules["move_sched"][r][c][0], + schedules["move_sched"][r][c][1], + get_pe_moves(r, c, top_length, left_length), + ) + pe_accums = execute_if_between( + comp, + schedules["accum_sched"][r][c][0], + schedules["accum_sched"][r][c][1], + [get_pe_invoke(r, c, 1)], + ) + output_writes = execute_if_between( + comp, + schedules["write_sched"][r][c][0], + schedules["write_sched"][r][c][1], + [py_ast.Enable(NAME_SCHEME["out write"].format(pe=f"pe_{r}_{c}"))], + ) + pe_control = ( + input_mem_updates + pe_fills + pe_moves + pe_accums + output_writes + ) + control_stmts.append(py_ast.StaticParComp(pe_control)) + # providing metadata + tag = counter() + source_map[ + tag + ] = f"pe_{r}_{c} filling: [{schedules['fill_sched'][r][c][0]},\ +{schedules['fill_sched'][r][c][1]}), \ +accumulating: [{schedules['accum_sched'][r][c][0]} \ +{schedules['accum_sched'][r][c][1]}), \ +writing: [{schedules['write_sched'][r][c][0]} \ +{schedules['write_sched'][r][c][1]})" + + # handles the coordination so that `idx_if_between` statements work correctly ` + for start, end in nec_ranges: + # build the control stmts that assign correct values to + # idx_between_{start}_{end}_reg, which is what the if stmts above^ rely on + incr_stmts.append(py_ast.Enable(f"idx_between_{start}_{end}_group")) + for calyx_add_group in calyx_add_groups: + incr_stmts.append(py_ast.Enable(calyx_add_group)) + while_ctrl = [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] + while_body = py_ast.StaticParComp(while_ctrl) + + # build the while loop with condition cond_reg. + # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 + cond_reg_port = comp.get_cell("cond_reg").port("out") + while_loop = cb.while_(cond_reg_port, while_body) + + control.append(while_loop) + + return py_ast.SeqComp(stmts=control), source_map + + +def create_systolic_array( + prog: cb.Builder, + top_length, + top_depth, + left_length, + left_depth, +): + """ + top_length: Number of PEs in each row. + top_depth: Number of elements processed by each PE in a row. + left_length: Number of PEs in each column. + left_depth: Number of elements processed by each PE in a col. + """ + assert top_depth == left_depth, ( + f"Cannot multiply matrices: " + f"{top_length}x{top_depth} and {left_depth}x{left_length}" + ) + pe(prog) + computational_unit = prog.component(SYSTOLIC_ARRAY_COMP) + depth_port = computational_unit.input("depth", BITWIDTH) + init_dyn_vals(computational_unit, depth_port, top_length + left_length + 4) + + schedules = gen_schedules( + top_length, top_depth, left_length, left_depth, computational_unit + ) + nec_ranges = set() + for sched in schedules.values(): + accum_nec_ranges(nec_ranges, sched) + calyx_add_groups = instantiate_calyx_adds(computational_unit, nec_ranges) + + for row in range(left_length): + for col in range(top_length): + # Instantiate the PEs and surronding registers + instantiate_pe(computational_unit, row, col) + + # Instantiate all the memories + for r in range(top_length): + instantiate_memory(computational_unit, "top", r, top_depth) + + for col in range(left_length): + instantiate_memory(computational_unit, "left", col, left_depth) + + idx_width = BITWIDTH + # Instantiate output memory + for i in range(left_length): + add_systolic_output_arguments(computational_unit, i, idx_width) + + # Instantiate all the PEs + for row in range(left_length): + for col in range(top_length): + # Instantiate the mover fabric + instantiate_data_move( + computational_unit, + row, + col, + col == top_length - 1, + row == left_length - 1, + ) + + # Instantiate output movement structure, i.e., writes to + # `computational_unit`'s output ports + instantiate_output_move(computational_unit, row, col) + + # instantiate groups that handle cond_reg and idx variables + instantiate_while_groups(computational_unit) + for start, end in nec_ranges: + # create the groups that create for idx_in_between registers + instantiate_idx_between(computational_unit, start, end) + init_idx_between(computational_unit, start, end) + + # Generate the control and set the source map + control, source_map = generate_control( + computational_unit, + top_length, + top_depth, + left_length, + left_depth, + schedules, + calyx_add_groups, + nec_ranges, + ) + computational_unit.control = control + prog.program.meta = source_map diff --git a/frontends/systolic-lang/gen_pe.py b/frontends/systolic-lang/gen_pe.py new file mode 100644 index 000000000..ba9caf101 --- /dev/null +++ b/frontends/systolic-lang/gen_pe.py @@ -0,0 +1,38 @@ +import calyx.builder as cb +from calyx import py_ast + +# Global constant for the current bitwidth. +BITWIDTH = 32 +INTWIDTH = 16 +FRACWIDTH = 16 +# Name of the pe component +PE_NAME = "mac_pe" + + +def pe(prog: cb.Builder): + comp = prog.component(name=PE_NAME, latency=1) + comp.input("top", BITWIDTH) + comp.input("left", BITWIDTH) + comp.input("mul_ready", 1) + comp.output("out", BITWIDTH) + acc = comp.reg("acc", BITWIDTH) + add = comp.fp_sop("adder", "add", BITWIDTH, INTWIDTH, FRACWIDTH) + mul = comp.pipelined_fp_smult("mul", BITWIDTH, INTWIDTH, FRACWIDTH) + + this = comp.this() + with comp.static_group("do_add", 1): + add.left = acc.out + add.right = mul.out + acc.in_ = add.out + acc.write_en = this.mul_ready + + with comp.static_group("do_mul", 1): + mul.left = this.top + mul.right = this.left + + par = py_ast.StaticParComp([py_ast.Enable("do_add"), py_ast.Enable("do_mul")]) + + with comp.continuous: + this.out = acc.out + + comp.control += par diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py new file mode 100644 index 000000000..c497f4cf3 --- /dev/null +++ b/frontends/systolic-lang/gen_post_op.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python3 + +import calyx.builder as cb +from calyx import py_ast +from gen_array_component import NAME_SCHEME +from gen_pe import BITWIDTH, INTWIDTH, FRACWIDTH +from fud.stages.verilator import numeric_types +from calyx.utils import float_to_fixed_point + + +# Name of the ouput array +OUT_MEM = "out_mem" +DEFAULT_POST_OP = "default_post_op" +LEAKY_RELU_POST_OP = "leaky_relu_post_op" +COND_REG = "cond_reg" +WRITE_DONE_COND = "write_done_cond" + + +def add_register_params(comp: cb.ComponentBuilder, name, width): + """ + Add params to component `comp` if we want to use a register named + `name` inside `comp.` Specifically adds the write_en, in, and out ports. + """ + comp.output(f"{name}_write_en", 1) + comp.output(f"{name}_in", width) + comp.input(f"{name}_out", width) + + +def add_write_mem_params(comp: cb.ComponentBuilder, name, addr_width): + """ + Add arguments to component `comp` if we want to write to a mem named `name` with + width of `addr_width` inside `comp.` + """ + comp.output(f"{name}_addr0", addr_width) + comp.output(f"{name}_write_data", BITWIDTH) + comp.output(f"{name}_write_en", 1) + comp.input(f"{name}_done", 1) + + +def add_systolic_input_params(comp: cb.ComponentBuilder, row_num, addr_width): + """ + Add ports "r_{row_num}_valid", "r_{row_num}_value", "r_{row_num}_idx" to comp. + These ports are meant to read from the systolic array output. + """ + comp.input(NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1) + comp.input(NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH) + comp.input(NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width) + + +def add_post_op_params(comp: cb.Builder, num_rows: int, idx_width: int): + """ + Adds correct parameters for post op component comp + """ + comp.output("computation_done", 1) + for r in range(num_rows): + add_write_mem_params(comp, OUT_MEM + f"_{r}", idx_width) + add_systolic_input_params(comp, r, idx_width) + + +def create_write_mem_groups(comp: cb.ComponentBuilder, row_num): + """ + Instantiates group that writes the systolic array values for `row_num` into + the output memory. + `comp` should have access to systolic array values through the parameters added + in `add_systolic_input_params()`. + """ + this = comp.this() + # ports to write to memory + write_en_port = this.port(OUT_MEM + f"_{row_num}_write_en") + write_data_port = this.port(OUT_MEM + f"_{row_num}_write_data") + addr0_port = this.port(OUT_MEM + f"_{row_num}_addr0") + + # ports to read from systolic array + valid_port = this.port(NAME_SCHEME["systolic valid signal"].format(row_num=row_num)) + value_port = this.port(NAME_SCHEME["systolic value signal"].format(row_num=row_num)) + idx_port = this.port(NAME_SCHEME["systolic idx signal"].format(row_num=row_num)) + + # group that writes output of systolic arrays to memory + with comp.static_group(f"write_r{row_num}", 1) as g: + g.asgn(write_en_port, valid_port) + g.asgn(write_data_port, value_port) + g.asgn(addr0_port, idx_port) + + +def done_condition_groups( + comp: cb.ComponentBuilder, + num_rows: int, + num_cols: int, + idx_width: int, + leaky_relu: bool, +): + """ + Writes to this.computation_done + For leaky relu, we wait until the relu operations are done for each row. + For default post op, you simply have to check when the systolic array output + is at the last entry. + """ + this = comp.this() + # ports to read from systolic array + if leaky_relu: + # Check if all relu operations have finished for each row + guard = comp.get_cell("relu_finished_wire_r0").out + for r in range(1, num_rows): + guard = guard & comp.get_cell(f"relu_finished_wire_r{r}").out + all_relu_finished_wire = comp.wire("all_relu_finished_wire", 1) + with comp.static_group(WRITE_DONE_COND, 1): + all_relu_finished_wire.in_ = guard @ 1 + this.computation_done = all_relu_finished_wire.out @ 1 + else: + final_row_valid = this.port(f"r{num_rows -1}_valid") + final_row_idx = this.port(f"r{num_rows-1}_idx") + max_idx = num_cols - 1 + # delay_reg delays writing to this.computation_done + delay_reg = comp.reg("delay_reg", 1) + final_col_idx_reached = final_row_idx == cb.ExprBuilder( + py_ast.ConstantPort(idx_width, max_idx) + ) + with comp.static_group(WRITE_DONE_COND, 1): + delay_reg.in_ = 1 + # When we are at the final index in the final row, we still need + # one cycle to write into the memory. Therefore, we delay computation_done + # by one cycle. + delay_reg.write_en = (final_row_valid & final_col_idx_reached) @ 1 + this.computation_done = delay_reg.done @ 1 + + +def default_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): + """ + Adds a default post-op to `prog`. + This post-op does nothing except immediately write to memory. + """ + comp = prog.component(name=DEFAULT_POST_OP) + add_post_op_params(comp, num_rows, idx_width) + for r in range(num_rows): + create_write_mem_groups(comp, r) + done_condition_groups(comp, num_rows, num_cols, idx_width, leaky_relu=False) + + comp.control = py_ast.StaticParComp( + [py_ast.Enable(WRITE_DONE_COND)] + # write to memory + + [py_ast.Enable(f"write_r{r}") for r in range(num_rows)] + ) + + +def leaky_relu_comp(prog: cb.Builder): + """ + Creates a dynamic, non-pipelined, leaky relu component. + This is the component that actually performs the leaky relu computation on + a given output. + """ + comp = prog.component(name="leaky_relu") + comp.input("value", BITWIDTH) + # Takes a memory and register (i.e., arguments that essentially act as ref cells) + add_write_mem_params(comp, OUT_MEM, BITWIDTH) + add_register_params(comp, "idx_reg", BITWIDTH) + + this = comp.this() + + addr0_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_addr0")) + write_data_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_write_data")) + write_en_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_write_en")) + write_done_port = this.port(OUT_MEM + "_done") + + fp_mult = comp.fp_sop("fp_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH) + lt = comp.fp_sop("val_lt", "lt", BITWIDTH, INTWIDTH, FRACWIDTH) + incr_idx = comp.add(BITWIDTH, "incr_idx") + write_mem = comp.wire("write_mem", 1) + + with comp.continuous: + # gt holds whether this.value > 0 + lt.left = this.value + lt.right = 0 + + with comp.group("do_relu") as g: + # Write_mem holds whether we should be writing to memory, which is when: + # a) multiplier is done, so we write fp_mult.out to mem + # b) this.value >=0 (i.e., !(this.value < 0)) so we write this.value to mem + write_mem.in_ = (fp_mult.done | ~lt.out) @ 1 + # Trigger the multiplier when we're not writing to memory. + fp_mult.left = numeric_types.FixedPoint( + str(float_to_fixed_point(0.01, FRACWIDTH)), BITWIDTH, INTWIDTH, True + ).unsigned_integer() + fp_mult.right = this.value + fp_mult.go = ~(write_mem.out) @ 1 + + # Increment idx_reg during the cycle that we write to memory. + incr_idx.left = this.idx_reg_out + incr_idx.right = 1 + this.idx_reg_in = write_mem.out @ incr_idx.out + this.idx_reg_write_en = write_mem.out @ 1 + + # Write to memory. + g.asgn(write_en_port, 1, write_mem.out) + g.asgn(addr0_port, this.idx_reg_out) + # Write value if this.value >= 0 + # Write mult.out if this.value < 0 + g.asgn(write_data_port, this.value, ~lt.out) + g.asgn(write_data_port, fp_mult.out, lt.out) + # Groups is done once we have written to memory. + g.done = write_done_port + + comp.control = py_ast.Enable("do_relu") + + +def create_leaky_relu_groups(comp: cb.ComponentBuilder, row, num_cols, addr_width): + """ + Creates the groups for the leaky relu post op, i.e., the post-op that + coordinates the leaky-relu execution. + """ + + def store_output_vals(comp: cb.ComponentBuilder, row, num_cols, addr_width): + """ + Helper function that looks at the systolic array output signsl (e.g., + `r0_valid`, `r0_value`, etc.) and creates signals that tells us when: a) + each row is ready for the leaky relu operations to start and b) + the output systolic array values (we need them in registers bc the systolic + array outputs are only available for one cycle). + """ + this = comp.this() + row_ready_wire = comp.wire(f"r{row}_ready_wire", 1) + row_ready_reg = comp.reg(f"r{row}_ready_reg", 1) + for col in range(num_cols): + wire_value = comp.wire(f"r{row}_c{col}_val_wire", BITWIDTH) + reg_value = comp.reg(f"r{row}_c{col}_val_reg", BITWIDTH) + val_ready = comp.wire(f"r{row}_c{col}_val_ready", 1) + valid_signal = this.port(f"r{row}_valid") + idx_signal = this.port(f"r{row}_idx") + value_signal = this.port(f"r{row}_value") + value_ready_signal = valid_signal & ( + idx_signal == cb.ExprBuilder(py_ast.ConstantPort(addr_width, col)) + ) + with comp.static_group(f"r{row}_c{col}_value_group", 1): + # Wire to detect and hold when the row is first valid. Once + # it is valid, we can safely start our relu operations. + row_ready_reg.in_ = valid_signal @ 1 + row_ready_reg.write_en = valid_signal @ 1 + row_ready_wire.in_ = (valid_signal | row_ready_reg.out) @ 1 + # Logic to hold the systolic array output values. We need registers + # because the output values for systolic arrays are only available + # for one cycle before they change. + val_ready.in_ = value_ready_signal @ 1 + wire_value.in_ = val_ready.out @ value_signal + wire_value.in_ = ~(val_ready.out) @ reg_value.out + reg_value.in_ = val_ready.out @ value_signal + reg_value.write_en = val_ready.out @ 1 + + # Helper function adds assignment wire.in = reg.out == col ? pe_{row}_{col}_out. + def build_assignment(group: cb.GroupBuilder, wire, register, output_val): + group.asgn( + wire.port("in"), + output_val.out, + register.port("out") == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, col)), + ) + + group = comp.static_group(f"r{row}_helper", 1) + + # Current value we are performing relu on. + cur_val = comp.wire(f"r{row}_cur_val", BITWIDTH) + # Current idx within the row (i.e., column) for the value we are performing relu on. + idx_reg = comp.reg(f"r{row}_cur_idx", BITWIDTH) + # Handling logic to hold the systolic array's output values so they're available + # for moer than one cycle. + store_output_vals(comp, row, num_cols, addr_width) + for col in range(num_cols): + output_val = comp.get_cell(f"r{row}_c{col}_val_wire") + # Assigning to cur_val wire so that we always have the current value of the + # row based on idx_reg. + build_assignment(group, cur_val, idx_reg, output_val) + + # Instantiate an instance of a leaky_relu component + relu_instance = comp.cell(f"leaky_relu_r{row}", py_ast.CompInst("leaky_relu", [])) + # Wire that tells us we are finished with relu operation for this row. + relu_finished_wire = comp.wire(f"relu_finished_wire_r{row}", 1) + row_ready_wire = comp.get_cell(f"r{row}_ready_wire") + + # Building connections betwen this and the leaky_relu cell + this_relu_io_ports = cb.build_connections( + cell1=comp.this(), + cell2=relu_instance, + root1=OUT_MEM + f"_{row}_", + root2=OUT_MEM + "_", + forward_ports=["addr0", "write_data", "write_en"], + reverse_ports=["done"], + ) + # Building connections between relu and idx_reg + relu_idx_io_ports = cb.build_connections( + cell1=idx_reg, + cell2=relu_instance, + root1="", + root2="idx_reg_", + forward_ports=["write_en", "in"], + reverse_ports=["out"], + ) + idx_limit_reached = idx_reg.out == cb.ExprBuilder( + py_ast.ConstantPort(BITWIDTH, num_cols) + ) + with comp.static_group(f"execute_relu_r{row}", 1) as g: + for i, o in this_relu_io_ports: + g.asgn(i, o) + for i, o in relu_idx_io_ports: + g.asgn(i, o) + # Handle incrementing the idx_reg. + relu_instance.go = ( + row_ready_wire.out & (~relu_finished_wire.out) + ) @ cb.ExprBuilder(py_ast.ConstantPort(1, 1)) + # input ports for relu_instance + relu_instance.value = cur_val.out + relu_finished_wire.in_ = idx_limit_reached @ 1 + + +def leaky_relu_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): + """ + Adds a dynamic leaky relu post op to `prog` + """ + # Create a leaky relu component. + leaky_relu_comp(prog) + comp = prog.component(name=LEAKY_RELU_POST_OP) + add_post_op_params(comp, num_rows, idx_width) + for r in range(num_rows): + create_leaky_relu_groups(comp, r, num_cols, idx_width) + done_condition_groups(comp, num_rows, num_cols, idx_width, leaky_relu=True) + + # all_groups go in one big static par. + all_groups = [py_ast.Enable(WRITE_DONE_COND)] + for r in range(num_rows): + all_groups.append(py_ast.Enable(f"r{r}_helper")) + all_groups.append(py_ast.Enable(f"execute_relu_r{r}")) + for c in range(num_cols): + all_groups.append(py_ast.Enable(f"r{r}_c{c}_value_group")) + + comp.control = py_ast.StaticParComp(all_groups) diff --git a/fud/fud/stages/verilator/numeric_types.py b/fud/fud/stages/verilator/numeric_types.py index 6450f3156..5d6fca493 100644 --- a/fud/fud/stages/verilator/numeric_types.py +++ b/fud/fud/stages/verilator/numeric_types.py @@ -214,9 +214,13 @@ def __initialize_with_decimal_repr(self, value: str): ) int_bits = np.binary_repr(int_partition, self.int_width) - frac_bits = np.binary_repr( - round(frac_partition * (2**self.frac_width)), self.frac_width - ) if self.frac_width > 0 else "" + frac_bits = ( + np.binary_repr( + round(frac_partition * (2**self.frac_width)), self.frac_width + ) + if self.frac_width > 0 + else "" + ) # Given the binary form of the integer part and fractional part of # the decimal, simply append the two strings. bits = int_bits + frac_bits @@ -313,3 +317,12 @@ def pretty_print(self): Hex String: 0x{self.hex_string_repr} Unsigned Integer: {self.uint_repr}""" ) + + +def bitnum_to_fixed(bitnum: Bitnum, int_width: int) -> FixedPoint: + return FixedPoint( + value="0b" + bitnum.bit_string_repr, + width=bitnum.width, + int_width=int_width, + is_signed=bitnum.is_signed, + ) diff --git a/fud/icarus/icarus.py b/fud/icarus/icarus.py index a770b4e35..6d5ebf979 100644 --- a/fud/icarus/icarus.py +++ b/fud/icarus/icarus.py @@ -57,7 +57,9 @@ def mktmp() -> SourceType.Directory: return TmpDir() # Step 2a: Dynamically retrieve the value of stages.verilog.data - @builder.step(description="Dynamically retrieve the value of stages.verilog.data") + @builder.step( + description="Dynamically retrieve the value of stages.verilog.data" + ) def get_verilog_data() -> SourceType.Path: data_path = config.get(["stages", "verilog", "data"]) path = Path(data_path) if data_path else None @@ -186,7 +188,7 @@ def cleanup(tmpdir: SourceType.Directory): # if we need to, convert dynamically sourced json to dat check_verilog_for_mem_read(input_data, data_path) - # otherwise, convert + # otherwise, convert json_to_dat(tmpdir, data_path) compile_with_iverilog(input_data, tmpdir) diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.expect b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect index f5097415d..b2e988ea2 100644 --- a/tests/correctness/systolic/leaky-relu/array-2-3-4.expect +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect @@ -1,5 +1,5 @@ { - "cycles": 20, + "cycles": 18, "memories": { "l0": [ "-1.7772064208984375", diff --git a/tests/correctness/systolic/leaky-relu/array-8.expect b/tests/correctness/systolic/leaky-relu/array-8.expect index 7628c9b73..1d8c768d2 100644 --- a/tests/correctness/systolic/leaky-relu/array-8.expect +++ b/tests/correctness/systolic/leaky-relu/array-8.expect @@ -1,5 +1,5 @@ { - "cycles": 41, + "cycles": 39, "memories": { "l0": [ "3.5089263916015625", diff --git a/tests/correctness/systolic/output/array-2-3-4.expect b/tests/correctness/systolic/output/array-2-3-4.expect index aa115c188..ca505ef07 100644 --- a/tests/correctness/systolic/output/array-2-3-4.expect +++ b/tests/correctness/systolic/output/array-2-3-4.expect @@ -1,47 +1,47 @@ { - "cycles": 16, + "cycles": 15, "memories": { "l0": [ - 62, - 2, - 58 + "-1.5258636474609375", + "1.37969970703125", + "3.964019775390625" ], "l1": [ - 93, - 28, - 61 + "-4.90814208984375", + "1.1556854248046875", + "0.088134765625" ], "out_mem_0": [ - 5304, - 5634, - 8244, - 1030 + "17.829559326171875", + "-14.9852752685546875", + "-0.7954864501953125", + "-15.9398193359375" ], "out_mem_1": [ - 8518, - 8879, - 11617, - 2068 + "13.2156982421875", + "-5.021575927734375", + "20.450347900390625", + "-28.945556640625" ], "t0": [ - 48, - 62, - 38 + "-3.7752532958984375", + "-4.9618072509765625", + "4.771636962890625" ], "t1": [ - 69, - 40, - 22 + "0.8634185791015625", + "-0.4265594482421875", + "-3.29949951171875" ], "t2": [ - 38, - 73, - 99 + "-3.8273162841796875", + "1.6114501953125", + "-2.2347869873046875" ], "t3": [ - 14, - 23, - 2 + "4.7815093994140625", + "-4.69775390625", + "-0.545501708984375" ] } } diff --git a/tests/correctness/systolic/output/array-2-3-4.systolic.data b/tests/correctness/systolic/output/array-2-3-4.systolic.data index 638b8e350..2677d6ac4 100644 --- a/tests/correctness/systolic/output/array-2-3-4.systolic.data +++ b/tests/correctness/systolic/output/array-2-3-4.systolic.data @@ -1,99 +1,107 @@ { "l0": { "data": [ - 62, - 2, - 58 + -1.5258562564849854, + 1.379702091217041, + 3.964019775390625 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l1": { "data": [ - 93, - 28, - 61 + -4.908147811889648, + 1.1556873321533203, + 0.08813953399658203 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_0": { "data": [ - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_1": { "data": [ - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t0": { "data": [ - 48, - 62, - 38 + -3.77524733543396, + -4.961813926696777, + 4.771636962890625 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t1": { "data": [ - 69, - 40, - 22 + 0.8634233474731445, + -0.42656421661376953, + -3.2995009422302246 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t2": { "data": [ - 38, - 73, - 99 + -3.8273227214813232, + 1.6114530563354492, + -2.2347795963287354 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t3": { "data": [ - 14, - 23, - 2 + 4.7815046310424805, + -4.697761535644531, + -0.5455026626586914 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } } diff --git a/tests/correctness/systolic/output/array-8.expect b/tests/correctness/systolic/output/array-8.expect index 944548e5a..24be67b10 100644 --- a/tests/correctness/systolic/output/array-8.expect +++ b/tests/correctness/systolic/output/array-8.expect @@ -1,245 +1,245 @@ { - "cycles": 31, + "cycles": 30, "memories": { "l0": [ - 26, - 46, - 44, - 62, - 47, - 38, - 13, - 94 + "3.3614654541015625", + "3.7810211181640625", + "-0.6595458984375", + "-2.00933837890625", + "-1.07269287109375", + "-1.7359161376953125", + "-2.23175048828125", + "3.242584228515625" ], "l1": [ - 7, - 14, - 72, - 44, - 71, - 6, - 33, - 14 + "-3.66552734375", + "1.862274169921875", + "-4.5985107421875", + "1.737396240234375", + "1.5211181640625", + "2.481170654296875", + "4.3662261962890625", + "-4.712066650390625" ], "l2": [ - 12, - 11, - 88, - 41, - 84, - 88, - 42, - 11 + "-0.1986236572265625", + "3.6620941162109375", + "-3.45025634765625", + "1.60711669921875", + "-4.554595947265625", + "1.3513336181640625", + "-3.6712799072265625", + "-1.1727142333984375" ], "l3": [ - 65, - 31, - 17, - 69, - 33, - 90, - 94, - 93 + "-4.38427734375", + "3.6719970703125", + "4.325927734375", + "3.3654632568359375", + "-3.818634033203125", + "2.7002716064453125", + "0.1087799072265625", + "-1.949493408203125" ], "l4": [ - 7, - 43, - 94, - 51, - 34, - 3, - 84, - 64 + "3.2269439697265625", + "-2.69219970703125", + "-3.09112548828125", + "-2.3430938720703125", + "2.85382080078125", + "1.8892059326171875", + "-0.634521484375", + "2.381866455078125" ], "l5": [ - 23, - 92, - 71, - 99, - 47, - 39, - 27, - 55 + "0.4718017578125", + "0.8296356201171875", + "1.4714813232421875", + "3.4707183837890625", + "1.939208984375", + "-0.3958892822265625", + "-4.3639373779296875", + "0.86492919921875" ], "l6": [ - 45, - 73, - 27, - 17, - 7, - 53, - 13, - 70 + "3.718292236328125", + "3.1377716064453125", + "1.5491790771484375", + "0.18115234375", + "-1.0565185546875", + "3.2894439697265625", + "-1.6756744384765625", + "-3.32159423828125" ], "l7": [ - 90, - 21, - 26, - 7, - 60, - 29, - 70, - 91 + "0.4992523193359375", + "2.626922607421875", + "3.8421630859375", + "1.6167449951171875", + "0.4383544921875", + "2.735015869140625", + "4.4162750244140625", + "-0.7459259033203125" ], "out_mem_0": [ - 15082, - 17066, - 25978, - 13905, - 17367, - 27929, - 17607, - 13732 + "-5.020233154296875", + "-17.630950927734375", + "-11.7227935791015625", + "-23.94586181640625", + "-20.5061187744140625", + "-18.622161865234375", + "19.1900177001953125", + "3.65228271484375" ], "out_mem_1": [ - 9378, - 10449, - 15741, - 10148, - 12877, - 18998, - 9314, - 9333 + "21.97125244140625", + "47.741729736328125", + "5.975616455078125", + "-11.5402069091796875", + "24.655303955078125", + "10.3508758544921875", + "-7.2060546875", + "-35.2868194580078125" ], "out_mem_2": [ - 15735, - 12897, - 24104, - 16444, - 16455, - 29104, - 17296, - 15490 + "-8.005645751953125", + "0.7089080810546875", + "-29.03765869140625", + "10.0974273681640625", + "-4.3226776123046875", + "-9.4420166015625", + "13.7893524169921875", + "-26.162811279296875" ], "out_mem_3": [ - 22450, - 26165, - 32194, - 24043, - 23784, - 33638, - 26276, - 24976 + "-36.066314697265625", + "36.6315155029296875", + "-54.45623779296875", + "23.7673797607421875", + "55.8004302978515625", + "-17.01385498046875", + "-30.425079345703125", + "-36.1455841064453125" ], "out_mem_4": [ - 15650, - 19069, - 21323, - 13406, - 19967, - 24453, - 17448, - 14934 + "11.5760345458984375", + "-43.1614990234375", + "32.2516937255859375", + "0.053802490234375", + "-51.6582183837890625", + "28.627716064453125", + "14.7799530029296875", + "31.807220458984375" ], "out_mem_5": [ - 18516, - 22029, - 30577, - 17767, - 20837, - 35265, - 21524, - 14972 + "-2.5281982421875", + "19.660186767578125", + "-6.4005126953125", + "-3.746063232421875", + "-2.146728515625", + "7.682373046875", + "-15.31072998046875", + "-21.81353759765625" ], "out_mem_6": [ - 13426, - 16673, - 19948, - 13367, - 15650, - 23464, - 18419, - 10693 + "-25.15228271484375", + "-9.1671295166015625", + "-17.158233642578125", + "-8.20404052734375", + "-3.4250640869140625", + "-17.01971435546875", + "19.3945770263671875", + "-2.08734130859375" ], "out_mem_7": [ - 15791, - 22708, - 22926, - 20251, - 23300, - 25717, - 19519, - 18585 + "-16.15911865234375", + "17.7563323974609375", + "-19.4623260498046875", + "-7.7472381591796875", + "41.1004180908203125", + "-1.3080902099609375", + "-21.5960693359375", + "0.1708831787109375" ], "t0": [ - 38, - 37, - 40, - 45, - 15, - 64, - 51, - 43 + "0.6451263427734375", + "-1.3166961669921875", + "-4.3086700439453125", + "2.2447357177734375", + "2.0837249755859375", + "-3.5662689208984375", + "1.9752197265625", + "-0.027435302734375" ], "t1": [ - 69, - 98, - 0, - 35, - 45, - 15, - 93, - 50 + "-4.8111724853515625", + "4.71002197265625", + "0.4647674560546875", + "4.4236602783203125", + "3.9444732666015625", + "-3.5243377685546875", + "1.02667236328125", + "-2.981353759765625" ], "t2": [ - 49, - 57, - 39, - 99, - 70, - 86, - 26, - 78 + "1.919586181640625", + "-4.0710296630859375", + "-2.6121063232421875", + "-0.96337890625", + "3.7477874755859375", + "-1.58636474609375", + "0.8641815185546875", + "-1.0011138916015625" ], "t3": [ - 91, - 46, - 8, - 36, - 58, - 57, - 63, - 12 + "-2.434356689453125", + "-4.969268798828125", + "0.7401275634765625", + "1.02825927734375", + "-4.4361114501953125", + "3.98602294921875", + "-1.322235107421875", + "1.4773101806640625" ], "t4": [ - 86, - 56, - 58, - 20, - 49, - 17, - 64, - 53 + "-2.4996795654296875", + "2.352020263671875", + "3.4475860595703125", + "4.74420166015625", + "-1.9682464599609375", + "-1.969635009765625", + "4.6419525146484375", + "-1.3448333740234375" ], "t5": [ - 71, - 94, - 72, - 83, - 87, - 97, - 24, - 57 + "0.34259033203125", + "-3.76025390625", + "-2.579803466796875", + "3.9580230712890625", + "1.7683563232421875", + "3.40496826171875", + "0.968505859375", + "3.2888946533203125" ], "t6": [ - 25, - 95, - 18, - 9, - 35, - 85, - 70, - 58 + "3.338348388671875", + "0.1703338623046875", + "-2.088653564453125", + "-4.548828125", + "-1.3649749755859375", + "-1.196014404296875", + "-1.540008544921875", + "-3.1365966796875" ], "t7": [ - 43, - 1, - 7, - 45, - 38, - 59, - 86, - 46 + "4.767669677734375", + "-4.9486083984375", + "0.883941650390625", + "-2.3918609619140625", + "-2.087799072265625", + "1.2293701171875", + "2.376678466796875", + "2.2551116943359375" ] } } diff --git a/tests/correctness/systolic/output/array-8.systolic.data b/tests/correctness/systolic/output/array-8.systolic.data index c490faa8c..4c6726a68 100644 --- a/tests/correctness/systolic/output/array-8.systolic.data +++ b/tests/correctness/systolic/output/array-8.systolic.data @@ -1,409 +1,433 @@ { "l0": { "data": [ - 26, - 46, - 44, - 62, - 47, - 38, - 13, - 94 + 3.3614635467529297, + 3.7810144424438477, + -0.6595420837402344, + -2.0093393325805664, + -1.072697639465332, + -1.735914945602417, + -2.231743335723877, + 3.242586135864258 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l1": { "data": [ - 7, - 14, - 72, - 44, - 71, - 6, - 33, - 14 + -3.6655306816101074, + 1.8622779846191406, + -4.598508834838867, + 1.7374038696289062, + 1.5211162567138672, + 2.48116397857666, + 4.366230010986328, + -4.712061882019043 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l2": { "data": [ - 12, - 11, - 88, - 41, - 84, - 88, - 42, - 11 + -0.19861793518066406, + 3.6620922088623047, + -3.450254201889038, + 1.607121467590332, + -4.554588794708252, + 1.3513288497924805, + -3.6712777614593506, + -1.172710657119751 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l3": { "data": [ - 65, - 31, - 17, - 69, - 33, - 90, - 94, - 93 + -4.384279251098633, + 3.6720046997070312, + 4.325924873352051, + 3.365457534790039, + -3.8186287879943848, + 2.700267791748047, + 0.10878324508666992, + -1.9494962692260742 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l4": { "data": [ - 7, - 43, - 94, - 51, - 34, - 3, - 84, - 64 + 3.226938247680664, + -2.69220232963562, + -3.0911314487457275, + -2.3430871963500977, + 2.8538217544555664, + 1.8892107009887695, + -0.6345248222351074, + 2.381865978240967 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l5": { "data": [ - 23, - 92, - 71, - 99, - 47, - 39, - 27, - 55 + 0.47180652618408203, + 0.8296308517456055, + 1.471487045288086, + 3.470722198486328, + 1.9392023086547852, + -0.39588451385498047, + -4.363941192626953, + 0.8649253845214844 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l6": { "data": [ - 45, - 73, - 27, - 17, - 7, - 53, - 13, - 70 + 3.718292236328125, + 3.1377687454223633, + 1.5491843223571777, + 0.18115758895874023, + -1.056511402130127, + 3.2894468307495117, + -1.6756761074066162, + -3.321586847305298 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l7": { "data": [ - 90, - 21, - 26, - 7, - 60, - 29, - 70, - 91 + 0.4992542266845703, + 2.6269302368164062, + 3.8421621322631836, + 1.6167521476745605, + 0.43836021423339844, + 2.73500919342041, + 4.4162797927856445, + -0.7459220886230469 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_0": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_1": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_2": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_3": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_4": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_5": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_6": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "out_mem_7": { "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t0": { "data": [ - 38, - 37, - 40, - 45, - 15, - 64, - 51, - 43 + 0.6451263427734375, + -1.3166892528533936, + -4.308672904968262, + 2.24473237991333, + 2.0837268829345703, + -3.566269874572754, + 1.9752159118652344, + -0.027441978454589844 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t1": { "data": [ - 69, - 98, - 0, - 35, - 45, - 15, - 93, - 50 + -4.8111772537231445, + 4.710016250610352, + 0.46476268768310547, + 4.42365837097168, + 3.944472312927246, + -3.5243332386016846, + 1.0266780853271484, + -2.9813599586486816 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t2": { "data": [ - 49, - 57, - 39, - 99, - 70, - 86, - 26, - 78 + 1.9195914268493652, + -4.071036338806152, + -2.61210560798645, + -0.963374137878418, + 3.7477893829345703, + -1.586371660232544, + 0.8641839027404785, + -1.0011076927185059 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t3": { "data": [ - 91, - 46, - 8, - 36, - 58, - 57, - 63, - 12 + -2.434360980987549, + -4.969264030456543, + 0.7401218414306641, + 1.0282669067382812, + -4.4361186027526855, + 3.986025810241699, + -1.3222312927246094, + 1.4773082733154297 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t4": { "data": [ - 86, - 56, - 58, - 20, - 49, - 17, - 64, - 53 + -2.499678134918213, + 2.3520255088806152, + 3.4475793838500977, + 4.744197845458984, + -1.9682538509368896, + -1.9696319103240967, + 4.64195442199707, + -1.344829797744751 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t5": { "data": [ - 71, - 94, - 72, - 83, - 87, - 97, - 24, - 57 + 0.3425884246826172, + -3.760256767272949, + -2.5798070430755615, + 3.9580202102661133, + 1.7683610916137695, + 3.4049606323242188, + 0.9685015678405762, + 3.2888946533203125 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t6": { "data": [ - 25, - 95, - 18, - 9, - 35, - 85, - 70, - 58 + 3.3383445739746094, + 0.17033672332763672, + -2.088654041290283, + -4.548826217651367, + -1.364973783493042, + -1.1960172653198242, + -1.5400052070617676, + -3.136591911315918 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "t7": { "data": [ - 43, - 1, - 7, - 45, - 38, - 59, - 86, - 46 + 4.767667770385742, + -4.948601722717285, + 0.8839473724365234, + -2.3918545246124268, + -2.087804079055786, + 1.2293744087219238, + 2.3766794204711914, + 2.255117893218994 ], "format": { - "is_signed": false, - "numeric_type": "bitnum", + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } } diff --git a/tests/correctness/systolic/pe/array-1.expect b/tests/correctness/systolic/pe/array-1.expect index df8dfe978..7d6cd6fec 100644 --- a/tests/correctness/systolic/pe/array-1.expect +++ b/tests/correctness/systolic/pe/array-1.expect @@ -1,9 +1,9 @@ { - "cycles": 16, + "cycles": 15, "pe_00": [ 0, - 120, - 360, - 760 + 7864320, + 23592960, + 49807360 ] } diff --git a/tests/correctness/systolic/pe/array-1.systolic.data b/tests/correctness/systolic/pe/array-1.systolic.data index 7383350ef..66db65a5b 100644 --- a/tests/correctness/systolic/pe/array-1.systolic.data +++ b/tests/correctness/systolic/pe/array-1.systolic.data @@ -1,37 +1,40 @@ { "t0": { "data": [ - 30, - 40, - 50 + 30.0, + 40.0, + 50.0 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, "l0": { "data": [ - 4, - 6, - 8 + 4.0, + 6.0, + 8.0 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, - "out_mem": { + "out_mem_0": { "data": [ [ - 0 + 0.0 ] ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } } diff --git a/tests/correctness/systolic/pe/array-1.systolic.jq b/tests/correctness/systolic/pe/array-1.systolic.jq index a61fe68a9..368314975 100644 --- a/tests/correctness/systolic/pe/array-1.systolic.jq +++ b/tests/correctness/systolic/pe/array-1.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main.systolic_array | ({ +.TOP.TOP.main.systolic_array_component | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, }) diff --git a/tests/correctness/systolic/pe/array-2.expect b/tests/correctness/systolic/pe/array-2.expect index 5bcf45bd8..57a94f77a 100644 --- a/tests/correctness/systolic/pe/array-2.expect +++ b/tests/correctness/systolic/pe/array-2.expect @@ -1,27 +1,27 @@ { - "cycles": 18, + "cycles": 17, "pe_00": [ 0, - 120, - 360, - 760 + 7864320, + 23592960, + 49807360 ], "pe_01": [ 0, - 40, - 160, - 400 + 2621440, + 10485760, + 26214400 ], "pe_10": [ 0, - 210, - 570, - 1120 + 13762560, + 37355520, + 73400320 ], "pe_11": [ 0, - 70, - 250, - 580 + 4587520, + 16384000, + 38010880 ] } diff --git a/tests/correctness/systolic/pe/array-2.systolic.data b/tests/correctness/systolic/pe/array-2.systolic.data index 7d11ae48d..60338697a 100644 --- a/tests/correctness/systolic/pe/array-2.systolic.data +++ b/tests/correctness/systolic/pe/array-2.systolic.data @@ -6,8 +6,9 @@ 50 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -18,8 +19,9 @@ 30 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -30,8 +32,9 @@ 8 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -42,21 +45,33 @@ 11 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, - "out_mem": { + "out_mem_0": { "data": [ - [ - [0,0], - [0,0] - ] + 0.0, + 0.0 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } } diff --git a/tests/correctness/systolic/pe/array-2.systolic.jq b/tests/correctness/systolic/pe/array-2.systolic.jq index 0cedc930a..abbe179ed 100644 --- a/tests/correctness/systolic/pe/array-2.systolic.jq +++ b/tests/correctness/systolic/pe/array-2.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main.systolic_array | ({ +.TOP.TOP.main.systolic_array_component | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, "pe_01": .pe_0_1.acc.out | unique, diff --git a/tests/correctness/systolic/pe/array-3.expect b/tests/correctness/systolic/pe/array-3.expect index f8afb09ec..014606b40 100644 --- a/tests/correctness/systolic/pe/array-3.expect +++ b/tests/correctness/systolic/pe/array-3.expect @@ -1,57 +1,57 @@ { - "cycles": 20, + "cycles": 19, "pe_00": [ 0, - 120, - 360, - 760 + 7864320, + 23592960, + 49807360 ], "pe_01": [ 0, - 40, - 160, - 400 + 2621440, + 10485760, + 26214400 ], "pe_02": [ 0, - 200, - 560, - 1120 + 13107200, + 36700160, + 73400320 ], "pe_10": [ 0, - 210, - 570, - 1120 + 13762560, + 37355520, + 73400320 ], "pe_11": [ 0, - 70, - 250, - 580 + 4587520, + 16384000, + 38010880 ], "pe_12": [ 0, - 350, - 890, - 1660 + 22937600, + 58327040, + 108789760 ], "pe_20": [ 0, - 30, - 150, - 400 + 1966080, + 9830400, + 26214400 ], "pe_21": [ 0, - 10, - 70, - 220 + 655360, + 4587520, + 14417920 ], "pe_22": [ 0, - 50, - 230, - 580 + 3276800, + 15073280, + 38010880 ] } diff --git a/tests/correctness/systolic/pe/array-3.systolic.data b/tests/correctness/systolic/pe/array-3.systolic.data index 5bc9b5ab6..1e898a6d3 100644 --- a/tests/correctness/systolic/pe/array-3.systolic.data +++ b/tests/correctness/systolic/pe/array-3.systolic.data @@ -6,8 +6,9 @@ 50 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -18,8 +19,9 @@ 30 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -30,8 +32,9 @@ 70 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -42,8 +45,9 @@ 8 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -54,8 +58,9 @@ 11 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, @@ -66,24 +71,55 @@ 5 ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } }, - "out_mem": { + "out_mem_0": { "data": [ [ - [0,0,0], - [0,0,0], - [0,0,0] - + 0.0, + 0.0, + 0.0 ] ], "format": { - "numeric_type": "bitnum", - "is_signed": false, + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + [ + 0.0, + 0.0, + 0.0 + ] + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_2": { + "data": [ + [ + 0.0, + 0.0, + 0.0 + ] + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", "width": 32 } } -} +} \ No newline at end of file diff --git a/tests/correctness/systolic/pe/array-3.systolic.jq b/tests/correctness/systolic/pe/array-3.systolic.jq index d79a90dc5..d79ac6978 100644 --- a/tests/correctness/systolic/pe/array-3.systolic.jq +++ b/tests/correctness/systolic/pe/array-3.systolic.jq @@ -1,4 +1,4 @@ -.TOP.TOP.main.systolic_array | ({ +.TOP.TOP.main.systolic_array_component | ({ "cycles":.clk | add, "pe_00": .pe_0_0.acc.out | unique, diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 62729030f..be94c43c9 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -4,14 +4,14 @@ import "primitives/pipelined.futil"; static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { cells { acc = std_reg(32); - add = std_add(32); - mul = pipelined_mult(); + adder = std_fp_sadd(32, 16, 16); + mul = pipelined_fp_smult(32, 16, 16); } wires { static<1> group do_add { - add.left = acc.out; - add.right = mul.out; - acc.in = add.out; + adder.left = acc.out; + adder.right = mul.out; + acc.in = adder.out; acc.write_en = mul_ready; } static<1> group do_mul { @@ -27,7 +27,7 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } } } -component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 2, l0_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1) { +component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 32, l0_addr0: 32, r0_valid: 1, r0_value: 32, r0_idx: 32) { cells { min_depth_4 = std_reg(32); lt_depth_4 = std_lt(32); @@ -41,10 +41,10 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); - t0_idx = std_reg(2); - t0_add = std_add(2); - l0_idx = std_reg(2); - l0_add = std_add(2); + t0_idx = std_reg(32); + t0_add = std_add(32); + l0_idx = std_reg(32); + l0_add = std_add(32); idx = std_reg(32); idx_add = std_add(32); cond_reg = std_reg(1); @@ -102,11 +102,11 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> depth_plus_6.right = 32'd6; } static<1> group t0_idx_init { - t0_idx.in = 2'd0; + t0_idx.in = 32'd0; t0_idx.write_en = 1'd1; } static<1> group t0_idx_update { - t0_add.left = 2'd1; + t0_add.left = 32'd1; t0_add.right = t0_idx.out; t0_idx.in = t0_add.out; t0_idx.write_en = 1'd1; @@ -117,11 +117,11 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> top_0_0.write_en = 1'd1; } static<1> group l0_idx_init { - l0_idx.in = 2'd0; + l0_idx.in = 32'd0; l0_idx.write_en = 1'd1; } static<1> group l0_idx_update { - l0_add.left = 2'd1; + l0_add.left = 32'd1; l0_add.right = l0_idx.out; l0_idx.in = l0_add.out; l0_idx.write_en = 1'd1; @@ -132,9 +132,9 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> left_0_0.write_en = 1'd1; } static<1> group pe_0_0_out_write { - out_mem_0_addr0 = 32'd0; - out_mem_0_write_data = pe_0_0.out; - out_mem_0_write_en = 1'd1; + r0_valid = 1'd1; + r0_value = pe_0_0.out; + r0_idx = 32'd0; } static<1> group init_idx { idx.in = 32'd0; @@ -150,7 +150,7 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> cond_reg.in = 1'd1; cond_reg.write_en = 1'd1; } - static<1> group lt_iter_limit_group { + static<1> group write_cond_reg { lt_iter_limit.left = idx_add.out; lt_iter_limit.right = iter_limit.out; cond_reg.in = lt_iter_limit.out; @@ -231,12 +231,12 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> init_idx; init_min_depth; init_cond_reg; + init_iter_limit; init_idx_between_5_depth_plus_5; init_idx_between_0_depth_plus_0; init_idx_between_1_depth_plus_1; init_idx_between_1_min_depth_4_plus_1; init_idx_between_depth_plus_5_depth_plus_6; - init_iter_limit; } while cond_reg.out { static par { @@ -269,37 +269,82 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> } static par { incr_idx; - lt_iter_limit_group; + write_cond_reg; idx_between_5_depth_plus_5_group; idx_between_0_depth_plus_0_group; idx_between_1_depth_plus_1_group; idx_between_1_min_depth_4_plus_1_group; idx_between_depth_plus_5_depth_plus_6_group; - depth_plus_5_group; depth_plus_0_group; depth_plus_1_group; - min_depth_4_plus_1_group; + depth_plus_5_group; depth_plus_6_group; + min_depth_4_plus_1_group; } } } } } } +component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: 32) -> (computation_done: 1, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1) { + cells { + delay_reg = std_reg(1); + } + wires { + static<1> group write_r0 { + out_mem_0_write_en = r0_valid; + out_mem_0_write_data = r0_value; + out_mem_0_addr0 = r0_idx; + } + static<1> group write_done_cond { + delay_reg.in = 1'd1; + delay_reg.write_en = r0_valid & r0_idx == 32'd0 ? 1'd1; + computation_done = delay_reg.done ? 1'd1; + } + } + control { + static par { + write_done_cond; + write_r0; + } + } +} component main() -> () { cells { - systolic_array = systolic_array_comp(); - @external t0 = std_mem_d1(32, 3, 2); - @external l0 = std_mem_d1(32, 3, 2); + systolic_array_component = systolic_array_comp(); + post_op_component = default_post_op(); + @external t0 = std_mem_d1(32, 3, 32); + @external l0 = std_mem_d1(32, 3, 32); @external out_mem_0 = std_mem_d1(32, 1, 32); + systolic_done = std_reg(1); + systolic_done_wire = std_wire(1); } wires { - + group perform_computation { + t0.addr0 = systolic_array_component.t0_addr0; + systolic_array_component.t0_read_data = t0.read_data; + l0.addr0 = systolic_array_component.l0_addr0; + systolic_array_component.l0_read_data = l0.read_data; + out_mem_0.write_data = post_op_component.out_mem_0_write_data; + out_mem_0.write_en = post_op_component.out_mem_0_write_en; + out_mem_0.addr0 = post_op_component.out_mem_0_addr0; + post_op_component.out_mem_0_done = out_mem_0.done; + post_op_component.r0_valid = systolic_array_component.r0_valid; + post_op_component.r0_value = systolic_array_component.r0_value; + post_op_component.r0_idx = systolic_array_component.r0_idx; + systolic_done.write_en = systolic_array_component.done ? 1'd1; + systolic_done.in = systolic_array_component.done ? 1'd1; + systolic_done_wire.in = systolic_array_component.done | systolic_done.out ? 1'd1; + systolic_array_component.go = !systolic_done_wire.out ? 1'd1; + systolic_array_component.depth = 32'd3; + post_op_component.go = 1'd1; + perform_computation[done] = post_op_component.computation_done; + } } control { - invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, l0_read_data=l0.read_data)(t0_addr0=t0.addr0, l0_addr0=l0.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en); + perform_computation; } } metadata #{ -0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) +0: pe_0_0 filling: [1,min_depth_4_plus_1), accumulating: [5 depth_plus_5), writing: [depth_plus_5 depth_plus_6) }# diff --git a/tests/frontend/systolic/array-2.expect b/tests/frontend/systolic/array-2.expect deleted file mode 100644 index e0682f062..000000000 --- a/tests/frontend/systolic/array-2.expect +++ /dev/null @@ -1,658 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -import "primitives/pipelined.futil"; -static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { - cells { - acc = std_reg(32); - add = std_add(32); - mul = pipelined_mult(); - } - wires { - static<1> group do_add { - add.left = acc.out; - add.right = mul.out; - acc.in = add.out; - acc.write_en = mul_ready; - } - static<1> group do_mul { - mul.left = top; - mul.right = left; - } - out = acc.out; - } - control { - static par { - do_add; - do_mul; - } - } -} -component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, l0_read_data: 32, l1_read_data: 32) -> (t0_addr0: 2, t1_addr0: 2, l0_addr0: 2, l1_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1, out_mem_1_addr0: 32, out_mem_1_write_data: 32, out_mem_1_write_en: 1) { - cells { - min_depth_4 = std_reg(32); - lt_depth_4 = std_lt(32); - iter_limit = std_reg(32); - iter_limit_add = std_add(32); - depth_plus_5 = std_add(32); - depth_plus_2 = std_add(32); - depth_plus_7 = std_add(32); - depth_plus_0 = std_add(32); - min_depth_4_plus_1 = std_add(32); - depth_plus_1 = std_add(32); - depth_plus_6 = std_add(32); - min_depth_4_plus_3 = std_add(32); - depth_plus_3 = std_add(32); - min_depth_4_plus_2 = std_add(32); - depth_plus_8 = std_add(32); - pe_0_0 = mac_pe(); - top_0_0 = std_reg(32); - left_0_0 = std_reg(32); - pe_0_1 = mac_pe(); - top_0_1 = std_reg(32); - left_0_1 = std_reg(32); - pe_1_0 = mac_pe(); - top_1_0 = std_reg(32); - left_1_0 = std_reg(32); - pe_1_1 = mac_pe(); - top_1_1 = std_reg(32); - left_1_1 = std_reg(32); - t0_idx = std_reg(2); - t0_add = std_add(2); - t1_idx = std_reg(2); - t1_add = std_add(2); - l0_idx = std_reg(2); - l0_add = std_add(2); - l1_idx = std_reg(2); - l1_add = std_add(2); - idx = std_reg(32); - idx_add = std_add(32); - cond_reg = std_reg(1); - lt_iter_limit = std_lt(32); - idx_between_5_depth_plus_5_reg = std_reg(1); - index_lt_depth_plus_5 = std_lt(32); - index_ge_5 = std_ge(32); - idx_between_5_depth_plus_5_comb = std_and(1); - idx_between_2_depth_plus_2_reg = std_reg(1); - index_lt_depth_plus_2 = std_lt(32); - index_ge_2 = std_ge(32); - idx_between_2_depth_plus_2_comb = std_and(1); - idx_between_7_depth_plus_7_reg = std_reg(1); - index_lt_depth_plus_7 = std_lt(32); - index_ge_7 = std_ge(32); - idx_between_7_depth_plus_7_comb = std_and(1); - idx_between_0_depth_plus_0_reg = std_reg(1); - index_lt_depth_plus_0 = std_lt(32); - idx_between_1_min_depth_4_plus_1_reg = std_reg(1); - index_lt_min_depth_4_plus_1 = std_lt(32); - index_ge_1 = std_ge(32); - idx_between_1_min_depth_4_plus_1_comb = std_and(1); - idx_between_1_depth_plus_1_reg = std_reg(1); - index_lt_depth_plus_1 = std_lt(32); - idx_between_1_depth_plus_1_comb = std_and(1); - idx_between_depth_plus_6_depth_plus_7_reg = std_reg(1); - index_ge_depth_plus_6 = std_ge(32); - idx_between_depth_plus_6_depth_plus_7_comb = std_and(1); - idx_between_3_min_depth_4_plus_3_reg = std_reg(1); - index_lt_min_depth_4_plus_3 = std_lt(32); - index_ge_3 = std_ge(32); - idx_between_3_min_depth_4_plus_3_comb = std_and(1); - idx_between_3_depth_plus_3_reg = std_reg(1); - index_lt_depth_plus_3 = std_lt(32); - idx_between_3_depth_plus_3_comb = std_and(1); - idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); - index_lt_depth_plus_6 = std_lt(32); - index_ge_depth_plus_5 = std_ge(32); - idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); - idx_between_2_min_depth_4_plus_2_reg = std_reg(1); - index_lt_min_depth_4_plus_2 = std_lt(32); - idx_between_2_min_depth_4_plus_2_comb = std_and(1); - idx_between_6_depth_plus_6_reg = std_reg(1); - index_ge_6 = std_ge(32); - idx_between_6_depth_plus_6_comb = std_and(1); - idx_between_depth_plus_7_depth_plus_8_reg = std_reg(1); - index_lt_depth_plus_8 = std_lt(32); - index_ge_depth_plus_7 = std_ge(32); - idx_between_depth_plus_7_depth_plus_8_comb = std_and(1); - } - wires { - static<1> group init_min_depth { - lt_depth_4.left = depth; - lt_depth_4.right = 32'd4; - min_depth_4.in = lt_depth_4.out ? depth; - min_depth_4.in = !lt_depth_4.out ? 32'd4; - min_depth_4.write_en = 1'd1; - } - static<1> group init_iter_limit { - iter_limit_add.left = 32'd8; - iter_limit_add.right = depth; - iter_limit.in = iter_limit_add.out; - iter_limit.write_en = 1'd1; - } - static<1> group depth_plus_5_group { - depth_plus_5.left = depth; - depth_plus_5.right = 32'd5; - } - static<1> group depth_plus_2_group { - depth_plus_2.left = depth; - depth_plus_2.right = 32'd2; - } - static<1> group depth_plus_7_group { - depth_plus_7.left = depth; - depth_plus_7.right = 32'd7; - } - static<1> group depth_plus_0_group { - depth_plus_0.left = depth; - depth_plus_0.right = 32'd0; - } - static<1> group min_depth_4_plus_1_group { - min_depth_4_plus_1.left = min_depth_4.out; - min_depth_4_plus_1.right = 32'd1; - } - static<1> group depth_plus_1_group { - depth_plus_1.left = depth; - depth_plus_1.right = 32'd1; - } - static<1> group depth_plus_6_group { - depth_plus_6.left = depth; - depth_plus_6.right = 32'd6; - } - static<1> group min_depth_4_plus_3_group { - min_depth_4_plus_3.left = min_depth_4.out; - min_depth_4_plus_3.right = 32'd3; - } - static<1> group depth_plus_3_group { - depth_plus_3.left = depth; - depth_plus_3.right = 32'd3; - } - static<1> group min_depth_4_plus_2_group { - min_depth_4_plus_2.left = min_depth_4.out; - min_depth_4_plus_2.right = 32'd2; - } - static<1> group depth_plus_8_group { - depth_plus_8.left = depth; - depth_plus_8.right = 32'd8; - } - static<1> group t0_idx_init { - t0_idx.in = 2'd0; - t0_idx.write_en = 1'd1; - } - static<1> group t0_idx_update { - t0_add.left = 2'd1; - t0_add.right = t0_idx.out; - t0_idx.in = t0_add.out; - t0_idx.write_en = 1'd1; - } - static<1> group t0_move { - t0_addr0 = t0_idx.out; - top_0_0.in = t0_read_data; - top_0_0.write_en = 1'd1; - } - static<1> group t1_idx_init { - t1_idx.in = 2'd0; - t1_idx.write_en = 1'd1; - } - static<1> group t1_idx_update { - t1_add.left = 2'd1; - t1_add.right = t1_idx.out; - t1_idx.in = t1_add.out; - t1_idx.write_en = 1'd1; - } - static<1> group t1_move { - t1_addr0 = t1_idx.out; - top_0_1.in = t1_read_data; - top_0_1.write_en = 1'd1; - } - static<1> group l0_idx_init { - l0_idx.in = 2'd0; - l0_idx.write_en = 1'd1; - } - static<1> group l0_idx_update { - l0_add.left = 2'd1; - l0_add.right = l0_idx.out; - l0_idx.in = l0_add.out; - l0_idx.write_en = 1'd1; - } - static<1> group l0_move { - l0_addr0 = l0_idx.out; - left_0_0.in = l0_read_data; - left_0_0.write_en = 1'd1; - } - static<1> group l1_idx_init { - l1_idx.in = 2'd0; - l1_idx.write_en = 1'd1; - } - static<1> group l1_idx_update { - l1_add.left = 2'd1; - l1_add.right = l1_idx.out; - l1_idx.in = l1_add.out; - l1_idx.write_en = 1'd1; - } - static<1> group l1_move { - l1_addr0 = l1_idx.out; - left_1_0.in = l1_read_data; - left_1_0.write_en = 1'd1; - } - static<1> group pe_0_0_right_move { - left_0_1.in = left_0_0.out; - left_0_1.write_en = 1'd1; - } - static<1> group pe_0_0_down_move { - top_1_0.in = top_0_0.out; - top_1_0.write_en = 1'd1; - } - static<1> group pe_0_0_out_write { - out_mem_0_addr0 = 32'd0; - out_mem_0_write_data = pe_0_0.out; - out_mem_0_write_en = 1'd1; - } - static<1> group pe_0_1_down_move { - top_1_1.in = top_0_1.out; - top_1_1.write_en = 1'd1; - } - static<1> group pe_0_1_out_write { - out_mem_0_addr0 = 32'd1; - out_mem_0_write_data = pe_0_1.out; - out_mem_0_write_en = 1'd1; - } - static<1> group pe_1_0_right_move { - left_1_1.in = left_1_0.out; - left_1_1.write_en = 1'd1; - } - static<1> group pe_1_0_out_write { - out_mem_1_addr0 = 32'd0; - out_mem_1_write_data = pe_1_0.out; - out_mem_1_write_en = 1'd1; - } - static<1> group pe_1_1_out_write { - out_mem_1_addr0 = 32'd1; - out_mem_1_write_data = pe_1_1.out; - out_mem_1_write_en = 1'd1; - } - static<1> group init_idx { - idx.in = 32'd0; - idx.write_en = 1'd1; - } - static<1> group incr_idx { - idx_add.left = idx.out; - idx_add.right = 32'd1; - idx.in = idx_add.out; - idx.write_en = 1'd1; - } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } - static<1> group lt_iter_limit_group { - lt_iter_limit.left = idx_add.out; - lt_iter_limit.right = iter_limit.out; - cond_reg.in = lt_iter_limit.out; - cond_reg.write_en = 1'd1; - } - static<1> group idx_between_5_depth_plus_5_group { - index_ge_5.left = idx_add.out; - index_ge_5.right = 32'd5; - index_lt_depth_plus_5.left = idx_add.out; - index_lt_depth_plus_5.right = depth_plus_5.out; - idx_between_5_depth_plus_5_comb.left = index_ge_5.out; - idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; - idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_depth_plus_5 { - idx_between_5_depth_plus_5_reg.in = 1'd0; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group idx_between_2_depth_plus_2_group { - index_ge_2.left = idx_add.out; - index_ge_2.right = 32'd2; - index_lt_depth_plus_2.left = idx_add.out; - index_lt_depth_plus_2.right = depth_plus_2.out; - idx_between_2_depth_plus_2_comb.left = index_ge_2.out; - idx_between_2_depth_plus_2_comb.right = index_lt_depth_plus_2.out; - idx_between_2_depth_plus_2_reg.in = idx_between_2_depth_plus_2_comb.out; - idx_between_2_depth_plus_2_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_depth_plus_2 { - idx_between_2_depth_plus_2_reg.in = 1'd0; - idx_between_2_depth_plus_2_reg.write_en = 1'd1; - } - static<1> group idx_between_7_depth_plus_7_group { - index_ge_7.left = idx_add.out; - index_ge_7.right = 32'd7; - index_lt_depth_plus_7.left = idx_add.out; - index_lt_depth_plus_7.right = depth_plus_7.out; - idx_between_7_depth_plus_7_comb.left = index_ge_7.out; - idx_between_7_depth_plus_7_comb.right = index_lt_depth_plus_7.out; - idx_between_7_depth_plus_7_reg.in = idx_between_7_depth_plus_7_comb.out; - idx_between_7_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group init_idx_between_7_depth_plus_7 { - idx_between_7_depth_plus_7_reg.in = 1'd0; - idx_between_7_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group idx_between_0_depth_plus_0_group { - index_lt_depth_plus_0.left = idx_add.out; - index_lt_depth_plus_0.right = depth_plus_0.out; - idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_depth_plus_0 { - idx_between_0_depth_plus_0_reg.in = 1'd1; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group idx_between_1_min_depth_4_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_min_depth_4_plus_1.left = idx_add.out; - index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; - idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_min_depth_4_plus_1 { - idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_1_depth_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_depth_plus_1.left = idx_add.out; - index_lt_depth_plus_1.right = depth_plus_1.out; - idx_between_1_depth_plus_1_comb.left = index_ge_1.out; - idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; - idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_depth_plus_1 { - idx_between_1_depth_plus_1_reg.in = 1'd0; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_6_depth_plus_7_group { - index_ge_depth_plus_6.left = idx_add.out; - index_ge_depth_plus_6.right = depth_plus_6.out; - index_lt_depth_plus_7.left = idx_add.out; - index_lt_depth_plus_7.right = depth_plus_7.out; - idx_between_depth_plus_6_depth_plus_7_comb.left = index_ge_depth_plus_6.out; - idx_between_depth_plus_6_depth_plus_7_comb.right = index_lt_depth_plus_7.out; - idx_between_depth_plus_6_depth_plus_7_reg.in = idx_between_depth_plus_6_depth_plus_7_comb.out; - idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_6_depth_plus_7 { - idx_between_depth_plus_6_depth_plus_7_reg.in = 1'd0; - idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group idx_between_3_min_depth_4_plus_3_group { - index_ge_3.left = idx_add.out; - index_ge_3.right = 32'd3; - index_lt_min_depth_4_plus_3.left = idx_add.out; - index_lt_min_depth_4_plus_3.right = min_depth_4_plus_3.out; - idx_between_3_min_depth_4_plus_3_comb.left = index_ge_3.out; - idx_between_3_min_depth_4_plus_3_comb.right = index_lt_min_depth_4_plus_3.out; - idx_between_3_min_depth_4_plus_3_reg.in = idx_between_3_min_depth_4_plus_3_comb.out; - idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_min_depth_4_plus_3 { - idx_between_3_min_depth_4_plus_3_reg.in = 1'd0; - idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; - } - static<1> group idx_between_3_depth_plus_3_group { - index_ge_3.left = idx_add.out; - index_ge_3.right = 32'd3; - index_lt_depth_plus_3.left = idx_add.out; - index_lt_depth_plus_3.right = depth_plus_3.out; - idx_between_3_depth_plus_3_comb.left = index_ge_3.out; - idx_between_3_depth_plus_3_comb.right = index_lt_depth_plus_3.out; - idx_between_3_depth_plus_3_reg.in = idx_between_3_depth_plus_3_comb.out; - idx_between_3_depth_plus_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_depth_plus_3 { - idx_between_3_depth_plus_3_reg.in = 1'd0; - idx_between_3_depth_plus_3_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_5_depth_plus_6_group { - index_ge_depth_plus_5.left = idx_add.out; - index_ge_depth_plus_5.right = depth_plus_5.out; - index_lt_depth_plus_6.left = idx_add.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; - idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_5_depth_plus_6 { - idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group idx_between_2_min_depth_4_plus_2_group { - index_ge_2.left = idx_add.out; - index_ge_2.right = 32'd2; - index_lt_min_depth_4_plus_2.left = idx_add.out; - index_lt_min_depth_4_plus_2.right = min_depth_4_plus_2.out; - idx_between_2_min_depth_4_plus_2_comb.left = index_ge_2.out; - idx_between_2_min_depth_4_plus_2_comb.right = index_lt_min_depth_4_plus_2.out; - idx_between_2_min_depth_4_plus_2_reg.in = idx_between_2_min_depth_4_plus_2_comb.out; - idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_min_depth_4_plus_2 { - idx_between_2_min_depth_4_plus_2_reg.in = 1'd0; - idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; - } - static<1> group idx_between_6_depth_plus_6_group { - index_ge_6.left = idx_add.out; - index_ge_6.right = 32'd6; - index_lt_depth_plus_6.left = idx_add.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_6_depth_plus_6_comb.left = index_ge_6.out; - idx_between_6_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_6_depth_plus_6_reg.in = idx_between_6_depth_plus_6_comb.out; - idx_between_6_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_6_depth_plus_6 { - idx_between_6_depth_plus_6_reg.in = 1'd0; - idx_between_6_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_7_depth_plus_8_group { - index_ge_depth_plus_7.left = idx_add.out; - index_ge_depth_plus_7.right = depth_plus_7.out; - index_lt_depth_plus_8.left = idx_add.out; - index_lt_depth_plus_8.right = depth_plus_8.out; - idx_between_depth_plus_7_depth_plus_8_comb.left = index_ge_depth_plus_7.out; - idx_between_depth_plus_7_depth_plus_8_comb.right = index_lt_depth_plus_8.out; - idx_between_depth_plus_7_depth_plus_8_reg.in = idx_between_depth_plus_7_depth_plus_8_comb.out; - idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_7_depth_plus_8 { - idx_between_depth_plus_7_depth_plus_8_reg.in = 1'd0; - idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; - } - } - control { - seq { - static par { - t0_idx_init; - t1_idx_init; - l0_idx_init; - l1_idx_init; - init_idx; - init_min_depth; - init_cond_reg; - init_idx_between_5_depth_plus_5; - init_idx_between_2_depth_plus_2; - init_idx_between_7_depth_plus_7; - init_idx_between_0_depth_plus_0; - init_idx_between_1_min_depth_4_plus_1; - init_idx_between_1_depth_plus_1; - init_idx_between_depth_plus_6_depth_plus_7; - init_idx_between_3_min_depth_4_plus_3; - init_idx_between_3_depth_plus_3; - init_idx_between_depth_plus_5_depth_plus_6; - init_idx_between_2_min_depth_4_plus_2; - init_idx_between_6_depth_plus_6; - init_idx_between_depth_plus_7_depth_plus_8; - init_iter_limit; - } - while cond_reg.out { - static par { - static par { - static par { - static if idx_between_0_depth_plus_0_reg.out { - static par { - l0_move; - l0_idx_update; - t0_move; - t0_idx_update; - } - } - static if idx_between_1_min_depth_4_plus_1_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_1_depth_plus_1_reg.out { - static par { - pe_0_0_down_move; - pe_0_0_right_move; - } - } - static if idx_between_5_depth_plus_5_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_5_depth_plus_6_reg.out { - static par { - pe_0_0_out_write; - } - } - } - static par { - static if idx_between_1_depth_plus_1_reg.out { - static par { - t1_move; - t1_idx_update; - } - } - static if idx_between_2_min_depth_4_plus_2_reg.out { - static par { - static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd0)(); - } - } - static if idx_between_2_depth_plus_2_reg.out { - static par { - pe_0_1_down_move; - } - } - static if idx_between_6_depth_plus_6_reg.out { - static par { - static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_6_depth_plus_7_reg.out { - static par { - pe_0_1_out_write; - } - } - } - static par { - static if idx_between_1_depth_plus_1_reg.out { - static par { - l1_move; - l1_idx_update; - } - } - static if idx_between_2_min_depth_4_plus_2_reg.out { - static par { - static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_2_depth_plus_2_reg.out { - static par { - pe_1_0_right_move; - } - } - static if idx_between_6_depth_plus_6_reg.out { - static par { - static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_6_depth_plus_7_reg.out { - static par { - pe_1_0_out_write; - } - } - } - static par { - static if idx_between_3_min_depth_4_plus_3_reg.out { - static par { - static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd0)(); - } - } - static if idx_between_7_depth_plus_7_reg.out { - static par { - static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_7_depth_plus_8_reg.out { - static par { - pe_1_1_out_write; - } - } - } - } - static par { - incr_idx; - lt_iter_limit_group; - idx_between_5_depth_plus_5_group; - idx_between_2_depth_plus_2_group; - idx_between_7_depth_plus_7_group; - idx_between_0_depth_plus_0_group; - idx_between_1_min_depth_4_plus_1_group; - idx_between_1_depth_plus_1_group; - idx_between_depth_plus_6_depth_plus_7_group; - idx_between_3_min_depth_4_plus_3_group; - idx_between_3_depth_plus_3_group; - idx_between_depth_plus_5_depth_plus_6_group; - idx_between_2_min_depth_4_plus_2_group; - idx_between_6_depth_plus_6_group; - idx_between_depth_plus_7_depth_plus_8_group; - depth_plus_5_group; - depth_plus_2_group; - depth_plus_7_group; - depth_plus_0_group; - min_depth_4_plus_1_group; - depth_plus_1_group; - depth_plus_6_group; - min_depth_4_plus_3_group; - depth_plus_3_group; - min_depth_4_plus_2_group; - depth_plus_8_group; - } - } - } - } - } -} -component main() -> () { - cells { - systolic_array = systolic_array_comp(); - @external t0 = std_mem_d1(32, 3, 2); - @external t1 = std_mem_d1(32, 3, 2); - @external l0 = std_mem_d1(32, 3, 2); - @external l1 = std_mem_d1(32, 3, 2); - @external out_mem_0 = std_mem_d1(32, 2, 32); - @external out_mem_1 = std_mem_d1(32, 2, 32); - } - wires { - - } - control { - invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, t1_read_data=t1.read_data, l0_read_data=l0.read_data, l1_read_data=l1.read_data)(t0_addr0=t0.addr0, t1_addr0=t1.addr0, l0_addr0=l0.addr0, l1_addr0=l1.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en, out_mem_1_addr0=out_mem_1.addr0, out_mem_1_write_data=out_mem_1.write_data, out_mem_1_write_en=out_mem_1.write_en); - } -} -metadata #{ -0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) -1: pe_0_1 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) -2: pe_1_0 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) -3: pe_1_1 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) -}# diff --git a/tests/frontend/systolic/array-2.systolic b/tests/frontend/systolic/array-2.systolic deleted file mode 100644 index f04951f74..000000000 --- a/tests/frontend/systolic/array-2.systolic +++ /dev/null @@ -1,6 +0,0 @@ -{ - "top_length": 2, - "top_depth": 3, - "left_length": 2, - "left_depth": 3 -} diff --git a/tests/frontend/systolic/array-3.expect b/tests/frontend/systolic/array-3.expect deleted file mode 100644 index 580d914d0..000000000 --- a/tests/frontend/systolic/array-3.expect +++ /dev/null @@ -1,1065 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -import "primitives/pipelined.futil"; -static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { - cells { - acc = std_reg(32); - add = std_add(32); - mul = pipelined_mult(); - } - wires { - static<1> group do_add { - add.left = acc.out; - add.right = mul.out; - acc.in = add.out; - acc.write_en = mul_ready; - } - static<1> group do_mul { - mul.left = top; - mul.right = left; - } - out = acc.out; - } - control { - static par { - do_add; - do_mul; - } - } -} -component systolic_array_comp(depth: 32, t0_read_data: 32, t1_read_data: 32, t2_read_data: 32, l0_read_data: 32, l1_read_data: 32, l2_read_data: 32) -> (t0_addr0: 2, t1_addr0: 2, t2_addr0: 2, l0_addr0: 2, l1_addr0: 2, l2_addr0: 2, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1, out_mem_1_addr0: 32, out_mem_1_write_data: 32, out_mem_1_write_en: 1, out_mem_2_addr0: 32, out_mem_2_write_data: 32, out_mem_2_write_en: 1) { - cells { - min_depth_4 = std_reg(32); - lt_depth_4 = std_lt(32); - iter_limit = std_reg(32); - iter_limit_add = std_add(32); - depth_plus_8 = std_add(32); - depth_plus_9 = std_add(32); - min_depth_4_plus_2 = std_add(32); - depth_plus_2 = std_add(32); - depth_plus_7 = std_add(32); - depth_plus_3 = std_add(32); - min_depth_4_plus_3 = std_add(32); - depth_plus_5 = std_add(32); - depth_plus_6 = std_add(32); - depth_plus_10 = std_add(32); - depth_plus_4 = std_add(32); - min_depth_4_plus_4 = std_add(32); - min_depth_4_plus_5 = std_add(32); - depth_plus_0 = std_add(32); - depth_plus_1 = std_add(32); - min_depth_4_plus_1 = std_add(32); - pe_0_0 = mac_pe(); - top_0_0 = std_reg(32); - left_0_0 = std_reg(32); - pe_0_1 = mac_pe(); - top_0_1 = std_reg(32); - left_0_1 = std_reg(32); - pe_0_2 = mac_pe(); - top_0_2 = std_reg(32); - left_0_2 = std_reg(32); - pe_1_0 = mac_pe(); - top_1_0 = std_reg(32); - left_1_0 = std_reg(32); - pe_1_1 = mac_pe(); - top_1_1 = std_reg(32); - left_1_1 = std_reg(32); - pe_1_2 = mac_pe(); - top_1_2 = std_reg(32); - left_1_2 = std_reg(32); - pe_2_0 = mac_pe(); - top_2_0 = std_reg(32); - left_2_0 = std_reg(32); - pe_2_1 = mac_pe(); - top_2_1 = std_reg(32); - left_2_1 = std_reg(32); - pe_2_2 = mac_pe(); - top_2_2 = std_reg(32); - left_2_2 = std_reg(32); - t0_idx = std_reg(2); - t0_add = std_add(2); - t1_idx = std_reg(2); - t1_add = std_add(2); - t2_idx = std_reg(2); - t2_add = std_add(2); - l0_idx = std_reg(2); - l0_add = std_add(2); - l1_idx = std_reg(2); - l1_add = std_add(2); - l2_idx = std_reg(2); - l2_add = std_add(2); - idx = std_reg(32); - idx_add = std_add(32); - cond_reg = std_reg(1); - lt_iter_limit = std_lt(32); - idx_between_depth_plus_8_depth_plus_9_reg = std_reg(1); - index_lt_depth_plus_9 = std_lt(32); - index_ge_depth_plus_8 = std_ge(32); - idx_between_depth_plus_8_depth_plus_9_comb = std_and(1); - idx_between_2_min_depth_4_plus_2_reg = std_reg(1); - index_lt_min_depth_4_plus_2 = std_lt(32); - index_ge_2 = std_ge(32); - idx_between_2_min_depth_4_plus_2_comb = std_and(1); - idx_between_2_depth_plus_2_reg = std_reg(1); - index_lt_depth_plus_2 = std_lt(32); - idx_between_2_depth_plus_2_comb = std_and(1); - idx_between_7_depth_plus_7_reg = std_reg(1); - index_lt_depth_plus_7 = std_lt(32); - index_ge_7 = std_ge(32); - idx_between_7_depth_plus_7_comb = std_and(1); - idx_between_3_depth_plus_3_reg = std_reg(1); - index_lt_depth_plus_3 = std_lt(32); - index_ge_3 = std_ge(32); - idx_between_3_depth_plus_3_comb = std_and(1); - idx_between_3_min_depth_4_plus_3_reg = std_reg(1); - index_lt_min_depth_4_plus_3 = std_lt(32); - idx_between_3_min_depth_4_plus_3_comb = std_and(1); - idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); - index_lt_depth_plus_6 = std_lt(32); - index_ge_depth_plus_5 = std_ge(32); - idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); - idx_between_depth_plus_9_depth_plus_10_reg = std_reg(1); - index_lt_depth_plus_10 = std_lt(32); - index_ge_depth_plus_9 = std_ge(32); - idx_between_depth_plus_9_depth_plus_10_comb = std_and(1); - idx_between_8_depth_plus_8_reg = std_reg(1); - index_lt_depth_plus_8 = std_lt(32); - index_ge_8 = std_ge(32); - idx_between_8_depth_plus_8_comb = std_and(1); - idx_between_depth_plus_6_depth_plus_7_reg = std_reg(1); - index_ge_depth_plus_6 = std_ge(32); - idx_between_depth_plus_6_depth_plus_7_comb = std_and(1); - idx_between_4_depth_plus_4_reg = std_reg(1); - index_lt_depth_plus_4 = std_lt(32); - index_ge_4 = std_ge(32); - idx_between_4_depth_plus_4_comb = std_and(1); - idx_between_4_min_depth_4_plus_4_reg = std_reg(1); - index_lt_min_depth_4_plus_4 = std_lt(32); - idx_between_4_min_depth_4_plus_4_comb = std_and(1); - idx_between_5_min_depth_4_plus_5_reg = std_reg(1); - index_lt_min_depth_4_plus_5 = std_lt(32); - index_ge_5 = std_ge(32); - idx_between_5_min_depth_4_plus_5_comb = std_and(1); - idx_between_5_depth_plus_5_reg = std_reg(1); - index_lt_depth_plus_5 = std_lt(32); - idx_between_5_depth_plus_5_comb = std_and(1); - idx_between_0_depth_plus_0_reg = std_reg(1); - index_lt_depth_plus_0 = std_lt(32); - idx_between_9_depth_plus_9_reg = std_reg(1); - index_ge_9 = std_ge(32); - idx_between_9_depth_plus_9_comb = std_and(1); - idx_between_1_depth_plus_1_reg = std_reg(1); - index_lt_depth_plus_1 = std_lt(32); - index_ge_1 = std_ge(32); - idx_between_1_depth_plus_1_comb = std_and(1); - idx_between_1_min_depth_4_plus_1_reg = std_reg(1); - index_lt_min_depth_4_plus_1 = std_lt(32); - idx_between_1_min_depth_4_plus_1_comb = std_and(1); - idx_between_6_depth_plus_6_reg = std_reg(1); - index_ge_6 = std_ge(32); - idx_between_6_depth_plus_6_comb = std_and(1); - idx_between_depth_plus_7_depth_plus_8_reg = std_reg(1); - index_ge_depth_plus_7 = std_ge(32); - idx_between_depth_plus_7_depth_plus_8_comb = std_and(1); - } - wires { - static<1> group init_min_depth { - lt_depth_4.left = depth; - lt_depth_4.right = 32'd4; - min_depth_4.in = lt_depth_4.out ? depth; - min_depth_4.in = !lt_depth_4.out ? 32'd4; - min_depth_4.write_en = 1'd1; - } - static<1> group init_iter_limit { - iter_limit_add.left = 32'd10; - iter_limit_add.right = depth; - iter_limit.in = iter_limit_add.out; - iter_limit.write_en = 1'd1; - } - static<1> group depth_plus_8_group { - depth_plus_8.left = depth; - depth_plus_8.right = 32'd8; - } - static<1> group depth_plus_9_group { - depth_plus_9.left = depth; - depth_plus_9.right = 32'd9; - } - static<1> group min_depth_4_plus_2_group { - min_depth_4_plus_2.left = min_depth_4.out; - min_depth_4_plus_2.right = 32'd2; - } - static<1> group depth_plus_2_group { - depth_plus_2.left = depth; - depth_plus_2.right = 32'd2; - } - static<1> group depth_plus_7_group { - depth_plus_7.left = depth; - depth_plus_7.right = 32'd7; - } - static<1> group depth_plus_3_group { - depth_plus_3.left = depth; - depth_plus_3.right = 32'd3; - } - static<1> group min_depth_4_plus_3_group { - min_depth_4_plus_3.left = min_depth_4.out; - min_depth_4_plus_3.right = 32'd3; - } - static<1> group depth_plus_5_group { - depth_plus_5.left = depth; - depth_plus_5.right = 32'd5; - } - static<1> group depth_plus_6_group { - depth_plus_6.left = depth; - depth_plus_6.right = 32'd6; - } - static<1> group depth_plus_10_group { - depth_plus_10.left = depth; - depth_plus_10.right = 32'd10; - } - static<1> group depth_plus_4_group { - depth_plus_4.left = depth; - depth_plus_4.right = 32'd4; - } - static<1> group min_depth_4_plus_4_group { - min_depth_4_plus_4.left = min_depth_4.out; - min_depth_4_plus_4.right = 32'd4; - } - static<1> group min_depth_4_plus_5_group { - min_depth_4_plus_5.left = min_depth_4.out; - min_depth_4_plus_5.right = 32'd5; - } - static<1> group depth_plus_0_group { - depth_plus_0.left = depth; - depth_plus_0.right = 32'd0; - } - static<1> group depth_plus_1_group { - depth_plus_1.left = depth; - depth_plus_1.right = 32'd1; - } - static<1> group min_depth_4_plus_1_group { - min_depth_4_plus_1.left = min_depth_4.out; - min_depth_4_plus_1.right = 32'd1; - } - static<1> group t0_idx_init { - t0_idx.in = 2'd0; - t0_idx.write_en = 1'd1; - } - static<1> group t0_idx_update { - t0_add.left = 2'd1; - t0_add.right = t0_idx.out; - t0_idx.in = t0_add.out; - t0_idx.write_en = 1'd1; - } - static<1> group t0_move { - t0_addr0 = t0_idx.out; - top_0_0.in = t0_read_data; - top_0_0.write_en = 1'd1; - } - static<1> group t1_idx_init { - t1_idx.in = 2'd0; - t1_idx.write_en = 1'd1; - } - static<1> group t1_idx_update { - t1_add.left = 2'd1; - t1_add.right = t1_idx.out; - t1_idx.in = t1_add.out; - t1_idx.write_en = 1'd1; - } - static<1> group t1_move { - t1_addr0 = t1_idx.out; - top_0_1.in = t1_read_data; - top_0_1.write_en = 1'd1; - } - static<1> group t2_idx_init { - t2_idx.in = 2'd0; - t2_idx.write_en = 1'd1; - } - static<1> group t2_idx_update { - t2_add.left = 2'd1; - t2_add.right = t2_idx.out; - t2_idx.in = t2_add.out; - t2_idx.write_en = 1'd1; - } - static<1> group t2_move { - t2_addr0 = t2_idx.out; - top_0_2.in = t2_read_data; - top_0_2.write_en = 1'd1; - } - static<1> group l0_idx_init { - l0_idx.in = 2'd0; - l0_idx.write_en = 1'd1; - } - static<1> group l0_idx_update { - l0_add.left = 2'd1; - l0_add.right = l0_idx.out; - l0_idx.in = l0_add.out; - l0_idx.write_en = 1'd1; - } - static<1> group l0_move { - l0_addr0 = l0_idx.out; - left_0_0.in = l0_read_data; - left_0_0.write_en = 1'd1; - } - static<1> group l1_idx_init { - l1_idx.in = 2'd0; - l1_idx.write_en = 1'd1; - } - static<1> group l1_idx_update { - l1_add.left = 2'd1; - l1_add.right = l1_idx.out; - l1_idx.in = l1_add.out; - l1_idx.write_en = 1'd1; - } - static<1> group l1_move { - l1_addr0 = l1_idx.out; - left_1_0.in = l1_read_data; - left_1_0.write_en = 1'd1; - } - static<1> group l2_idx_init { - l2_idx.in = 2'd0; - l2_idx.write_en = 1'd1; - } - static<1> group l2_idx_update { - l2_add.left = 2'd1; - l2_add.right = l2_idx.out; - l2_idx.in = l2_add.out; - l2_idx.write_en = 1'd1; - } - static<1> group l2_move { - l2_addr0 = l2_idx.out; - left_2_0.in = l2_read_data; - left_2_0.write_en = 1'd1; - } - static<1> group pe_0_0_right_move { - left_0_1.in = left_0_0.out; - left_0_1.write_en = 1'd1; - } - static<1> group pe_0_0_down_move { - top_1_0.in = top_0_0.out; - top_1_0.write_en = 1'd1; - } - static<1> group pe_0_0_out_write { - out_mem_0_addr0 = 32'd0; - out_mem_0_write_data = pe_0_0.out; - out_mem_0_write_en = 1'd1; - } - static<1> group pe_0_1_right_move { - left_0_2.in = left_0_1.out; - left_0_2.write_en = 1'd1; - } - static<1> group pe_0_1_down_move { - top_1_1.in = top_0_1.out; - top_1_1.write_en = 1'd1; - } - static<1> group pe_0_1_out_write { - out_mem_0_addr0 = 32'd1; - out_mem_0_write_data = pe_0_1.out; - out_mem_0_write_en = 1'd1; - } - static<1> group pe_0_2_down_move { - top_1_2.in = top_0_2.out; - top_1_2.write_en = 1'd1; - } - static<1> group pe_0_2_out_write { - out_mem_0_addr0 = 32'd2; - out_mem_0_write_data = pe_0_2.out; - out_mem_0_write_en = 1'd1; - } - static<1> group pe_1_0_right_move { - left_1_1.in = left_1_0.out; - left_1_1.write_en = 1'd1; - } - static<1> group pe_1_0_down_move { - top_2_0.in = top_1_0.out; - top_2_0.write_en = 1'd1; - } - static<1> group pe_1_0_out_write { - out_mem_1_addr0 = 32'd0; - out_mem_1_write_data = pe_1_0.out; - out_mem_1_write_en = 1'd1; - } - static<1> group pe_1_1_right_move { - left_1_2.in = left_1_1.out; - left_1_2.write_en = 1'd1; - } - static<1> group pe_1_1_down_move { - top_2_1.in = top_1_1.out; - top_2_1.write_en = 1'd1; - } - static<1> group pe_1_1_out_write { - out_mem_1_addr0 = 32'd1; - out_mem_1_write_data = pe_1_1.out; - out_mem_1_write_en = 1'd1; - } - static<1> group pe_1_2_down_move { - top_2_2.in = top_1_2.out; - top_2_2.write_en = 1'd1; - } - static<1> group pe_1_2_out_write { - out_mem_1_addr0 = 32'd2; - out_mem_1_write_data = pe_1_2.out; - out_mem_1_write_en = 1'd1; - } - static<1> group pe_2_0_right_move { - left_2_1.in = left_2_0.out; - left_2_1.write_en = 1'd1; - } - static<1> group pe_2_0_out_write { - out_mem_2_addr0 = 32'd0; - out_mem_2_write_data = pe_2_0.out; - out_mem_2_write_en = 1'd1; - } - static<1> group pe_2_1_right_move { - left_2_2.in = left_2_1.out; - left_2_2.write_en = 1'd1; - } - static<1> group pe_2_1_out_write { - out_mem_2_addr0 = 32'd1; - out_mem_2_write_data = pe_2_1.out; - out_mem_2_write_en = 1'd1; - } - static<1> group pe_2_2_out_write { - out_mem_2_addr0 = 32'd2; - out_mem_2_write_data = pe_2_2.out; - out_mem_2_write_en = 1'd1; - } - static<1> group init_idx { - idx.in = 32'd0; - idx.write_en = 1'd1; - } - static<1> group incr_idx { - idx_add.left = idx.out; - idx_add.right = 32'd1; - idx.in = idx_add.out; - idx.write_en = 1'd1; - } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } - static<1> group lt_iter_limit_group { - lt_iter_limit.left = idx_add.out; - lt_iter_limit.right = iter_limit.out; - cond_reg.in = lt_iter_limit.out; - cond_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_8_depth_plus_9_group { - index_ge_depth_plus_8.left = idx_add.out; - index_ge_depth_plus_8.right = depth_plus_8.out; - index_lt_depth_plus_9.left = idx_add.out; - index_lt_depth_plus_9.right = depth_plus_9.out; - idx_between_depth_plus_8_depth_plus_9_comb.left = index_ge_depth_plus_8.out; - idx_between_depth_plus_8_depth_plus_9_comb.right = index_lt_depth_plus_9.out; - idx_between_depth_plus_8_depth_plus_9_reg.in = idx_between_depth_plus_8_depth_plus_9_comb.out; - idx_between_depth_plus_8_depth_plus_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_8_depth_plus_9 { - idx_between_depth_plus_8_depth_plus_9_reg.in = 1'd0; - idx_between_depth_plus_8_depth_plus_9_reg.write_en = 1'd1; - } - static<1> group idx_between_2_min_depth_4_plus_2_group { - index_ge_2.left = idx_add.out; - index_ge_2.right = 32'd2; - index_lt_min_depth_4_plus_2.left = idx_add.out; - index_lt_min_depth_4_plus_2.right = min_depth_4_plus_2.out; - idx_between_2_min_depth_4_plus_2_comb.left = index_ge_2.out; - idx_between_2_min_depth_4_plus_2_comb.right = index_lt_min_depth_4_plus_2.out; - idx_between_2_min_depth_4_plus_2_reg.in = idx_between_2_min_depth_4_plus_2_comb.out; - idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_min_depth_4_plus_2 { - idx_between_2_min_depth_4_plus_2_reg.in = 1'd0; - idx_between_2_min_depth_4_plus_2_reg.write_en = 1'd1; - } - static<1> group idx_between_2_depth_plus_2_group { - index_ge_2.left = idx_add.out; - index_ge_2.right = 32'd2; - index_lt_depth_plus_2.left = idx_add.out; - index_lt_depth_plus_2.right = depth_plus_2.out; - idx_between_2_depth_plus_2_comb.left = index_ge_2.out; - idx_between_2_depth_plus_2_comb.right = index_lt_depth_plus_2.out; - idx_between_2_depth_plus_2_reg.in = idx_between_2_depth_plus_2_comb.out; - idx_between_2_depth_plus_2_reg.write_en = 1'd1; - } - static<1> group init_idx_between_2_depth_plus_2 { - idx_between_2_depth_plus_2_reg.in = 1'd0; - idx_between_2_depth_plus_2_reg.write_en = 1'd1; - } - static<1> group idx_between_7_depth_plus_7_group { - index_ge_7.left = idx_add.out; - index_ge_7.right = 32'd7; - index_lt_depth_plus_7.left = idx_add.out; - index_lt_depth_plus_7.right = depth_plus_7.out; - idx_between_7_depth_plus_7_comb.left = index_ge_7.out; - idx_between_7_depth_plus_7_comb.right = index_lt_depth_plus_7.out; - idx_between_7_depth_plus_7_reg.in = idx_between_7_depth_plus_7_comb.out; - idx_between_7_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group init_idx_between_7_depth_plus_7 { - idx_between_7_depth_plus_7_reg.in = 1'd0; - idx_between_7_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group idx_between_3_depth_plus_3_group { - index_ge_3.left = idx_add.out; - index_ge_3.right = 32'd3; - index_lt_depth_plus_3.left = idx_add.out; - index_lt_depth_plus_3.right = depth_plus_3.out; - idx_between_3_depth_plus_3_comb.left = index_ge_3.out; - idx_between_3_depth_plus_3_comb.right = index_lt_depth_plus_3.out; - idx_between_3_depth_plus_3_reg.in = idx_between_3_depth_plus_3_comb.out; - idx_between_3_depth_plus_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_depth_plus_3 { - idx_between_3_depth_plus_3_reg.in = 1'd0; - idx_between_3_depth_plus_3_reg.write_en = 1'd1; - } - static<1> group idx_between_3_min_depth_4_plus_3_group { - index_ge_3.left = idx_add.out; - index_ge_3.right = 32'd3; - index_lt_min_depth_4_plus_3.left = idx_add.out; - index_lt_min_depth_4_plus_3.right = min_depth_4_plus_3.out; - idx_between_3_min_depth_4_plus_3_comb.left = index_ge_3.out; - idx_between_3_min_depth_4_plus_3_comb.right = index_lt_min_depth_4_plus_3.out; - idx_between_3_min_depth_4_plus_3_reg.in = idx_between_3_min_depth_4_plus_3_comb.out; - idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; - } - static<1> group init_idx_between_3_min_depth_4_plus_3 { - idx_between_3_min_depth_4_plus_3_reg.in = 1'd0; - idx_between_3_min_depth_4_plus_3_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_5_depth_plus_6_group { - index_ge_depth_plus_5.left = idx_add.out; - index_ge_depth_plus_5.right = depth_plus_5.out; - index_lt_depth_plus_6.left = idx_add.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; - idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_5_depth_plus_6 { - idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_9_depth_plus_10_group { - index_ge_depth_plus_9.left = idx_add.out; - index_ge_depth_plus_9.right = depth_plus_9.out; - index_lt_depth_plus_10.left = idx_add.out; - index_lt_depth_plus_10.right = depth_plus_10.out; - idx_between_depth_plus_9_depth_plus_10_comb.left = index_ge_depth_plus_9.out; - idx_between_depth_plus_9_depth_plus_10_comb.right = index_lt_depth_plus_10.out; - idx_between_depth_plus_9_depth_plus_10_reg.in = idx_between_depth_plus_9_depth_plus_10_comb.out; - idx_between_depth_plus_9_depth_plus_10_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_9_depth_plus_10 { - idx_between_depth_plus_9_depth_plus_10_reg.in = 1'd0; - idx_between_depth_plus_9_depth_plus_10_reg.write_en = 1'd1; - } - static<1> group idx_between_8_depth_plus_8_group { - index_ge_8.left = idx_add.out; - index_ge_8.right = 32'd8; - index_lt_depth_plus_8.left = idx_add.out; - index_lt_depth_plus_8.right = depth_plus_8.out; - idx_between_8_depth_plus_8_comb.left = index_ge_8.out; - idx_between_8_depth_plus_8_comb.right = index_lt_depth_plus_8.out; - idx_between_8_depth_plus_8_reg.in = idx_between_8_depth_plus_8_comb.out; - idx_between_8_depth_plus_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_8_depth_plus_8 { - idx_between_8_depth_plus_8_reg.in = 1'd0; - idx_between_8_depth_plus_8_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_6_depth_plus_7_group { - index_ge_depth_plus_6.left = idx_add.out; - index_ge_depth_plus_6.right = depth_plus_6.out; - index_lt_depth_plus_7.left = idx_add.out; - index_lt_depth_plus_7.right = depth_plus_7.out; - idx_between_depth_plus_6_depth_plus_7_comb.left = index_ge_depth_plus_6.out; - idx_between_depth_plus_6_depth_plus_7_comb.right = index_lt_depth_plus_7.out; - idx_between_depth_plus_6_depth_plus_7_reg.in = idx_between_depth_plus_6_depth_plus_7_comb.out; - idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_6_depth_plus_7 { - idx_between_depth_plus_6_depth_plus_7_reg.in = 1'd0; - idx_between_depth_plus_6_depth_plus_7_reg.write_en = 1'd1; - } - static<1> group idx_between_4_depth_plus_4_group { - index_ge_4.left = idx_add.out; - index_ge_4.right = 32'd4; - index_lt_depth_plus_4.left = idx_add.out; - index_lt_depth_plus_4.right = depth_plus_4.out; - idx_between_4_depth_plus_4_comb.left = index_ge_4.out; - idx_between_4_depth_plus_4_comb.right = index_lt_depth_plus_4.out; - idx_between_4_depth_plus_4_reg.in = idx_between_4_depth_plus_4_comb.out; - idx_between_4_depth_plus_4_reg.write_en = 1'd1; - } - static<1> group init_idx_between_4_depth_plus_4 { - idx_between_4_depth_plus_4_reg.in = 1'd0; - idx_between_4_depth_plus_4_reg.write_en = 1'd1; - } - static<1> group idx_between_4_min_depth_4_plus_4_group { - index_ge_4.left = idx_add.out; - index_ge_4.right = 32'd4; - index_lt_min_depth_4_plus_4.left = idx_add.out; - index_lt_min_depth_4_plus_4.right = min_depth_4_plus_4.out; - idx_between_4_min_depth_4_plus_4_comb.left = index_ge_4.out; - idx_between_4_min_depth_4_plus_4_comb.right = index_lt_min_depth_4_plus_4.out; - idx_between_4_min_depth_4_plus_4_reg.in = idx_between_4_min_depth_4_plus_4_comb.out; - idx_between_4_min_depth_4_plus_4_reg.write_en = 1'd1; - } - static<1> group init_idx_between_4_min_depth_4_plus_4 { - idx_between_4_min_depth_4_plus_4_reg.in = 1'd0; - idx_between_4_min_depth_4_plus_4_reg.write_en = 1'd1; - } - static<1> group idx_between_5_min_depth_4_plus_5_group { - index_ge_5.left = idx_add.out; - index_ge_5.right = 32'd5; - index_lt_min_depth_4_plus_5.left = idx_add.out; - index_lt_min_depth_4_plus_5.right = min_depth_4_plus_5.out; - idx_between_5_min_depth_4_plus_5_comb.left = index_ge_5.out; - idx_between_5_min_depth_4_plus_5_comb.right = index_lt_min_depth_4_plus_5.out; - idx_between_5_min_depth_4_plus_5_reg.in = idx_between_5_min_depth_4_plus_5_comb.out; - idx_between_5_min_depth_4_plus_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_min_depth_4_plus_5 { - idx_between_5_min_depth_4_plus_5_reg.in = 1'd0; - idx_between_5_min_depth_4_plus_5_reg.write_en = 1'd1; - } - static<1> group idx_between_5_depth_plus_5_group { - index_ge_5.left = idx_add.out; - index_ge_5.right = 32'd5; - index_lt_depth_plus_5.left = idx_add.out; - index_lt_depth_plus_5.right = depth_plus_5.out; - idx_between_5_depth_plus_5_comb.left = index_ge_5.out; - idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; - idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_depth_plus_5 { - idx_between_5_depth_plus_5_reg.in = 1'd0; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group idx_between_0_depth_plus_0_group { - index_lt_depth_plus_0.left = idx_add.out; - index_lt_depth_plus_0.right = depth_plus_0.out; - idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_depth_plus_0 { - idx_between_0_depth_plus_0_reg.in = 1'd1; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group idx_between_9_depth_plus_9_group { - index_ge_9.left = idx_add.out; - index_ge_9.right = 32'd9; - index_lt_depth_plus_9.left = idx_add.out; - index_lt_depth_plus_9.right = depth_plus_9.out; - idx_between_9_depth_plus_9_comb.left = index_ge_9.out; - idx_between_9_depth_plus_9_comb.right = index_lt_depth_plus_9.out; - idx_between_9_depth_plus_9_reg.in = idx_between_9_depth_plus_9_comb.out; - idx_between_9_depth_plus_9_reg.write_en = 1'd1; - } - static<1> group init_idx_between_9_depth_plus_9 { - idx_between_9_depth_plus_9_reg.in = 1'd0; - idx_between_9_depth_plus_9_reg.write_en = 1'd1; - } - static<1> group idx_between_1_depth_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_depth_plus_1.left = idx_add.out; - index_lt_depth_plus_1.right = depth_plus_1.out; - idx_between_1_depth_plus_1_comb.left = index_ge_1.out; - idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; - idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_depth_plus_1 { - idx_between_1_depth_plus_1_reg.in = 1'd0; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_1_min_depth_4_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_min_depth_4_plus_1.left = idx_add.out; - index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; - idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_min_depth_4_plus_1 { - idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_6_depth_plus_6_group { - index_ge_6.left = idx_add.out; - index_ge_6.right = 32'd6; - index_lt_depth_plus_6.left = idx_add.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_6_depth_plus_6_comb.left = index_ge_6.out; - idx_between_6_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_6_depth_plus_6_reg.in = idx_between_6_depth_plus_6_comb.out; - idx_between_6_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_6_depth_plus_6 { - idx_between_6_depth_plus_6_reg.in = 1'd0; - idx_between_6_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_7_depth_plus_8_group { - index_ge_depth_plus_7.left = idx_add.out; - index_ge_depth_plus_7.right = depth_plus_7.out; - index_lt_depth_plus_8.left = idx_add.out; - index_lt_depth_plus_8.right = depth_plus_8.out; - idx_between_depth_plus_7_depth_plus_8_comb.left = index_ge_depth_plus_7.out; - idx_between_depth_plus_7_depth_plus_8_comb.right = index_lt_depth_plus_8.out; - idx_between_depth_plus_7_depth_plus_8_reg.in = idx_between_depth_plus_7_depth_plus_8_comb.out; - idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_7_depth_plus_8 { - idx_between_depth_plus_7_depth_plus_8_reg.in = 1'd0; - idx_between_depth_plus_7_depth_plus_8_reg.write_en = 1'd1; - } - } - control { - seq { - static par { - t0_idx_init; - t1_idx_init; - t2_idx_init; - l0_idx_init; - l1_idx_init; - l2_idx_init; - init_idx; - init_min_depth; - init_cond_reg; - init_idx_between_depth_plus_8_depth_plus_9; - init_idx_between_2_min_depth_4_plus_2; - init_idx_between_2_depth_plus_2; - init_idx_between_7_depth_plus_7; - init_idx_between_3_depth_plus_3; - init_idx_between_3_min_depth_4_plus_3; - init_idx_between_depth_plus_5_depth_plus_6; - init_idx_between_depth_plus_9_depth_plus_10; - init_idx_between_8_depth_plus_8; - init_idx_between_depth_plus_6_depth_plus_7; - init_idx_between_4_depth_plus_4; - init_idx_between_4_min_depth_4_plus_4; - init_idx_between_5_min_depth_4_plus_5; - init_idx_between_5_depth_plus_5; - init_idx_between_0_depth_plus_0; - init_idx_between_9_depth_plus_9; - init_idx_between_1_depth_plus_1; - init_idx_between_1_min_depth_4_plus_1; - init_idx_between_6_depth_plus_6; - init_idx_between_depth_plus_7_depth_plus_8; - init_iter_limit; - } - while cond_reg.out { - static par { - static par { - static par { - static if idx_between_0_depth_plus_0_reg.out { - static par { - l0_move; - l0_idx_update; - t0_move; - t0_idx_update; - } - } - static if idx_between_1_min_depth_4_plus_1_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_1_depth_plus_1_reg.out { - static par { - pe_0_0_down_move; - pe_0_0_right_move; - } - } - static if idx_between_5_depth_plus_5_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_5_depth_plus_6_reg.out { - static par { - pe_0_0_out_write; - } - } - } - static par { - static if idx_between_1_depth_plus_1_reg.out { - static par { - t1_move; - t1_idx_update; - } - } - static if idx_between_2_min_depth_4_plus_2_reg.out { - static par { - static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd0)(); - } - } - static if idx_between_2_depth_plus_2_reg.out { - static par { - pe_0_1_down_move; - pe_0_1_right_move; - } - } - static if idx_between_6_depth_plus_6_reg.out { - static par { - static invoke pe_0_1(top=top_0_1.out, left=left_0_1.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_6_depth_plus_7_reg.out { - static par { - pe_0_1_out_write; - } - } - } - static par { - static if idx_between_2_depth_plus_2_reg.out { - static par { - t2_move; - t2_idx_update; - } - } - static if idx_between_3_min_depth_4_plus_3_reg.out { - static par { - static invoke pe_0_2(top=top_0_2.out, left=left_0_2.out, mul_ready=1'd0)(); - } - } - static if idx_between_3_depth_plus_3_reg.out { - static par { - pe_0_2_down_move; - } - } - static if idx_between_7_depth_plus_7_reg.out { - static par { - static invoke pe_0_2(top=top_0_2.out, left=left_0_2.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_7_depth_plus_8_reg.out { - static par { - pe_0_2_out_write; - } - } - } - static par { - static if idx_between_1_depth_plus_1_reg.out { - static par { - l1_move; - l1_idx_update; - } - } - static if idx_between_2_min_depth_4_plus_2_reg.out { - static par { - static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_2_depth_plus_2_reg.out { - static par { - pe_1_0_down_move; - pe_1_0_right_move; - } - } - static if idx_between_6_depth_plus_6_reg.out { - static par { - static invoke pe_1_0(top=top_1_0.out, left=left_1_0.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_6_depth_plus_7_reg.out { - static par { - pe_1_0_out_write; - } - } - } - static par { - static if idx_between_3_min_depth_4_plus_3_reg.out { - static par { - static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd0)(); - } - } - static if idx_between_3_depth_plus_3_reg.out { - static par { - pe_1_1_down_move; - pe_1_1_right_move; - } - } - static if idx_between_7_depth_plus_7_reg.out { - static par { - static invoke pe_1_1(top=top_1_1.out, left=left_1_1.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_7_depth_plus_8_reg.out { - static par { - pe_1_1_out_write; - } - } - } - static par { - static if idx_between_4_min_depth_4_plus_4_reg.out { - static par { - static invoke pe_1_2(top=top_1_2.out, left=left_1_2.out, mul_ready=1'd0)(); - } - } - static if idx_between_4_depth_plus_4_reg.out { - static par { - pe_1_2_down_move; - } - } - static if idx_between_8_depth_plus_8_reg.out { - static par { - static invoke pe_1_2(top=top_1_2.out, left=left_1_2.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_8_depth_plus_9_reg.out { - static par { - pe_1_2_out_write; - } - } - } - static par { - static if idx_between_2_depth_plus_2_reg.out { - static par { - l2_move; - l2_idx_update; - } - } - static if idx_between_3_min_depth_4_plus_3_reg.out { - static par { - static invoke pe_2_0(top=top_2_0.out, left=left_2_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_3_depth_plus_3_reg.out { - static par { - pe_2_0_right_move; - } - } - static if idx_between_7_depth_plus_7_reg.out { - static par { - static invoke pe_2_0(top=top_2_0.out, left=left_2_0.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_7_depth_plus_8_reg.out { - static par { - pe_2_0_out_write; - } - } - } - static par { - static if idx_between_4_min_depth_4_plus_4_reg.out { - static par { - static invoke pe_2_1(top=top_2_1.out, left=left_2_1.out, mul_ready=1'd0)(); - } - } - static if idx_between_4_depth_plus_4_reg.out { - static par { - pe_2_1_right_move; - } - } - static if idx_between_8_depth_plus_8_reg.out { - static par { - static invoke pe_2_1(top=top_2_1.out, left=left_2_1.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_8_depth_plus_9_reg.out { - static par { - pe_2_1_out_write; - } - } - } - static par { - static if idx_between_5_min_depth_4_plus_5_reg.out { - static par { - static invoke pe_2_2(top=top_2_2.out, left=left_2_2.out, mul_ready=1'd0)(); - } - } - static if idx_between_9_depth_plus_9_reg.out { - static par { - static invoke pe_2_2(top=top_2_2.out, left=left_2_2.out, mul_ready=1'd1)(); - } - } - static if idx_between_depth_plus_9_depth_plus_10_reg.out { - static par { - pe_2_2_out_write; - } - } - } - } - static par { - incr_idx; - lt_iter_limit_group; - idx_between_depth_plus_8_depth_plus_9_group; - idx_between_2_min_depth_4_plus_2_group; - idx_between_2_depth_plus_2_group; - idx_between_7_depth_plus_7_group; - idx_between_3_depth_plus_3_group; - idx_between_3_min_depth_4_plus_3_group; - idx_between_depth_plus_5_depth_plus_6_group; - idx_between_depth_plus_9_depth_plus_10_group; - idx_between_8_depth_plus_8_group; - idx_between_depth_plus_6_depth_plus_7_group; - idx_between_4_depth_plus_4_group; - idx_between_4_min_depth_4_plus_4_group; - idx_between_5_min_depth_4_plus_5_group; - idx_between_5_depth_plus_5_group; - idx_between_0_depth_plus_0_group; - idx_between_9_depth_plus_9_group; - idx_between_1_depth_plus_1_group; - idx_between_1_min_depth_4_plus_1_group; - idx_between_6_depth_plus_6_group; - idx_between_depth_plus_7_depth_plus_8_group; - depth_plus_8_group; - depth_plus_9_group; - min_depth_4_plus_2_group; - depth_plus_2_group; - depth_plus_7_group; - depth_plus_3_group; - min_depth_4_plus_3_group; - depth_plus_5_group; - depth_plus_6_group; - depth_plus_10_group; - depth_plus_4_group; - min_depth_4_plus_4_group; - min_depth_4_plus_5_group; - depth_plus_0_group; - depth_plus_1_group; - min_depth_4_plus_1_group; - } - } - } - } - } -} -component main() -> () { - cells { - systolic_array = systolic_array_comp(); - @external t0 = std_mem_d1(32, 3, 2); - @external t1 = std_mem_d1(32, 3, 2); - @external t2 = std_mem_d1(32, 3, 2); - @external l0 = std_mem_d1(32, 3, 2); - @external l1 = std_mem_d1(32, 3, 2); - @external l2 = std_mem_d1(32, 3, 2); - @external out_mem_0 = std_mem_d1(32, 3, 32); - @external out_mem_1 = std_mem_d1(32, 3, 32); - @external out_mem_2 = std_mem_d1(32, 3, 32); - } - wires { - - } - control { - invoke systolic_array(depth=32'd3, t0_read_data=t0.read_data, t1_read_data=t1.read_data, t2_read_data=t2.read_data, l0_read_data=l0.read_data, l1_read_data=l1.read_data, l2_read_data=l2.read_data)(t0_addr0=t0.addr0, t1_addr0=t1.addr0, t2_addr0=t2.addr0, l0_addr0=l0.addr0, l1_addr0=l1.addr0, l2_addr0=l2.addr0, out_mem_0_addr0=out_mem_0.addr0, out_mem_0_write_data=out_mem_0.write_data, out_mem_0_write_en=out_mem_0.write_en, out_mem_1_addr0=out_mem_1.addr0, out_mem_1_write_data=out_mem_1.write_data, out_mem_1_write_en=out_mem_1.write_en, out_mem_2_addr0=out_mem_2.addr0, out_mem_2_write_data=out_mem_2.write_data, out_mem_2_write_en=out_mem_2.write_en); - } -} -metadata #{ -0: pe_0_0 filling: [1,min_depth_4_plus_1) accumulating: [5 depth_plus_5) -1: pe_0_1 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) -2: pe_0_2 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) -3: pe_1_0 filling: [2,min_depth_4_plus_2) accumulating: [6 depth_plus_6) -4: pe_1_1 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) -5: pe_1_2 filling: [4,min_depth_4_plus_4) accumulating: [8 depth_plus_8) -6: pe_2_0 filling: [3,min_depth_4_plus_3) accumulating: [7 depth_plus_7) -7: pe_2_1 filling: [4,min_depth_4_plus_4) accumulating: [8 depth_plus_8) -8: pe_2_2 filling: [5,min_depth_4_plus_5) accumulating: [9 depth_plus_9) -}# diff --git a/tests/frontend/systolic/array-3.systolic b/tests/frontend/systolic/array-3.systolic deleted file mode 100644 index b412e48ef..000000000 --- a/tests/frontend/systolic/array-3.systolic +++ /dev/null @@ -1,6 +0,0 @@ -{ - "top_length": 3, - "top_depth": 3, - "left_length": 3, - "left_depth": 3 -} From e098eae23003bcdda332ca665c88e72369173c29 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Wed, 6 Sep 2023 18:21:36 -0400 Subject: [PATCH 064/189] Builder: infer more widths (#1683) --- calyx-py/calyx/builder.py | 231 ++++++++++++++++--------- calyx-py/calyx/gen_exp.py | 16 +- calyx-py/calyx/queue_call.py | 6 +- calyx-py/test/correctness/arbiter_6.py | 36 ++-- calyx-py/test/correctness/fifo.py | 22 +-- calyx-py/test/correctness/pifo.py | 28 +-- frontends/mrxl/mrxl/gen_calyx.py | 2 +- 7 files changed, 199 insertions(+), 142 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index e33f9ac81..a11cd0968 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -132,16 +132,17 @@ def control(self, builder: Union[ast.Control, ControlBuilder]): else: self.component.controls = builder - def get_port_width(self, name: str) -> int: + def port_width(self, port: ExprBuilder) -> int: + """Get the width of an expression, which may be a port of this component.""" + name = ExprBuilder.unwrap(port).item.id.name for input in self.component.inputs: if input.id.name == name: return input.width for output in self.component.outputs: if output.id.name == name: return output.width - raise NotFoundError( - f"couldn't find port {name} on component {self.component.name}" - ) + # Give up. + return None def get_cell(self, name: str) -> CellBuilder: """Retrieve a cell builder by name.""" @@ -318,7 +319,7 @@ def binary( """Generate a binary cell of the kind specified in `operation`.""" self.prog.import_("primitives/binary_operators.futil") name = name or self.generate_name(operation) - assert isinstance(name, str) + assert isinstance(name, str), f"name {name} is not a string" return self.cell(name, ast.Stdlib.op(operation, size, signed)) def add(self, size: int, name: str = None, signed: bool = False) -> CellBuilder: @@ -435,43 +436,64 @@ def binary_use(self, left, right, cell, groupname=None): cell.right = right return CellAndGroup(cell, comb_group) - def eq_use(self, left, right, width, signed=False, cellname=None): + def try_infer_width(self, width, left, right): + """If `width` is None, try to infer it from `left` or `right`. + If that fails, raise an error. + """ + width = width or self.infer_width(left) or self.infer_width(right) + if not width: + raise WidthInferenceError( + "Cannot infer widths from `left` or `right`. " + "Consider providing width as an argument." + ) + return width + + def eq_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` == `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.eq(width, cellname, signed)) - def neq_use(self, left, right, width, signed=False, cellname=None): + def neq_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` != `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.neq(width, cellname, signed)) - def lt_use(self, left, right, width, signed=False, cellname=None): + def lt_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` < `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.lt(width, cellname, signed)) - def le_use(self, left, right, width, signed=False, cellname=None): + def le_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` <= `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.le(width, cellname, signed)) - def ge_use(self, left, right, width, signed=False, cellname=None): + def ge_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` >= `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.ge(width, cellname, signed)) - def gt_use(self, left, right, width, signed=False, cellname=None): + def gt_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to check if `left` > `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.gt(width, cellname, signed)) - def add_use(self, left, right, width, signed=False, cellname=None): + def add_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to compute `left` + `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.add(width, cellname, signed)) - def sub_use(self, left, right, width, signed=False, cellname=None): + def sub_use(self, left, right, signed=False, cellname=None, width=None): """Inserts wiring into `self` to compute `left` - `right`.""" + width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.sub(width, cellname, signed)) - def bitwise_flip_reg(self, reg, width, cellname=None): + def bitwise_flip_reg(self, reg, cellname=None): """Inserts wiring into `self` to bitwise-flip the contents of `reg` and put the result back into `reg`. """ cellname = cellname or f"{reg.name}_not" + width = reg.infer_width_reg() not_cell = self.not_(width, cellname) with self.group(f"{cellname}_group") as not_group: not_cell.in_ = reg.out @@ -480,9 +502,10 @@ def bitwise_flip_reg(self, reg, width, cellname=None): not_group.done = reg.done return not_group - def incr(self, reg, width, val=1, signed=False, cellname=None): + def incr(self, reg, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" + width = reg.infer_width_reg() add_cell = self.add(width, cellname, signed) with self.group(f"{cellname}_group") as incr_group: add_cell.left = reg.out @@ -492,9 +515,10 @@ def incr(self, reg, width, val=1, signed=False, cellname=None): incr_group.done = reg.done return incr_group - def decr(self, reg, width, val=1, signed=False, cellname=None): + def decr(self, reg, val=1, signed=False, cellname=None): """Inserts wiring into `self` to perform `reg := reg - val`.""" cellname = cellname or f"{reg.name}_decr" + width = reg.infer_width_reg() sub_cell = self.sub(width, cellname, signed) with self.group(f"{cellname}_group") as decr_group: sub_cell.left = reg.out @@ -620,7 +644,7 @@ def sub_store_in_reg( ) def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None, signed=False): - """Adds wiring into `self to perform `reg := left == right`.""" + """Inserts wiring into `self` to perform `reg := left == right`.""" return self.op_store_in_reg( self.eq(width, cellname, signed), left, right, cellname, 1, ans_reg ) @@ -628,11 +652,33 @@ def eq_store_in_reg(self, left, right, cellname, width, ans_reg=None, signed=Fal def neq_store_in_reg( self, left, right, cellname, width, ans_reg=None, signed=False ): - """Adds wiring into `self to perform `reg := left != right`.""" + """Inserts wiring into `self` to perform `reg := left != right`.""" return self.op_store_in_reg( self.neq(width, cellname, signed), left, right, cellname, 1, ans_reg ) + def infer_width(self, expr) -> int: + """Infer the width of an expression.""" + if isinstance(expr, int): # We can't infer the width of an integer. + return None + if self.port_width(expr): # It's an in/out port of this component! + return self.port_width(expr) + expr = ExprBuilder.unwrap(expr) # We unwrap the expr. + if isinstance(expr, ast.Atom): # Inferring width of Atom. + if isinstance(expr.item, ast.ThisPort): # Atom is a ThisPort. + # If we can infer it from this, great, otherwise give up. + return self.port_width(expr) + # Not a ThisPort, but maybe some `cell.port`? + cell_name = expr.item.id.name + port_name = expr.item.name + cell_builder = self.index[cell_name] + if not isinstance(cell_builder, CellBuilder): + return None # Something is wrong, we should have a CellBuilder + # Okay, we really have a CellBuilder. + # Let's try to infer the width of the port. + # If this fails, give up. + return cell_builder.infer_width(port_name) + @dataclass(frozen=True) class CellAndGroup: @@ -852,6 +898,11 @@ def __ne__(self, other: ExprBuilder): """Construct an inequality comparison with ==.""" return ExprBuilder(ast.Neq(self.expr, other.expr)) + @property + def name(self): + """Get the name of the expression.""" + return self.expr.name + @classmethod def unwrap(cls, obj): """Unwrap an expression builder, or return the object if it is not one.""" @@ -940,6 +991,66 @@ def is_seq_mem_d1(self) -> bool: """Check if the cell is a SeqMemD1 cell.""" return self.is_primitive("seq_mem_d1") + def infer_width_reg(self) -> int: + """Infer the width of a register. That is, the width of `reg.in`.""" + assert self._cell.comp.id == "std_reg", "Cell is not a register" + return self._cell.comp.args[0] + + def infer_width(self, port_name) -> int: + """Infer the width of a port on the cell.""" + inst = self._cell.comp + prim = inst.id + if prim == "std_reg": + if port_name in ("in", "out"): + return inst.args[0] + if port_name == "write_en": + return 1 + return None + # XXX(Caleb): add all the primitive names instead of adding whenever I need one + if prim in ( + "std_add", + "std_sub", + "std_lt", + "std_le", + "std_ge", + "std_gt", + "std_eq", + "std_neq", + "std_sgt", + "std_slt", + "std_fp_sgt", + "std_fp_slt", + ): + if port_name in ("left", "right"): + return inst.args[0] + if prim in ("std_mem_d1", "seq_mem_d1"): + if port_name == "write_en": + return 1 + if port_name == "addr0": + return inst.args[2] + if port_name == "in": + return inst.args[0] + if prim == "seq_mem_d1" and port_name == "read_en": + return 1 + if prim in ( + "std_mult_pipe", + "std_smult_pipe", + "std_mod_pipe", + "std_smod_pipe", + "std_div_pipe", + "std_sdiv_pipe", + "std_fp_smult_pipe", + ): + if port_name in ("left", "right"): + return inst.args[0] + if port_name == "go": + return 1 + if prim == "std_wire" and port_name == "in": + return inst.args[0] + + # Give up. + return None + @property def name(self) -> str: """Get the name of the cell.""" @@ -1061,6 +1172,20 @@ def __enter__(self): def __exit__(self, exc, value, tb): TLS.groups.pop() + def infer_width(self, expr): + """Try to guess the width of a port expression in this group.""" + assert isinstance(expr, ast.Atom) + if isinstance(expr.item, ast.ThisPort): + return self.comp.port_width(expr) + cell_name = expr.item.id.name + port_name = expr.item.name + + cell_builder = self.comp.index[cell_name] + if not isinstance(cell_builder, CellBuilder): + return None + + return cell_builder.infer_width(port_name) + def const(width: int, value: int) -> ExprBuilder: """Build a sized integer constant expression. @@ -1077,8 +1202,6 @@ def infer_width(expr): Return an int, or None if we don't have a guess. """ - assert TLS.groups, "int width inference only works inside `with group:`" - group_builder: GroupBuilder = TLS.groups[-1] # Deal with `done` holes. expr = ExprBuilder.unwrap(expr) @@ -1086,72 +1209,10 @@ def infer_width(expr): assert expr.name == "done", f"unknown hole {expr.name}" return 1 - # Otherwise, it's a `cell.port` lookup. - assert isinstance(expr, ast.Atom) - if isinstance(expr.item, ast.ThisPort): - name = expr.item.id.name - return group_builder.comp.get_port_width(name) - cell_name = expr.item.id.name - port_name = expr.item.name - - # Look up the component for the referenced cell. - cell_builder = group_builder.comp.index[cell_name] - if isinstance(cell_builder, CellBuilder): - inst = cell_builder._cell.comp - else: - return None - - # Extract widths from stdlib components we know. - prim = inst.id - if prim == "std_reg": - if port_name == "in": - return inst.args[0] - elif port_name == "write_en": - return 1 - # XXX(Caleb): add all the primitive names instead of adding whenever I need one - elif prim in ( - "std_add", - "std_lt", - "std_le", - "std_ge", - "std_gt", - "std_eq", - "std_sgt", - "std_slt", - "std_fp_sgt", - "std_fp_slt", - ): - if port_name == "left" or port_name == "right": - return inst.args[0] - elif prim == "std_mem_d1" or prim == "seq_mem_d1": - if port_name == "write_en": - return 1 - elif port_name == "addr0": - return inst.args[2] - elif port_name == "in": - return inst.args[0] - if prim == "seq_mem_d1": - if port_name == "read_en": - return 1 - elif prim in ( - "std_mult_pipe", - "std_smult_pipe", - "std_mod_pipe", - "std_smod_pipe", - "std_div_pipe", - "std_sdiv_pipe", - "std_fp_smult_pipe", - ): - if port_name == "left" or port_name == "right": - return inst.args[0] - elif port_name == "go": - return 1 - elif prim == "std_wire": - if port_name == "in": - return inst.args[0] + assert TLS.groups, "int width inference only works inside `with group:`" + group_builder: GroupBuilder = TLS.groups[-1] - # Give up. - return None + return group_builder.infer_width(expr) def ctx_asgn(lhs: ExprBuilder, rhs: Union[ExprBuilder, CondExprBuilder]): diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index 9a7412282..32509d9db 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -68,9 +68,9 @@ def generate_fp_pow_component( pow.in_ = mul.out execute_mul.done = pow.done - incr_count = comp.incr(count, width, 1, is_signed) + incr_count = comp.incr(count, 1, is_signed) - cond = comp.lt_use(count.out, comp.this().integer_exp, width, is_signed) + cond = comp.lt_use(count.out, comp.this().integer_exp, is_signed, None, width) with comp.continuous: comp.this().out = pow.out @@ -561,7 +561,6 @@ def generate_fp_pow_full( comp.input("base", width) comp.input("exp_value", width) comp.output("out", width) - lt = comp.lt(width, "lt", is_signed) div = comp.cell( "div", @@ -608,8 +607,9 @@ def generate_fp_pow_full( base_lt_zero = comp.lt_use( comp.this().base, const_zero.out, - width, is_signed, + None, + width, ) new_exp_val = comp.reg("new_exp_val", width) @@ -637,7 +637,13 @@ def generate_fp_pow_full( gen_reciprocal(comp, "set_base_reciprocal", new_base_reg, div, const_one) gen_reciprocal(comp, "set_res_reciprocal", res, div, const_one), - base_lt_one = comp.lt_use(stored_base_reg.out, const_one.out, width, is_signed) + base_lt_one = comp.lt_use( + stored_base_reg.out, + const_one.out, + is_signed, + None, + width, + ) base_reciprocal = if_with(base_lt_one, comp.get_group("set_base_reciprocal")) diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index f1c37d8be..e8e0ad1cc 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -55,9 +55,9 @@ def insert_main(prog, queue): cmd = main.reg("command", 2) # The command we're currently processing value = main.reg("value", 32) # The value we're currently processing - incr_i = main.incr(i, 32) # i++ - incr_j = main.incr(j, 32) # j++ - cmd_le_1 = main.le_use(cmd.out, 1, 2) # cmd <= 1 + incr_i = main.incr(i) # i++ + incr_j = main.incr(j) # j++ + cmd_le_1 = main.le_use(cmd.out, 1) # cmd <= 1 read_cmd = main.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") write_cmd_to_reg = main.mem_write_seq_d1_to_reg(commands, cmd, "write_cmd_phase2") diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index c84ab8c90..6c087f741 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -29,28 +29,22 @@ def add_wrap2(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells and groups to compute equality and lt - i_eq_0 = wrap.eq_use(i, 0, 32) - i_eq_1 = wrap.eq_use(i, 1, 32) - j_lt_4 = wrap.lt_use(j, 4, 32) - j_lt_8 = wrap.lt_use(j, 8, 32) + i_eq_0 = wrap.eq_use(i, 0) + i_eq_1 = wrap.eq_use(i, 1) + j_lt_4 = wrap.lt_use(j, 4) + j_lt_8 = wrap.lt_use(j, 8) # Load `j` unchanged into `j_mod_4`. unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") # Wiring to perform j-4 and j-8. Either of these will store the result in `j_mod_4`. - j_minus_4, j_mod_4 = wrap.sub_store_in_reg( - j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 - ) - j_minus_8, j_mod_4 = wrap.sub_store_in_reg( - j, cb.const(32, 8), "j_minus_8", 32, j_mod_4 - ) + j_minus_4, j_mod_4 = wrap.sub_store_in_reg(j, 4, "j_minus_4", 32, j_mod_4) + j_minus_8, j_mod_4 = wrap.sub_store_in_reg(j, 8, "j_minus_8", 32, j_mod_4) load_from_mems = [ # Add wiring to load the value `j_mod_4` from all of the memory cells. # We'll have to invoke the correct one of these groups later on. - wrap.mem_load_to_mem( - mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" - ) + wrap.mem_load_to_mem(mems[i], j_mod_4.out, ans, 0, f"load_from_mem{i}") for i in range(6) ] @@ -118,23 +112,19 @@ def add_wrap3(prog): j_mod_4 = wrap.reg("j_mod_4", 32) # Additional cells to compute equality, and lt - i_eq_0 = wrap.eq_use(i, 0, 32) - i_eq_1 = wrap.eq_use(i, 1, 32) - i_eq_2 = wrap.eq_use(i, 2, 32) - j_lt_4 = wrap.lt_use(j, 4, 32) + i_eq_0 = wrap.eq_use(i, 0) + i_eq_1 = wrap.eq_use(i, 1) + i_eq_2 = wrap.eq_use(i, 2) + j_lt_4 = wrap.lt_use(j, 4) # Load `j` unchanged into `j_mod_4`. unchanged = wrap.reg_store(j_mod_4, j, "j_unchanged") # Wiring to perform j-4 and store the result in `j_mod_4`. - subcell, j_mod_4 = wrap.sub_store_in_reg( - j, cb.const(32, 4), "j_minus_4", 32, j_mod_4 - ) + subcell, j_mod_4 = wrap.sub_store_in_reg(j, 4, "j_minus_4", 32, j_mod_4) emit_from_mems = [ - wrap.mem_load_to_mem( - mems[i], j_mod_4.out, ans, cb.const(32, 0), f"load_from_mem{i}" - ) + wrap.mem_load_to_mem(mems[i], j_mod_4.out, ans, 0, f"load_from_mem{i}") for i in range(6) ] diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index a22a1db0a..5df6616ac 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -36,20 +36,20 @@ def insert_fifo(prog, name): len = fifo.reg("len", 32) # The length of the FIFO. # Cells and groups to compute equality - cmd_eq_0 = fifo.eq_use(cmd, 0, 2) - cmd_eq_1 = fifo.eq_use(cmd, 1, 2) - cmd_eq_2 = fifo.eq_use(cmd, 2, 2) + cmd_eq_0 = fifo.eq_use(cmd, 0) + cmd_eq_1 = fifo.eq_use(cmd, 1) + cmd_eq_2 = fifo.eq_use(cmd, 2) - write_eq_max_queue_len = fifo.eq_use(write.out, MAX_QUEUE_LEN, 32) - read_eq_max_queue_len = fifo.eq_use(read.out, MAX_QUEUE_LEN, 32) - len_eq_0 = fifo.eq_use(len.out, 0, 32) - len_eq_max_queue_len = fifo.eq_use(len.out, MAX_QUEUE_LEN, 32) + write_eq_max_queue_len = fifo.eq_use(write.out, MAX_QUEUE_LEN) + read_eq_max_queue_len = fifo.eq_use(read.out, MAX_QUEUE_LEN) + len_eq_0 = fifo.eq_use(len.out, 0) + len_eq_max_queue_len = fifo.eq_use(len.out, MAX_QUEUE_LEN) # Cells and groups to increment read and write registers - write_incr = fifo.incr(write, 32) # write++ - read_incr = fifo.incr(read, 32) # read++ - len_incr = fifo.incr(len, 32) # len++ - len_decr = fifo.decr(len, 32) # len-- + write_incr = fifo.incr(write) # write++ + read_incr = fifo.incr(read) # read++ + len_incr = fifo.incr(len) # len++ + len_decr = fifo.decr(len) # len-- # Cells and groups to modify flags, which are registers flash_write = fifo.reg_store(write, 0, "flash_write") # write := 0 diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index bb2c7d6e9..3997e1a79 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -110,25 +110,25 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): hot = pifo.reg("hot", 1) # Some equality checks. - hot_eq_0 = pifo.eq_use(hot.out, 0, 1) - hot_eq_1 = pifo.eq_use(hot.out, 1, 1) - flow_eq_0 = pifo.eq_use(flow.out, 0, 1) - flow_eq_1 = pifo.eq_use(flow.out, 1, 1) - len_eq_0 = pifo.eq_use(len.out, 0, 32) - len_eq_max_queue_len = pifo.eq_use(len.out, MAX_QUEUE_LEN, 32) - cmd_eq_0 = pifo.eq_use(cmd, 0, 2) - cmd_eq_1 = pifo.eq_use(cmd, 1, 2) - cmd_eq_2 = pifo.eq_use(cmd, 2, 2) - err_eq_0 = pifo.eq_use(err.out, 0, 1) - err_neq_0 = pifo.neq_use(err.out, cb.const(1, 0), 1) + hot_eq_0 = pifo.eq_use(hot.out, 0) + hot_eq_1 = pifo.eq_use(hot.out, 1) + flow_eq_0 = pifo.eq_use(flow.out, 0) + flow_eq_1 = pifo.eq_use(flow.out, 1) + len_eq_0 = pifo.eq_use(len.out, 0) + len_eq_max_queue_len = pifo.eq_use(len.out, MAX_QUEUE_LEN) + cmd_eq_0 = pifo.eq_use(cmd, 0) + cmd_eq_1 = pifo.eq_use(cmd, 1) + cmd_eq_2 = pifo.eq_use(cmd, 2) + err_eq_0 = pifo.eq_use(err.out, 0) + err_neq_0 = pifo.neq_use(err.out, 0) - flip_hot = pifo.bitwise_flip_reg(hot, 1) + flip_hot = pifo.bitwise_flip_reg(hot) raise_err = pifo.reg_store(err, 1, "raise_err") # err := 1 lower_err = pifo.reg_store(err, 0, "lower_err") # err := 0 flash_ans = pifo.reg_store(ans, 0, "flash_ans") # ans := 0 - len_incr = pifo.incr(len, 32) # len++ - len_decr = pifo.decr(len, 32) # len-- + len_incr = pifo.incr(len) # len++ + len_decr = pifo.decr(len) # len-- # The main logic. pifo.control += [ diff --git a/frontends/mrxl/mrxl/gen_calyx.py b/frontends/mrxl/mrxl/gen_calyx.py index 151e0f9b8..19152834e 100644 --- a/frontends/mrxl/mrxl/gen_calyx.py +++ b/frontends/mrxl/mrxl/gen_calyx.py @@ -34,7 +34,7 @@ def cond_group( less_than = comp.cell(cell, Stdlib.op("lt", 32, signed=False)) with comp.comb_group(group_name): less_than.left = idx.out - less_than.right = cb.const(32, arr_size) + less_than.right = arr_size # ANCHOR_END: cond_group return cell, group_name From 17c6002309f2e7f518cf06438597d0902116da71 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Thu, 7 Sep 2023 08:22:28 -0400 Subject: [PATCH 065/189] Move `numeric_types.py` from `fud/verilator` to `calyx-py` (#1715) * refactor numeric types * moved test * changed error location * fix test location --- .github/workflows/rust.yml | 2 +- calyx-py/calyx/gen_exp.py | 30 +++++++------------ calyx-py/calyx/gen_ln.py | 2 +- calyx-py/calyx/gen_msb.py | 15 ---------- .../calyx}/numeric_types.py | 11 ++++++- .../tests => calyx-py/test}/numeric_types.py | 3 +- frontends/relay/relay_visitor.py | 2 +- frontends/systolic-lang/convert-mems.py | 2 +- .../systolic-lang/gen_array_component.py | 2 +- frontends/systolic-lang/gen_post_op.py | 4 +-- fud/fud/errors.py | 10 ------- fud/fud/stages/interpreter.py | 20 ++++++------- fud/fud/stages/verilator/json_to_dat.py | 4 +-- fud/fud/stages/verilator/tables.py | 2 +- fud/fud/xclrun.py | 25 +++++++++------- 15 files changed, 54 insertions(+), 80 deletions(-) rename {fud/fud/stages/verilator => calyx-py/calyx}/numeric_types.py (98%) rename {fud/fud/stages/verilator/tests => calyx-py/test}/numeric_types.py (97%) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6b0bba593..de3ab4ed9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -115,7 +115,7 @@ jobs: - name: Run Python Tests working-directory: /home/calyx - run: pytest fud/fud/stages/verilator/tests/numeric_types.py + run: pytest calyx-py/test/numeric_types.py evaluation: name: Polybench Integration diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index 32509d9db..b7d5c7064 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -8,9 +8,8 @@ ) from calyx.utils import float_to_fixed_point from math import factorial, log2 -from fud.stages.verilator import numeric_types +from calyx.numeric_types import FixedPoint from calyx.gen_ln import generate_ln - from calyx.builder import ( Builder, ComponentBuilder, @@ -19,7 +18,6 @@ if_with, invoke, CellBuilder, - ExprBuilder, const, HI, par, @@ -52,7 +50,7 @@ def generate_fp_pow_component( # groups with comp.group("init") as init: - pow.in_ = numeric_types.FixedPoint( + pow.in_ = FixedPoint( "1.0", width, int_width, is_signed=is_signed ).unsigned_integer() pow.write_en = 1 @@ -105,14 +103,12 @@ def generate_cells( comp.const( "one", width, - numeric_types.FixedPoint( - "1.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) comp.const( "e", width, - numeric_types.FixedPoint( + FixedPoint( str(float_to_fixed_point(2.7182818284, frac_width)), width, int_width, @@ -124,7 +120,7 @@ def generate_cells( comp.const( "negative_one", width, - numeric_types.FixedPoint( + FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) @@ -168,7 +164,7 @@ def generate_cells( # reciprocal factorials for i in range(2, degree + 1): fixed_point_value = float_to_fixed_point(1.0 / factorial(i), frac_width) - value = numeric_types.FixedPoint( + value = FixedPoint( str(fixed_point_value), width, int_width, is_signed=is_signed ).unsigned_integer() comp.const(f"reciprocal_factorial{i}", width, value) @@ -540,9 +536,7 @@ def gen_constant_cell( return comp.const( name, width, - numeric_types.FixedPoint( - value, width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint(value, width, int_width, is_signed=is_signed).unsigned_integer(), ) @@ -571,16 +565,12 @@ def generate_fp_pow_full( const_one = comp.const( "one", width, - numeric_types.FixedPoint( - "1.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) const_zero = comp.const( "zero", width, - numeric_types.FixedPoint( - "0.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("0.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) mult = comp.cell( "mult", @@ -597,7 +587,7 @@ def generate_fp_pow_full( const_neg_one = comp.const( "neg_one", width, - numeric_types.FixedPoint( + FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) diff --git a/calyx-py/calyx/gen_ln.py b/calyx-py/calyx/gen_ln.py index 209813e42..e6c60b474 100644 --- a/calyx-py/calyx/gen_ln.py +++ b/calyx-py/calyx/gen_ln.py @@ -6,7 +6,7 @@ Import, ) from calyx.utils import float_to_fixed_point -from fud.stages.verilator import numeric_types +from calyx import numeric_types from calyx.gen_msb import gen_msb_calc from calyx.builder import Builder, ComponentBuilder, CellBuilder, HI, par, invoke diff --git a/calyx-py/calyx/gen_msb.py b/calyx-py/calyx/gen_msb.py index d86481ad5..8f7ae5e15 100644 --- a/calyx-py/calyx/gen_msb.py +++ b/calyx-py/calyx/gen_msb.py @@ -1,26 +1,11 @@ from typing import List from calyx.py_ast import ( - Connect, - CompVar, - Cell, - Group, - ConstantPort, - CompPort, Stdlib, Component, - ThisPort, - HolePort, - PortDef, - SeqComp, - Enable, - While, - Control, - CombGroup, ) from calyx.builder import ( Builder, CellAndGroup, - ComponentBuilder, const, HI, while_with, diff --git a/fud/fud/stages/verilator/numeric_types.py b/calyx-py/calyx/numeric_types.py similarity index 98% rename from fud/fud/stages/verilator/numeric_types.py rename to calyx-py/calyx/numeric_types.py index 5d6fca493..da5c901ed 100644 --- a/fud/fud/stages/verilator/numeric_types.py +++ b/calyx-py/calyx/numeric_types.py @@ -5,11 +5,20 @@ from fractions import Fraction from dataclasses import dataclass from decimal import Decimal, getcontext -from fud.errors import InvalidNumericType import math import logging as log +class InvalidNumericType(Exception): + """ + An error raised when an invalid numeric type is provided. + """ + + def __init__(self, msg): + msg = f"""Invalid Numeric Type: {msg}""" + super().__init__(msg) + + @dataclass class NumericType: """Interface for a numeric type. diff --git a/fud/fud/stages/verilator/tests/numeric_types.py b/calyx-py/test/numeric_types.py similarity index 97% rename from fud/fud/stages/verilator/tests/numeric_types.py rename to calyx-py/test/numeric_types.py index b4d4d445d..b48e6d2d8 100644 --- a/fud/fud/stages/verilator/tests/numeric_types.py +++ b/calyx-py/test/numeric_types.py @@ -1,6 +1,5 @@ from random import randint -from fud.stages.verilator.numeric_types import FixedPoint, Bitnum -from fud.errors import InvalidNumericType +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from hypothesis import given, strategies as st # type: ignore import numpy as np import pytest # type: ignore diff --git a/frontends/relay/relay_visitor.py b/frontends/relay/relay_visitor.py index 6ccc36282..be4b0ac34 100755 --- a/frontends/relay/relay_visitor.py +++ b/frontends/relay/relay_visitor.py @@ -24,7 +24,7 @@ Component, ) from calyx.utils import float_to_fixed_point -from fud.stages.verilator import numeric_types +from calyx import numeric_types from dahlia_impl import emit_components calyx_keywords_list = ["input"] diff --git a/frontends/systolic-lang/convert-mems.py b/frontends/systolic-lang/convert-mems.py index 22af8aaf4..2d6c09905 100644 --- a/frontends/systolic-lang/convert-mems.py +++ b/frontends/systolic-lang/convert-mems.py @@ -1,6 +1,6 @@ import argparse import json -from fud.stages.verilator import numeric_types +from calyx import numeric_types if __name__ == "__main__": diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index e7a75ef91..a6ea12d40 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -2,7 +2,7 @@ import numpy as np from gen_pe import pe, PE_NAME, BITWIDTH -import calyx.builder as cb +from calyx import builder as cb from calyx import py_ast # Global constant for the current bitwidth. diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index c497f4cf3..ce4fcf164 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import calyx.builder as cb +from calyx import builder as cb from calyx import py_ast from gen_array_component import NAME_SCHEME from gen_pe import BITWIDTH, INTWIDTH, FRACWIDTH -from fud.stages.verilator import numeric_types +from calyx import numeric_types from calyx.utils import float_to_fixed_point diff --git a/fud/fud/errors.py b/fud/fud/errors.py index 96e7f0b35..e29911408 100644 --- a/fud/fud/errors.py +++ b/fud/fud/errors.py @@ -255,16 +255,6 @@ def __init__(self, path): super().__init__(msg) -class InvalidNumericType(FudError): - """ - An error raised when an invalid numeric type is provided. - """ - - def __init__(self, msg): - msg = f"""Invalid Numeric Type: {msg}""" - super().__init__(msg) - - class Malformed(FudError): """ An error raised when the input to a stage is malformed in some manner. diff --git a/fud/fud/stages/interpreter.py b/fud/fud/stages/interpreter.py index 7a9b65130..9eca39b99 100644 --- a/fud/fud/stages/interpreter.py +++ b/fud/fud/stages/interpreter.py @@ -3,8 +3,7 @@ from pathlib import Path import simplejson as sjson import numpy as np -from fud.stages.verilator.numeric_types import FixedPoint, Bitnum -from fud.errors import InvalidNumericType +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed from fud.utils import shell, TmpDir, unwrap_or, transparent_shell from fud import config as cfg @@ -88,8 +87,9 @@ def _is_data_converter(self): def _define_steps(self, input_data, builder, config): script = config["stages", self.name, "exec"] - data_path_exists: bool = (config["stages", "verilog", "data"] or - config.get(["stages", "mrxl", "data"])) + data_path_exists: bool = config["stages", "verilog", "data"] or config.get( + ["stages", "mrxl", "data"] + ) cmd = [ script, @@ -118,7 +118,9 @@ def mktmp() -> SourceType.Directory: """ return TmpDir() - @builder.step(description="Dynamically retrieve the value of stages.verilog.data") + @builder.step( + description="Dynamically retrieve the value of stages.verilog.data" + ) def get_verilog_data() -> SourceType.Path: data_path = config.get(["stages", "verilog", "data"]) path = Path(data_path) if data_path else None @@ -197,9 +199,7 @@ def parse_output( data_path = get_verilog_data() if data_path_exists: - convert_json_to_interp_json( - tmpdir, data_path - ) + convert_json_to_interp_json(tmpdir, data_path) if self._is_data_converter(): if data_path_exists: @@ -213,9 +213,7 @@ def parse_output( result = interpret(input_data, tmpdir) if "--raw" in cmd: - return parse_output( - result, data_path, tmpdir - ) + return parse_output(result, data_path, tmpdir) else: return result diff --git a/fud/fud/stages/verilator/json_to_dat.py b/fud/fud/stages/verilator/json_to_dat.py index f74f86190..a988f62ff 100644 --- a/fud/fud/stages/verilator/json_to_dat.py +++ b/fud/fud/stages/verilator/json_to_dat.py @@ -1,8 +1,8 @@ import simplejson as sjson import numpy as np -from .numeric_types import FixedPoint, Bitnum +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from pathlib import Path -from fud.errors import InvalidNumericType, Malformed +from fud.errors import Malformed import logging as log diff --git a/fud/fud/stages/verilator/tables.py b/fud/fud/stages/verilator/tables.py index eae5c6241..e802a90ed 100644 --- a/fud/fud/stages/verilator/tables.py +++ b/fud/fud/stages/verilator/tables.py @@ -1,6 +1,6 @@ from itertools import product from decimal import Decimal -from fud.stages.verilator.numeric_types import FixedPoint +from calyx.numeric_types import FixedPoint def compute_exp_frac_table(frac_width: int): diff --git a/fud/fud/xclrun.py b/fud/fud/xclrun.py index 7141a0c4d..67fbda642 100644 --- a/fud/fud/xclrun.py +++ b/fud/fud/xclrun.py @@ -36,7 +36,7 @@ from typing import Mapping, Any, Dict from pathlib import Path from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed -from fud.errors import InvalidNumericType +from calyx.numeric_types import InvalidNumericType def mem_to_buf(mem): @@ -96,8 +96,9 @@ def run(xclbin: Path, data: Mapping[str, Any]) -> Dict[str, Any]: # Collect the output data. for buf in buffers: buf.sync_from_device() - mems = {name: buf_to_mem(data[name]["format"], buf) - for name, buf in zip(data, buffers)} + mems = { + name: buf_to_mem(data[name]["format"], buf) for name, buf in zip(data, buffers) + } # PYNQ recommends explicitly freeing its resources. del buffers @@ -118,14 +119,16 @@ def _dtype(fmt) -> np.dtype: def xclrun(): # Parse command-line arguments. parser = argparse.ArgumentParser( - description='run a compiled XRT program', + description="run a compiled XRT program", + ) + parser.add_argument("bin", metavar="XCLBIN", help="the .xclbin binary file to run") + parser.add_argument("data", metavar="DATA", help="the JSON input data file") + parser.add_argument( + "--out", + "-o", + metavar="FILE", + help="write JSON results to a file instead of stdout", ) - parser.add_argument('bin', metavar='XCLBIN', - help='the .xclbin binary file to run') - parser.add_argument('data', metavar='DATA', - help='the JSON input data file') - parser.add_argument('--out', '-o', metavar='FILE', - help='write JSON results to a file instead of stdout') args = parser.parse_args() # Load the input JSON data file. @@ -136,7 +139,7 @@ def xclrun(): out_data = run(Path(args.bin), in_data) # Dump the output JSON data. - outfile = open(args.out, 'w') if args.out else sys.stdout + outfile = open(args.out, "w") if args.out else sys.stdout sjson.dump(out_data, outfile, indent=2, use_decimal=True) From d62ffb36ad58fd6095af93a4672c630b93bb7c92 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Thu, 7 Sep 2023 09:17:15 -0400 Subject: [PATCH 066/189] Revert "Move `numeric_types.py` from `fud/verilator` to `calyx-py` (#1715)" (#1718) This reverts commit 1edf3eccafc2fe57d3712771132bc65eb71baa57. --- .github/workflows/rust.yml | 2 +- calyx-py/calyx/gen_exp.py | 30 ++++++++++++------- calyx-py/calyx/gen_ln.py | 2 +- calyx-py/calyx/gen_msb.py | 15 ++++++++++ frontends/relay/relay_visitor.py | 2 +- frontends/systolic-lang/convert-mems.py | 2 +- .../systolic-lang/gen_array_component.py | 2 +- frontends/systolic-lang/gen_post_op.py | 4 +-- fud/fud/errors.py | 10 +++++++ fud/fud/stages/interpreter.py | 20 +++++++------ fud/fud/stages/verilator/json_to_dat.py | 4 +-- .../fud/stages/verilator}/numeric_types.py | 11 +------ fud/fud/stages/verilator/tables.py | 2 +- .../stages/verilator/tests}/numeric_types.py | 3 +- fud/fud/xclrun.py | 25 +++++++--------- 15 files changed, 80 insertions(+), 54 deletions(-) rename {calyx-py/calyx => fud/fud/stages/verilator}/numeric_types.py (98%) rename {calyx-py/test => fud/fud/stages/verilator/tests}/numeric_types.py (97%) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index de3ab4ed9..6b0bba593 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -115,7 +115,7 @@ jobs: - name: Run Python Tests working-directory: /home/calyx - run: pytest calyx-py/test/numeric_types.py + run: pytest fud/fud/stages/verilator/tests/numeric_types.py evaluation: name: Polybench Integration diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index b7d5c7064..32509d9db 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -8,8 +8,9 @@ ) from calyx.utils import float_to_fixed_point from math import factorial, log2 -from calyx.numeric_types import FixedPoint +from fud.stages.verilator import numeric_types from calyx.gen_ln import generate_ln + from calyx.builder import ( Builder, ComponentBuilder, @@ -18,6 +19,7 @@ if_with, invoke, CellBuilder, + ExprBuilder, const, HI, par, @@ -50,7 +52,7 @@ def generate_fp_pow_component( # groups with comp.group("init") as init: - pow.in_ = FixedPoint( + pow.in_ = numeric_types.FixedPoint( "1.0", width, int_width, is_signed=is_signed ).unsigned_integer() pow.write_en = 1 @@ -103,12 +105,14 @@ def generate_cells( comp.const( "one", width, - FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), + numeric_types.FixedPoint( + "1.0", width, int_width, is_signed=is_signed + ).unsigned_integer(), ) comp.const( "e", width, - FixedPoint( + numeric_types.FixedPoint( str(float_to_fixed_point(2.7182818284, frac_width)), width, int_width, @@ -120,7 +124,7 @@ def generate_cells( comp.const( "negative_one", width, - FixedPoint( + numeric_types.FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) @@ -164,7 +168,7 @@ def generate_cells( # reciprocal factorials for i in range(2, degree + 1): fixed_point_value = float_to_fixed_point(1.0 / factorial(i), frac_width) - value = FixedPoint( + value = numeric_types.FixedPoint( str(fixed_point_value), width, int_width, is_signed=is_signed ).unsigned_integer() comp.const(f"reciprocal_factorial{i}", width, value) @@ -536,7 +540,9 @@ def gen_constant_cell( return comp.const( name, width, - FixedPoint(value, width, int_width, is_signed=is_signed).unsigned_integer(), + numeric_types.FixedPoint( + value, width, int_width, is_signed=is_signed + ).unsigned_integer(), ) @@ -565,12 +571,16 @@ def generate_fp_pow_full( const_one = comp.const( "one", width, - FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), + numeric_types.FixedPoint( + "1.0", width, int_width, is_signed=is_signed + ).unsigned_integer(), ) const_zero = comp.const( "zero", width, - FixedPoint("0.0", width, int_width, is_signed=is_signed).unsigned_integer(), + numeric_types.FixedPoint( + "0.0", width, int_width, is_signed=is_signed + ).unsigned_integer(), ) mult = comp.cell( "mult", @@ -587,7 +597,7 @@ def generate_fp_pow_full( const_neg_one = comp.const( "neg_one", width, - FixedPoint( + numeric_types.FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) diff --git a/calyx-py/calyx/gen_ln.py b/calyx-py/calyx/gen_ln.py index e6c60b474..209813e42 100644 --- a/calyx-py/calyx/gen_ln.py +++ b/calyx-py/calyx/gen_ln.py @@ -6,7 +6,7 @@ Import, ) from calyx.utils import float_to_fixed_point -from calyx import numeric_types +from fud.stages.verilator import numeric_types from calyx.gen_msb import gen_msb_calc from calyx.builder import Builder, ComponentBuilder, CellBuilder, HI, par, invoke diff --git a/calyx-py/calyx/gen_msb.py b/calyx-py/calyx/gen_msb.py index 8f7ae5e15..d86481ad5 100644 --- a/calyx-py/calyx/gen_msb.py +++ b/calyx-py/calyx/gen_msb.py @@ -1,11 +1,26 @@ from typing import List from calyx.py_ast import ( + Connect, + CompVar, + Cell, + Group, + ConstantPort, + CompPort, Stdlib, Component, + ThisPort, + HolePort, + PortDef, + SeqComp, + Enable, + While, + Control, + CombGroup, ) from calyx.builder import ( Builder, CellAndGroup, + ComponentBuilder, const, HI, while_with, diff --git a/frontends/relay/relay_visitor.py b/frontends/relay/relay_visitor.py index be4b0ac34..6ccc36282 100755 --- a/frontends/relay/relay_visitor.py +++ b/frontends/relay/relay_visitor.py @@ -24,7 +24,7 @@ Component, ) from calyx.utils import float_to_fixed_point -from calyx import numeric_types +from fud.stages.verilator import numeric_types from dahlia_impl import emit_components calyx_keywords_list = ["input"] diff --git a/frontends/systolic-lang/convert-mems.py b/frontends/systolic-lang/convert-mems.py index 2d6c09905..22af8aaf4 100644 --- a/frontends/systolic-lang/convert-mems.py +++ b/frontends/systolic-lang/convert-mems.py @@ -1,6 +1,6 @@ import argparse import json -from calyx import numeric_types +from fud.stages.verilator import numeric_types if __name__ == "__main__": diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index a6ea12d40..e7a75ef91 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -2,7 +2,7 @@ import numpy as np from gen_pe import pe, PE_NAME, BITWIDTH -from calyx import builder as cb +import calyx.builder as cb from calyx import py_ast # Global constant for the current bitwidth. diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index ce4fcf164..c497f4cf3 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -from calyx import builder as cb +import calyx.builder as cb from calyx import py_ast from gen_array_component import NAME_SCHEME from gen_pe import BITWIDTH, INTWIDTH, FRACWIDTH -from calyx import numeric_types +from fud.stages.verilator import numeric_types from calyx.utils import float_to_fixed_point diff --git a/fud/fud/errors.py b/fud/fud/errors.py index e29911408..96e7f0b35 100644 --- a/fud/fud/errors.py +++ b/fud/fud/errors.py @@ -255,6 +255,16 @@ def __init__(self, path): super().__init__(msg) +class InvalidNumericType(FudError): + """ + An error raised when an invalid numeric type is provided. + """ + + def __init__(self, msg): + msg = f"""Invalid Numeric Type: {msg}""" + super().__init__(msg) + + class Malformed(FudError): """ An error raised when the input to a stage is malformed in some manner. diff --git a/fud/fud/stages/interpreter.py b/fud/fud/stages/interpreter.py index 9eca39b99..7a9b65130 100644 --- a/fud/fud/stages/interpreter.py +++ b/fud/fud/stages/interpreter.py @@ -3,7 +3,8 @@ from pathlib import Path import simplejson as sjson import numpy as np -from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType +from fud.stages.verilator.numeric_types import FixedPoint, Bitnum +from fud.errors import InvalidNumericType from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed from fud.utils import shell, TmpDir, unwrap_or, transparent_shell from fud import config as cfg @@ -87,9 +88,8 @@ def _is_data_converter(self): def _define_steps(self, input_data, builder, config): script = config["stages", self.name, "exec"] - data_path_exists: bool = config["stages", "verilog", "data"] or config.get( - ["stages", "mrxl", "data"] - ) + data_path_exists: bool = (config["stages", "verilog", "data"] or + config.get(["stages", "mrxl", "data"])) cmd = [ script, @@ -118,9 +118,7 @@ def mktmp() -> SourceType.Directory: """ return TmpDir() - @builder.step( - description="Dynamically retrieve the value of stages.verilog.data" - ) + @builder.step(description="Dynamically retrieve the value of stages.verilog.data") def get_verilog_data() -> SourceType.Path: data_path = config.get(["stages", "verilog", "data"]) path = Path(data_path) if data_path else None @@ -199,7 +197,9 @@ def parse_output( data_path = get_verilog_data() if data_path_exists: - convert_json_to_interp_json(tmpdir, data_path) + convert_json_to_interp_json( + tmpdir, data_path + ) if self._is_data_converter(): if data_path_exists: @@ -213,7 +213,9 @@ def parse_output( result = interpret(input_data, tmpdir) if "--raw" in cmd: - return parse_output(result, data_path, tmpdir) + return parse_output( + result, data_path, tmpdir + ) else: return result diff --git a/fud/fud/stages/verilator/json_to_dat.py b/fud/fud/stages/verilator/json_to_dat.py index a988f62ff..f74f86190 100644 --- a/fud/fud/stages/verilator/json_to_dat.py +++ b/fud/fud/stages/verilator/json_to_dat.py @@ -1,8 +1,8 @@ import simplejson as sjson import numpy as np -from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType +from .numeric_types import FixedPoint, Bitnum from pathlib import Path -from fud.errors import Malformed +from fud.errors import InvalidNumericType, Malformed import logging as log diff --git a/calyx-py/calyx/numeric_types.py b/fud/fud/stages/verilator/numeric_types.py similarity index 98% rename from calyx-py/calyx/numeric_types.py rename to fud/fud/stages/verilator/numeric_types.py index da5c901ed..5d6fca493 100644 --- a/calyx-py/calyx/numeric_types.py +++ b/fud/fud/stages/verilator/numeric_types.py @@ -5,20 +5,11 @@ from fractions import Fraction from dataclasses import dataclass from decimal import Decimal, getcontext +from fud.errors import InvalidNumericType import math import logging as log -class InvalidNumericType(Exception): - """ - An error raised when an invalid numeric type is provided. - """ - - def __init__(self, msg): - msg = f"""Invalid Numeric Type: {msg}""" - super().__init__(msg) - - @dataclass class NumericType: """Interface for a numeric type. diff --git a/fud/fud/stages/verilator/tables.py b/fud/fud/stages/verilator/tables.py index e802a90ed..eae5c6241 100644 --- a/fud/fud/stages/verilator/tables.py +++ b/fud/fud/stages/verilator/tables.py @@ -1,6 +1,6 @@ from itertools import product from decimal import Decimal -from calyx.numeric_types import FixedPoint +from fud.stages.verilator.numeric_types import FixedPoint def compute_exp_frac_table(frac_width: int): diff --git a/calyx-py/test/numeric_types.py b/fud/fud/stages/verilator/tests/numeric_types.py similarity index 97% rename from calyx-py/test/numeric_types.py rename to fud/fud/stages/verilator/tests/numeric_types.py index b48e6d2d8..b4d4d445d 100644 --- a/calyx-py/test/numeric_types.py +++ b/fud/fud/stages/verilator/tests/numeric_types.py @@ -1,5 +1,6 @@ from random import randint -from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType +from fud.stages.verilator.numeric_types import FixedPoint, Bitnum +from fud.errors import InvalidNumericType from hypothesis import given, strategies as st # type: ignore import numpy as np import pytest # type: ignore diff --git a/fud/fud/xclrun.py b/fud/fud/xclrun.py index 67fbda642..7141a0c4d 100644 --- a/fud/fud/xclrun.py +++ b/fud/fud/xclrun.py @@ -36,7 +36,7 @@ from typing import Mapping, Any, Dict from pathlib import Path from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed -from calyx.numeric_types import InvalidNumericType +from fud.errors import InvalidNumericType def mem_to_buf(mem): @@ -96,9 +96,8 @@ def run(xclbin: Path, data: Mapping[str, Any]) -> Dict[str, Any]: # Collect the output data. for buf in buffers: buf.sync_from_device() - mems = { - name: buf_to_mem(data[name]["format"], buf) for name, buf in zip(data, buffers) - } + mems = {name: buf_to_mem(data[name]["format"], buf) + for name, buf in zip(data, buffers)} # PYNQ recommends explicitly freeing its resources. del buffers @@ -119,16 +118,14 @@ def _dtype(fmt) -> np.dtype: def xclrun(): # Parse command-line arguments. parser = argparse.ArgumentParser( - description="run a compiled XRT program", - ) - parser.add_argument("bin", metavar="XCLBIN", help="the .xclbin binary file to run") - parser.add_argument("data", metavar="DATA", help="the JSON input data file") - parser.add_argument( - "--out", - "-o", - metavar="FILE", - help="write JSON results to a file instead of stdout", + description='run a compiled XRT program', ) + parser.add_argument('bin', metavar='XCLBIN', + help='the .xclbin binary file to run') + parser.add_argument('data', metavar='DATA', + help='the JSON input data file') + parser.add_argument('--out', '-o', metavar='FILE', + help='write JSON results to a file instead of stdout') args = parser.parse_args() # Load the input JSON data file. @@ -139,7 +136,7 @@ def xclrun(): out_data = run(Path(args.bin), in_data) # Dump the output JSON data. - outfile = open(args.out, "w") if args.out else sys.stdout + outfile = open(args.out, 'w') if args.out else sys.stdout sjson.dump(out_data, outfile, indent=2, use_decimal=True) From 71d0abebae2499b015aa09a44249df0c3f48a8b5 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:19:59 -0400 Subject: [PATCH 067/189] Cleaner Systolic Array Code (#1716) * fix mem width problem * rewrote test * cleaner/refactored code: * fix errors * small formatting changes * minor formatting --- calyx-py/calyx/builder.py | 63 +++++++++++++++- frontends/systolic-lang/gen-systolic.py | 53 +++++++++---- .../systolic-lang/gen_array_component.py | 36 ++++----- frontends/systolic-lang/gen_pe.py | 8 ++ frontends/systolic-lang/gen_post_op.py | 74 +++++++------------ tests/frontend/systolic/array-1.expect | 30 ++++---- 6 files changed, 166 insertions(+), 98 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index a11cd0968..86a2d5985 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -1247,6 +1247,59 @@ def seq(*args) -> ast.SeqComp: return ast.SeqComp([as_control(x) for x in args]) +def add_comp_params(comp: ComponentBuilder, input_ports: List, output_ports: List): + """ + Adds `input_ports`/`output_ports` as inputs/outputs to comp. + `input_ports`/`output_ports` should contain an (input_name, input_width) pair. + """ + for name, width in input_ports: + comp.input(name, width) + for name, width in output_ports: + comp.output(name, width) + + +def add_read_mem_params(comp: ComponentBuilder, name, data_width, addr_width): + """ + Add parameters to component `comp` if we want to read from a mem named + `name` with address width of `addr_width` and data width of `data_width`. + """ + add_comp_params( + comp, + input_ports=[(f"{name}_read_data", data_width)], + output_ports=[(f"{name}_addr0", addr_width)], + ) + + +def add_write_mem_params(comp: ComponentBuilder, name, data_width, addr_width): + """ + Add arguments to component `comp` if we want to write to a mem named + `name` with address width of `addr_width` and data width of `data_width`. + """ + add_comp_params( + comp, + input_ports=[(f"{name}_done", 1)], + output_ports=[ + (f"{name}_addr0", addr_width), + (f"{name}_write_data", data_width), + (f"{name}_write_en", 1), + ], + ) + + +def add_register_params(comp: ComponentBuilder, name, width): + """ + Add params to component `comp` if we want to use a register named `name`. + """ + add_comp_params( + comp, + input_ports=[(f"{name}_done", 1), (f"{name}_out", width)], + output_ports=[ + (f"{name}_in", width), + (f"{name}_write_en", 1), + ], + ) + + def build_connections( cell1: Union[CellBuilder, ThisBuilder], cell2: Union[CellBuilder, ThisBuilder], @@ -1258,10 +1311,12 @@ def build_connections( """ Intended for wiring together two cells whose ports have similar names. For each `name` in `forward_port_names`, adds the following connection: - `(cell1.root1_name,cell2.root2_name)` - For `backwards_port_names`, adds the following connection: - `(cell2.root2_name,cell1.root1_name)` - Returns a list of the resulting connections. + `(cell1.root1name, cell2.root2name)` + For each `name` in `backwards_port_names`, adds the following connection: + `(cell2.root2name, cell1.root1name)` + `root1name` refers to the string formed by `root1 + name` (i.e., no underscore + between root1 and name) + Returns a list of the resulting connections """ res = [] for port in forward_ports: diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 7c67e1292..0df164e59 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import calyx.builder as cb +from calyx.utils import bits_needed from gen_array_component import ( create_systolic_array, BITWIDTH, @@ -31,13 +32,11 @@ def create_mem_connections( If `read_mem` == False, then connects memory ports such that `component_builder` can write to memory. """ - # XXX(Caleb): should change idx_width to be more precise - idx_width = BITWIDTH mem = main.mem_d1( mem_name, BITWIDTH, mem_size, - idx_width, + bits_needed(mem_size), is_external=True, ) input_portname = ["addr0"] if read_mem else ["write_data", "write_en", "addr0"] @@ -47,12 +46,18 @@ def create_mem_connections( ) -def build_main(prog, post_op_component_name): +def build_main( + prog, top_length, top_depth, left_length, left_depth, post_op_component_name +): """ Build the main component. It basically connects the ports of the systolic component and post_op component in a single group so that they run. """ + assert top_depth == left_depth, ( + f"Cannot multiply matrices: " + f"{top_length}x{top_depth} and {left_depth}x{left_length}" + ) main = prog.component("main") systolic_array = main.cell( "systolic_array_component", py_ast.CompInst(SYSTOLIC_ARRAY_COMP, []) @@ -63,7 +68,7 @@ def build_main(prog, post_op_component_name): # Connections contains the RTL-like connections between the ports of # systolic_array_comp and the post_op. # Also connects the input memories to the systolic_array_comp and - # output memories to the post_op. + # output memories to the post_op_component. connections = [] # Connect input memories to systolic_array for r in range(top_length): @@ -102,27 +107,32 @@ def build_main(prog, post_op_component_name): # Use a wire and register so that we have a signal that tells us when # systolic array component is done. This way, we don't retrigger systolic_array_comp # when it has already finished. - systolic_array_done = main.reg("systolic_done", 1) + systolic_done_reg = main.reg("systolic_done", 1) systolic_done_wire = main.wire("systolic_done_wire", 1) with main.group("perform_computation") as g: for i, o in connections: g.asgn(i, o) # Use systolic_done_wire to avoid retriggering systolic array after # it is done. - systolic_array_done.write_en = systolic_array.done @ 1 - systolic_array_done.in_ = systolic_array.done @ 1 - systolic_done_wire.in_ = (systolic_array.done | systolic_array_done.out) @ 1 + systolic_done_reg.write_en = systolic_array.done @ 1 + systolic_done_reg.in_ = systolic_array.done @ 1 + systolic_done_wire.in_ = (systolic_array.done | systolic_done_reg.out) @ 1 systolic_array.go = ~systolic_done_wire.out @ py_ast.ConstantPort(1, 1) systolic_array.depth = py_ast.ConstantPort(BITWIDTH, left_depth) # Triggering post_op component. post_op.go = py_ast.ConstantPort(1, 1) + # Group is done when post_op is done. g.done = post_op.computation_done main.control = py_ast.Enable("perform_computation") -if __name__ == "__main__": +def parse_arguments() -> (int, int, int, int, bool): + """ + Parses arguments and returns the following outputs: + top_length, top_depth, left_length, left_depth, leaky_relu + """ import argparse import json @@ -166,7 +176,11 @@ def build_main(prog, post_op_component_name): "Need to pass either `FILE` or all of `" "-tl TOP_LENGTH -td TOP_DEPTH -ll LEFT_LENGTH -ld LEFT_DEPTH`" ) + return (top_length, top_depth, left_length, left_depth, leaky_relu) + +if __name__ == "__main__": + (top_length, top_depth, left_length, left_depth, leaky_relu) = parse_arguments() # Building the main component prog = cb.Builder() create_systolic_array( @@ -178,13 +192,26 @@ def build_main(prog, post_op_component_name): ) if leaky_relu: leaky_relu_post_op( - prog, num_rows=left_length, num_cols=top_length, idx_width=BITWIDTH + prog, + num_rows=left_length, + num_cols=top_length, + idx_width=bits_needed(top_length), ) post_op_component_name = LEAKY_RELU_POST_OP else: default_post_op( - prog, num_rows=left_length, num_cols=top_length, idx_width=BITWIDTH + prog, + num_rows=left_length, + num_cols=top_length, + idx_width=bits_needed(top_length), ) post_op_component_name = DEFAULT_POST_OP - build_main(prog, post_op_component_name) + build_main( + prog, + top_length=top_length, + top_depth=top_depth, + left_length=left_length, + left_depth=left_depth, + post_op_component_name=post_op_component_name, + ) prog.program.emit() diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index e7a75ef91..1ab92664c 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -4,6 +4,7 @@ from gen_pe import pe, PE_NAME, BITWIDTH import calyx.builder as cb from calyx import py_ast +from calyx.utils import bits_needed # Global constant for the current bitwidth. DEPTH = "depth" @@ -75,24 +76,21 @@ def build_group(self, comp: cb.ComponentBuilder) -> str: return group_name -def add_read_mem_arguments(comp: cb.ComponentBuilder, name, addr_width): - """ - Add arguments to component `comp` if we want to read from a mem named `name` with - width of `addr_width` - """ - comp.input(f"{name}_read_data", BITWIDTH) - comp.output(f"{name}_addr0", addr_width) - - -def add_systolic_output_arguments(comp: cb.ComponentBuilder, row_num, addr_width): +def add_systolic_output_params(comp: cb.ComponentBuilder, row_num, addr_width): """ Add output arguments to systolic array component `comp` for row `row_num`. The ouptut arguments alllow the systolic array to expose its outputs for `row_num` without writing to memory (e.g., r0_valid, r0_value, r0_idx). """ - comp.output(NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1) - comp.output(NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH) - comp.output(NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width) + cb.add_comp_params( + comp, + input_ports=[], + output_ports=[ + (NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1), + (NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH), + (NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width), + ], + ) def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): @@ -112,10 +110,9 @@ def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): else: raise Exception(f"Invalid top_or_left: {top_or_left}") - # XXX(Caleb): should change to be exact - idx_width = BITWIDTH + idx_width = bits_needed(size) # Instantiate the memory - add_read_mem_arguments(comp, name, idx_width) + cb.add_read_mem_params(comp, name, data_width=BITWIDTH, addr_width=idx_width) this = comp.this() addr0_port = this.port(name + "_addr0") read_data_port = this.port(name + "_read_data") @@ -268,7 +265,7 @@ def get_pe_invoke(r, c, mul_ready): ) -def init_dyn_vals(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): +def init_runtime_vals(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): """ Builds group that instantiates the dynamic/runtime values for the systolic array: its depth and iteration limit/count (since its iteration limit depends on @@ -646,7 +643,7 @@ def create_systolic_array( pe(prog) computational_unit = prog.component(SYSTOLIC_ARRAY_COMP) depth_port = computational_unit.input("depth", BITWIDTH) - init_dyn_vals(computational_unit, depth_port, top_length + left_length + 4) + init_runtime_vals(computational_unit, depth_port, top_length + left_length + 4) schedules = gen_schedules( top_length, top_depth, left_length, left_depth, computational_unit @@ -668,10 +665,9 @@ def create_systolic_array( for col in range(left_length): instantiate_memory(computational_unit, "left", col, left_depth) - idx_width = BITWIDTH # Instantiate output memory for i in range(left_length): - add_systolic_output_arguments(computational_unit, i, idx_width) + add_systolic_output_params(computational_unit, i, bits_needed(top_length)) # Instantiate all the PEs for row in range(left_length): diff --git a/frontends/systolic-lang/gen_pe.py b/frontends/systolic-lang/gen_pe.py index ba9caf101..9ce6c635c 100644 --- a/frontends/systolic-lang/gen_pe.py +++ b/frontends/systolic-lang/gen_pe.py @@ -10,6 +10,14 @@ def pe(prog: cb.Builder): + """ + Builds a pipelined "multiply and accumulate" PE that multiplies its `top` + and `left` input values, and accumulate the value. + The output is displayed through the `out` port. + This PE can accept new inputs every cycle: therefore it has a `mul_ready` + parameter to signal whether the output of the multiplier should be accumulated + yet. + """ comp = prog.component(name=PE_NAME, latency=1) comp.input("top", BITWIDTH) comp.input("left", BITWIDTH) diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index c497f4cf3..1b1d2556e 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -16,35 +16,20 @@ WRITE_DONE_COND = "write_done_cond" -def add_register_params(comp: cb.ComponentBuilder, name, width): - """ - Add params to component `comp` if we want to use a register named - `name` inside `comp.` Specifically adds the write_en, in, and out ports. - """ - comp.output(f"{name}_write_en", 1) - comp.output(f"{name}_in", width) - comp.input(f"{name}_out", width) - - -def add_write_mem_params(comp: cb.ComponentBuilder, name, addr_width): - """ - Add arguments to component `comp` if we want to write to a mem named `name` with - width of `addr_width` inside `comp.` - """ - comp.output(f"{name}_addr0", addr_width) - comp.output(f"{name}_write_data", BITWIDTH) - comp.output(f"{name}_write_en", 1) - comp.input(f"{name}_done", 1) - - def add_systolic_input_params(comp: cb.ComponentBuilder, row_num, addr_width): """ Add ports "r_{row_num}_valid", "r_{row_num}_value", "r_{row_num}_idx" to comp. These ports are meant to read from the systolic array output. """ - comp.input(NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1) - comp.input(NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH) - comp.input(NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width) + cb.add_comp_params( + comp, + input_ports=[ + (NAME_SCHEME["systolic valid signal"].format(row_num=row_num), 1), + (NAME_SCHEME["systolic value signal"].format(row_num=row_num), BITWIDTH), + (NAME_SCHEME["systolic idx signal"].format(row_num=row_num), addr_width), + ], + output_ports=[], + ) def add_post_op_params(comp: cb.Builder, num_rows: int, idx_width: int): @@ -53,7 +38,9 @@ def add_post_op_params(comp: cb.Builder, num_rows: int, idx_width: int): """ comp.output("computation_done", 1) for r in range(num_rows): - add_write_mem_params(comp, OUT_MEM + f"_{r}", idx_width) + cb.add_write_mem_params( + comp, OUT_MEM + f"_{r}", data_width=BITWIDTH, addr_width=idx_width + ) add_systolic_input_params(comp, r, idx_width) @@ -142,7 +129,7 @@ def default_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): ) -def leaky_relu_comp(prog: cb.Builder): +def leaky_relu_comp(prog: cb.Builder, idx_width: int): """ Creates a dynamic, non-pipelined, leaky relu component. This is the component that actually performs the leaky relu computation on @@ -151,20 +138,15 @@ def leaky_relu_comp(prog: cb.Builder): comp = prog.component(name="leaky_relu") comp.input("value", BITWIDTH) # Takes a memory and register (i.e., arguments that essentially act as ref cells) - add_write_mem_params(comp, OUT_MEM, BITWIDTH) - add_register_params(comp, "idx_reg", BITWIDTH) + cb.add_write_mem_params(comp, OUT_MEM, data_width=BITWIDTH, addr_width=idx_width) + cb.add_register_params(comp, "idx_reg", idx_width) this = comp.this() - addr0_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_addr0")) - write_data_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_write_data")) - write_en_port = cb.ExprBuilder.unwrap(this.port(OUT_MEM + "_write_en")) - write_done_port = this.port(OUT_MEM + "_done") - fp_mult = comp.fp_sop("fp_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH) lt = comp.fp_sop("val_lt", "lt", BITWIDTH, INTWIDTH, FRACWIDTH) - incr_idx = comp.add(BITWIDTH, "incr_idx") - write_mem = comp.wire("write_mem", 1) + incr_idx = comp.add(idx_width, "incr_idx") + write_mem = comp.wire("should_write_mem", 1) with comp.continuous: # gt holds whether this.value > 0 @@ -190,14 +172,13 @@ def leaky_relu_comp(prog: cb.Builder): this.idx_reg_write_en = write_mem.out @ 1 # Write to memory. - g.asgn(write_en_port, 1, write_mem.out) - g.asgn(addr0_port, this.idx_reg_out) + this.out_mem_write_en = write_mem.out @ 1 + this.out_mem_addr0 = this.idx_reg_out # Write value if this.value >= 0 # Write mult.out if this.value < 0 - g.asgn(write_data_port, this.value, ~lt.out) - g.asgn(write_data_port, fp_mult.out, lt.out) - # Groups is done once we have written to memory. - g.done = write_done_port + this.out_mem_write_data = ~lt.out @ this.value + this.out_mem_write_data = lt.out @ fp_mult.out + g.done = this.out_mem_done comp.control = py_ast.Enable("do_relu") @@ -205,7 +186,7 @@ def leaky_relu_comp(prog: cb.Builder): def create_leaky_relu_groups(comp: cb.ComponentBuilder, row, num_cols, addr_width): """ Creates the groups for the leaky relu post op, i.e., the post-op that - coordinates the leaky-relu execution. + coordinates the execution of the leaky relu component. """ def store_output_vals(comp: cb.ComponentBuilder, row, num_cols, addr_width): @@ -257,7 +238,7 @@ def build_assignment(group: cb.GroupBuilder, wire, register, output_val): # Current value we are performing relu on. cur_val = comp.wire(f"r{row}_cur_val", BITWIDTH) # Current idx within the row (i.e., column) for the value we are performing relu on. - idx_reg = comp.reg(f"r{row}_cur_idx", BITWIDTH) + idx_reg = comp.reg(f"r{row}_cur_idx", addr_width) # Handling logic to hold the systolic array's output values so they're available # for moer than one cycle. store_output_vals(comp, row, num_cols, addr_width) @@ -273,7 +254,8 @@ def build_assignment(group: cb.GroupBuilder, wire, register, output_val): relu_finished_wire = comp.wire(f"relu_finished_wire_r{row}", 1) row_ready_wire = comp.get_cell(f"r{row}_ready_wire") - # Building connections betwen this and the leaky_relu cell + # Need to pass this component's memory ports another layer down to + # the leaky_relu cell. this_relu_io_ports = cb.build_connections( cell1=comp.this(), cell2=relu_instance, @@ -289,7 +271,7 @@ def build_assignment(group: cb.GroupBuilder, wire, register, output_val): root1="", root2="idx_reg_", forward_ports=["write_en", "in"], - reverse_ports=["out"], + reverse_ports=["out", "done"], ) idx_limit_reached = idx_reg.out == cb.ExprBuilder( py_ast.ConstantPort(BITWIDTH, num_cols) @@ -313,7 +295,7 @@ def leaky_relu_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): Adds a dynamic leaky relu post op to `prog` """ # Create a leaky relu component. - leaky_relu_comp(prog) + leaky_relu_comp(prog, idx_width) comp = prog.component(name=LEAKY_RELU_POST_OP) add_post_op_params(comp, num_rows, idx_width) for r in range(num_rows): diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index be94c43c9..9bc38f15d 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -27,7 +27,7 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } } } -component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 32, l0_addr0: 32, r0_valid: 1, r0_value: 32, r0_idx: 32) { +component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 2, l0_addr0: 2, r0_valid: 1, r0_value: 32, r0_idx: 1) { cells { min_depth_4 = std_reg(32); lt_depth_4 = std_lt(32); @@ -41,10 +41,10 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); - t0_idx = std_reg(32); - t0_add = std_add(32); - l0_idx = std_reg(32); - l0_add = std_add(32); + t0_idx = std_reg(2); + t0_add = std_add(2); + l0_idx = std_reg(2); + l0_add = std_add(2); idx = std_reg(32); idx_add = std_add(32); cond_reg = std_reg(1); @@ -102,11 +102,11 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> depth_plus_6.right = 32'd6; } static<1> group t0_idx_init { - t0_idx.in = 32'd0; + t0_idx.in = 2'd0; t0_idx.write_en = 1'd1; } static<1> group t0_idx_update { - t0_add.left = 32'd1; + t0_add.left = 2'd1; t0_add.right = t0_idx.out; t0_idx.in = t0_add.out; t0_idx.write_en = 1'd1; @@ -117,11 +117,11 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> top_0_0.write_en = 1'd1; } static<1> group l0_idx_init { - l0_idx.in = 32'd0; + l0_idx.in = 2'd0; l0_idx.write_en = 1'd1; } static<1> group l0_idx_update { - l0_add.left = 32'd1; + l0_add.left = 2'd1; l0_add.right = l0_idx.out; l0_idx.in = l0_add.out; l0_idx.write_en = 1'd1; @@ -134,7 +134,7 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> static<1> group pe_0_0_out_write { r0_valid = 1'd1; r0_value = pe_0_0.out; - r0_idx = 32'd0; + r0_idx = 1'd0; } static<1> group init_idx { idx.in = 32'd0; @@ -286,7 +286,7 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> } } } -component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: 32) -> (computation_done: 1, out_mem_0_addr0: 32, out_mem_0_write_data: 32, out_mem_0_write_en: 1) { +component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: 1) -> (computation_done: 1, out_mem_0_addr0: 1, out_mem_0_write_data: 32, out_mem_0_write_en: 1) { cells { delay_reg = std_reg(1); } @@ -298,7 +298,7 @@ component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: } static<1> group write_done_cond { delay_reg.in = 1'd1; - delay_reg.write_en = r0_valid & r0_idx == 32'd0 ? 1'd1; + delay_reg.write_en = r0_valid & r0_idx == 1'd0 ? 1'd1; computation_done = delay_reg.done ? 1'd1; } } @@ -313,9 +313,9 @@ component main() -> () { cells { systolic_array_component = systolic_array_comp(); post_op_component = default_post_op(); - @external t0 = std_mem_d1(32, 3, 32); - @external l0 = std_mem_d1(32, 3, 32); - @external out_mem_0 = std_mem_d1(32, 1, 32); + @external t0 = std_mem_d1(32, 3, 2); + @external l0 = std_mem_d1(32, 3, 2); + @external out_mem_0 = std_mem_d1(32, 1, 1); systolic_done = std_reg(1); systolic_done_wire = std_wire(1); } From d74e7ffe12fad6b070e8256b83f2ee236eabdd69 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:09:12 -0400 Subject: [PATCH 068/189] Add Regular ReLU Post Op for Systolic Arrays (#1720) * better arg parsing * add relu post op * python formatting * simplified interface * small changes --- frontends/systolic-lang/check-output.py | 8 +- frontends/systolic-lang/gen-systolic.py | 115 ++--- .../systolic-lang/gen_array_component.py | 65 +-- frontends/systolic-lang/gen_post_op.py | 149 +++--- .../systolic-lang/systolic_arg_parser.py | 65 +++ runt.toml | 1 + .../systolic/leaky-relu/array-2-3-4.systolic | 4 +- .../systolic/leaky-relu/array-8.systolic | 2 +- .../systolic/relu/array-2-3-4.expect | 47 ++ .../systolic/relu/array-2-3-4.systolic | 7 + .../systolic/relu/array-2-3-4.systolic.data | 108 +++++ .../correctness/systolic/relu/array-8.expect | 245 ++++++++++ .../systolic/relu/array-8.systolic | 7 + .../systolic/relu/array-8.systolic.data | 434 ++++++++++++++++++ 14 files changed, 1071 insertions(+), 186 deletions(-) create mode 100644 frontends/systolic-lang/systolic_arg_parser.py create mode 100644 tests/correctness/systolic/relu/array-2-3-4.expect create mode 100644 tests/correctness/systolic/relu/array-2-3-4.systolic create mode 100644 tests/correctness/systolic/relu/array-2-3-4.systolic.data create mode 100644 tests/correctness/systolic/relu/array-8.expect create mode 100644 tests/correctness/systolic/relu/array-8.systolic create mode 100644 tests/correctness/systolic/relu/array-8.systolic.data diff --git a/frontends/systolic-lang/check-output.py b/frontends/systolic-lang/check-output.py index 6548b39f3..49b3a2782 100644 --- a/frontends/systolic-lang/check-output.py +++ b/frontends/systolic-lang/check-output.py @@ -22,7 +22,7 @@ parser.add_argument("-td", "--top-depth", type=int) parser.add_argument("-ll", "--left-length", type=int) parser.add_argument("-ld", "--left-depth", type=int) - parser.add_argument("-r", "--leaky-relu", action="store_true") + parser.add_argument("-p", "--post-op", type=str, default=None) parser.add_argument("-j", "--json-file", type=str) args = parser.parse_args() @@ -31,7 +31,7 @@ td = args.top_depth ll = args.left_length ld = args.left_depth - relu = args.leaky_relu + post_op = args.post_op json_file = args.json_file assert td == ld, f"Cannot multiply matrices: " f"{tl}x{td} and {ld}x{ll}" @@ -49,8 +49,10 @@ top[r][c] = json_data[f"t{c}"][r] matmul_result = np.matmul(left, top) - if relu: + if post_op == "leaky-relu": matmul_result = np.where(matmul_result > 0, matmul_result, matmul_result * 0.01) + elif post_op == "relu": + matmul_result = np.where(matmul_result > 0, matmul_result, 0) res = [] for r in range(ll): diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 0df164e59..99245f1d7 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import calyx.builder as cb -from calyx.utils import bits_needed from gen_array_component import ( create_systolic_array, BITWIDTH, @@ -9,12 +8,16 @@ ) from gen_post_op import ( default_post_op, + relu_post_op, leaky_relu_post_op, OUT_MEM, DEFAULT_POST_OP, + RELU_POST_OP, LEAKY_RELU_POST_OP, ) +from systolic_arg_parser import SystolicConfiguration, SUPPORTED_POST_OPS from calyx import py_ast +from calyx.utils import bits_needed def create_mem_connections( @@ -39,24 +42,24 @@ def create_mem_connections( bits_needed(mem_size), is_external=True, ) - input_portname = ["addr0"] if read_mem else ["write_data", "write_en", "addr0"] - output_portnames = ["read_data"] if read_mem else ["done"] + input_port_names = ["addr0"] if read_mem else ["write_data", "write_en", "addr0"] + output_port_names = ["read_data"] if read_mem else ["done"] return cb.build_connections( - mem, component_builder, "", f"{mem_name}_", input_portname, output_portnames + mem, component_builder, "", f"{mem_name}_", input_port_names, output_port_names ) -def build_main( - prog, top_length, top_depth, left_length, left_depth, post_op_component_name -): +def build_main(prog, config: SystolicConfiguration, post_op_component_name): """ Build the main component. It basically connects the ports of the systolic component and post_op component in a single group so that they run. """ - assert top_depth == left_depth, ( - f"Cannot multiply matrices: " - f"{top_length}x{top_depth} and {left_depth}x{left_length}" + top_length, top_depth, left_length, left_depth = ( + config.top_length, + config.top_depth, + config.left_length, + config.left_depth, ) main = prog.component("main") systolic_array = main.cell( @@ -128,90 +131,30 @@ def build_main( main.control = py_ast.Enable("perform_computation") -def parse_arguments() -> (int, int, int, int, bool): - """ - Parses arguments and returns the following outputs: - top_length, top_depth, left_length, left_depth, leaky_relu - """ - import argparse - import json - - # Arg parsing - parser = argparse.ArgumentParser(description="Process some integers.") - parser.add_argument("file", nargs="?", type=str) - parser.add_argument("-tl", "--top-length", type=int) - parser.add_argument("-td", "--top-depth", type=int) - parser.add_argument("-ll", "--left-length", type=int) - parser.add_argument("-ld", "--left-depth", type=int) - parser.add_argument("-r", "--leaky-relu", action="store_true") - - args = parser.parse_args() - - top_length, top_depth, left_length, left_depth, leaky_relu = ( - None, - None, - None, - None, - False, - ) - - fields = [args.top_length, args.top_depth, args.left_length, args.left_depth] - if all(map(lambda x: x is not None, fields)): - top_length = args.top_length - top_depth = args.top_depth - left_length = args.left_length - left_depth = args.left_depth - leaky_relu = args.leaky_relu - elif args.file is not None: - with open(args.file, "r") as f: - spec = json.load(f) - top_length = spec["top_length"] - top_depth = spec["top_depth"] - left_length = spec["left_length"] - left_depth = spec["left_depth"] - # default to not perform leaky_relu - leaky_relu = spec.get("leaky_relu", False) - else: - parser.error( - "Need to pass either `FILE` or all of `" - "-tl TOP_LENGTH -td TOP_DEPTH -ll LEFT_LENGTH -ld LEFT_DEPTH`" - ) - return (top_length, top_depth, left_length, left_depth, leaky_relu) - - if __name__ == "__main__": - (top_length, top_depth, left_length, left_depth, leaky_relu) = parse_arguments() + systolic_config = SystolicConfiguration() + systolic_config.parse_arguments() # Building the main component prog = cb.Builder() - create_systolic_array( - prog, - top_length=top_length, - top_depth=top_depth, - left_length=left_length, - left_depth=left_depth, - ) - if leaky_relu: - leaky_relu_post_op( - prog, - num_rows=left_length, - num_cols=top_length, - idx_width=bits_needed(top_length), - ) + create_systolic_array(prog, systolic_config) + if systolic_config.post_op == "leaky-relu": + leaky_relu_post_op(prog, config=systolic_config) post_op_component_name = LEAKY_RELU_POST_OP + elif systolic_config.post_op == "relu": + relu_post_op(prog, config=systolic_config) + post_op_component_name = RELU_POST_OP + elif systolic_config.post_op is None: + default_post_op(prog, config=systolic_config) + post_op_component_name = DEFAULT_POST_OP else: - default_post_op( - prog, - num_rows=left_length, - num_cols=top_length, - idx_width=bits_needed(top_length), + raise ValueError( + f"{systolic_config.post_op} not supported as a post op. \ + Supported post ops are {SUPPORTED_POST_OPS}" ) - post_op_component_name = DEFAULT_POST_OP + build_main( prog, - top_length=top_length, - top_depth=top_depth, - left_length=left_length, - left_depth=left_depth, + config=systolic_config, post_op_component_name=post_op_component_name, ) prog.program.emit() diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index 1ab92664c..5741c44ce 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -5,6 +5,7 @@ import calyx.builder as cb from calyx import py_ast from calyx.utils import bits_needed +from systolic_arg_parser import SystolicConfiguration # Global constant for the current bitwidth. DEPTH = "depth" @@ -430,10 +431,7 @@ def accum_nec_ranges(nec_ranges, schedule): def gen_schedules( - top_length, - top_depth, - left_length, - left_depth, + config: SystolicConfiguration, comp: cb.ComponentBuilder, ): """ @@ -450,6 +448,7 @@ def gen_schedules( `pe_write_sched` contains when to "write" the PE value into the output ports (e.g., this.r0_valid) """ + left_length, top_length = config.left_length, config.top_length depth_port = comp.this().depth min_depth_4_port = comp.get_cell("min_depth_4").port("out") schedules = {} @@ -498,10 +497,7 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): def generate_control( comp: cb.ComponentBuilder, - top_length, - top_depth, - left_length, - left_depth, + config: SystolicConfiguration, schedules, calyx_add_groups, nec_ranges, @@ -517,8 +513,8 @@ def generate_control( c. Move the data needed by each PE 3. Writes the PE values into external memory """ - control = [] + top_length, left_length = config.top_length, config.left_length # Initialize all memories. init_indices: list[py_ast.Control] = [ @@ -623,62 +619,54 @@ def counter(): return py_ast.SeqComp(stmts=control), source_map -def create_systolic_array( - prog: cb.Builder, - top_length, - top_depth, - left_length, - left_depth, -): +def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): """ top_length: Number of PEs in each row. top_depth: Number of elements processed by each PE in a row. left_length: Number of PEs in each column. left_depth: Number of elements processed by each PE in a col. """ - assert top_depth == left_depth, ( - f"Cannot multiply matrices: " - f"{top_length}x{top_depth} and {left_depth}x{left_length}" - ) pe(prog) computational_unit = prog.component(SYSTOLIC_ARRAY_COMP) depth_port = computational_unit.input("depth", BITWIDTH) - init_runtime_vals(computational_unit, depth_port, top_length + left_length + 4) - - schedules = gen_schedules( - top_length, top_depth, left_length, left_depth, computational_unit + init_runtime_vals( + computational_unit, depth_port, config.top_length + config.left_length + 4 ) + + schedules = gen_schedules(config, computational_unit) nec_ranges = set() for sched in schedules.values(): accum_nec_ranges(nec_ranges, sched) calyx_add_groups = instantiate_calyx_adds(computational_unit, nec_ranges) - for row in range(left_length): - for col in range(top_length): + for row in range(config.left_length): + for col in range(config.top_length): # Instantiate the PEs and surronding registers instantiate_pe(computational_unit, row, col) # Instantiate all the memories - for r in range(top_length): - instantiate_memory(computational_unit, "top", r, top_depth) + for r in range(config.top_length): + instantiate_memory(computational_unit, "top", r, config.top_depth) - for col in range(left_length): - instantiate_memory(computational_unit, "left", col, left_depth) + for col in range(config.left_length): + instantiate_memory(computational_unit, "left", col, config.left_depth) # Instantiate output memory - for i in range(left_length): - add_systolic_output_params(computational_unit, i, bits_needed(top_length)) + for i in range(config.left_length): + add_systolic_output_params( + computational_unit, i, bits_needed(config.top_length) + ) # Instantiate all the PEs - for row in range(left_length): - for col in range(top_length): + for row in range(config.left_length): + for col in range(config.top_length): # Instantiate the mover fabric instantiate_data_move( computational_unit, row, col, - col == top_length - 1, - row == left_length - 1, + col == config.top_length - 1, + row == config.left_length - 1, ) # Instantiate output movement structure, i.e., writes to @@ -695,10 +683,7 @@ def create_systolic_array( # Generate the control and set the source map control, source_map = generate_control( computational_unit, - top_length, - top_depth, - left_length, - left_depth, + config, schedules, calyx_add_groups, nec_ranges, diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index 1b1d2556e..b2ae0e558 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -6,11 +6,14 @@ from gen_pe import BITWIDTH, INTWIDTH, FRACWIDTH from fud.stages.verilator import numeric_types from calyx.utils import float_to_fixed_point +from systolic_arg_parser import SystolicConfiguration +from calyx.utils import bits_needed # Name of the ouput array OUT_MEM = "out_mem" DEFAULT_POST_OP = "default_post_op" +RELU_POST_OP = "relu_post_op" LEAKY_RELU_POST_OP = "leaky_relu_post_op" COND_REG = "cond_reg" WRITE_DONE_COND = "write_done_cond" @@ -44,7 +47,36 @@ def add_post_op_params(comp: cb.Builder, num_rows: int, idx_width: int): add_systolic_input_params(comp, r, idx_width) -def create_write_mem_groups(comp: cb.ComponentBuilder, row_num): +def create_immediate_done_condition( + comp: cb.ComponentBuilder, + num_rows: int, + num_cols: int, + idx_width: int, +): + """ + Creates wiring for an "immediate" done condition. + In other words, the done condition is triggered the cycle after the + systolic array presents its final value. + """ + this = comp.this() + final_row_valid = this.port(f"r{num_rows -1}_valid") + final_row_idx = this.port(f"r{num_rows-1}_idx") + max_idx = num_cols - 1 + # delay_reg delays writing to this.computation_done + delay_reg = comp.reg("delay_reg", 1) + final_col_idx_reached = final_row_idx == cb.ExprBuilder( + py_ast.ConstantPort(idx_width, max_idx) + ) + with comp.static_group(WRITE_DONE_COND, 1): + delay_reg.in_ = 1 + # When we are at the final index in the final row, we still need + # one cycle to write into the memory. Therefore, we delay computation_done + # by one cycle. + delay_reg.write_en = (final_row_valid & final_col_idx_reached) @ 1 + this.computation_done = delay_reg.done @ 1 + + +def imm_write_mem_groups(comp: cb.ComponentBuilder, row_num: int, perform_relu: bool): """ Instantiates group that writes the systolic array values for `row_num` into the output memory. @@ -62,65 +94,41 @@ def create_write_mem_groups(comp: cb.ComponentBuilder, row_num): value_port = this.port(NAME_SCHEME["systolic value signal"].format(row_num=row_num)) idx_port = this.port(NAME_SCHEME["systolic idx signal"].format(row_num=row_num)) - # group that writes output of systolic arrays to memory - with comp.static_group(f"write_r{row_num}", 1) as g: - g.asgn(write_en_port, valid_port) - g.asgn(write_data_port, value_port) - g.asgn(addr0_port, idx_port) - - -def done_condition_groups( - comp: cb.ComponentBuilder, - num_rows: int, - num_cols: int, - idx_width: int, - leaky_relu: bool, -): - """ - Writes to this.computation_done - For leaky relu, we wait until the relu operations are done for each row. - For default post op, you simply have to check when the systolic array output - is at the last entry. - """ - this = comp.this() - # ports to read from systolic array - if leaky_relu: - # Check if all relu operations have finished for each row - guard = comp.get_cell("relu_finished_wire_r0").out - for r in range(1, num_rows): - guard = guard & comp.get_cell(f"relu_finished_wire_r{r}").out - all_relu_finished_wire = comp.wire("all_relu_finished_wire", 1) - with comp.static_group(WRITE_DONE_COND, 1): - all_relu_finished_wire.in_ = guard @ 1 - this.computation_done = all_relu_finished_wire.out @ 1 + if perform_relu: + # lt operator to see if value is < 0 + lt = comp.fp_sop(f"val_lt_r{row_num}", "lt", BITWIDTH, INTWIDTH, FRACWIDTH) + # group that writes output of systolic arrays to memory + with comp.static_group(f"write_r{row_num}", 1) as g: + lt.left = value_port + lt.right = 0 + g.asgn(write_en_port, valid_port) + g.asgn(write_data_port, value_port, ~lt.out) + g.asgn(write_data_port, 0, lt.out) + g.asgn(addr0_port, idx_port) else: - final_row_valid = this.port(f"r{num_rows -1}_valid") - final_row_idx = this.port(f"r{num_rows-1}_idx") - max_idx = num_cols - 1 - # delay_reg delays writing to this.computation_done - delay_reg = comp.reg("delay_reg", 1) - final_col_idx_reached = final_row_idx == cb.ExprBuilder( - py_ast.ConstantPort(idx_width, max_idx) - ) - with comp.static_group(WRITE_DONE_COND, 1): - delay_reg.in_ = 1 - # When we are at the final index in the final row, we still need - # one cycle to write into the memory. Therefore, we delay computation_done - # by one cycle. - delay_reg.write_en = (final_row_valid & final_col_idx_reached) @ 1 - this.computation_done = delay_reg.done @ 1 + with comp.static_group(f"write_r{row_num}", 1) as g: + g.asgn(write_en_port, valid_port) + g.asgn(write_data_port, value_port) + g.asgn(addr0_port, idx_port) -def default_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): +def imm_write_mem_post_op( + prog: cb.Builder, config: SystolicConfiguration, perform_relu: bool +): """ - Adds a default post-op to `prog`. This post-op does nothing except immediately write to memory. + If perform_relu is true, then writes 0 to memory if result < 0, and writes + the result to memory otherwise. In other words, it performs relu on the value + before writing to memory. """ - comp = prog.component(name=DEFAULT_POST_OP) + (num_rows, num_cols) = config.get_output_dimensions() + idx_width = bits_needed(num_cols) + post_op_name = RELU_POST_OP if perform_relu else DEFAULT_POST_OP + comp = prog.component(name=post_op_name) add_post_op_params(comp, num_rows, idx_width) for r in range(num_rows): - create_write_mem_groups(comp, r) - done_condition_groups(comp, num_rows, num_cols, idx_width, leaky_relu=False) + imm_write_mem_groups(comp, r, perform_relu=perform_relu) + create_immediate_done_condition(comp, num_rows, num_cols, idx_width) comp.control = py_ast.StaticParComp( [py_ast.Enable(WRITE_DONE_COND)] @@ -129,6 +137,21 @@ def default_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): ) +def default_post_op(prog: cb.Builder, config: SystolicConfiguration): + """ + Default post op that immediately writes to output memory. + """ + imm_write_mem_post_op(prog=prog, config=config, perform_relu=False) + + +def relu_post_op(prog: cb.Builder, config: SystolicConfiguration): + """ + Relu post op that (combinationally) performs relu before + immediately writing the result to memory. + """ + imm_write_mem_post_op(prog=prog, config=config, perform_relu=True) + + def leaky_relu_comp(prog: cb.Builder, idx_width: int): """ Creates a dynamic, non-pipelined, leaky relu component. @@ -183,6 +206,22 @@ def leaky_relu_comp(prog: cb.Builder, idx_width: int): comp.control = py_ast.Enable("do_relu") +def create_leaky_relu_done_condition(comp: cb.ComponentBuilder, num_rows: int): + """ + The done condition for leaky relu components is triggered once all of the + leaky relu operations have finished. + """ + this = comp.this() + # Check if all relu operations have finished for each row + guard = comp.get_cell("relu_finished_wire_r0").out + for r in range(1, num_rows): + guard = guard & comp.get_cell(f"relu_finished_wire_r{r}").out + all_relu_finished_wire = comp.wire("all_relu_finished_wire", 1) + with comp.static_group(WRITE_DONE_COND, 1): + all_relu_finished_wire.in_ = guard @ 1 + this.computation_done = all_relu_finished_wire.out @ 1 + + def create_leaky_relu_groups(comp: cb.ComponentBuilder, row, num_cols, addr_width): """ Creates the groups for the leaky relu post op, i.e., the post-op that @@ -290,17 +329,19 @@ def build_assignment(group: cb.GroupBuilder, wire, register, output_val): relu_finished_wire.in_ = idx_limit_reached @ 1 -def leaky_relu_post_op(prog: cb.Builder, num_rows, num_cols, idx_width): +def leaky_relu_post_op(prog: cb.Builder, config: SystolicConfiguration): """ Adds a dynamic leaky relu post op to `prog` """ + num_rows, num_cols = config.get_output_dimensions() + idx_width = bits_needed(num_cols) # Create a leaky relu component. leaky_relu_comp(prog, idx_width) comp = prog.component(name=LEAKY_RELU_POST_OP) add_post_op_params(comp, num_rows, idx_width) for r in range(num_rows): create_leaky_relu_groups(comp, r, num_cols, idx_width) - done_condition_groups(comp, num_rows, num_cols, idx_width, leaky_relu=True) + create_leaky_relu_done_condition(comp, num_rows) # all_groups go in one big static par. all_groups = [py_ast.Enable(WRITE_DONE_COND)] diff --git a/frontends/systolic-lang/systolic_arg_parser.py b/frontends/systolic-lang/systolic_arg_parser.py new file mode 100644 index 000000000..e787e7b63 --- /dev/null +++ b/frontends/systolic-lang/systolic_arg_parser.py @@ -0,0 +1,65 @@ +import argparse +import json + +SUPPORTED_POST_OPS = ["leaky-relu", "relu"] + + +class SystolicConfiguration: + """ + A class that represents a "systolic configuration". Includes: + top_length, top_depth, left_length, left_depth + post_op + post_op has a default of None, the other values have no default: their value + must be provided. + """ + + def parse_arguments(self): + """ + Parses arguments to give self the following fields: + top_length, top_depth, left_length, left_depth, and post_op + """ + + # Arg parsing + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument("file", nargs="?", type=str) + parser.add_argument("-tl", "--top-length", type=int) + parser.add_argument("-td", "--top-depth", type=int) + parser.add_argument("-ll", "--left-length", type=int) + parser.add_argument("-ld", "--left-depth", type=int) + parser.add_argument("-p", "--post-op", type=str, default=None) + + args = parser.parse_args() + + fields = [args.top_length, args.top_depth, args.left_length, args.left_depth] + if all(map(lambda x: x is not None, fields)): + self.top_length = args.top_length + self.top_depth = args.top_depth + self.left_length = args.left_length + self.left_depth = args.left_depth + self.post_op = args.post_op + elif args.file is not None: + with open(args.file, "r") as f: + spec = json.load(f) + self.top_length = spec["top_length"] + self.top_depth = spec["top_depth"] + self.left_length = spec["left_length"] + self.left_depth = spec["left_depth"] + # default to not perform leaky_relu + self.post_op = spec.get("post_op", None) + else: + parser.error( + "Need to pass either `FILE` or all of `" + "-tl TOP_LENGTH -td TOP_DEPTH -ll LEFT_LENGTH -ld LEFT_DEPTH`" + ) + assert self.top_depth == self.left_depth, ( + f"Cannot multiply matrices: " + f"{self.top_length}x{self.top_depth} and \ + {self.left_depth}x{self.left_length}" + ) + + def get_output_dimensions(self): + """ + Returns the dimensions of the output systolic array (in the form + of num_rows x num_cols) + """ + return (self.left_length, self.top_length) diff --git a/runt.toml b/runt.toml index dec851872..50b15d8e0 100644 --- a/runt.toml +++ b/runt.toml @@ -266,6 +266,7 @@ name = "[frontend] systolic array output correctness" paths = [ "tests/correctness/systolic/output/*.systolic", "tests/correctness/systolic/leaky-relu/*.systolic", + "tests/correctness/systolic/relu/*.systolic", ] cmd = """ fud e --from systolic --to dat \ diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic index 4394a5bd2..b3b1ee271 100644 --- a/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.systolic @@ -2,6 +2,6 @@ "top_length": 4, "top_depth": 3, "left_length": 2, - "left_depth": 3, - "leaky_relu": true + "left_depth": 3, + "post_op": "leaky-relu" } \ No newline at end of file diff --git a/tests/correctness/systolic/leaky-relu/array-8.systolic b/tests/correctness/systolic/leaky-relu/array-8.systolic index b92e26302..2a86a684a 100644 --- a/tests/correctness/systolic/leaky-relu/array-8.systolic +++ b/tests/correctness/systolic/leaky-relu/array-8.systolic @@ -3,5 +3,5 @@ "top_depth": 8, "left_length": 8, "left_depth": 8, - "leaky_relu": true + "post_op": "leaky-relu" } \ No newline at end of file diff --git a/tests/correctness/systolic/relu/array-2-3-4.expect b/tests/correctness/systolic/relu/array-2-3-4.expect new file mode 100644 index 000000000..63064e7a8 --- /dev/null +++ b/tests/correctness/systolic/relu/array-2-3-4.expect @@ -0,0 +1,47 @@ +{ + "cycles": 15, + "memories": { + "l0": [ + "3.349822998046875", + "3.6539764404296875", + "0.0511016845703125" + ], + "l1": [ + "-0.1660003662109375", + "3.43817138671875", + "0.1073760986328125" + ], + "out_mem_0": [ + "12.569793701171875", + "0", + "1.2611541748046875", + "8.012969970703125" + ], + "out_mem_1": [ + "0", + "0", + "0.964019775390625", + "1.9193878173828125" + ], + "t0": [ + "4.0580596923828125", + "-0.2537078857421875", + "-1.896697998046875" + ], + "t1": [ + "-1.2882843017578125", + "-3.0372772216796875", + "3.0884552001953125" + ], + "t2": [ + "0.073028564453125", + "0.2735595703125", + "0.3317718505859375" + ], + "t3": [ + "1.702178955078125", + "0.6259765625", + "0.4635009765625" + ] + } +} diff --git a/tests/correctness/systolic/relu/array-2-3-4.systolic b/tests/correctness/systolic/relu/array-2-3-4.systolic new file mode 100644 index 000000000..b6e90c92c --- /dev/null +++ b/tests/correctness/systolic/relu/array-2-3-4.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 4, + "top_depth": 3, + "left_length": 2, + "left_depth": 3, + "post_op": "relu" +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu/array-2-3-4.systolic.data b/tests/correctness/systolic/relu/array-2-3-4.systolic.data new file mode 100644 index 000000000..823b904b4 --- /dev/null +++ b/tests/correctness/systolic/relu/array-2-3-4.systolic.data @@ -0,0 +1,108 @@ +{ + "l0": { + "data": [ + 3.349827766418457, + 3.6539793014526367, + 0.05110502243041992 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + -0.16600513458251953, + 3.4381656646728516, + 0.1073751449584961 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + 4.058065414428711, + -0.2537107467651367, + -1.8967020511627197 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + -1.2882888317108154, + -3.0372798442840576, + 3.0884532928466797 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + 0.07303619384765625, + 0.27355289459228516, + 0.3317680358886719 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + 1.702174186706543, + 0.6259689331054688, + 0.4635009765625 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu/array-8.expect b/tests/correctness/systolic/relu/array-8.expect new file mode 100644 index 000000000..c7ae4dd1f --- /dev/null +++ b/tests/correctness/systolic/relu/array-8.expect @@ -0,0 +1,245 @@ +{ + "cycles": 30, + "memories": { + "l0": [ + "-1.49566650390625", + "-0.9142608642578125", + "-2.6135711669921875", + "1.4980010986328125", + "-3.4720001220703125", + "3.4763031005859375", + "-0.016571044921875", + "-2.989044189453125" + ], + "l1": [ + "-1.33184814453125", + "2.9468841552734375", + "1.7263946533203125", + "-1.7017974853515625", + "-1.13458251953125", + "-4.711273193359375", + "-0.290771484375", + "-4.2563934326171875" + ], + "l2": [ + "1.1874237060546875", + "-3.408599853515625", + "-1.801544189453125", + "1.1929931640625", + "-1.8954010009765625", + "-3.1168060302734375", + "0.3030242919921875", + "-1.095611572265625" + ], + "l3": [ + "-2.2605743408203125", + "-4.778472900390625", + "4.631988525390625", + "-2.366485595703125", + "2.2865142822265625", + "-1.9458465576171875", + "2.51043701171875", + "-0.420989990234375" + ], + "l4": [ + "2.081451416015625", + "-2.0117034912109375", + "-3.0953369140625", + "0.8167266845703125", + "-0.9581451416015625", + "-2.253204345703125", + "3.2512359619140625", + "0.8149871826171875" + ], + "l5": [ + "4.9659271240234375", + "-4.0330352783203125", + "0.3494110107421875", + "0.9843292236328125", + "-1.1136932373046875", + "-0.161285400390625", + "3.5453338623046875", + "-4.283843994140625" + ], + "l6": [ + "3.9283294677734375", + "1.32122802734375", + "-0.6650543212890625", + "4.8896026611328125", + "2.450042724609375", + "2.7947235107421875", + "1.7928314208984375", + "-1.518035888671875" + ], + "l7": [ + "-4.6738739013671875", + "-4.4643096923828125", + "0.1487274169921875", + "-3.4300994873046875", + "2.415863037109375", + "-3.8175506591796875", + "3.8909149169921875", + "-0.361236572265625" + ], + "out_mem_0": [ + "0", + "0", + "0", + "23.335174560546875", + "5.11322021484375", + "0", + "0.1280364990234375", + "0" + ], + "out_mem_1": [ + "0", + "1.920379638671875", + "0", + "45.25958251953125", + "32.78094482421875", + "0", + "0", + "33.4017333984375" + ], + "out_mem_2": [ + "0", + "0", + "0", + "29.5540618896484375", + "23.58514404296875", + "0", + "0.9548797607421875", + "0" + ], + "out_mem_3": [ + "21.81707763671875", + "0", + "0", + "5.942596435546875", + "19.353363037109375", + "0", + "6.6043853759765625", + "21.3936614990234375" + ], + "out_mem_4": [ + "0", + "1.3929443359375", + "0", + "16.4472808837890625", + "16.946075439453125", + "0", + "21.7616119384765625", + "0" + ], + "out_mem_5": [ + "29.9978179931640625", + "0", + "0", + "18.637359619140625", + "42.1724090576171875", + "0", + "6.4488067626953125", + "4.316436767578125" + ], + "out_mem_6": [ + "34.8578338623046875", + "18.028961181640625", + "23.9514617919921875", + "0", + "16.2915496826171875", + "2.3678436279296875", + "15.6302032470703125", + "0" + ], + "out_mem_7": [ + "0", + "0", + "0", + "27.7047271728515625", + "18.578521728515625", + "0", + "14.9741973876953125", + "10.2684478759765625" + ], + "t0": [ + "4.9021759033203125", + "-2.5044708251953125", + "4.5919189453125", + "0.601043701171875", + "2.68255615234375", + "4.476806640625", + "1.82684326171875", + "2.19659423828125" + ], + "t1": [ + "3.4096832275390625", + "4.9857330322265625", + "-3.820037841796875", + "-0.70623779296875", + "4.9615936279296875", + "-2.083038330078125", + "-2.567901611328125", + "1.8252105712890625" + ], + "t2": [ + "-0.772216796875", + "4.754638671875", + "-0.936676025390625", + "2.935699462890625", + "2.22613525390625", + "1.5690155029296875", + "-1.6681365966796875", + "0.73956298828125" + ], + "t3": [ + "-3.9584503173828125", + "0.05987548828125", + "-0.902618408203125", + "3.788360595703125", + "-3.4463958740234375", + "-4.98907470703125", + "2.5916900634765625", + "-4.97015380859375" + ], + "t4": [ + "0.08782958984375", + "-0.653778076171875", + "1.889984130859375", + "3.657745361328125", + "-1.1245880126953125", + "-3.8535003662109375", + "3.775634765625", + "-4.5704193115234375" + ], + "t5": [ + "-0.3739166259765625", + "1.5081634521484375", + "0.3743133544921875", + "3.133514404296875", + "-1.101104736328125", + "0.3949737548828125", + "-3.9834136962890625", + "2.9597930908203125" + ], + "t6": [ + "1.1507720947265625", + "-4.7238922119140625", + "-3.618682861328125", + "-0.121856689453125", + "3.2436065673828125", + "3.9204864501953125", + "2.1115570068359375", + "4.709442138671875" + ], + "t7": [ + "0.51519775390625", + "2.701629638671875", + "4.22308349609375", + "-3.078399658203125", + "0.3193511962890625", + "-1.3680877685546875", + "1.766815185546875", + "-1.8860321044921875" + ] + } +} diff --git a/tests/correctness/systolic/relu/array-8.systolic b/tests/correctness/systolic/relu/array-8.systolic new file mode 100644 index 000000000..28171f964 --- /dev/null +++ b/tests/correctness/systolic/relu/array-8.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 8, + "top_depth": 8, + "left_length": 8, + "left_depth": 8, + "post_op": "relu" +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu/array-8.systolic.data b/tests/correctness/systolic/relu/array-8.systolic.data new file mode 100644 index 000000000..34b867727 --- /dev/null +++ b/tests/correctness/systolic/relu/array-8.systolic.data @@ -0,0 +1,434 @@ +{ + "l0": { + "data": [ + -1.4956629276275635, + -0.9142565727233887, + -2.6135730743408203, + 1.4980006217956543, + -3.472006320953369, + 3.476308822631836, + -0.016571044921875, + -2.989037036895752 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + -1.3318490982055664, + 2.9468870162963867, + 1.726388931274414, + -1.7017900943756104, + -1.1345791816711426, + -4.711271286010742, + -0.2907705307006836, + -4.256398677825928 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l2": { + "data": [ + 1.187424659729004, + -3.408595323562622, + -1.801539659500122, + 1.1929893493652344, + -1.8953990936279297, + -3.116804361343384, + 0.3030214309692383, + -1.0956144332885742 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l3": { + "data": [ + -2.2605812549591064, + -4.778478145599365, + 4.631991386413574, + -2.3664891719818115, + 2.2865095138549805, + -1.9458460807800293, + 2.51043701171875, + -0.42099571228027344 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l4": { + "data": [ + 2.0814504623413086, + -2.011702060699463, + -3.095329999923706, + 0.8167314529418945, + -0.9581432342529297, + -2.253211736679077, + 3.2512292861938477, + 0.8149852752685547 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l5": { + "data": [ + 4.965932846069336, + -4.033029079437256, + 0.34941768646240234, + 0.9843292236328125, + -1.1136901378631592, + -0.16128921508789062, + 3.5453338623046875, + -4.283846855163574 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l6": { + "data": [ + 3.9283323287963867, + 1.3212251663208008, + -0.6650471687316895, + 4.8896074295043945, + 2.45003604888916, + 2.7947306632995605, + 1.7928242683410645, + -1.5180349349975586 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l7": { + "data": [ + -4.673877716064453, + -4.464309215545654, + 0.14873123168945312, + -3.4300994873046875, + 2.415858268737793, + -3.8175439834594727, + 3.890915870666504, + -0.36124229431152344 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_2": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_3": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_4": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_5": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_6": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_7": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + 4.902173042297363, + -2.5044643878936768, + 4.591917037963867, + 0.601048469543457, + 2.6825523376464844, + 4.476808547973633, + 1.8268499374389648, + 2.1965885162353516 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + 3.4096832275390625, + 4.9857330322265625, + -3.8200438022613525, + -0.706233024597168, + 4.961596488952637, + -2.0830368995666504, + -2.5678956508636475, + 1.825209617614746 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + -0.7722148895263672, + 4.754638671875, + -0.9366703033447266, + 2.935696601867676, + 2.2261343002319336, + 1.569009780883789, + -1.6681408882141113, + 0.7395687103271484 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + -3.9584505558013916, + 0.05988121032714844, + -0.9026155471801758, + 3.7883644104003906, + -3.446394205093384, + -4.989075660705566, + 2.5916852951049805, + -4.970152378082275 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t4": { + "data": [ + 0.08782482147216797, + -0.6537842750549316, + 1.8899774551391602, + 3.6577377319335938, + -1.1245930194854736, + -3.853501081466675, + 3.7756290435791016, + -4.57042121887207 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t5": { + "data": [ + -0.3739175796508789, + 1.5081634521484375, + 0.3743171691894531, + 3.1335086822509766, + -1.1011040210723877, + 0.39496898651123047, + -3.983415365219116, + 2.9597973823547363 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t6": { + "data": [ + 1.1507759094238281, + -4.7238874435424805, + -3.618685007095337, + -0.12185335159301758, + 3.2436037063598633, + 3.9204845428466797, + 2.1115517616271973, + 4.709440231323242 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t7": { + "data": [ + 0.5151915550231934, + 2.7016282081604004, + 4.223084449768066, + -3.078404664993286, + 0.31935787200927734, + -1.3680875301361084, + 1.7668190002441406, + -1.8860268592834473 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file From 750a7c97bbac57cb703f5394ce07233754815e23 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:47:32 -0400 Subject: [PATCH 069/189] Dynamic Implementation of ReLU (#1727) * dynamic relu implementation * formatting --- frontends/systolic-lang/gen-systolic.py | 36 +- frontends/systolic-lang/gen_post_op.py | 182 +++++--- .../systolic-lang/systolic_arg_parser.py | 2 +- runt.toml | 1 + .../systolic/leaky-relu/array-2-3-4.expect | 2 +- .../systolic/leaky-relu/array-8.expect | 2 +- .../systolic/relu-dynamic/array-2-3-4.expect | 47 ++ .../relu-dynamic/array-2-3-4.systolic | 7 + .../relu-dynamic/array-2-3-4.systolic.data | 108 +++++ .../systolic/relu-dynamic/array-8.expect | 245 ++++++++++ .../systolic/relu-dynamic/array-8.systolic | 7 + .../relu-dynamic/array-8.systolic.data | 434 ++++++++++++++++++ 12 files changed, 1000 insertions(+), 73 deletions(-) create mode 100644 tests/correctness/systolic/relu-dynamic/array-2-3-4.expect create mode 100644 tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic create mode 100644 tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data create mode 100644 tests/correctness/systolic/relu-dynamic/array-8.expect create mode 100644 tests/correctness/systolic/relu-dynamic/array-8.systolic create mode 100644 tests/correctness/systolic/relu-dynamic/array-8.systolic.data diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index 99245f1d7..dfe992b6e 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 import calyx.builder as cb +from systolic_arg_parser import SystolicConfiguration +from calyx import py_ast +from calyx.utils import bits_needed from gen_array_component import ( create_systolic_array, BITWIDTH, @@ -10,14 +13,22 @@ default_post_op, relu_post_op, leaky_relu_post_op, + relu_dynamic_post_op, OUT_MEM, DEFAULT_POST_OP, RELU_POST_OP, LEAKY_RELU_POST_OP, + RELU_DYNAMIC_POST_OP, ) -from systolic_arg_parser import SystolicConfiguration, SUPPORTED_POST_OPS -from calyx import py_ast -from calyx.utils import bits_needed + +# Dict that maps command line arguments (e.g., "leaky-relu") to component names +# and function that creates them. +POST_OP_DICT = { + None: (DEFAULT_POST_OP, default_post_op), + "leaky-relu": (LEAKY_RELU_POST_OP, leaky_relu_post_op), + "relu": (RELU_POST_OP, relu_post_op), + "relu-dynamic": (RELU_DYNAMIC_POST_OP, relu_dynamic_post_op), +} def create_mem_connections( @@ -90,7 +101,7 @@ def build_main(prog, config: SystolicConfiguration, post_op_component_name): # Connect outout memories to post_op, and systolic_array_output to # post_op inputs. for i in range(left_length): - # connect output memory to post op + # Connect output memory to post op. want to write to this memory. connections += create_mem_connections( main, post_op, OUT_MEM + f"_{i}", top_length, read_mem=False ) @@ -137,19 +148,16 @@ def build_main(prog, config: SystolicConfiguration, post_op_component_name): # Building the main component prog = cb.Builder() create_systolic_array(prog, systolic_config) - if systolic_config.post_op == "leaky-relu": - leaky_relu_post_op(prog, config=systolic_config) - post_op_component_name = LEAKY_RELU_POST_OP - elif systolic_config.post_op == "relu": - relu_post_op(prog, config=systolic_config) - post_op_component_name = RELU_POST_OP - elif systolic_config.post_op is None: - default_post_op(prog, config=systolic_config) - post_op_component_name = DEFAULT_POST_OP + if systolic_config.post_op in POST_OP_DICT.keys(): + post_op_component_name, component_building_func = POST_OP_DICT[ + systolic_config.post_op + ] + component_building_func(prog, config=systolic_config) else: raise ValueError( f"{systolic_config.post_op} not supported as a post op. \ - Supported post ops are {SUPPORTED_POST_OPS}" + Supported post ops are (None means you pass no argument for -p) \ + {POST_OP_DICT.keys()}" ) build_main( diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index b2ae0e558..206c39332 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -15,6 +15,7 @@ DEFAULT_POST_OP = "default_post_op" RELU_POST_OP = "relu_post_op" LEAKY_RELU_POST_OP = "leaky_relu_post_op" +RELU_DYNAMIC_POST_OP = "relu_dynamic_post_op" COND_REG = "cond_reg" WRITE_DONE_COND = "write_done_cond" @@ -152,23 +153,31 @@ def relu_post_op(prog: cb.Builder, config: SystolicConfiguration): imm_write_mem_post_op(prog=prog, config=config, perform_relu=True) -def leaky_relu_comp(prog: cb.Builder, idx_width: int): +def add_dynamic_op_params(comp: cb.ComponentBuilder, idx_width: int): + """ + Adds neccesary parameters for dynamic ops, including: + 1) Input value + 1) Parameters to write the result of the op to memory. + 2) Input index (for the memory to write to) + """ + comp.input("value", BITWIDTH) + comp.input("idx", idx_width) + cb.add_write_mem_params(comp, OUT_MEM, data_width=BITWIDTH, addr_width=idx_width) + + +def leaky_relu_comp(prog: cb.Builder, idx_width: int) -> cb.ComponentBuilder: """ Creates a dynamic, non-pipelined, leaky relu component. This is the component that actually performs the leaky relu computation on a given output. """ - comp = prog.component(name="leaky_relu") - comp.input("value", BITWIDTH) - # Takes a memory and register (i.e., arguments that essentially act as ref cells) - cb.add_write_mem_params(comp, OUT_MEM, data_width=BITWIDTH, addr_width=idx_width) - cb.add_register_params(comp, "idx_reg", idx_width) + comp = prog.component(name="leaky_relu_op") + add_dynamic_op_params(comp, idx_width) this = comp.this() fp_mult = comp.fp_sop("fp_mult", "mult_pipe", BITWIDTH, INTWIDTH, FRACWIDTH) lt = comp.fp_sop("val_lt", "lt", BITWIDTH, INTWIDTH, FRACWIDTH) - incr_idx = comp.add(idx_width, "incr_idx") write_mem = comp.wire("should_write_mem", 1) with comp.continuous: @@ -188,15 +197,9 @@ def leaky_relu_comp(prog: cb.Builder, idx_width: int): fp_mult.right = this.value fp_mult.go = ~(write_mem.out) @ 1 - # Increment idx_reg during the cycle that we write to memory. - incr_idx.left = this.idx_reg_out - incr_idx.right = 1 - this.idx_reg_in = write_mem.out @ incr_idx.out - this.idx_reg_write_en = write_mem.out @ 1 - # Write to memory. this.out_mem_write_en = write_mem.out @ 1 - this.out_mem_addr0 = this.idx_reg_out + this.out_mem_addr0 = this.idx # Write value if this.value >= 0 # Write mult.out if this.value < 0 this.out_mem_write_data = ~lt.out @ this.value @@ -205,24 +208,68 @@ def leaky_relu_comp(prog: cb.Builder, idx_width: int): comp.control = py_ast.Enable("do_relu") + return comp + -def create_leaky_relu_done_condition(comp: cb.ComponentBuilder, num_rows: int): +def relu_dynamic_comp(prog: cb.Builder, idx_width: int): + """ + Creates a dynamic, regular RELU component. + This dynamic implementation is meant to be compared to a static + ReLU implementation in order to show the benefits of static groups and + control. + """ + comp = prog.component(name="relu_dynamic_op") + add_dynamic_op_params(comp, idx_width) + + this = comp.this() + + lt = comp.fp_sop("val_lt", "lt", BITWIDTH, INTWIDTH, FRACWIDTH) + + with comp.continuous: + # gt holds whether this.value > 0 + lt.left = this.value + lt.right = 0 + + with comp.group("do_relu") as g: + # Write to memory. + this.out_mem_write_en = 1 + this.out_mem_addr0 = this.idx + # Write value if this.value >= 0 + # Write mult.out if this.value < 0 + this.out_mem_write_data = ~lt.out @ this.value + this.out_mem_write_data = lt.out @ 0 + + # It takes one cycle to write to g + g.done = this.out_mem_done + + comp.control = py_ast.Enable("do_relu") + + return comp + + +def generate_dynamic_post_op_done(comp: cb.ComponentBuilder, num_rows: int): """ The done condition for leaky relu components is triggered once all of the leaky relu operations have finished. """ this = comp.this() # Check if all relu operations have finished for each row - guard = comp.get_cell("relu_finished_wire_r0").out + guard = comp.get_cell("op_finished_wire_r0").out for r in range(1, num_rows): - guard = guard & comp.get_cell(f"relu_finished_wire_r{r}").out - all_relu_finished_wire = comp.wire("all_relu_finished_wire", 1) + guard = guard & comp.get_cell(f"op_finished_wire_r{r}").out + all_row_finished_wire = comp.wire("all_row_finished_wire", 1) with comp.static_group(WRITE_DONE_COND, 1): - all_relu_finished_wire.in_ = guard @ 1 - this.computation_done = all_relu_finished_wire.out @ 1 + all_row_finished_wire.in_ = guard @ 1 + this.computation_done = all_row_finished_wire.out @ 1 -def create_leaky_relu_groups(comp: cb.ComponentBuilder, row, num_cols, addr_width): +def create_dynamic_post_op_groups( + comp: cb.ComponentBuilder, + row: int, + num_cols: int, + addr_width: int, + op_component: cb.ComponentBuilder, +): """ Creates the groups for the leaky relu post op, i.e., the post-op that coordinates the execution of the leaky relu component. @@ -230,7 +277,7 @@ def create_leaky_relu_groups(comp: cb.ComponentBuilder, row, num_cols, addr_widt def store_output_vals(comp: cb.ComponentBuilder, row, num_cols, addr_width): """ - Helper function that looks at the systolic array output signsl (e.g., + Helper function that looks at the systolic array output signals (e.g., `r0_valid`, `r0_value`, etc.) and creates signals that tells us when: a) each row is ready for the leaky relu operations to start and b) the output systolic array values (we need them in registers bc the systolic @@ -249,7 +296,7 @@ def store_output_vals(comp: cb.ComponentBuilder, row, num_cols, addr_width): value_ready_signal = valid_signal & ( idx_signal == cb.ExprBuilder(py_ast.ConstantPort(addr_width, col)) ) - with comp.static_group(f"r{row}_c{col}_value_group", 1): + with comp.continuous: # Wire to detect and hold when the row is first valid. Once # it is valid, we can safely start our relu operations. row_ready_reg.in_ = valid_signal @ 1 @@ -265,90 +312,113 @@ def store_output_vals(comp: cb.ComponentBuilder, row, num_cols, addr_width): reg_value.write_en = val_ready.out @ 1 # Helper function adds assignment wire.in = reg.out == col ? pe_{row}_{col}_out. - def build_assignment(group: cb.GroupBuilder, wire, register, output_val): - group.asgn( + def build_assignment(wire, register, output_val): + comp.continuous.asgn( wire.port("in"), output_val.out, register.port("out") == cb.ExprBuilder(py_ast.ConstantPort(BITWIDTH, col)), ) - group = comp.static_group(f"r{row}_helper", 1) - # Current value we are performing relu on. cur_val = comp.wire(f"r{row}_cur_val", BITWIDTH) # Current idx within the row (i.e., column) for the value we are performing relu on. idx_reg = comp.reg(f"r{row}_cur_idx", addr_width) # Handling logic to hold the systolic array's output values so they're available - # for moer than one cycle. + # for more than one cycle. store_output_vals(comp, row, num_cols, addr_width) for col in range(num_cols): output_val = comp.get_cell(f"r{row}_c{col}_val_wire") # Assigning to cur_val wire so that we always have the current value of the # row based on idx_reg. - build_assignment(group, cur_val, idx_reg, output_val) + build_assignment(cur_val, idx_reg, output_val) # Instantiate an instance of a leaky_relu component - relu_instance = comp.cell(f"leaky_relu_r{row}", py_ast.CompInst("leaky_relu", [])) + op_instance = comp.cell( + f"{op_component.component.name}_r{row}", + py_ast.CompInst(op_component.component.name, []), + ) # Wire that tells us we are finished with relu operation for this row. - relu_finished_wire = comp.wire(f"relu_finished_wire_r{row}", 1) + row_finished_wire = comp.wire(f"op_finished_wire_r{row}", 1) row_ready_wire = comp.get_cell(f"r{row}_ready_wire") + incr_idx = comp.add(bits_needed(num_cols), f"incr_idx_r{row}") # Need to pass this component's memory ports another layer down to # the leaky_relu cell. this_relu_io_ports = cb.build_connections( cell1=comp.this(), - cell2=relu_instance, + cell2=op_instance, root1=OUT_MEM + f"_{row}_", root2=OUT_MEM + "_", forward_ports=["addr0", "write_data", "write_en"], reverse_ports=["done"], ) - # Building connections between relu and idx_reg - relu_idx_io_ports = cb.build_connections( - cell1=idx_reg, - cell2=relu_instance, - root1="", - root2="idx_reg_", - forward_ports=["write_en", "in"], - reverse_ports=["out", "done"], - ) idx_limit_reached = idx_reg.out == cb.ExprBuilder( py_ast.ConstantPort(BITWIDTH, num_cols) ) with comp.static_group(f"execute_relu_r{row}", 1) as g: for i, o in this_relu_io_ports: g.asgn(i, o) - for i, o in relu_idx_io_ports: - g.asgn(i, o) # Handle incrementing the idx_reg. - relu_instance.go = ( - row_ready_wire.out & (~relu_finished_wire.out) + incr_idx.left = idx_reg.out + incr_idx.right = 1 + idx_reg.in_ = incr_idx.out + # Increment idx once the op is done executing + idx_reg.write_en = op_instance.done @ 1 + + op_instance.go = ( + row_ready_wire.out & (~row_finished_wire.out) & (~op_instance.done) ) @ cb.ExprBuilder(py_ast.ConstantPort(1, 1)) # input ports for relu_instance - relu_instance.value = cur_val.out - relu_finished_wire.in_ = idx_limit_reached @ 1 + op_instance.value = cur_val.out + op_instance.idx = idx_reg.out + row_finished_wire.in_ = idx_limit_reached @ 1 -def leaky_relu_post_op(prog: cb.Builder, config: SystolicConfiguration): +def dynamic_post_op( + prog: cb.Builder, + config: SystolicConfiguration, + post_op_component_name: str, + op_component: cb.ComponentBuilder, +): """ - Adds a dynamic leaky relu post op to `prog` + Adds a dynamic post op that performs handles the coordination so that + `op_component` (which can be dynamic) gets executed dynamically on each + systolic array output. """ num_rows, num_cols = config.get_output_dimensions() idx_width = bits_needed(num_cols) # Create a leaky relu component. - leaky_relu_comp(prog, idx_width) - comp = prog.component(name=LEAKY_RELU_POST_OP) + comp = prog.component(name=post_op_component_name) add_post_op_params(comp, num_rows, idx_width) for r in range(num_rows): - create_leaky_relu_groups(comp, r, num_cols, idx_width) - create_leaky_relu_done_condition(comp, num_rows) + create_dynamic_post_op_groups(comp, r, num_cols, idx_width, op_component) + generate_dynamic_post_op_done(comp, num_rows) # all_groups go in one big static par. all_groups = [py_ast.Enable(WRITE_DONE_COND)] for r in range(num_rows): - all_groups.append(py_ast.Enable(f"r{r}_helper")) all_groups.append(py_ast.Enable(f"execute_relu_r{r}")) - for c in range(num_cols): - all_groups.append(py_ast.Enable(f"r{r}_c{c}_value_group")) comp.control = py_ast.StaticParComp(all_groups) + + +def leaky_relu_post_op(prog: cb.Builder, config: SystolicConfiguration): + _, num_cols = config.get_output_dimensions() + leaky_relu_op_comp = leaky_relu_comp(prog, idx_width=bits_needed(num_cols)) + dynamic_post_op( + prog=prog, + config=config, + post_op_component_name=LEAKY_RELU_POST_OP, + op_component=leaky_relu_op_comp, + ) + + +def relu_dynamic_post_op(prog: cb.Builder, config: SystolicConfiguration): + _, num_cols = config.get_output_dimensions() + relu_dynamic_op_comp = relu_dynamic_comp(prog, idx_width=bits_needed(num_cols)) + dynamic_post_op( + prog=prog, + config=config, + post_op_component_name=RELU_DYNAMIC_POST_OP, + op_component=relu_dynamic_op_comp, + ) diff --git a/frontends/systolic-lang/systolic_arg_parser.py b/frontends/systolic-lang/systolic_arg_parser.py index e787e7b63..c2461e2f1 100644 --- a/frontends/systolic-lang/systolic_arg_parser.py +++ b/frontends/systolic-lang/systolic_arg_parser.py @@ -1,7 +1,7 @@ import argparse import json -SUPPORTED_POST_OPS = ["leaky-relu", "relu"] +SUPPORTED_POST_OPS = ["leaky-relu", "relu", "relu-dynamic"] class SystolicConfiguration: diff --git a/runt.toml b/runt.toml index 50b15d8e0..258ccb760 100644 --- a/runt.toml +++ b/runt.toml @@ -267,6 +267,7 @@ paths = [ "tests/correctness/systolic/output/*.systolic", "tests/correctness/systolic/leaky-relu/*.systolic", "tests/correctness/systolic/relu/*.systolic", + "tests/correctness/systolic/relu-dynamic/*.systolic", ] cmd = """ fud e --from systolic --to dat \ diff --git a/tests/correctness/systolic/leaky-relu/array-2-3-4.expect b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect index b2e988ea2..a9bd75bc9 100644 --- a/tests/correctness/systolic/leaky-relu/array-2-3-4.expect +++ b/tests/correctness/systolic/leaky-relu/array-2-3-4.expect @@ -1,5 +1,5 @@ { - "cycles": 18, + "cycles": 22, "memories": { "l0": [ "-1.7772064208984375", diff --git a/tests/correctness/systolic/leaky-relu/array-8.expect b/tests/correctness/systolic/leaky-relu/array-8.expect index 1d8c768d2..b7473d7ca 100644 --- a/tests/correctness/systolic/leaky-relu/array-8.expect +++ b/tests/correctness/systolic/leaky-relu/array-8.expect @@ -1,5 +1,5 @@ { - "cycles": 39, + "cycles": 47, "memories": { "l0": [ "3.5089263916015625", diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect b/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect new file mode 100644 index 000000000..f642045e3 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect @@ -0,0 +1,47 @@ +{ + "cycles": 19, + "memories": { + "l0": [ + "3.349822998046875", + "3.6539764404296875", + "0.0511016845703125" + ], + "l1": [ + "-0.1660003662109375", + "3.43817138671875", + "0.1073760986328125" + ], + "out_mem_0": [ + "12.569793701171875", + "0", + "1.2611541748046875", + "8.012969970703125" + ], + "out_mem_1": [ + "0", + "0", + "0.964019775390625", + "1.9193878173828125" + ], + "t0": [ + "4.0580596923828125", + "-0.2537078857421875", + "-1.896697998046875" + ], + "t1": [ + "-1.2882843017578125", + "-3.0372772216796875", + "3.0884552001953125" + ], + "t2": [ + "0.073028564453125", + "0.2735595703125", + "0.3317718505859375" + ], + "t3": [ + "1.702178955078125", + "0.6259765625", + "0.4635009765625" + ] + } +} diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic b/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic new file mode 100644 index 000000000..c738489e1 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 4, + "top_depth": 3, + "left_length": 2, + "left_depth": 3, + "post_op": "relu-dynamic" +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data b/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data new file mode 100644 index 000000000..823b904b4 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data @@ -0,0 +1,108 @@ +{ + "l0": { + "data": [ + 3.349827766418457, + 3.6539793014526367, + 0.05110502243041992 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + -0.16600513458251953, + 3.4381656646728516, + 0.1073751449584961 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + 4.058065414428711, + -0.2537107467651367, + -1.8967020511627197 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + -1.2882888317108154, + -3.0372798442840576, + 3.0884532928466797 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + 0.07303619384765625, + 0.27355289459228516, + 0.3317680358886719 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + 1.702174186706543, + 0.6259689331054688, + 0.4635009765625 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu-dynamic/array-8.expect b/tests/correctness/systolic/relu-dynamic/array-8.expect new file mode 100644 index 000000000..d8627be63 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-8.expect @@ -0,0 +1,245 @@ +{ + "cycles": 38, + "memories": { + "l0": [ + "-1.49566650390625", + "-0.9142608642578125", + "-2.6135711669921875", + "1.4980010986328125", + "-3.4720001220703125", + "3.4763031005859375", + "-0.016571044921875", + "-2.989044189453125" + ], + "l1": [ + "-1.33184814453125", + "2.9468841552734375", + "1.7263946533203125", + "-1.7017974853515625", + "-1.13458251953125", + "-4.711273193359375", + "-0.290771484375", + "-4.2563934326171875" + ], + "l2": [ + "1.1874237060546875", + "-3.408599853515625", + "-1.801544189453125", + "1.1929931640625", + "-1.8954010009765625", + "-3.1168060302734375", + "0.3030242919921875", + "-1.095611572265625" + ], + "l3": [ + "-2.2605743408203125", + "-4.778472900390625", + "4.631988525390625", + "-2.366485595703125", + "2.2865142822265625", + "-1.9458465576171875", + "2.51043701171875", + "-0.420989990234375" + ], + "l4": [ + "2.081451416015625", + "-2.0117034912109375", + "-3.0953369140625", + "0.8167266845703125", + "-0.9581451416015625", + "-2.253204345703125", + "3.2512359619140625", + "0.8149871826171875" + ], + "l5": [ + "4.9659271240234375", + "-4.0330352783203125", + "0.3494110107421875", + "0.9843292236328125", + "-1.1136932373046875", + "-0.161285400390625", + "3.5453338623046875", + "-4.283843994140625" + ], + "l6": [ + "3.9283294677734375", + "1.32122802734375", + "-0.6650543212890625", + "4.8896026611328125", + "2.450042724609375", + "2.7947235107421875", + "1.7928314208984375", + "-1.518035888671875" + ], + "l7": [ + "-4.6738739013671875", + "-4.4643096923828125", + "0.1487274169921875", + "-3.4300994873046875", + "2.415863037109375", + "-3.8175506591796875", + "3.8909149169921875", + "-0.361236572265625" + ], + "out_mem_0": [ + "0", + "0", + "0", + "23.335174560546875", + "5.11322021484375", + "0", + "0.1280364990234375", + "0" + ], + "out_mem_1": [ + "0", + "1.920379638671875", + "0", + "45.25958251953125", + "32.78094482421875", + "0", + "0", + "33.4017333984375" + ], + "out_mem_2": [ + "0", + "0", + "0", + "29.5540618896484375", + "23.58514404296875", + "0", + "0.9548797607421875", + "0" + ], + "out_mem_3": [ + "21.81707763671875", + "0", + "0", + "5.942596435546875", + "19.353363037109375", + "0", + "6.6043853759765625", + "21.3936614990234375" + ], + "out_mem_4": [ + "0", + "1.3929443359375", + "0", + "16.4472808837890625", + "16.946075439453125", + "0", + "21.7616119384765625", + "0" + ], + "out_mem_5": [ + "29.9978179931640625", + "0", + "0", + "18.637359619140625", + "42.1724090576171875", + "0", + "6.4488067626953125", + "4.316436767578125" + ], + "out_mem_6": [ + "34.8578338623046875", + "18.028961181640625", + "23.9514617919921875", + "0", + "16.2915496826171875", + "2.3678436279296875", + "15.6302032470703125", + "0" + ], + "out_mem_7": [ + "0", + "0", + "0", + "27.7047271728515625", + "18.578521728515625", + "0", + "14.9741973876953125", + "10.2684478759765625" + ], + "t0": [ + "4.9021759033203125", + "-2.5044708251953125", + "4.5919189453125", + "0.601043701171875", + "2.68255615234375", + "4.476806640625", + "1.82684326171875", + "2.19659423828125" + ], + "t1": [ + "3.4096832275390625", + "4.9857330322265625", + "-3.820037841796875", + "-0.70623779296875", + "4.9615936279296875", + "-2.083038330078125", + "-2.567901611328125", + "1.8252105712890625" + ], + "t2": [ + "-0.772216796875", + "4.754638671875", + "-0.936676025390625", + "2.935699462890625", + "2.22613525390625", + "1.5690155029296875", + "-1.6681365966796875", + "0.73956298828125" + ], + "t3": [ + "-3.9584503173828125", + "0.05987548828125", + "-0.902618408203125", + "3.788360595703125", + "-3.4463958740234375", + "-4.98907470703125", + "2.5916900634765625", + "-4.97015380859375" + ], + "t4": [ + "0.08782958984375", + "-0.653778076171875", + "1.889984130859375", + "3.657745361328125", + "-1.1245880126953125", + "-3.8535003662109375", + "3.775634765625", + "-4.5704193115234375" + ], + "t5": [ + "-0.3739166259765625", + "1.5081634521484375", + "0.3743133544921875", + "3.133514404296875", + "-1.101104736328125", + "0.3949737548828125", + "-3.9834136962890625", + "2.9597930908203125" + ], + "t6": [ + "1.1507720947265625", + "-4.7238922119140625", + "-3.618682861328125", + "-0.121856689453125", + "3.2436065673828125", + "3.9204864501953125", + "2.1115570068359375", + "4.709442138671875" + ], + "t7": [ + "0.51519775390625", + "2.701629638671875", + "4.22308349609375", + "-3.078399658203125", + "0.3193511962890625", + "-1.3680877685546875", + "1.766815185546875", + "-1.8860321044921875" + ] + } +} diff --git a/tests/correctness/systolic/relu-dynamic/array-8.systolic b/tests/correctness/systolic/relu-dynamic/array-8.systolic new file mode 100644 index 000000000..ea8c555b8 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-8.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 8, + "top_depth": 8, + "left_length": 8, + "left_depth": 8, + "post_op": "relu-dynamic" +} \ No newline at end of file diff --git a/tests/correctness/systolic/relu-dynamic/array-8.systolic.data b/tests/correctness/systolic/relu-dynamic/array-8.systolic.data new file mode 100644 index 000000000..34b867727 --- /dev/null +++ b/tests/correctness/systolic/relu-dynamic/array-8.systolic.data @@ -0,0 +1,434 @@ +{ + "l0": { + "data": [ + -1.4956629276275635, + -0.9142565727233887, + -2.6135730743408203, + 1.4980006217956543, + -3.472006320953369, + 3.476308822631836, + -0.016571044921875, + -2.989037036895752 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l1": { + "data": [ + -1.3318490982055664, + 2.9468870162963867, + 1.726388931274414, + -1.7017900943756104, + -1.1345791816711426, + -4.711271286010742, + -0.2907705307006836, + -4.256398677825928 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l2": { + "data": [ + 1.187424659729004, + -3.408595323562622, + -1.801539659500122, + 1.1929893493652344, + -1.8953990936279297, + -3.116804361343384, + 0.3030214309692383, + -1.0956144332885742 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l3": { + "data": [ + -2.2605812549591064, + -4.778478145599365, + 4.631991386413574, + -2.3664891719818115, + 2.2865095138549805, + -1.9458460807800293, + 2.51043701171875, + -0.42099571228027344 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l4": { + "data": [ + 2.0814504623413086, + -2.011702060699463, + -3.095329999923706, + 0.8167314529418945, + -0.9581432342529297, + -2.253211736679077, + 3.2512292861938477, + 0.8149852752685547 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l5": { + "data": [ + 4.965932846069336, + -4.033029079437256, + 0.34941768646240234, + 0.9843292236328125, + -1.1136901378631592, + -0.16128921508789062, + 3.5453338623046875, + -4.283846855163574 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l6": { + "data": [ + 3.9283323287963867, + 1.3212251663208008, + -0.6650471687316895, + 4.8896074295043945, + 2.45003604888916, + 2.7947306632995605, + 1.7928242683410645, + -1.5180349349975586 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "l7": { + "data": [ + -4.673877716064453, + -4.464309215545654, + 0.14873123168945312, + -3.4300994873046875, + 2.415858268737793, + -3.8175439834594727, + 3.890915870666504, + -0.36124229431152344 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_0": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_1": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_2": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_3": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_4": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_5": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_6": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "out_mem_7": { + "data": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t0": { + "data": [ + 4.902173042297363, + -2.5044643878936768, + 4.591917037963867, + 0.601048469543457, + 2.6825523376464844, + 4.476808547973633, + 1.8268499374389648, + 2.1965885162353516 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t1": { + "data": [ + 3.4096832275390625, + 4.9857330322265625, + -3.8200438022613525, + -0.706233024597168, + 4.961596488952637, + -2.0830368995666504, + -2.5678956508636475, + 1.825209617614746 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t2": { + "data": [ + -0.7722148895263672, + 4.754638671875, + -0.9366703033447266, + 2.935696601867676, + 2.2261343002319336, + 1.569009780883789, + -1.6681408882141113, + 0.7395687103271484 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t3": { + "data": [ + -3.9584505558013916, + 0.05988121032714844, + -0.9026155471801758, + 3.7883644104003906, + -3.446394205093384, + -4.989075660705566, + 2.5916852951049805, + -4.970152378082275 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t4": { + "data": [ + 0.08782482147216797, + -0.6537842750549316, + 1.8899774551391602, + 3.6577377319335938, + -1.1245930194854736, + -3.853501081466675, + 3.7756290435791016, + -4.57042121887207 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t5": { + "data": [ + -0.3739175796508789, + 1.5081634521484375, + 0.3743171691894531, + 3.1335086822509766, + -1.1011040210723877, + 0.39496898651123047, + -3.983415365219116, + 2.9597973823547363 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t6": { + "data": [ + 1.1507759094238281, + -4.7238874435424805, + -3.618685007095337, + -0.12185335159301758, + 3.2436037063598633, + 3.9204845428466797, + 2.1115517616271973, + 4.709440231323242 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + }, + "t7": { + "data": [ + 0.5151915550231934, + 2.7016282081604004, + 4.223084449768066, + -3.078404664993286, + 0.31935787200927734, + -1.3680875301361084, + 1.7668190002441406, + -1.8860268592834473 + ], + "format": { + "frac_width": 16, + "is_signed": true, + "numeric_type": "fixed_point", + "width": 32 + } + } +} \ No newline at end of file From bd2382de3898c73c8ef4f653521f9a3053371d4e Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 24 Sep 2023 12:18:51 -0400 Subject: [PATCH 070/189] [fud] Fix environment variables for real-FPGA runs (#1728) This should probably fix #1724, superseding the `fix-pynq` branch (apparently @nathanielnrn and I stumbled on the same issue). We were setting the environment variables like `XCL_EMULATION_MODE=hw` in hardware-execution mode, where what we should be doing is not setting this at all in this mode. --- fud/fud/stages/xilinx/execution.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fud/fud/stages/xilinx/execution.py b/fud/fud/stages/xilinx/execution.py index 06e292d38..86a496e3c 100644 --- a/fud/fud/stages/xilinx/execution.py +++ b/fud/fud/stages/xilinx/execution.py @@ -83,13 +83,14 @@ def configure(): # Create the `emconfig.json` file that the simulator loudly (but # perhaps unnecessarily?) complains about if it's missing. - platform = config["stages", "xclbin", "device"] - utilpath = os.path.join(vitis_path, 'bin', 'emconfigutil') - shell( - f'{utilpath} --platform {platform} --od {new_dir.name}', - capture_stdout=False, - stdout_as_debug=True, - ) + if emu_mode != 'hw': + platform = config["stages", "xclbin", "device"] + utilpath = os.path.join(vitis_path, 'bin', 'emconfigutil') + shell( + f'{utilpath} --platform {platform} --od {new_dir.name}', + capture_stdout=False, + stdout_as_debug=True, + ) @builder.step() def run(xclbin: SourceType.Path) -> SourceType.String: @@ -110,10 +111,15 @@ def run(xclbin: SourceType.Path) -> SourceType.String: f"{xclbin_abs} {data_abs}" ) envs = { - "EMCONFIG_PATH": new_dir.name, - "XCL_EMULATION_MODE": emu_mode, # hw_emu or hw "XRT_INI_PATH": xrt_ini_path, } + if emu_mode != 'hw': + # `hw` denotes actual hardware execution. In other modes, + # configure emulation. + envs.update({ + "EMCONFIG_PATH": new_dir.name, + "XCL_EMULATION_MODE": emu_mode, # hw_emu or hw + }) # Invoke xclrun. start_time = time.time() @@ -125,7 +131,7 @@ def run(xclbin: SourceType.Path) -> SourceType.String: stdout_as_debug=True, ) end_time = time.time() - log.debug(f"Emulation time: {end_time - start_time} sec") + log.debug(f"Execution time: {end_time - start_time} sec") # Add xrt log output to our debug output. if os.path.exists(self.xrt_output_logname): From 6a0636a2f70421fd2a12a1e83f9940619e35c3b5 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 9 Oct 2023 20:17:48 -0400 Subject: [PATCH 071/189] Improve Static Inline (#1734) * improved static inline * clippy --- calyx-opt/src/passes/static_inliner.rs | 143 ++++++++++++++++--------- 1 file changed, 95 insertions(+), 48 deletions(-) diff --git a/calyx-opt/src/passes/static_inliner.rs b/calyx-opt/src/passes/static_inliner.rs index ee259b175..3fe598da6 100644 --- a/calyx-opt/src/passes/static_inliner.rs +++ b/calyx-opt/src/passes/static_inliner.rs @@ -50,11 +50,18 @@ impl StaticInliner { // all guards also must update so that guard -> guard & %[offset, offset+latency] since that // is when the group will be active in the control, i.e., dst = guard ? src // becomes dst = guard & %[offset, offset+latency] ? src + // total_latency is the latency of the entire control block being inlined. fn update_assignments_timing( assigns: &mut Vec>, offset: u64, latency: u64, + total_latency: u64, ) { + if offset == 0 && latency == total_latency { + // In this special case, we do nothing, since the timing guards + // would be redundant. + return; + } for assign in assigns { Self::update_assignment_timing(assign, offset, latency); } @@ -151,10 +158,11 @@ impl StaticInliner { &mut g_assigns, cur_offset, stmt_latency, + *latency, ); // add g_assigns to seq_group_assigns seq_group_assigns.extend(g_assigns.into_iter()); - // updates cur_offset so that next stmt gets its static timign + // updates cur_offset so that next stmt gets its static timing // offset appropriately cur_offset += stmt_latency; } @@ -194,6 +202,7 @@ impl StaticInliner { &mut g_assigns, 0, stmt_latency, + *latency, ); // add g_assigns to par_group_assigns par_group_assigns.extend(g_assigns.into_iter()); @@ -209,40 +218,25 @@ impl StaticInliner { latency, attributes, }) => { - let if_group = builder.add_static_group("static_if", *latency); - let mut if_group_assigns: Vec< - ir::Assignment, - > = vec![]; - structure!( builder; - let cond = prim std_reg(port.borrow().width); - let cond_wire = prim std_wire(port.borrow().width); - ); - // build_cond_assigns makes assigns such that - // cond_wire.in can guard all of the tru branch assigns, - // and !cond_wire.in can guard all fo the false branch assigns x - let cond_assigns = StaticInliner::make_cond_assigns( - Rc::clone(&cond), - Rc::clone(&cond_wire), - Rc::clone(port), - *latency, - builder, - ); - if_group_assigns.extend(cond_assigns.to_vec()); + // Making sure max of the two branches latency is the latency + // of the if statement let tbranch_latency = tbranch.get_latency(); let fbranch_latency = fbranch.get_latency(); let max_latency = std::cmp::max(tbranch_latency, fbranch_latency); assert_eq!(max_latency, *latency, "if group latency and max of the if branch latencies do not match"); - // turn tbranch into group and put assigns into tgroup_assigns + + // Inline assignments in tbranch and fbranch, and get resulting + // tgroup_assigns and fgroup_assigns let tgroup = StaticInliner::inline_static_control(tbranch, builder); + let mut tgroup_assigns: Vec> = + tgroup.borrow_mut().assignments.clone(); assert_eq!( tbranch_latency, tgroup.borrow().get_latency(), "tru branch and tru branch group latency do not match" ); - let mut tgroup_assigns: Vec> = - tgroup.borrow_mut().assignments.clone(); // turn fgroup (if it exists) into group and put assigns into fgroup_assigns let mut fgroup_assigns: Vec> = match **fbranch { @@ -258,32 +252,85 @@ impl StaticInliner { fgroup_assigns } }; - // need to do two things: - // add cond_wire.out ? in front of each tgroup assignment - // (and ! cond_wire.out for fgroup assignemnts) - // add %[0:tbranch_latency] in front of each tgroup assignment - // (and %[0: fbranch_latency]) in front of each fgroup assignment - let cond_wire_guard = - ir::Guard::Port(cond_wire.borrow().get("out")); - let not_cond_wire_guard = - ir::Guard::Not(Box::new(cond_wire_guard.clone())); - tgroup_assigns.iter_mut().for_each(|assign| { - // adds the %[0:tbranch_latency] ? guard - Self::update_assignment_timing(assign, 0, tbranch_latency); - // adds the cond_wire ? guard - assign - .guard - .update(|guard| guard.and(cond_wire_guard.clone())) - }); + + // if_group = the eventual group we inline all the assignments + // into. + let if_group = builder.add_static_group("static_if", *latency); + let mut if_group_assigns: Vec< + ir::Assignment, + > = vec![]; + if *latency == 1 { + // Special case: if latency = 1, we don't need a register + // to hold the value of the cond port. + let cond_port_guard = ir::Guard::Port(Rc::clone(port)); + let not_cond_port_guard = + ir::Guard::Not(Box::new(cond_port_guard.clone())); + tgroup_assigns.iter_mut().for_each(|assign| { + // adds the cond_port ? guard + assign + .guard + .update(|guard| guard.and(cond_port_guard.clone())) + }); + fgroup_assigns.iter_mut().for_each(|assign| { + // adds the !cond_port ? guard + assign.guard.update(|guard| { + guard.and(not_cond_port_guard.clone()) + }) + }); + } else { + // If latency != 1, we do need a register to hold the + // value of the cond port. + structure!( builder; + let cond = prim std_reg(port.borrow().width); + let cond_wire = prim std_wire(port.borrow().width); + ); + // build_cond_assigns makes assigns such that + // cond_wire.in can guard all of the tru branch assigns, + // and !cond_wire.in can guard all fo the false branch assigns + let cond_assigns = StaticInliner::make_cond_assigns( + Rc::clone(&cond), + Rc::clone(&cond_wire), + Rc::clone(port), + *latency, + builder, + ); + if_group_assigns.extend(cond_assigns.to_vec()); + + // need to do two things: + // add cond_wire.out ? in front of each tgroup assignment + // (and ! cond_wire.out for fgroup assignemnts) + // add %[0:tbranch_latency] in front of each tgroup assignment + // (and %[0: fbranch_latency]) in front of each fgroup assignment + let cond_wire_guard = + ir::Guard::Port(cond_wire.borrow().get("out")); + let not_cond_wire_guard = + ir::Guard::Not(Box::new(cond_wire_guard.clone())); + tgroup_assigns.iter_mut().for_each(|assign| { + // adds the %[0:tbranch_latency] ? guard + Self::update_assignment_timing( + assign, + 0, + tbranch_latency, + ); + // adds the cond_wire ? guard + assign + .guard + .update(|guard| guard.and(cond_wire_guard.clone())) + }); + fgroup_assigns.iter_mut().for_each(|assign| { + // adds the %[0:fbranch_latency] ? guard + Self::update_assignment_timing( + assign, + 0, + fbranch_latency, + ); + // adds the !cond_wire ? guard + assign.guard.update(|guard| { + guard.and(not_cond_wire_guard.clone()) + }) + }); + } if_group_assigns.extend(tgroup_assigns); - fgroup_assigns.iter_mut().for_each(|assign| { - // adds the %[0:fbranch_latency] ? guard - Self::update_assignment_timing(assign, 0, fbranch_latency); - // adds the !cond_wire ? guard - assign - .guard - .update(|guard| guard.and(not_cond_wire_guard.clone())) - }); if_group_assigns.extend(fgroup_assigns); if_group.borrow_mut().assignments = if_group_assigns; if_group.borrow_mut().attributes = attributes.clone(); From 17d164e7d2b985cb229b59b2da907b7378859626 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Tue, 10 Oct 2023 09:12:15 -0700 Subject: [PATCH 072/189] Create IDL Backend (#1729) * WIP, add to backend options * add serde_json dependency for IDL backend * WIP work on IDL * Minimal working version of IDL generator Some open questions: Naming and placement. This is probably not xilinx specific so should be moved up a level into just src. Also, naming is generic and not good and should be changed TODO: Only works withs d1 memories, but should not be hard to alter * Let IDL generator handle multi-dim mems Previously could only handle 1 dimension mems. NOTE: This flattens dimensions into a single size variable that is spit out. However it may be useful to maintain info about shape of memory? Need to think about this more * add basic runt tests * clippy formatting * rename idl to yxi and make serde_json call shorter * add error conversion for serde_json for yxi backend * update runt tests for yxi * update cargo lock with serde_json * formatting * move yxi up a directory * WIP of extracting utility functions * Refactor toplevel and yxi util functions Moved things into calyx-ir/utils. Things like get_mem_info and functions that get memories marked as external, along with their names * clippy and formatting --- Cargo.lock | 2 + Cargo.toml | 1 + calyx-backend/Cargo.toml | 1 + calyx-backend/src/backend_opt.rs | 3 + calyx-backend/src/lib.rs | 2 + calyx-backend/src/xilinx/toplevel.rs | 75 +++-------- calyx-backend/src/yxi.rs | 73 +++++++++++ calyx-ir/src/lib.rs | 2 + calyx-ir/src/utils.rs | 94 ++++++++++++++ calyx-utils/Cargo.toml | 2 + calyx-utils/src/errors.rs | 6 + src/cmdline.rs | 5 + tests/backend/yxi/dot-product.expect | 20 +++ tests/backend/yxi/dot-product.futil | 93 +++++++++++++ tests/backend/yxi/seq-mem-d4-add.expect | 20 +++ tests/backend/yxi/seq-mem-d4-add.futil | 166 ++++++++++++++++++++++++ 16 files changed, 508 insertions(+), 57 deletions(-) create mode 100644 calyx-backend/src/yxi.rs create mode 100644 calyx-ir/src/utils.rs create mode 100644 tests/backend/yxi/dot-product.expect create mode 100644 tests/backend/yxi/dot-product.futil create mode 100644 tests/backend/yxi/seq-mem-d4-add.expect create mode 100644 tests/backend/yxi/seq-mem-d4-add.futil diff --git a/Cargo.lock b/Cargo.lock index 3b80102a4..613ad2c27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,6 +208,7 @@ dependencies = [ "petgraph", "quick-xml", "serde", + "serde_json", "serde_sexpr", "serde_with 3.3.0", "smallvec", @@ -279,6 +280,7 @@ dependencies = [ "itertools 0.11.0", "petgraph", "serde", + "serde_json", "string-interner", "symbol_table", ] diff --git a/Cargo.toml b/Cargo.toml index b4fbd9044..3d4328718 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ lazy_static = "1" linked-hash-map = "0.5" smallvec = "1" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" serde_sexpr = "0.1.0" serde_with = "3" pest = "2" diff --git a/calyx-backend/Cargo.toml b/calyx-backend/Cargo.toml index dfe6c4b91..9ccd175e3 100644 --- a/calyx-backend/Cargo.toml +++ b/calyx-backend/Cargo.toml @@ -18,6 +18,7 @@ string-interner.workspace = true itertools.workspace = true linked-hash-map.workspace = true serde = { workspace = true } +serde_json.workspace = true serde_with = { workspace = true, optional = true } serde_sexpr = { workspace = true, optional = true } smallvec.workspace = true diff --git a/calyx-backend/src/backend_opt.rs b/calyx-backend/src/backend_opt.rs index fec1144cf..f07df18a4 100644 --- a/calyx-backend/src/backend_opt.rs +++ b/calyx-backend/src/backend_opt.rs @@ -12,6 +12,7 @@ pub enum BackendOpt { Mlir, Resources, Sexp, + Yxi, None, } @@ -26,6 +27,7 @@ fn backends() -> Vec<(&'static str, BackendOpt)> { ("mlir", BackendOpt::Mlir), ("resources", BackendOpt::Resources), ("sexp", BackendOpt::Sexp), + ("yxi", BackendOpt::Yxi), ("none", BackendOpt::None), ] } @@ -67,6 +69,7 @@ impl ToString for BackendOpt { Self::Verilog => "verilog", Self::Xilinx => "xilinx", Self::XilinxXml => "xilinx-xml", + Self::Yxi => "yxi", Self::Calyx => "calyx", Self::None => "none", } diff --git a/calyx-backend/src/lib.rs b/calyx-backend/src/lib.rs index 04efe3577..3d102da8c 100644 --- a/calyx-backend/src/lib.rs +++ b/calyx-backend/src/lib.rs @@ -2,10 +2,12 @@ mod backend_opt; mod traits; mod verilog; +mod yxi; pub use backend_opt::BackendOpt; pub use traits::Backend; pub use verilog::VerilogBackend; +pub use yxi::YxiBackend; #[cfg(feature = "mlir")] mod mlir; diff --git a/calyx-backend/src/xilinx/toplevel.rs b/calyx-backend/src/xilinx/toplevel.rs index 543754123..5f98fa3c5 100644 --- a/calyx-backend/src/xilinx/toplevel.rs +++ b/calyx-backend/src/xilinx/toplevel.rs @@ -4,6 +4,7 @@ use super::{ }; use crate::traits::Backend; use calyx_ir as ir; +use calyx_ir::utils::GetMemInfo; use calyx_utils::{CalyxResult, Error}; use vast::v05::ast as v; @@ -37,14 +38,14 @@ impl Backend for XilinxInterfaceBackend { .find(|c| c.name == prog.entrypoint) .unwrap(); - let memories = external_memories(toplevel); + let memories = ir::utils::external_memories_names(toplevel); if memories.is_empty() { return Err(Error::misc( "Program has no memories marked with attribute @external.".to_owned() + " Please make sure that at least one memory is marked as @external.")); } - let mem_info = get_mem_info(toplevel); + let mem_info = toplevel.get_mem_info(); let mut modules = vec![top_level(toplevel)]; for (i, mem) in mem_info.iter().enumerate() { @@ -52,7 +53,7 @@ impl Backend for XilinxInterfaceBackend { &format!("SINGLE_PORT_BRAM_{}", i), mem.width, mem.size, - mem.idx_size, + mem.idx_sizes[0], )) } @@ -71,7 +72,7 @@ impl Backend for XilinxInterfaceBackend { 64, mem.width, mem.size, - mem.idx_size, + mem.idx_sizes[0], )) } @@ -93,61 +94,21 @@ impl Backend for XilinxInterfaceBackend { } } -fn external_memories_cells(comp: &ir::Component) -> Vec> { - comp.cells - .iter() - // find external memories - .filter(|cell_ref| { - let cell = cell_ref.borrow(); - // NOTE(rachit): We only support one dimensional std_mem_d1 memories - if cell.attributes.has(ir::BoolAttr::External) { - if !cell.is_primitive(Some("std_mem_d1")) { - panic!("cell `{}' marked with `@external' but is not a std_mem_d1. The AXI generator currently only supports `std_mem_d1'", cell.name()) - } else { - true - } - } else { - false - } - }) - .cloned() - .collect() -} - -/// Parameters for single dimensional memory -struct MemInfo { - width: u64, - size: u64, - idx_size: u64, -} - -// Returns a vector of tuples containing external memory info of [comp] of form: -// [(WIDTH, SIZE, IDX_SIZE)] -fn get_mem_info(comp: &ir::Component) -> Vec { - external_memories_cells(comp) - .iter() - .map(|cr| { - let cell = cr.borrow(); - MemInfo { - width: cell.get_parameter("WIDTH").unwrap(), - size: cell.get_parameter("SIZE").unwrap(), - idx_size: cell.get_parameter("IDX_SIZE").unwrap(), - } - }) - .collect() -} - -// Returns Vec of memory names -fn external_memories(comp: &ir::Component) -> Vec { - external_memories_cells(comp) - .iter() - .map(|cell_ref| cell_ref.borrow().name().to_string()) - .collect() +// Gets all memory cells in top level marked external. +//Panics if not all memories are 1-d +fn external_1d_memories_cells(comp: &ir::Component) -> Vec> { + let memories = ir::utils::external_memories_cells(comp); + for memory in memories.iter() { + if !memory.borrow().is_primitive(Some("std_mem_d1")) { + panic!("cell `{}' marked with `@external' but is not a std_mem_d1. The AXI generator currently only supports `std_mem_d1'", memory.borrow().name()) + } + } + memories } fn top_level(toplevel: &ir::Component) -> v::Module { - let memories = &external_memories(toplevel); - let mem_info = get_mem_info(toplevel); + let memories = &ir::utils::external_memories_names(toplevel); + let mem_info = &external_1d_memories_cells(toplevel).get_mem_info(); assert!(!memories.is_empty()); // At least 1 memory should exist within the toplevel let mut module = v::Module::new("Toplevel"); @@ -232,7 +193,7 @@ fn top_level(toplevel: &ir::Component) -> v::Module { let width = mem_info[idx].width; module.add_decl(v::Decl::new_wire(&write_data, width)); module.add_decl(v::Decl::new_wire(&read_data, width)); - module.add_decl(v::Decl::new_wire(&addr0, mem_info[idx].idx_size)); + module.add_decl(v::Decl::new_wire(&addr0, mem_info[idx].idx_sizes[0])); module.add_decl(v::Decl::new_wire(&write_en, 1)); module.add_decl(v::Decl::new_wire(&done, 1)); diff --git a/calyx-backend/src/yxi.rs b/calyx-backend/src/yxi.rs new file mode 100644 index 000000000..5b7f4af9b --- /dev/null +++ b/calyx-backend/src/yxi.rs @@ -0,0 +1,73 @@ +use crate::traits::Backend; +use calyx_ir as ir; +use calyx_ir::utils::GetMemInfo; +use calyx_utils::CalyxResult; +use serde::Serialize; +/// Backend that generates the YXI Interface Definition Language. +/// YXI aims to be a description of toplevel hardware modules that we can then consume +/// to create things like AXI wrappers on arbitrary programs +#[derive(Default)] +pub struct YxiBackend; + +#[derive(Serialize)] +struct ProgramInterface<'a> { + toplevel: &'a str, + memories: Vec>, +} + +#[derive(Serialize)] +struct Memory<'a> { + name: &'a str, + width: u64, + size: u64, //number of cells in memory +} + +impl Backend for YxiBackend { + fn name(&self) -> &'static str { + "yxi" + } + + fn validate(_ctx: &ir::Context) -> CalyxResult<()> { + Ok(()) + } + + fn link_externs( + _prog: &ir::Context, + _write: &mut calyx_utils::OutputFile, + ) -> CalyxResult<()> { + Ok(()) + } + + fn emit( + prog: &ir::Context, + file: &mut calyx_utils::OutputFile, + ) -> CalyxResult<()> { + let toplevel = prog + .components + .iter() + .find(|comp| comp.name == prog.entrypoint) + .unwrap(); + + let memory_names = ir::utils::external_memories_names(toplevel); + let mem_infos = toplevel.get_mem_info(); + + let memories: Vec = memory_names + .iter() + .zip(mem_infos.iter()) + .map(|(memory_name, mem_info)| Memory { + name: memory_name, + width: mem_info.width, + size: mem_info.size, + }) + .collect(); + + let program_interface = ProgramInterface { + toplevel: toplevel.name.as_ref(), + memories, + }; + + serde_json::to_writer_pretty(file.get_write(), &program_interface)?; + + Ok(()) + } +} diff --git a/calyx-ir/src/lib.rs b/calyx-ir/src/lib.rs index 265d7a02c..abafbef09 100644 --- a/calyx-ir/src/lib.rs +++ b/calyx-ir/src/lib.rs @@ -57,3 +57,5 @@ mod macros; /// Serializer methods for IR nodes. pub mod serializers; + +pub mod utils; diff --git a/calyx-ir/src/utils.rs b/calyx-ir/src/utils.rs new file mode 100644 index 000000000..f93f99bb2 --- /dev/null +++ b/calyx-ir/src/utils.rs @@ -0,0 +1,94 @@ +//! Helpers used to examine calyx programs. Used in Xilinx and Yxi backends among others. +use super::{BoolAttr, Cell, Component, RRC}; +// Returns Vec of memory names +pub fn external_memories_names(comp: &Component) -> Vec { + external_memories_cells(comp) + .iter() + .map(|cell_ref| cell_ref.borrow().name().to_string()) + .collect() +} + +// Gets all memory cells in top level marked external. +pub fn external_memories_cells(comp: &Component) -> Vec> { + comp.cells + .iter() + // find external memories + .filter(|cell_ref| { + let cell = cell_ref.borrow(); + cell.attributes.has(BoolAttr::External) + }) + .cloned() + .collect() +} + +/// Parameters for std memories +pub struct MemInfo { + pub width: u64, + pub size: u64, + //idx port width, in case size is ambiguous + pub idx_sizes: Vec, +} + +// Returns a vector of tuples containing external memory info of [comp] of form: +// [(WIDTH, SIZE, IDX_SIZE)] +pub trait GetMemInfo { + fn get_mem_info(&self) -> Vec; +} + +impl GetMemInfo for Vec> { + fn get_mem_info(&self) -> Vec { + self.iter() + .map(|cr| { + let mem = cr.borrow(); + let mem_size: u64; + let mut idx_sizes: Vec = Vec::new(); + let idx_count: u64; + match mem.prototype.get_name().unwrap().as_ref() { + "std_mem_d1" | "seq_mem_d1" => { + mem_size = mem.get_parameter("SIZE").unwrap(); + idx_count = 1; + } + "std_mem_d2" | "seq_mem_d2" => { + mem_size = mem.get_parameter("D0_SIZE").unwrap() + * mem.get_parameter("D1_SIZE").unwrap(); + idx_count = 2; + } + "std_mem_d3" | "seq_mem_d3" => { + mem_size = mem.get_parameter("D0_SIZE").unwrap() + * mem.get_parameter("D1_SIZE").unwrap() + * mem.get_parameter("D2_SIZE").unwrap(); + idx_count = 3; + } + "std_mem_d4" | "seq_mem_d4" => { + mem_size = mem.get_parameter("D0_SIZE").unwrap() + * mem.get_parameter("D1_SIZE").unwrap() + * mem.get_parameter("D2_SIZE").unwrap() + * mem.get_parameter("D3_SIZE").unwrap(); + idx_count = 4; + } + _ => { + panic!("cell `{}' marked with `@external' but is not a memory primitive.", mem.name()) + } + }; + if idx_count == 1 { + idx_sizes.push(mem.get_parameter("IDX_SIZE").unwrap()); + } else { + for i in 1..idx_count { + idx_sizes.push(mem.get_parameter(format!("D{}_IDX_SIZE",i)).unwrap()); + } + } + MemInfo { + width: mem.get_parameter("WIDTH").unwrap(), + size: mem_size, + idx_sizes + } + }) + .collect() + } +} + +impl GetMemInfo for Component { + fn get_mem_info(&self) -> Vec { + external_memories_cells(self).get_mem_info() + } +} diff --git a/calyx-utils/Cargo.toml b/calyx-utils/Cargo.toml index 65fb0b640..b8e445d91 100644 --- a/calyx-utils/Cargo.toml +++ b/calyx-utils/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true homepage.workspace = true categories.workspace = true readme.workspace = true +serde_json.workspace = true [features] default = [] @@ -17,6 +18,7 @@ serialize = ["dep:serde", "symbol_table/serde"] [dependencies] serde = { workspace = true, features = ["derive"], optional = true } +serde_json.workspace = true atty.workspace = true string-interner.workspace = true itertools.workspace = true diff --git a/calyx-utils/src/errors.rs b/calyx-utils/src/errors.rs index 86a5948b7..6aeb9fb53 100644 --- a/calyx-utils/src/errors.rs +++ b/calyx-utils/src/errors.rs @@ -197,3 +197,9 @@ impl From for Error { Error::write_error(format!("IO Error: {}", e)) } } + +impl From for Error { + fn from(e: serde_json::Error) -> Self { + Error::write_error(format!("serde_json Error: {}", e)) + } +} diff --git a/src/cmdline.rs b/src/cmdline.rs index 067f321b4..c15b14177 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -5,6 +5,7 @@ use calyx_backend::SexpBackend; use calyx_backend::{ xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, Backend, BackendOpt, MlirBackend, ResourcesBackend, VerilogBackend, + YxiBackend, }; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; @@ -145,6 +146,10 @@ impl Opts { let backend = XilinxXmlBackend; backend.run(context, self.output) } + BackendOpt::Yxi => { + let backend = YxiBackend; + backend.run(context, self.output) + } BackendOpt::Calyx => { ir::Printer::write_context( &context, diff --git a/tests/backend/yxi/dot-product.expect b/tests/backend/yxi/dot-product.expect new file mode 100644 index 000000000..2a4e1221f --- /dev/null +++ b/tests/backend/yxi/dot-product.expect @@ -0,0 +1,20 @@ +{ + "toplevel": "main", + "memories": [ + { + "name": "A0", + "width": 32, + "size": 8 + }, + { + "name": "B0", + "width": 32, + "size": 8 + }, + { + "name": "v0", + "width": 32, + "size": 1 + } + ] +} \ No newline at end of file diff --git a/tests/backend/yxi/dot-product.futil b/tests/backend/yxi/dot-product.futil new file mode 100644 index 000000000..abf815854 --- /dev/null +++ b/tests/backend/yxi/dot-product.futil @@ -0,0 +1,93 @@ +// -b yxi +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main() -> () { + cells { + @external(1) A0 = std_mem_d1(32,8,4); + A_read0_0 = std_reg(32); + @external(1) B0 = std_mem_d1(32,8,4); + B_read0_0 = std_reg(32); + add0 = std_add(32); + add1 = std_add(4); + bin_read0_0 = std_reg(32); + const0 = std_const(4,0); + const1 = std_const(4,7); + const2 = std_const(1,0); + const3 = std_const(4,1); + dot_0 = std_reg(32); + i0 = std_reg(4); + le0 = std_le(4); + mult_pipe0 = std_mult_pipe(32); + @external(1) v0 = std_mem_d1(32,1,1); + } + wires { + comb group cond0 { + le0.left = i0.out; + le0.right = const1.out; + } + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + group let1<"static"=4> { + bin_read0_0.in = mult_pipe0.out; + bin_read0_0.write_en = mult_pipe0.done; + let1[done] = bin_read0_0.done; + mult_pipe0.left = A_read0_0.out; + mult_pipe0.right = B_read0_0.out; + mult_pipe0.go = !mult_pipe0.done ? 1'd1; + } + group let2<"static"=1> { + dot_0.in = bin_read0_0.out; + dot_0.write_en = 1'd1; + let2[done] = dot_0.done; + } + group upd0<"static"=1> { + A_read0_0.write_en = 1'd1; + A0.addr0 = i0.out; + A_read0_0.in = 1'd1 ? A0.read_data; + upd0[done] = A_read0_0.done ? 1'd1; + } + group upd1<"static"=1> { + B_read0_0.write_en = 1'd1; + B0.addr0 = i0.out; + B_read0_0.in = 1'd1 ? B0.read_data; + upd1[done] = B_read0_0.done ? 1'd1; + } + group upd2<"static"=1> { + v0.write_en = 1'd1; + add0.left = v0.read_data; + add0.right = dot_0.out; + v0.addr0 = const2.out; + v0.write_data = 1'd1 ? add0.out; + upd2[done] = v0.done ? 1'd1; + } + group upd3<"static"=1> { + i0.write_en = 1'd1; + add1.left = i0.out; + add1.right = const3.out; + i0.in = 1'd1 ? add1.out; + upd3[done] = i0.done ? 1'd1; + } + } + control { + // ANCHOR: control + seq { + let0; + while le0.out with cond0 { + seq { + par { + upd0; + upd1; + } + let1; + let2; + upd2; + upd3; + } + } + } + // ANCHOR_END: control + } +} diff --git a/tests/backend/yxi/seq-mem-d4-add.expect b/tests/backend/yxi/seq-mem-d4-add.expect new file mode 100644 index 000000000..9e6e49644 --- /dev/null +++ b/tests/backend/yxi/seq-mem-d4-add.expect @@ -0,0 +1,20 @@ +{ + "toplevel": "main", + "memories": [ + { + "name": "in1", + "width": 32, + "size": 24 + }, + { + "name": "in2", + "width": 32, + "size": 24 + }, + { + "name": "out", + "width": 32, + "size": 24 + } + ] +} \ No newline at end of file diff --git a/tests/backend/yxi/seq-mem-d4-add.futil b/tests/backend/yxi/seq-mem-d4-add.futil new file mode 100644 index 000000000..7f7ff4c7f --- /dev/null +++ b/tests/backend/yxi/seq-mem-d4-add.futil @@ -0,0 +1,166 @@ +// -b yxi +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +import "primitives/memories.futil"; + +component main() -> () { + cells { + @external in1 = seq_mem_d4(32,3,2,1,4,2,2,1,3); + @external in2 = seq_mem_d4(32,3,2,1,4,2,2,1,3); + @external out = seq_mem_d4(32,3,2,1,4,2,2,1,3); + + // Compute primitives + add = std_add(32); + in1_reg = std_reg(32); + in2_reg = std_reg(32); + in3_reg = std_reg(32); + in4_reg = std_reg(32); + + // Counter + i = std_reg(2); + j = std_reg(2); + k = std_reg(1); + l = std_reg(3); + + lt = std_lt(2); + lt2 = std_lt(2); + lt3 = std_lt(1); + lt4 = std_lt(3); + + + add_i = std_add(2); + add_j = std_add(2); + add_k = std_add(1); + add_l = std_add(3); + } + wires { + group init_i{ + i.write_en = 1'd1; + i.in = 2'd0; + init_i[done] = i.done; + } + group init_j{ + j.write_en = 1'd1; + j.in = 2'd0; + init_j[done] = j.done; + } + group init_k{ + k.write_en = 1'd1; + k.in = 1'd0; + init_k[done] = k.done; + } + group init_l{ + l.write_en = 1'd1; + l.in = 3'd0; + init_l[done] = l.done; + } + comb group i_lt { + lt.left = i.out; + lt.right = 2'd3; + } + comb group j_lt { + lt2.left = j.out; + lt2.right = 2'd2; + } + comb group k_lt { + lt3.left = k.out; + lt3.right = 1'd1; + } + comb group l_lt { + lt4.left = l.out; + lt4.right = 3'd4; + } + group read_in1{ + in1.addr0 = i.out; + in1.addr1 = j.out; + in1.addr2 = k.out; + in1.addr3 = l.out; + in1.read_en = 1'd1; + in1_reg.write_en = in1.read_done; + in1_reg.in = in1.read_data; + read_in1[done] = in1_reg.done; + } + group read_in2{ + in2.addr0 = i.out; + in2.addr1 = j.out; + in2.addr2 = k.out; + in2.addr3 = l.out; + in2.read_en = 1'd1; + in2_reg.write_en = in2.read_done; + in2_reg.in = in2.read_data; + read_in2[done] = in2_reg.done; + } + group update_val { + add.left = in1_reg.out; + add.right = in2_reg.out; + out.addr0 = i.out; + out.addr1 = j.out; + out.addr2 = k.out; + out.addr3 = l.out; + out.write_en = 1'd1; + out.write_data = add.out; + update_val[done] = out.write_done; + } + group incr_i { + add_i.left = i.out; + add_i.right = 2'd1; + i.write_en = 1'd1; + i.in = add_i.out; + incr_i[done] = i.done; + } + group incr_j { + add_j.left = j.out; + add_j.right = 2'd1; + j.write_en = 1'd1; + j.in = add_j.out; + incr_j[done] = j.done; + } + group incr_k { + add_k.left = k.out; + add_k.right = 1'd1; + k.write_en = 1'd1; + k.in = add_k.out; + incr_k[done] = k.done; + } + group incr_l { + add_l.left = l.out; + add_l.right = 3'd1; + l.write_en = 1'd1; + l.in = add_l.out; + incr_l[done] = l.done; + } + } + control { + seq { + init_i; + while lt.out with i_lt { + seq{ + init_j; + while lt2.out with j_lt{ + seq{ + init_k; + while lt3.out with k_lt{ + seq{ + init_l; + while lt4.out with l_lt{ + seq{ + par{ + read_in1; + read_in2; + } + update_val; + incr_l; + } + } + incr_k; + } + } + incr_j; + } + } + incr_i; + } + } + } + } +} From b94c7338a9d7bd7899b6c16464df853fcc971d19 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:18:20 -0400 Subject: [PATCH 073/189] Improve systolic array (#1735) * reduce register usage * even fewer registers * tests hopefully pass * removed extraneous file --- .../systolic-lang/gen_array_component.py | 286 +++++++----------- runt.toml | 2 + tests/frontend/systolic/array-1.expect | 284 +++++------------ 3 files changed, 189 insertions(+), 383 deletions(-) diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index 5741c44ce..ab2ca39b3 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -16,8 +16,6 @@ NAME_SCHEME = { # Indexing into the memory "index name": "{prefix}_idx", - "index init": "{prefix}_idx_init", - "index update": "{prefix}_idx_update", # Move data from main memories "memory move": "{prefix}_move", "out write": "{pe}_out_write", @@ -62,19 +60,15 @@ def __str__(self): + str(self.const) ) - def build_group(self, comp: cb.ComponentBuilder) -> str: + def implement_add(self, comp: cb.ComponentBuilder) -> str: """ - Builds a static Calyx group (latency 1) that implements `self` - Note that we avoid creating duplicate groups. - Returns the group name + Implements the `CalyxAdd` by creating an adder that adds the two values """ - group_name = str(self) + "_group" - if comp.try_get_group(group_name) is None: + if comp.try_get_cell(str(self)) is None: add = comp.add(BITWIDTH, str(self)) - with comp.static_group(group_name, 1): + with comp.continuous: add.left = self.port add.right = self.const - return group_name def add_systolic_output_params(comp: cb.ComponentBuilder, row_num, addr_width): @@ -117,13 +111,15 @@ def instantiate_memory(comp: cb.ComponentBuilder, top_or_left, idx, size): this = comp.this() addr0_port = this.port(name + "_addr0") read_data_port = this.port(name + "_read_data") - # Instantiate the indexing register - idx = instantiate_indexor(comp, name, idx_width) + # Get the indexing value, taking into account offset + # For example, for l2, we want to access idx-2 (since we want to wait two + # cycles before we start feeding memories in) + idx_val = get_indexor(comp, idx_width, offset=idx) # Register to save the value from the memory. Defined by [[instantiate_pe]]. target = comp.get_cell(target_reg) group_name = NAME_SCHEME["memory move"].format(prefix=name) with comp.static_group(group_name, 1) as g: - g.asgn(addr0_port, idx.out) + g.asgn(addr0_port, idx_val.out) target.in_ = read_data_port target.write_en = 1 @@ -138,37 +134,23 @@ def instantiate_pe(comp: cb.ComponentBuilder, row: int, col: int): comp.reg(f"left_{row}_{col}", BITWIDTH) -def instantiate_indexor(comp: cb.ComponentBuilder, prefix, width) -> cb.CellBuilder: +def get_indexor(comp: cb.ComponentBuilder, width: int, offset: int) -> cb.CellBuilder: """ - Instantiate an indexor for accessing memory with name `prefix`. - Generates structure to initialize and update the indexor. - - The initializor starts sets the memories to their maximum value - because we expect all indices to be incremented once before - being used. - - Returns (cells, structure) + Gets (instantiates if needed) an indexor for accessing memory with offset + `offset` (as compared to the iteration idx) """ - name = NAME_SCHEME["index name"].format(prefix=prefix) - - reg = comp.reg(name, width) - add = comp.add(width, f"{prefix}_add") - - init_name = NAME_SCHEME["index init"].format(prefix=prefix) - with comp.static_group(init_name, 1): - # Initialize the indexor to 0 - reg.in_ = 0 - reg.write_en = 1 - - upd_name = NAME_SCHEME["index update"].format(prefix=prefix) - with comp.static_group(upd_name, 1): - # Increment the indexor. - add.left = 1 - add.right = reg.out - reg.in_ = add.out - reg.write_en = 1 - - return reg + if comp.try_get_cell(f"idx_minus_{offset}_res") is None: + idx = comp.get_cell("idx") + # idx has width bitwidth + sub = comp.sub(BITWIDTH, f"idx_minus_{offset}") + sub_res = comp.slice(f"idx_minus_{offset}_res", BITWIDTH, width) + with comp.continuous: + sub.left = idx.out + sub.right = offset + sub_res.in_ = sub.out + return sub_res + else: + return comp.get_cell(f"idx_minus_{offset}_res") def instantiate_data_move( @@ -223,10 +205,8 @@ def get_memory_updates(row, col): movers = [] if col == 0: movers.append(NAME_SCHEME["memory move"].format(prefix=f"l{row}")) - movers.append(NAME_SCHEME["index update"].format(prefix=f"l{row}")) if row == 0: movers.append(NAME_SCHEME["memory move"].format(prefix=f"t{col}")) - movers.append(NAME_SCHEME["index update"].format(prefix=f"t{col}")) mover_enables = [py_ast.Enable(name) for name in movers] return mover_enables @@ -266,23 +246,15 @@ def get_pe_invoke(r, c, mul_ready): ) -def init_runtime_vals(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): +def init_iter_limit(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): """ Builds group that instantiates the dynamic/runtime values for the systolic array: its depth and iteration limit/count (since its iteration limit depends on its depth). iteration limit = depth + partial_iter_limit """ - min_depth_4 = comp.reg("min_depth_4", BITWIDTH) - lt_depth_4 = comp.lt(BITWIDTH, "lt_depth_4") iter_limit = comp.reg("iter_limit", BITWIDTH) iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") - with comp.static_group("init_min_depth", 1): - lt_depth_4.left = depth_port - lt_depth_4.right = 4 - min_depth_4.in_ = lt_depth_4.out @ depth_port - min_depth_4.in_ = ~lt_depth_4.out @ 4 - min_depth_4.write_en = 1 with comp.static_group("init_iter_limit", 1): iter_limit_add.left = partial_iter_limit iter_limit_add.right = depth_port @@ -290,7 +262,7 @@ def init_runtime_vals(comp: cb.ComponentBuilder, depth_port, partial_iter_limit) iter_limit.write_en = 1 -def instantiate_while_groups(comp: cb.ComponentBuilder): +def instantiate_idx_groups(comp: cb.ComponentBuilder): """ Builds groups that instantiate idx to 0 and increment idx. Also builds groups that set cond_reg to 1 (runs before the while loop) @@ -298,7 +270,6 @@ def instantiate_while_groups(comp: cb.ComponentBuilder): """ idx = comp.reg("idx", BITWIDTH) add = comp.add(BITWIDTH, "idx_add") - cond_reg = comp.reg("cond_reg", 1) iter_limit = comp.get_cell("iter_limit") lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") @@ -310,14 +281,9 @@ def instantiate_while_groups(comp: cb.ComponentBuilder): add.right = 1 idx.in_ = add.out idx.write_en = 1 - with comp.static_group("init_cond_reg", 1): - cond_reg.in_ = 1 - cond_reg.write_en = 1 - with comp.static_group("write_cond_reg", 1): - lt_iter_limit.left = add.out + with comp.continuous: + lt_iter_limit.left = idx.out lt_iter_limit.right = iter_limit.out - cond_reg.in_ = lt_iter_limit.out - cond_reg.write_en = 1 def instantiate_calyx_adds(comp, nec_ranges) -> list: @@ -326,85 +292,67 @@ def instantiate_calyx_adds(comp, nec_ranges) -> list: specified add. Returns a list of all the group names that we created. """ - calyx_add_groups = set() for lo, hi in nec_ranges: if type(lo) == CalyxAdd: - group_name = lo.build_group(comp) - calyx_add_groups.add(group_name) + lo.implement_add(comp) if type(hi) == CalyxAdd: - group_name = hi.build_group(comp) - calyx_add_groups.add(group_name) - group_list = list(calyx_add_groups) - # sort for testing purposes - group_list.sort() - return group_list + hi.implement_add(comp) -def instantiate_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: +def check_idx_lower_bound(comp: cb.ComponentBuilder, lo): + """ + Creates assignments to test if idx >= lo """ - Instantiates a static group and register called "idx_between_{lo}_{hi}_reg/group" - that should output whether idx is between [lo, hi). That is, whether lo <= idx < hi. + if type(lo) == CalyxAdd: + lo_value = comp.get_cell(str(lo)).port("out") + else: + lo_value = lo + idx = comp.get_cell("idx") + index_ge = f"index_ge_{lo}" + ge = comp.ge(BITWIDTH, index_ge) + with comp.continuous: + ge.left = idx.out + ge.right = lo_value + - Note: If you're trying to understand why this works, we are checking `idx_add` which - is one higher than idx. This offsets the cycle it takes to update the register. +def check_idx_upper_bound(comp: cb.ComponentBuilder, hi): + """ + Creates assignments to test if idx < hi """ if type(hi) == CalyxAdd: hi_value = comp.get_cell(str(hi)).port("out") else: hi_value = hi - if type(lo) == CalyxAdd: - lo_value = comp.get_cell(str(lo)).port("out") - else: - lo_value = lo - reg_str = NAME_SCHEME["idx between reg"].format(lo=lo, hi=hi) - group_str = NAME_SCHEME["idx between group"].format(lo=lo, hi=hi) + idx = comp.get_cell("idx") index_lt = f"index_lt_{hi}" - index_ge = f"index_ge_{lo}" - reg = comp.reg(reg_str, 1) - idx_add = comp.get_cell("idx_add") - # If no upper bound, then only need to check reg >= lo - lt = ( - comp.get_cell(index_lt) - if comp.try_get_cell(index_lt) is not None - else comp.lt(BITWIDTH, index_lt) - ) + lt = comp.lt(BITWIDTH, index_lt) + with comp.continuous: + lt.left = idx.out + lt.right = hi_value + + +def check_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: + """ + Creates assignments to check whether idx is between [lo, hi). + That is, whether lo <= idx < hi. + """ + # This is the name of the combinational cell that checks the condition + idx_between_str = f"idx_between_{lo}_{hi}_comb" + lt = comp.get_cell(f"index_lt_{hi}") # if lo == 0, then only need to check if reg < hi if type(lo) == int and lo == 0: - with comp.static_group(group_str, 1): - lt.left = idx_add.out - lt.right = hi_value - reg.in_ = lt.out - reg.write_en = 1 + # In this case, the `wire` cell is the cell checking the condition. + wire = comp.wire(idx_between_str, 1) + with comp.continuous: + wire.in_ = lt.out # need to check if reg >= lo and reg < hi else: - ge = ( - comp.get_cell(index_ge) - if comp.try_get_cell(index_ge) is not None - else comp.ge(BITWIDTH, index_ge) - ) - and_ = comp.and_(1, f"idx_between_{lo}_{hi}_comb") - with comp.static_group(group_str, 1): - ge.left = idx_add.out - ge.right = lo_value - lt.left = idx_add.out - lt.right = hi_value - and_.left = ge.out + ge = comp.get_cell(f"index_ge_{lo}") + # In this case, the `and` cell is the cell checking the condition. + and_ = comp.and_(1, idx_between_str) + with comp.continuous: and_.right = lt.out - reg.in_ = and_.out - reg.write_en = 1 - - -def init_idx_between(comp: cb.ComponentBuilder, lo, hi): - """ - Builds a group to set initial state for register idx_between_{lo}_{hi}_reg. - """ - # if lo == 0, then the idx will initially be in between the interval, so - # need to set idx_between to high - start_hi = 1 if lo == 0 else 0 - idx_between = comp.get_cell(NAME_SCHEME["idx between reg"].format(lo=lo, hi=hi)) - with comp.static_group(NAME_SCHEME["idx between init"].format(lo=lo, hi=hi), 1): - idx_between.in_ = start_hi - idx_between.write_en = 1 + and_.left = ge.out def accum_nec_ranges(nec_ranges, schedule): @@ -450,19 +398,17 @@ def gen_schedules( """ left_length, top_length = config.left_length, config.top_length depth_port = comp.this().depth - min_depth_4_port = comp.get_cell("min_depth_4").port("out") schedules = {} update_sched = np.zeros((left_length, top_length), dtype=object) pe_fill_sched = np.zeros((left_length, top_length), dtype=object) pe_accum_sched = np.zeros((left_length, top_length), dtype=object) pe_move_sched = np.zeros((left_length, top_length), dtype=object) - # will only actually use one of the following two schedules pe_write_sched = np.zeros((left_length, top_length), dtype=object) for row in range(0, left_length): for col in range(0, top_length): pos = row + col update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) - pe_fill_sched[row][col] = (pos + 1, CalyxAdd(min_depth_4_port, pos + 1)) + pe_fill_sched[row][col] = (pos + 1, pos + 5) pe_accum_sched[row][col] = (pos + 5, CalyxAdd(depth_port, pos + 5)) pe_move_sched[row][col] = (pos + 1, CalyxAdd(depth_port, pos + 1)) pe_write_sched[row][col] = ( @@ -486,7 +432,7 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): """ if not body: return [] - if_cell = comp.get_cell(f"idx_between_{start}_{end}_reg") + if_cell = comp.get_cell(f"idx_between_{start}_{end}_comb") return [ cb.static_if( if_cell.out, @@ -496,47 +442,32 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): def generate_control( - comp: cb.ComponentBuilder, - config: SystolicConfiguration, - schedules, - calyx_add_groups, - nec_ranges, + comp: cb.ComponentBuilder, config: SystolicConfiguration, schedules ): """ Logically, control performs the following actions: 1. Initialize all the memory indexors and idx and idx_between registers at the start - 2. Build a static repeat with a one cycle body that: + 2. Build a static loop with a one cycle body that: a. Updates memory indices if needed/feeds memory into systolic array. b. Invokes the PEs correctly (mul_ready should only be hi if the multiplier's values are ready). c. Move the data needed by each PE - 3. Writes the PE values into external memory + 3. Writes the PE values into output ports of the component when necessary """ control = [] top_length, left_length = config.top_length, config.left_length # Initialize all memories. - init_indices: list[py_ast.Control] = [ - py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"t{idx}")) - for idx in range(top_length) - ] - init_indices.extend( - [ - py_ast.Enable(NAME_SCHEME["index init"].format(prefix=f"l{idx}")) - for idx in range(left_length) - ] - + [ - py_ast.Enable("init_idx"), - py_ast.Enable("init_min_depth"), - py_ast.Enable("init_cond_reg"), - py_ast.Enable("init_iter_limit"), - ] - + [py_ast.Enable(f"init_idx_between_{lo}_{hi}") for (lo, hi) in nec_ranges] + control.append( + py_ast.StaticParComp( + [ + py_ast.Enable("init_idx"), + py_ast.Enable("init_iter_limit"), + ] + ) ) - control.append(py_ast.StaticParComp(init_indices)) - # source_pos metadata init init_tag = 0 source_map = {} @@ -549,8 +480,7 @@ def counter(): # end source pos init - control_stmts = [] - incr_stmts = [py_ast.Enable("incr_idx"), py_ast.Enable("write_cond_reg")] + while_body_stmts = [py_ast.Enable("incr_idx")] for r in range(left_length): for c in range(top_length): # build 4 if stmts for the 4 schedules that we need to account for @@ -587,7 +517,7 @@ def counter(): pe_control = ( input_mem_updates + pe_fills + pe_moves + pe_accums + output_writes ) - control_stmts.append(py_ast.StaticParComp(pe_control)) + while_body_stmts.append(py_ast.StaticParComp(pe_control)) # providing metadata tag = counter() source_map[ @@ -599,19 +529,10 @@ def counter(): writing: [{schedules['write_sched'][r][c][0]} \ {schedules['write_sched'][r][c][1]})" - # handles the coordination so that `idx_if_between` statements work correctly ` - for start, end in nec_ranges: - # build the control stmts that assign correct values to - # idx_between_{start}_{end}_reg, which is what the if stmts above^ rely on - incr_stmts.append(py_ast.Enable(f"idx_between_{start}_{end}_group")) - for calyx_add_group in calyx_add_groups: - incr_stmts.append(py_ast.Enable(calyx_add_group)) - while_ctrl = [py_ast.StaticParComp(control_stmts), py_ast.StaticParComp(incr_stmts)] - while_body = py_ast.StaticParComp(while_ctrl) + while_body = py_ast.StaticParComp(while_body_stmts) # build the while loop with condition cond_reg. - # num repeats = (top_length - 1) + (left_length - 1) + (top_depth - 1) + 5 + 1 - cond_reg_port = comp.get_cell("cond_reg").port("out") + cond_reg_port = comp.get_cell("lt_iter_limit").port("out") while_loop = cb.while_(cond_reg_port, while_body) control.append(while_loop) @@ -629,7 +550,8 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): pe(prog) computational_unit = prog.component(SYSTOLIC_ARRAY_COMP) depth_port = computational_unit.input("depth", BITWIDTH) - init_runtime_vals( + # initialize the iteration limit to top_length + left_length + depth + 4 + init_iter_limit( computational_unit, depth_port, config.top_length + config.left_length + 4 ) @@ -637,7 +559,20 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): nec_ranges = set() for sched in schedules.values(): accum_nec_ranges(nec_ranges, sched) - calyx_add_groups = instantiate_calyx_adds(computational_unit, nec_ranges) + instantiate_calyx_adds(computational_unit, nec_ranges) + + # instantiate groups that handles the idx variables + instantiate_idx_groups(computational_unit) + list1, list2 = zip(*nec_ranges) + nec_ranges_beg = set(list1) + nec_ranges_end = set(list2) + for val in nec_ranges_beg: + check_idx_lower_bound(computational_unit, val) + for val in nec_ranges_end: + check_idx_upper_bound(computational_unit, val) + for start, end in nec_ranges: + # create the assignments that help determine if idx is in between + check_idx_between(computational_unit, start, end) for row in range(config.left_length): for col in range(config.top_length): @@ -673,20 +608,7 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): # `computational_unit`'s output ports instantiate_output_move(computational_unit, row, col) - # instantiate groups that handle cond_reg and idx variables - instantiate_while_groups(computational_unit) - for start, end in nec_ranges: - # create the groups that create for idx_in_between registers - instantiate_idx_between(computational_unit, start, end) - init_idx_between(computational_unit, start, end) - # Generate the control and set the source map - control, source_map = generate_control( - computational_unit, - config, - schedules, - calyx_add_groups, - nec_ranges, - ) + control, source_map = generate_control(computational_unit, config, schedules) computational_unit.control = control prog.program.meta = source_map diff --git a/runt.toml b/runt.toml index 258ccb760..7ba72defc 100644 --- a/runt.toml +++ b/runt.toml @@ -257,6 +257,7 @@ fud e --from systolic --to jq \ --through vcd_json \ -s verilog.data {}.data \ -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ -s jq.file {}.jq \ {} -q """ @@ -274,6 +275,7 @@ fud e --from systolic --to dat \ --through verilog \ -s verilog.data {}.data \ -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ {} -q """ diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 9bc38f15d..1c7b2f703 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -29,105 +29,99 @@ static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { } component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> (t0_addr0: 2, l0_addr0: 2, r0_valid: 1, r0_value: 32, r0_idx: 1) { cells { - min_depth_4 = std_reg(32); - lt_depth_4 = std_lt(32); iter_limit = std_reg(32); iter_limit_add = std_add(32); depth_plus_5 = std_add(32); depth_plus_0 = std_add(32); depth_plus_1 = std_add(32); - min_depth_4_plus_1 = std_add(32); depth_plus_6 = std_add(32); - pe_0_0 = mac_pe(); - top_0_0 = std_reg(32); - left_0_0 = std_reg(32); - t0_idx = std_reg(2); - t0_add = std_add(2); - l0_idx = std_reg(2); - l0_add = std_add(2); idx = std_reg(32); idx_add = std_add(32); - cond_reg = std_reg(1); lt_iter_limit = std_lt(32); - idx_between_5_depth_plus_5_reg = std_reg(1); - index_lt_depth_plus_5 = std_lt(32); + index_ge_0 = std_ge(32); + index_ge_1 = std_ge(32); + index_ge_depth_plus_5 = std_ge(32); index_ge_5 = std_ge(32); - idx_between_5_depth_plus_5_comb = std_and(1); - idx_between_0_depth_plus_0_reg = std_reg(1); index_lt_depth_plus_0 = std_lt(32); - idx_between_1_depth_plus_1_reg = std_reg(1); index_lt_depth_plus_1 = std_lt(32); - index_ge_1 = std_ge(32); - idx_between_1_depth_plus_1_comb = std_and(1); - idx_between_1_min_depth_4_plus_1_reg = std_reg(1); - index_lt_min_depth_4_plus_1 = std_lt(32); - idx_between_1_min_depth_4_plus_1_comb = std_and(1); - idx_between_depth_plus_5_depth_plus_6_reg = std_reg(1); + index_lt_5 = std_lt(32); + index_lt_depth_plus_5 = std_lt(32); index_lt_depth_plus_6 = std_lt(32); - index_ge_depth_plus_5 = std_ge(32); + idx_between_5_depth_plus_5_comb = std_and(1); + idx_between_1_5_comb = std_and(1); + idx_between_0_depth_plus_0_comb = std_wire(1); + idx_between_1_depth_plus_1_comb = std_and(1); idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); + pe_0_0 = mac_pe(); + top_0_0 = std_reg(32); + left_0_0 = std_reg(32); + idx_minus_0 = std_sub(32); + idx_minus_0_res = std_slice(32, 2); } wires { - static<1> group init_min_depth { - lt_depth_4.left = depth; - lt_depth_4.right = 32'd4; - min_depth_4.in = lt_depth_4.out ? depth; - min_depth_4.in = !lt_depth_4.out ? 32'd4; - min_depth_4.write_en = 1'd1; - } static<1> group init_iter_limit { iter_limit_add.left = 32'd6; iter_limit_add.right = depth; iter_limit.in = iter_limit_add.out; iter_limit.write_en = 1'd1; } - static<1> group depth_plus_5_group { - depth_plus_5.left = depth; - depth_plus_5.right = 32'd5; - } - static<1> group depth_plus_0_group { - depth_plus_0.left = depth; - depth_plus_0.right = 32'd0; - } - static<1> group depth_plus_1_group { - depth_plus_1.left = depth; - depth_plus_1.right = 32'd1; - } - static<1> group min_depth_4_plus_1_group { - min_depth_4_plus_1.left = min_depth_4.out; - min_depth_4_plus_1.right = 32'd1; - } - static<1> group depth_plus_6_group { - depth_plus_6.left = depth; - depth_plus_6.right = 32'd6; - } - static<1> group t0_idx_init { - t0_idx.in = 2'd0; - t0_idx.write_en = 1'd1; + depth_plus_5.left = depth; + depth_plus_5.right = 32'd5; + depth_plus_0.left = depth; + depth_plus_0.right = 32'd0; + depth_plus_1.left = depth; + depth_plus_1.right = 32'd1; + depth_plus_6.left = depth; + depth_plus_6.right = 32'd6; + static<1> group init_idx { + idx.in = 32'd0; + idx.write_en = 1'd1; } - static<1> group t0_idx_update { - t0_add.left = 2'd1; - t0_add.right = t0_idx.out; - t0_idx.in = t0_add.out; - t0_idx.write_en = 1'd1; + static<1> group incr_idx { + idx_add.left = idx.out; + idx_add.right = 32'd1; + idx.in = idx_add.out; + idx.write_en = 1'd1; } + lt_iter_limit.left = idx.out; + lt_iter_limit.right = iter_limit.out; + index_ge_0.left = idx.out; + index_ge_0.right = 32'd0; + index_ge_1.left = idx.out; + index_ge_1.right = 32'd1; + index_ge_depth_plus_5.left = idx.out; + index_ge_depth_plus_5.right = depth_plus_5.out; + index_ge_5.left = idx.out; + index_ge_5.right = 32'd5; + index_lt_depth_plus_0.left = idx.out; + index_lt_depth_plus_0.right = depth_plus_0.out; + index_lt_depth_plus_1.left = idx.out; + index_lt_depth_plus_1.right = depth_plus_1.out; + index_lt_5.left = idx.out; + index_lt_5.right = 32'd5; + index_lt_depth_plus_5.left = idx.out; + index_lt_depth_plus_5.right = depth_plus_5.out; + index_lt_depth_plus_6.left = idx.out; + index_lt_depth_plus_6.right = depth_plus_6.out; + idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; + idx_between_5_depth_plus_5_comb.left = index_ge_5.out; + idx_between_1_5_comb.right = index_lt_5.out; + idx_between_1_5_comb.left = index_ge_1.out; + idx_between_0_depth_plus_0_comb.in = index_lt_depth_plus_0.out; + idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; + idx_between_1_depth_plus_1_comb.left = index_ge_1.out; + idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; + idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; + idx_minus_0.left = idx.out; + idx_minus_0.right = 32'd0; + idx_minus_0_res.in = idx_minus_0.out; static<1> group t0_move { - t0_addr0 = t0_idx.out; + t0_addr0 = idx_minus_0_res.out; top_0_0.in = t0_read_data; top_0_0.write_en = 1'd1; } - static<1> group l0_idx_init { - l0_idx.in = 2'd0; - l0_idx.write_en = 1'd1; - } - static<1> group l0_idx_update { - l0_add.left = 2'd1; - l0_add.right = l0_idx.out; - l0_idx.in = l0_add.out; - l0_idx.write_en = 1'd1; - } static<1> group l0_move { - l0_addr0 = l0_idx.out; + l0_addr0 = idx_minus_0_res.out; left_0_0.in = l0_read_data; left_0_0.write_en = 1'd1; } @@ -136,151 +130,39 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> r0_value = pe_0_0.out; r0_idx = 1'd0; } - static<1> group init_idx { - idx.in = 32'd0; - idx.write_en = 1'd1; - } - static<1> group incr_idx { - idx_add.left = idx.out; - idx_add.right = 32'd1; - idx.in = idx_add.out; - idx.write_en = 1'd1; - } - static<1> group init_cond_reg { - cond_reg.in = 1'd1; - cond_reg.write_en = 1'd1; - } - static<1> group write_cond_reg { - lt_iter_limit.left = idx_add.out; - lt_iter_limit.right = iter_limit.out; - cond_reg.in = lt_iter_limit.out; - cond_reg.write_en = 1'd1; - } - static<1> group idx_between_5_depth_plus_5_group { - index_ge_5.left = idx_add.out; - index_ge_5.right = 32'd5; - index_lt_depth_plus_5.left = idx_add.out; - index_lt_depth_plus_5.right = depth_plus_5.out; - idx_between_5_depth_plus_5_comb.left = index_ge_5.out; - idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; - idx_between_5_depth_plus_5_reg.in = idx_between_5_depth_plus_5_comb.out; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group init_idx_between_5_depth_plus_5 { - idx_between_5_depth_plus_5_reg.in = 1'd0; - idx_between_5_depth_plus_5_reg.write_en = 1'd1; - } - static<1> group idx_between_0_depth_plus_0_group { - index_lt_depth_plus_0.left = idx_add.out; - index_lt_depth_plus_0.right = depth_plus_0.out; - idx_between_0_depth_plus_0_reg.in = index_lt_depth_plus_0.out; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group init_idx_between_0_depth_plus_0 { - idx_between_0_depth_plus_0_reg.in = 1'd1; - idx_between_0_depth_plus_0_reg.write_en = 1'd1; - } - static<1> group idx_between_1_depth_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_depth_plus_1.left = idx_add.out; - index_lt_depth_plus_1.right = depth_plus_1.out; - idx_between_1_depth_plus_1_comb.left = index_ge_1.out; - idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; - idx_between_1_depth_plus_1_reg.in = idx_between_1_depth_plus_1_comb.out; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_depth_plus_1 { - idx_between_1_depth_plus_1_reg.in = 1'd0; - idx_between_1_depth_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_1_min_depth_4_plus_1_group { - index_ge_1.left = idx_add.out; - index_ge_1.right = 32'd1; - index_lt_min_depth_4_plus_1.left = idx_add.out; - index_lt_min_depth_4_plus_1.right = min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_comb.left = index_ge_1.out; - idx_between_1_min_depth_4_plus_1_comb.right = index_lt_min_depth_4_plus_1.out; - idx_between_1_min_depth_4_plus_1_reg.in = idx_between_1_min_depth_4_plus_1_comb.out; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group init_idx_between_1_min_depth_4_plus_1 { - idx_between_1_min_depth_4_plus_1_reg.in = 1'd0; - idx_between_1_min_depth_4_plus_1_reg.write_en = 1'd1; - } - static<1> group idx_between_depth_plus_5_depth_plus_6_group { - index_ge_depth_plus_5.left = idx_add.out; - index_ge_depth_plus_5.right = depth_plus_5.out; - index_lt_depth_plus_6.left = idx_add.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; - idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_reg.in = idx_between_depth_plus_5_depth_plus_6_comb.out; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } - static<1> group init_idx_between_depth_plus_5_depth_plus_6 { - idx_between_depth_plus_5_depth_plus_6_reg.in = 1'd0; - idx_between_depth_plus_5_depth_plus_6_reg.write_en = 1'd1; - } } control { seq { static par { - t0_idx_init; - l0_idx_init; init_idx; - init_min_depth; - init_cond_reg; init_iter_limit; - init_idx_between_5_depth_plus_5; - init_idx_between_0_depth_plus_0; - init_idx_between_1_depth_plus_1; - init_idx_between_1_min_depth_4_plus_1; - init_idx_between_depth_plus_5_depth_plus_6; } - while cond_reg.out { + while lt_iter_limit.out { static par { + incr_idx; static par { - static par { - static if idx_between_0_depth_plus_0_reg.out { - static par { - l0_move; - l0_idx_update; - t0_move; - t0_idx_update; - } + static if idx_between_0_depth_plus_0_comb.out { + static par { + l0_move; + t0_move; } - static if idx_between_1_min_depth_4_plus_1_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); - } + } + static if idx_between_1_5_comb.out { + static par { + static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); } - static if idx_between_5_depth_plus_5_reg.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); - } + } + static if idx_between_5_depth_plus_5_comb.out { + static par { + static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); } - static if idx_between_depth_plus_5_depth_plus_6_reg.out { - static par { - pe_0_0_out_write; - } + } + static if idx_between_depth_plus_5_depth_plus_6_comb.out { + static par { + pe_0_0_out_write; } } } - static par { - incr_idx; - write_cond_reg; - idx_between_5_depth_plus_5_group; - idx_between_0_depth_plus_0_group; - idx_between_1_depth_plus_1_group; - idx_between_1_min_depth_4_plus_1_group; - idx_between_depth_plus_5_depth_plus_6_group; - depth_plus_0_group; - depth_plus_1_group; - depth_plus_5_group; - depth_plus_6_group; - min_depth_4_plus_1_group; - } } } } @@ -346,5 +228,5 @@ component main() -> () { } } metadata #{ -0: pe_0_0 filling: [1,min_depth_4_plus_1), accumulating: [5 depth_plus_5), writing: [depth_plus_5 depth_plus_6) +0: pe_0_0 filling: [1,5), accumulating: [5 depth_plus_5), writing: [depth_plus_5 depth_plus_6) }# From 0f42f5de208ecc5862a9ed2717c9c07c661c9b64 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 11 Oct 2023 11:04:25 -0400 Subject: [PATCH 074/189] disable playground workflow --- .github/workflows/{playground.yml => playground.yml.skip} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{playground.yml => playground.yml.skip} (100%) diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml.skip similarity index 100% rename from .github/workflows/playground.yml rename to .github/workflows/playground.yml.skip From e35b08673b8f175631bc6bc68f101d2404739bc1 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 12 Oct 2023 10:55:34 -0400 Subject: [PATCH 075/189] add signext primitive (#1739) --- primitives/binary_operators.futil | 2 +- primitives/binary_operators.sv | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 0ea6f0c28..473f8abfe 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -145,5 +145,5 @@ extern "binary_operators.sv" { comb primitive std_sle<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: 1); comb primitive std_slsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_srsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); - + comb primitive std_signext<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); } diff --git a/primitives/binary_operators.sv b/primitives/binary_operators.sv index 8570dd04c..ec8bbb3a1 100644 --- a/primitives/binary_operators.sv +++ b/primitives/binary_operators.sv @@ -740,3 +740,26 @@ module std_srsh #( ); assign out = left >>> right; endmodule + +// Signed extension +module std_signext #( + parameter IN_WIDTH = 32, + parameter OUT_WIDTH = 32 +) ( + input wire logic [IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + localparam EXTEND = OUT_WIDTH - IN_WIDTH; + assign out = { {EXTEND {in[IN_WIDTH-1]}}, in}; + + `ifdef VERILATOR + always_comb begin + if (IN_WIDTH > OUT_WIDTH) + $error( + "std_signext: Output width less than input width\n", + "IN_WIDTH: %0d", IN_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule \ No newline at end of file From b6758d9d47d20b8079a4dc23036e2296491cc6a9 Mon Sep 17 00:00:00 2001 From: paili0628 <92661158+paili0628@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:32:39 -0400 Subject: [PATCH 076/189] Schedule compaction (#1722) * added schedule compaction pass * debug * fmt * changed test cases and added schedule-compaction to default pipeline * addressed comments * fmt * debug * debug * changed the group enable to static par * allowed non-enable control and recalculated latency * add schedule-compaction to default pass * restored invoke-memory.futil * fixed bug * fmt * restore pass ordering * debug * fmt and fix test cases * fix test cases * fix test cases --- calyx-frontend/src/attribute.rs | 3 + calyx-opt/src/analysis/control_order.rs | 88 ++++++++- calyx-opt/src/analysis/read_write_set.rs | 52 ++++- calyx-opt/src/default_passes.rs | 10 +- calyx-opt/src/passes/compile_invoke.rs | 8 +- calyx-opt/src/passes/mod.rs | 2 + calyx-opt/src/passes/schedule_compaction.rs | 180 ++++++++++++++++++ calyx-opt/src/passes/static_promotion.rs | 4 +- examples/dahlia/dot-product.expect | 2 +- examples/futil/dot-product.expect | 78 ++++---- examples/futil/simple.expect | 32 ++-- examples/futil/vectorized-add.expect | 68 +++---- tests/correctness/exp/any-base-1.expect | 2 +- tests/correctness/exp/any-base-2.expect | 2 +- tests/correctness/exp/any-base-3.expect | 2 +- tests/correctness/exp/neg-base.expect | 2 +- tests/correctness/invoke-memory.futil | 2 +- .../ntt-pipeline/ntt-16-reduced-4.expect | 2 +- tests/correctness/seq.futil | 2 +- tests/passes/compile-invoke/static-ref.expect | 5 + .../schedule-compaction.expect | 52 +++++ .../schedule-compaction.futil | 59 ++++++ .../passes/static-promotion/component.expect | 2 +- tests/passes/static-promotion/groups.expect | 2 +- tests/passes/static-promotion/invoke.expect | 4 +- .../static-promotion/multi-static.expect | 4 +- .../static-promotion/upgrade-bound.expect | 2 +- 27 files changed, 550 insertions(+), 121 deletions(-) create mode 100644 calyx-opt/src/passes/schedule_compaction.rs create mode 100644 tests/passes/schedule-compaction/schedule-compaction.expect create mode 100644 tests/passes/schedule-compaction/schedule-compaction.futil diff --git a/calyx-frontend/src/attribute.rs b/calyx-frontend/src/attribute.rs index 834e5895b..76cdb57e5 100644 --- a/calyx-frontend/src/attribute.rs +++ b/calyx-frontend/src/attribute.rs @@ -103,6 +103,9 @@ pub enum NumAttr { #[strum(serialize = "promote_static")] /// Promote the group or control to static with the annotated latency PromoteStatic, + #[strum(serialize = "compactable")] + /// suggest that the current static seq block is compactable + Compactable, } impl From for Attribute { fn from(attr: NumAttr) -> Self { diff --git a/calyx-opt/src/analysis/control_order.rs b/calyx-opt/src/analysis/control_order.rs index f62d5c45c..27102ebfe 100644 --- a/calyx-opt/src/analysis/control_order.rs +++ b/calyx-opt/src/analysis/control_order.rs @@ -34,8 +34,28 @@ impl ControlOrder { let cell = cr.borrow(); match cell.prototype { // Ignore constants and _this - ir::CellType::Constant { .. } - | ir::CellType::ThisComponent => None, + ir::CellType::Constant { .. } => None, + ir::CellType::ThisComponent => None, + _ => Some(cell.name()), + } + }) + .unique() + } + + fn get_cells_static_seq( + ports: Vec>, + ) -> impl Iterator { + ports + .into_iter() + .filter_map(|p| { + let cr = p.borrow().cell_parent(); + let cell = cr.borrow(); + match cell.prototype { + // Ignore constants and _this + ir::CellType::Constant { .. } => None, + ir::CellType::ThisComponent => { + Some(ir::Id::new("this_comp")) + } _ => Some(cell.name()), } }) @@ -123,4 +143,68 @@ impl ControlOrder { Err(Error::misc(format!("No possible sequential ordering. Control programs exhibit data race:\n{}", msg))) } } + + // returns a graph of dependency for input programs + // input control programs are considered to have data dependency if: + // 1. subsequent program writes to cells that previous program reads from + // 2. subsequent program writes to cells that previous program writes to + // 3. subsequent program reads from cells that previous program writes to + pub fn get_dependency_graph_static_seq( + stmts: impl Iterator, + dependency: &mut HashMap>, + latency_map: &mut HashMap, + ) -> DiGraph, ()> { + // Directed graph where edges means that a control program must be run before. + let mut gr: DiGraph, ()> = DiGraph::new(); + + // Mapping name of cell to all the indices that read or write to it. + let mut reads: HashMap> = HashMap::default(); + let mut writes: HashMap> = HashMap::default(); + + for c in stmts { + let (port_reads, port_writes) = + ReadWriteSet::control_port_read_write_set_static(&c); + let r_cells = Self::get_cells_static_seq(port_reads); + let w_cells = Self::get_cells_static_seq(port_writes); + let latency = c.get_latency(); + let idx = gr.add_node(Some(c)); + dependency.insert(idx, Vec::new()); + latency_map.insert(idx, latency); + + for cell in r_cells { + if let Some(wr_idxs) = writes.get(&cell) { + for wr_idx in wr_idxs { + if !wr_idx.eq(&idx) { + gr.add_edge(*wr_idx, idx, ()); + dependency.entry(idx).or_default().push(*wr_idx); + } + } + } + reads.entry(cell).or_default().push(idx); + } + + for cell in w_cells { + if let Some(wr_idxs) = writes.get(&cell) { + for wr_idx in wr_idxs { + if !wr_idx.eq(&idx) { + gr.add_edge(*wr_idx, idx, ()); + dependency.entry(idx).or_default().push(*wr_idx); + } + } + } + + if let Some(r_idxs) = reads.get(&cell) { + for r_idx in r_idxs { + if !r_idx.eq(&idx) { + gr.add_edge(*r_idx, idx, ()); + dependency.entry(idx).or_default().push(*r_idx); + } + } + } + + writes.entry(cell).or_default().push(idx); + } + } + gr + } } diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index e1cb8baad..de1103e7b 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -165,11 +165,30 @@ impl ReadWriteSet { ir::StaticControl::Invoke(ir::StaticInvoke { inputs, outputs, + ref_cells, .. }) => { - let inps = inputs.iter().map(|(_, p)| p).cloned(); - let outs = outputs.iter().map(|(_, p)| p).cloned(); - (inps.collect(), outs.collect()) + let mut inps: Vec> = + inputs.iter().map(|(_, p)| p).cloned().collect(); + let mut outs: Vec> = + outputs.iter().map(|(_, p)| p).cloned().collect(); + for (_, cell) in ref_cells.iter() { + for port in cell.borrow().ports.iter() { + match port.borrow().direction { + ir::Direction::Input => { + outs.push(Rc::clone(port)); + } + ir::Direction::Output => { + inps.push(Rc::clone(port)); + } + _ => { + outs.push(Rc::clone(port)); + inps.push(Rc::clone(port)); + } + } + } + } + (inps, outs) } } } @@ -190,22 +209,39 @@ impl ReadWriteSet { inputs, outputs, comb_group, + ref_cells, .. }) => { let inps = inputs.iter().map(|(_, p)| p).cloned(); let outs = outputs.iter().map(|(_, p)| p).cloned(); + let mut r: Vec> = inps.collect(); + let mut w: Vec> = outs.collect(); + + for (_, cell) in ref_cells { + for port in cell.borrow().ports.iter() { + match port.borrow().direction { + ir::Direction::Input => { + w.push(Rc::clone(port)); + } + ir::Direction::Output => { + r.push(Rc::clone(port)); + } + _ => { + w.push(Rc::clone(port)); + r.push(Rc::clone(port)); + } + } + } + } match comb_group { Some(cgr) => { let cg = cgr.borrow(); let assigns = cg.assignments.iter(); let reads = Self::port_read_set(assigns.clone()); let writes = Self::port_write_set(assigns); - ( - reads.chain(inps).collect(), - writes.chain(outs).collect(), - ) + (reads.chain(r).collect(), writes.chain(w).collect()) } - None => (inps.collect(), outs.collect()), + None => (r, w), } } ir::Control::Seq(ir::Seq { stmts, .. }) diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 517fca366..72f1062d8 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -6,10 +6,10 @@ use crate::passes::{ DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, - RegisterUnsharing, RemoveIds, ResetInsertion, SimplifyStaticGuards, - SimplifyWithControl, StaticInliner, StaticPromotion, SynthesisPapercut, - TopDownCompileControl, TopDownStaticTiming, UnrollBounded, WellFormed, - WireInliner, WrapMain, + RegisterUnsharing, RemoveIds, ResetInsertion, ScheduleCompaction, + SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticPromotion, + SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, + UnrollBounded, WellFormed, WireInliner, WrapMain, }; use crate::traversal::Named; use crate::{pass_manager::PassManager, register_alias}; @@ -36,6 +36,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -93,6 +94,7 @@ impl PassManager { CompileInvoke, // creates dead comb groups AttributePromotion, StaticPromotion, + ScheduleCompaction, CompileRepeat, DeadGroupRemoval, // Since previous passes potentially create dead groups CollapseControl, diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 3458ce344..92b26a45c 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -128,11 +128,11 @@ impl CompileInvoke { /// /// Since this pass eliminates all ref cells in post order, we expect that /// invoked component already had all of its ref cells removed. - fn ref_cells_to_ports( + fn ref_cells_to_ports( &mut self, inv_cell: RRC, ref_cells: impl Iterator)>, - ) -> Vec> { + ) -> Vec> { let inv_comp = inv_cell.borrow().type_name().unwrap(); let mut assigns = Vec::new(); for (ref_cell_name, cell) in ref_cells { @@ -361,6 +361,10 @@ impl Visitor for CompileInvoke { let invoke_group = builder.add_static_group("static_invoke", s.latency); + invoke_group.borrow_mut().assignments.extend( + self.ref_cells_to_ports(Rc::clone(&s.comp), s.ref_cells.drain(..)), + ); + // comp.go = 1'd1; structure!(builder; let one = constant(1, 1); diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index a12982c38..cf9d261a3 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -28,6 +28,7 @@ mod par_to_seq; mod register_unsharing; mod remove_ids; mod reset_insertion; +mod schedule_compaction; mod simplify_static_guards; mod static_inliner; mod static_promotion; @@ -73,6 +74,7 @@ pub use par_to_seq::ParToSeq; pub use register_unsharing::RegisterUnsharing; pub use remove_ids::RemoveIds; pub use reset_insertion::ResetInsertion; +pub use schedule_compaction::ScheduleCompaction; pub use simplify_static_guards::SimplifyStaticGuards; pub use simplify_with_control::SimplifyWithControl; pub use static_inliner::StaticInliner; diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs new file mode 100644 index 000000000..9b873eee4 --- /dev/null +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -0,0 +1,180 @@ +use crate::traversal::Action; +use crate::{ + analysis, + traversal::{Named, Visitor}, +}; +use calyx_ir as ir; +use petgraph::{algo, graph::NodeIndex}; +use std::collections::HashMap; + +#[derive(Default)] +/// for static seqs that are statically promoted by the compiler, +/// aggressively compacts the execution schedule so that the execution +/// order of control operators still respects data dependency +/// Example: see tests/passes/schedule-compaction/schedule-compaction.rs +pub struct ScheduleCompaction; + +impl Named for ScheduleCompaction { + fn name() -> &'static str { + "schedule-compaction" + } + + fn description() -> &'static str { + "Aggressively compact schedule for static seqs which were promoted from generic seqs" + } +} + +impl Visitor for ScheduleCompaction { + fn iteration_order() -> crate::traversal::Order + where + Self: Sized, + { + crate::traversal::Order::Post + } + + fn finish_static_seq( + &mut self, + s: &mut calyx_ir::StaticSeq, + comp: &mut calyx_ir::Component, + sigs: &calyx_ir::LibrarySignatures, + _comps: &[calyx_ir::Component], + ) -> crate::traversal::VisResult { + // records the corresponding node indices that each control program + // has data dependency on + let mut dependency: HashMap> = HashMap::new(); + // records the latency of corresponding control operator for each node index + let mut latency_map: HashMap = HashMap::new(); + // records the scheduled start time of corresponding control operator for each node index + let mut schedule: HashMap = HashMap::new(); + + let mut builder = ir::Builder::new(comp, sigs); + + let mut total_order = + analysis::ControlOrder::::get_dependency_graph_static_seq( + s.stmts.drain(..), + &mut dependency, + &mut latency_map, + ); + + if let Ok(order) = algo::toposort(&total_order, None) { + let mut total_time: u64 = 0; + let mut stmts: Vec = Vec::new(); + + for i in order { + let mut start: u64 = 0; + for node in dependency.get(&i).unwrap() { + let allow_start = schedule[node] + latency_map[node]; + if allow_start > start { + start = allow_start; + } + } + schedule.insert(i, start); + + let control = total_order[i].take().unwrap(); + let mut st_seq_stmts: Vec = Vec::new(); + if start > 0 { + let no_op = builder.add_static_group("no-op", start); + + st_seq_stmts.push(ir::StaticControl::Enable( + ir::StaticEnable { + group: no_op, + attributes: ir::Attributes::default(), + }, + )); + } + if start + latency_map[&i] > total_time { + total_time = start + latency_map[&i]; + } + + st_seq_stmts.push(control); + stmts.push(ir::StaticControl::Seq(ir::StaticSeq { + stmts: st_seq_stmts, + attributes: ir::Attributes::default(), + latency: start + latency_map[&i], + })); + } + + let s_par = ir::StaticControl::Par(ir::StaticPar { + stmts, + attributes: ir::Attributes::default(), + latency: total_time, + }); + return Ok(Action::static_change(s_par)); + } else { + println!( + "Error when producing topo sort. Dependency graph has a cycle." + ); + } + Ok(Action::Continue) + } + + fn finish_static_repeat( + &mut self, + s: &mut ir::StaticRepeat, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + s.latency = s.body.get_latency() * s.num_repeats; + Ok(Action::Continue) + } + + fn finish_static_par( + &mut self, + s: &mut ir::StaticPar, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + let mut latency: u64 = 0; + for stmt in s.stmts.iter() { + latency = std::cmp::max(latency, stmt.get_latency()); + } + s.latency = latency; + Ok(Action::Continue) + } + + fn finish_static_if( + &mut self, + s: &mut ir::StaticIf, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + s.latency = + std::cmp::max(s.tbranch.get_latency(), s.fbranch.get_latency()); + Ok(Action::Continue) + } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> crate::traversal::VisResult { + if comp.is_static() { + comp.latency = Some( + std::num::NonZeroU64::new( + comp.control.borrow().get_latency().unwrap(), + ) + .unwrap(), + ); + } + Ok(Action::Continue) + } + + fn static_invoke( + &mut self, + s: &mut ir::StaticInvoke, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + comps: &[ir::Component], + ) -> crate::traversal::VisResult { + for comp in comps { + if comp.name.eq(&s.comp.borrow().type_name().unwrap()) { + s.latency = u64::from(comp.latency.unwrap()); + } + } + Ok(Action::Continue) + } +} diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index a4fd888fa..f71a4934d 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -476,9 +476,11 @@ impl StaticPromotion { _ => unreachable!("We do not insert non-static controls other than group enables with `promote_static` attribute") } } + let mut attributes = ir::Attributes::default(); + attributes.insert(ir::NumAttr::Compactable, 1); ir::Control::Static(StaticControl::Seq(ir::StaticSeq { stmts: static_seq_st, - attributes: ir::Attributes::default(), + attributes, latency, })) } diff --git a/examples/dahlia/dot-product.expect b/examples/dahlia/dot-product.expect index 1241bd92e..3e1a2e914 100644 --- a/examples/dahlia/dot-product.expect +++ b/examples/dahlia/dot-product.expect @@ -1,5 +1,5 @@ { - "cycles": 98, + "cycles": 90, "memories": { "A": [ 27, diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index b90294a1e..0bbfdc060 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -28,92 +28,92 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_seq_go = std_wire(1); - @generated while_wrapper_early_reset_static_seq_done = std_wire(1); + @generated while_wrapper_early_reset_static_par_go = std_wire(1); + @generated while_wrapper_early_reset_static_par_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 4'd1 & early_reset_static_par_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 4'd7 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 4'd1 & early_reset_static_par_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 4'd7 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm.out == 4'd7 & early_reset_static_seq_go.out ? const3.out; + add1.left = fsm.out == 4'd1 & early_reset_static_par_go.out ? i0.out; + add1.right = fsm.out == 4'd1 & early_reset_static_par_go.out ? const3.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 4'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 4'd0; - fsm.in = fsm.out != 4'd8 & early_reset_static_seq_go.out ? adder0.out; + fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 4'd0; + fsm.in = fsm.out != 4'd7 & early_reset_static_par_go.out ? adder0.out; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 4'd1; - add0.left = fsm.out == 4'd6 & early_reset_static_seq_go.out ? v0.read_data; - add0.right = fsm.out == 4'd6 & early_reset_static_seq_go.out ? B_read0_0.out; - v0.write_en = fsm.out == 4'd6 & early_reset_static_seq_go.out ? 1'd1; + add0.left = fsm.out == 4'd6 & early_reset_static_par_go.out ? v0.read_data; + add0.right = fsm.out == 4'd6 & early_reset_static_par_go.out ? B_read0_0.out; + v0.write_en = fsm.out == 4'd6 & early_reset_static_par_go.out ? 1'd1; v0.clk = clk; - v0.addr0 = fsm.out == 4'd6 & early_reset_static_seq_go.out ? const2.out; + v0.addr0 = fsm.out == 4'd6 & early_reset_static_par_go.out ? const2.out; v0.reset = reset; - v0.write_data = fsm.out == 4'd6 & early_reset_static_seq_go.out ? add0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? 1'd1; + v0.write_data = fsm.out == 4'd6 & early_reset_static_par_go.out ? add0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; A0.reset = reset; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; mult_pipe0.clk = clk; - mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? A_read0_0.out; - mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? 1'd1; + mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? A_read0_0.out; + mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? 1'd1; mult_pipe0.reset = reset; - mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? B_read0_0.out; - adder0.left = early_reset_static_seq_go.out ? fsm.out; - adder0.right = early_reset_static_seq_go.out ? 4'd1; + mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? B_read0_0.out; + adder0.left = early_reset_static_par_go.out ? fsm.out; + adder0.right = early_reset_static_par_go.out ? 4'd1; invoke0_done.in = i0.done; - early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 4'd8 & early_reset_static_seq_go.out ? const1.out; + early_reset_static_par_done.in = ud0.out; + le0.left = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? const1.out; signal_reg.write_en = fsm.out == 4'd0 & signal_reg.out | fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 4'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5) & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5 & fsm.out < 4'd6) & early_reset_static_par_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; - B_read0_0.in = fsm.out == 4'd5 & early_reset_static_seq_go.out ? A_read0_0.out; + B_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 4'd5 & early_reset_static_par_go.out ? A_read0_0.out; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 4'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; - A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4) & early_reset_static_seq_go.out ? 1'd1; + early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; + A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4 & fsm.out >= 4'd1 & fsm.out < 4'd5 & fsm.out < 4'd5) & early_reset_static_par_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; - A_read0_0.in = fsm.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; + A_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 4'd4 & early_reset_static_par_go.out ? mult_pipe0.out; } control {} } diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 4f61bc431..16a037543 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -6,29 +6,29 @@ static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done @generated ud = undef(1); @generated adder = std_add(3); @generated signal_reg = std_reg(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); - @generated wrapper_early_reset_static_seq_go = std_wire(1); - @generated wrapper_early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); + @generated wrapper_early_reset_static_par_go = std_wire(1); + @generated wrapper_early_reset_static_par_done = std_wire(1); } wires { - done = wrapper_early_reset_static_seq_done.out ? 1'd1; - fsm.write_en = early_reset_static_seq_go.out ? 1'd1; + done = wrapper_early_reset_static_par_done.out ? 1'd1; + fsm.write_en = early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; - fsm.in = fsm.out != 3'd4 & early_reset_static_seq_go.out ? adder.out; - fsm.in = fsm.out == 3'd4 & early_reset_static_seq_go.out ? 3'd0; - adder.left = early_reset_static_seq_go.out ? fsm.out; - adder.right = early_reset_static_seq_go.out ? 3'd1; - wrapper_early_reset_static_seq_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_go.in = wrapper_early_reset_static_seq_go.out ? 1'd1; - signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + fsm.in = fsm.out != 3'd4 & early_reset_static_par_go.out ? adder.out; + fsm.in = fsm.out == 3'd4 & early_reset_static_par_go.out ? 3'd0; + adder.left = early_reset_static_par_go.out ? fsm.out; + adder.right = early_reset_static_par_go.out ? 3'd1; + wrapper_early_reset_static_par_go.in = go; + wrapper_early_reset_static_par_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; + early_reset_static_par_done.in = ud.out; + signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; + signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; - early_reset_static_seq_done.in = ud.out; - wrapper_early_reset_static_seq_go.in = go; + early_reset_static_par_go.in = wrapper_early_reset_static_par_go.out ? 1'd1; } control {} } diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index 005c8bc0f..507224343 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -25,85 +25,85 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_seq_go = std_wire(1); - @generated early_reset_static_seq_done = std_wire(1); + @generated early_reset_static_par_go = std_wire(1); + @generated early_reset_static_par_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_seq_go = std_wire(1); - @generated while_wrapper_early_reset_static_seq_done = std_wire(1); + @generated while_wrapper_early_reset_static_par_go = std_wire(1); + @generated while_wrapper_early_reset_static_par_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_seq_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_par_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 3'd2 & early_reset_static_seq_go.out ? add1.out; + i0.in = fsm.out == 3'd2 & early_reset_static_par_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 3'd2 & early_reset_static_seq_go.out ? i0.out; - add1.right = fsm.out == 3'd2 & early_reset_static_seq_go.out ? const2.out; + add1.left = fsm.out == 3'd2 & early_reset_static_par_go.out ? i0.out; + add1.right = fsm.out == 3'd2 & early_reset_static_par_go.out ? const2.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 3'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out != 3'd3 & early_reset_static_seq_go.out ? adder0.out; - fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 3'd0; + fsm.in = fsm.out != 3'd3 & early_reset_static_par_go.out ? adder0.out; + fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 3'd0; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 3'd1; - add0.left = fsm.out == 3'd1 & early_reset_static_seq_go.out ? A_read0_0.out; - add0.right = fsm.out == 3'd1 & early_reset_static_seq_go.out ? B_read0_0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 1'd1; + add0.left = fsm.out == 3'd1 & early_reset_static_par_go.out ? A_read0_0.out; + add0.right = fsm.out == 3'd1 & early_reset_static_par_go.out ? B_read0_0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + A0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; A0.reset = reset; - Sum0.write_en = fsm.out == 3'd1 & early_reset_static_seq_go.out ? 1'd1; + Sum0.write_en = fsm.out == 3'd1 & early_reset_static_par_go.out ? 1'd1; Sum0.clk = clk; - Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_seq_go.out ? i0.out; + Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_par_go.out ? i0.out; Sum0.reset = reset; - Sum0.write_data = fsm.out == 3'd1 & early_reset_static_seq_go.out ? add0.out; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; + Sum0.write_data = fsm.out == 3'd1 & early_reset_static_par_go.out ? add0.out; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; - adder0.left = early_reset_static_seq_go.out ? fsm.out; - adder0.right = early_reset_static_seq_go.out ? 3'd1; + adder0.left = early_reset_static_par_go.out ? fsm.out; + adder0.right = early_reset_static_par_go.out ? 3'd1; invoke0_done.in = i0.done; - early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; - le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? const1.out; + early_reset_static_par_done.in = ud0.out; + le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? const1.out; signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; + B0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? B0.read_data; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; - early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; - A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; + early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; + A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? A0.read_data; } control {} } diff --git a/tests/correctness/exp/any-base-1.expect b/tests/correctness/exp/any-base-1.expect index 8517668be..04633a564 100644 --- a/tests/correctness/exp/any-base-1.expect +++ b/tests/correctness/exp/any-base-1.expect @@ -1,5 +1,5 @@ { - "cycles": 220, + "cycles": 213, "memories": { "b": [ "4.5" diff --git a/tests/correctness/exp/any-base-2.expect b/tests/correctness/exp/any-base-2.expect index 1c1ad7e19..d415bab29 100644 --- a/tests/correctness/exp/any-base-2.expect +++ b/tests/correctness/exp/any-base-2.expect @@ -1,5 +1,5 @@ { - "cycles": 215, + "cycles": 208, "memories": { "b": [ "7.5" diff --git a/tests/correctness/exp/any-base-3.expect b/tests/correctness/exp/any-base-3.expect index 71f36e7fe..721f012ce 100644 --- a/tests/correctness/exp/any-base-3.expect +++ b/tests/correctness/exp/any-base-3.expect @@ -1,5 +1,5 @@ { - "cycles": 307, + "cycles": 304, "memories": { "b": [ "0.75" diff --git a/tests/correctness/exp/neg-base.expect b/tests/correctness/exp/neg-base.expect index 8f9d46610..2ff0c5df1 100644 --- a/tests/correctness/exp/neg-base.expect +++ b/tests/correctness/exp/neg-base.expect @@ -1,5 +1,5 @@ { - "cycles": 228, + "cycles": 223, "memories": { "b": [ "-2.600006103515625" diff --git a/tests/correctness/invoke-memory.futil b/tests/correctness/invoke-memory.futil index 48a2fc054..4b672f2ed 100644 --- a/tests/correctness/invoke-memory.futil +++ b/tests/correctness/invoke-memory.futil @@ -51,4 +51,4 @@ component main() -> () { (dest_write_data=d.write_data, dest_write_en=d.write_en, dest_addr0=d.addr0, src_addr0=s.addr0); } } -} +} \ No newline at end of file diff --git a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect index 4000a995f..fecc29a73 100644 --- a/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect +++ b/tests/correctness/ntt-pipeline/ntt-16-reduced-4.expect @@ -1,5 +1,5 @@ { - "cycles": 681, + "cycles": 663, "memories": { "a": [ 7371, diff --git a/tests/correctness/seq.futil b/tests/correctness/seq.futil index 66a2c2e3c..2d9b72e32 100644 --- a/tests/correctness/seq.futil +++ b/tests/correctness/seq.futil @@ -37,4 +37,4 @@ component main() -> () { commit; } } -} +} \ No newline at end of file diff --git a/tests/passes/compile-invoke/static-ref.expect b/tests/passes/compile-invoke/static-ref.expect index a21e4a6bf..e81780ca0 100644 --- a/tests/passes/compile-invoke/static-ref.expect +++ b/tests/passes/compile-invoke/static-ref.expect @@ -47,6 +47,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { reg_to_mem[done] = mem.done; } static<2> group static_invoke { + mem.addr0 = adder.out_addr0; + mem.write_data = adder.out_write_data; + mem.write_en = adder.out_write_en; + adder.out_read_data = mem.read_data; + adder.out_done = mem.done; adder.go = 1'd1; } } diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect new file mode 100644 index 000000000..bf7291c5c --- /dev/null +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -0,0 +1,52 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + a = std_add(32); + } + wires { + static<1> group A { + a_reg.write_en = 1'd1; + a_reg.in = 32'd5; + } + static<10> group C { + c_reg.write_en = %0 ? 1'd1; + c_reg.in = 32'd10; + } + static<1> group B { + b_reg.write_en = 1'd1; + a.right = c_reg.out; + a.left = a_reg.out; + b_reg.in = a.out; + } + static<10> group D { + d_reg.write_en = %0 ? 1'd1; + d_reg.in = a_reg.out; + } + static<1> group no-op { + } + static<10> group no-op0 { + } + } + control { + static<11> par { + static<10> seq { + C; + } + static<1> seq { + A; + } + static<11> seq { + no-op; + D; + } + static<11> seq { + no-op0; + B; + } + } + } +} diff --git a/tests/passes/schedule-compaction/schedule-compaction.futil b/tests/passes/schedule-compaction/schedule-compaction.futil new file mode 100644 index 000000000..048f335c7 --- /dev/null +++ b/tests/passes/schedule-compaction/schedule-compaction.futil @@ -0,0 +1,59 @@ +// -p validate -p schedule-compaction +// for control operators under static seq, +// we consider the subsequent control operator B to have data dependency on +// prior operator A in the following three cases: +// 1. B writes to a cell A reads from +// 2. B reads from a cell A writes to +// 3. B writes to a cell A writes to +// As such, we can draw the following dependency graph for the control program: +// A C +// | \ / +// | \ / +// | \ / +// | \ +// | / \ +// | / \ +// | / \ +// B D +// So we can compact the execution schedule to respect this data dependency +import "primitives/core.futil"; + +component main () -> () { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + a = std_add(32); + } + + wires { + static<1> group A { + a_reg.in = 32'd5; + a_reg.write_en = 1'd1; + } + + static<10> group C { + c_reg.in = 32'd10; + c_reg.write_en = %0 ? 1'd1; + } + + static<1> group B { + a.left = a_reg.out; + a.right = c_reg.out; + b_reg.in = a.out; + b_reg.write_en = 1'd1; + } + + static<10> group D { + d_reg.in = a_reg.out; + d_reg.write_en = %0 ? 1'd1; + } + } + + control { + @compactable static seq { + A; C; B; D; + } + } +} \ No newline at end of file diff --git a/tests/passes/static-promotion/component.expect b/tests/passes/static-promotion/component.expect index e4992bc5e..5515c1b23 100644 --- a/tests/passes/static-promotion/component.expect +++ b/tests/passes/static-promotion/component.expect @@ -20,7 +20,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { A0; B0; C0; diff --git a/tests/passes/static-promotion/groups.expect b/tests/passes/static-promotion/groups.expect index c58440401..c46b3770e 100644 --- a/tests/passes/static-promotion/groups.expect +++ b/tests/passes/static-promotion/groups.expect @@ -34,7 +34,7 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don } control { seq { - static<4> seq { + @compactable static<4> seq { one_cycle0; two_cycles0; mem_wrt_to_done0; diff --git a/tests/passes/static-promotion/invoke.expect b/tests/passes/static-promotion/invoke.expect index 17cec7544..cb0f4671b 100644 --- a/tests/passes/static-promotion/invoke.expect +++ b/tests/passes/static-promotion/invoke.expect @@ -11,7 +11,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset r } } control { - static<2> seq { + @compactable static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-promotion/multi-static.expect b/tests/passes/static-promotion/multi-static.expect index 75306c664..5413970bf 100644 --- a/tests/passes/static-promotion/multi-static.expect +++ b/tests/passes/static-promotion/multi-static.expect @@ -11,7 +11,7 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done } } control { - static<3> seq { + @compactable static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset re } } control { - static<2> seq { + @compactable static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-promotion/upgrade-bound.expect b/tests/passes/static-promotion/upgrade-bound.expect index 78554d15a..fa3f416a1 100644 --- a/tests/passes/static-promotion/upgrade-bound.expect +++ b/tests/passes/static-promotion/upgrade-bound.expect @@ -22,7 +22,7 @@ static<15> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done don } control { @bound(5) static repeat 5 { - static<3> seq { + @compactable static<3> seq { A0; B0; C0; From eb383ae94230b2af81f410649b52ae836006a1fd Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Thu, 12 Oct 2023 15:55:06 -0400 Subject: [PATCH 077/189] [Cider Adapter] Fix missing `package.json` and minor tweaks (#1741) * reconstruct package.json * touch up the top of the readme --- .gitignore | 2 ++ cider-dap/README.md | 40 +++++++++++++++++++++++-------- cider-dap/calyxDebug/extension.js | 16 +++++++------ cider-dap/calyxDebug/package.json | 37 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 cider-dap/calyxDebug/package.json diff --git a/.gitignore b/.gitignore index e37748d2f..750d98b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ __pycache__ tests/xilinx/cocotb/**/hdl .vscode/settings.json + +!cider-dap/calyxDebug/package.json diff --git a/cider-dap/README.md b/cider-dap/README.md index 7e0d6c1af..672f1ee1b 100644 --- a/cider-dap/README.md +++ b/cider-dap/README.md @@ -1,16 +1,37 @@ -## About the Name? -Inspired by the comforting essence of apple cider, our sub-crate tries to bring some of that warmth to debugging. Now, onto what this project is and what's been brewing! - -cider-dap is a sub-crate created for facilitating debugging processes. The name is inspired by the core name "Cider", and "dap" stands for Debug Adapter Protocol! -### Project Overview: +# Cider Debug Adapter +## Installing the extension +Navigate to your vscode extension directory `~/.vscode/extensions` for local +installations. For WSL users, you need to use the *server's* extension folder not +the normal installation in windows. Once in the appropriate folder create a +symlink for the extension +``` +ln -s /cider-dap/calyxDebug cider.cider-dap-0.0.1 +``` + +Once vscode is reloaded, the extension should be active and viewable in the +`Cider dap` tab of the output panel. You will also need to create a symlink for +the cider-dap binary somewhere on your path. From some directory on your PATH: +``` +ln -s /target/debug/cider-dap +``` + +You can then launch the adapter with the Launch Program (Multi Session) action + +## Known issues + * The launch action can sometimes attempt a connection before the server is + ready and will cause a failure, subsequent attempts will work until the + server closes. Ideally the extension would wait until the server has fully launched. + + +## Project Overview: Cider-dap is a debug adapter protocol implementation using Rust, which aids in debugging processes. It interfaces with IDEs or other tools using the Debug Adapter Protocol. -This project primarily leverages the Debug Adapter Protocol (DAP) for its functionality. The structure is organized into different directories and files which encapsulate the functionalities: +This project primarily leverages the Debug Adapter Protocol (DAP) for its functionality. The structure is organized into different directories and files which encapsulate the functionalities:

1.``` cider-dap ``` directory: The main directory which contains the following sub-directories and files: -
-        ```calyxDebug```: Contains the file responsible for debugging extensions and related utilities. So it is a dedicated directory for VSCode debugging extensions. It establishes the bridge between your Rust codebase and the VSCode debugging environment.
-        ```src```: Houses the Rust source files for the project. It contains the project's core functionalities, logic, and structures.
+
+        ```calyxDebug```: Contains the file responsible for debugging extensions and related utilities. So it is a dedicated directory for VSCode debugging extensions. It establishes the bridge between your Rust codebase and the VSCode debugging environment.
+        ```src```: Houses the Rust source files for the project. It contains the project's core functionalities, logic, and structures.
        ```cargo.lock``` & ```cargo.toml```: Standard Rust project files detailing dependencies and project metadata.
3. ```src``` directory:
        ```adapter.rs```: Defines the primary adapter structure for the project and its associated functionalities. Not just any adapter, this file structures the fundamental protocols, handling the translation of high-level debugging commands into actionable, low-level instructions.
@@ -102,4 +123,3 @@ The following dependencies have been added to the project as specified in the ca - Implement more detailed logging to provide insights into server operations. This would be especially useful in identifying issues or understanding the flow of commands and responses. ### Asynchronous Processing: - Consider incorporating asynchronous command processing. This would allow the server to handle multiple requests concurrently, offering faster response times and smoother user experiences, especially in complex debugging scenarios. - diff --git a/cider-dap/calyxDebug/extension.js b/cider-dap/calyxDebug/extension.js index 65af7769c..43cfb9c31 100644 --- a/cider-dap/calyxDebug/extension.js +++ b/cider-dap/calyxDebug/extension.js @@ -6,7 +6,7 @@ const net = require('net'); let debugAdapter = null; let programName = null; // Store the program name // Create output channel -let outputChannel = vscode.window.createOutputChannel("cider dap"); +let outputChannel = vscode.window.createOutputChannel("Cider dap"); function logToPanel(message) { console.log("inside logPanel"); @@ -43,6 +43,7 @@ class CiderDebugAdapterDescriptorFactory { createDebugAdapterDescriptor(session) { // Return a new debug adapter descriptor logToPanel("creating adapter descriptor"); + return new vscode.DebugAdapterServer(this._startDebugServer(session)); } @@ -75,7 +76,7 @@ class CiderDebugAdapter { } // Start the debug adapter process start(port) { - logToPanel('begining of start'); + logToPanel('beginning of start'); // Spawn a new child process for the debug adapter // Include the port as a command line argument @@ -91,7 +92,10 @@ class CiderDebugAdapter { logToPanel(data.toString()); }); - logToPanel('Debugger started on port ' + port + '!'); + this.adapterProcess.on('spawn', () => { + logToPanel('Debugger started on port ' + port + '!'); + }); + } stop() { @@ -110,13 +114,11 @@ function activate(context) { logToPanel('Extension activated!'); // Start the debug server explicitly - const factory = new CiderDebugAdapterDescriptorFactory('/home/basantkhalil/calyx2/target/debug/cider-dap', vscode.workspace.rootPath, outputChannel); + const factory = new CiderDebugAdapterDescriptorFactory('cider-dap', vscode.workspace.rootPath, outputChannel); context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('cider-dap', factory)); logToPanel("after start server"); // Update the adapter path with the serverPort and use it for starting the debug adapter - const adapterPath = '/home/basantkhalil/calyx2/target/debug/cider-dap'; - const cwd = vscode.workspace.rootPath; logToPanel("before startDebugging"); /* context.subscriptions.push(vscode.commands.registerCommand('cider.startDebugging', startDebugging)); context.subscriptions.push(vscode.commands.registerCommand('cider.stopDebugging', stopDebugging)); @@ -139,4 +141,4 @@ function deactivate() { module.exports = { activate, deactivate -}; \ No newline at end of file +}; diff --git a/cider-dap/calyxDebug/package.json b/cider-dap/calyxDebug/package.json new file mode 100644 index 000000000..b011db3e3 --- /dev/null +++ b/cider-dap/calyxDebug/package.json @@ -0,0 +1,37 @@ +{ + "name": "cider-dap", + "displayName": "Cider", + "version": "0.0.1", + "publisher": "Cider", + "description": "A debug adapter for Calyx files", + "author": { + "name": "...", + "email": "..." + }, + "engines": { + "vscode": "^1.54.0" + }, + "icon": "", + "categories": [ + "Debuggers" + ], + "main": "./extension.js", + "contributes": { + "breakpoints": [ + { + "language": "calyx" + } + ], + "debuggers": [ + { + "type": "cider-dap", + "label": "Cider Debug", + "configurationAttributes": {} + } + ] + }, + "activationEvents": [ + "onDebug", + "onLanguage:calyx" + ] +} From cee9e697731ae5b39259feb909933b9d76332c63 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 13 Oct 2023 11:50:03 -0400 Subject: [PATCH 078/189] fix checking for large constants (#1743) --- calyx-ir/src/builder.rs | 9 +++++++-- tests/errors/insufficient-params.expect | 2 +- tests/parsing/comb-component.expect | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/calyx-ir/src/builder.rs b/calyx-ir/src/builder.rs index 78aa36968..547533e53 100644 --- a/calyx-ir/src/builder.rs +++ b/calyx-ir/src/builder.rs @@ -2,7 +2,7 @@ //! representation. use crate::{self as ir, LibrarySignatures, Nothing, RRC, WRC}; use calyx_frontend::BoolAttr; -use std::rc::Rc; +use std::{cmp, rc::Rc}; use super::{CellType, PortDef}; @@ -162,7 +162,12 @@ impl<'a> Builder<'a> { pub fn add_constant(&mut self, val: u64, width: u64) -> RRC { // Ensure that the value can fit within the width assert!( - val < (1 << width), + val < match width.cmp(&64) { + cmp::Ordering::Less => 1 << width, + cmp::Ordering::Equal => u64::MAX, + cmp::Ordering::Greater => + panic!("Widths greater than 64 are not supported."), + }, "Constant value {} cannot fit in {} bits", val, width diff --git a/tests/errors/insufficient-params.expect b/tests/errors/insufficient-params.expect index 25f8b07e8..09ebb3bff 100644 --- a/tests/errors/insufficient-params.expect +++ b/tests/errors/insufficient-params.expect @@ -1,5 +1,5 @@ ---CODE--- 101 ---STDERR--- -thread 'main' panicked at 'Failed to add primitive.: Malformed Structure: Invalid parameter binding for primitive `std_fp_div_pipe`. Requires 3 parameters but provided with 1.', calyx-ir/src/builder.rs:219:14 +thread 'main' panicked at 'Failed to add primitive.: Malformed Structure: Invalid parameter binding for primitive `std_fp_div_pipe`. Requires 3 parameters but provided with 1.', calyx-ir/src/builder.rs:224:14 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/parsing/comb-component.expect b/tests/parsing/comb-component.expect index c7551bf46..ec96480a0 100644 --- a/tests/parsing/comb-component.expect +++ b/tests/parsing/comb-component.expect @@ -2,6 +2,7 @@ import "primitives/core.futil"; comb component custom_lt(left: 4, right: 4) -> (out: 1) { cells { lt = std_lt(4); + c0 = std_const(64, 1000); } wires { lt.left = left; From b2ff0901fdc7be4b1626b3c1d37290bcb0a112ae Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 15 Oct 2023 10:39:55 -0400 Subject: [PATCH 079/189] version 0.6.1 --- CHANGELOG.md | 8 ++++++++ Cargo.lock | 14 +++++++------- Cargo.toml | 14 +++++++------- calyx-utils/Cargo.toml | 1 - 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e072263c7..126533096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## Current + +## 0.6.1 +- Fix checking for large constants (#1743) +- Better static inlining for single cycle `if` (#1734) +- Implement `schedule-compaction` pass to optimize inferred static islands (#1722) +- Add `std_signext` primitive + ## 0.6.0 - BREAKING: Deprecate `Cell::find_with_attr` in favor of `Cell::find_with_unique_attr`. The former is error-prone because pass logic might implicitly assume that there is only one port with a particular attribute. - BREAKING: Redesign the `ir::Rewriter` interface to take all the rewrite maps when constructing the `ir::Rewriter` struct. diff --git a/Cargo.lock b/Cargo.lock index 613ad2c27..3c535cebc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "calyx" -version = "0.6.0" +version = "0.6.1" dependencies = [ "argh", "atty", @@ -196,7 +196,7 @@ dependencies = [ [[package]] name = "calyx-backend" -version = "0.6.0" +version = "0.6.1" dependencies = [ "calyx-frontend", "calyx-ir", @@ -218,7 +218,7 @@ dependencies = [ [[package]] name = "calyx-frontend" -version = "0.6.0" +version = "0.6.1" dependencies = [ "atty", "calyx-utils", @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "calyx-ir" -version = "0.6.0" +version = "0.6.1" dependencies = [ "calyx-frontend", "calyx-utils", @@ -254,7 +254,7 @@ dependencies = [ [[package]] name = "calyx-opt" -version = "0.6.0" +version = "0.6.1" dependencies = [ "calyx-ir", "calyx-utils", @@ -270,11 +270,11 @@ dependencies = [ [[package]] name = "calyx-stdlib" -version = "0.6.0" +version = "0.6.1" [[package]] name = "calyx-utils" -version = "0.6.0" +version = "0.6.1" dependencies = [ "atty", "itertools 0.11.0", diff --git a/Cargo.toml b/Cargo.toml index 3d4328718..70dedd238 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ description = "Compiler Infrastructure for Hardware Accelerator Generation" categories = ["compilers"] homepage = "https://calyxir.org" edition = "2021" -version = "0.6.0" +version = "0.6.1" rust-version = "1.67" [workspace.dependencies] @@ -43,11 +43,11 @@ pest = "2" pest_derive = "2" pest_consume = "1" argh = "0.1" -calyx-utils = { path = "calyx-utils", version = "0.6.0" } -calyx-ir = { path = "calyx-ir", version = "0.6.0" } -calyx-frontend = { path = "calyx-frontend", version = "0.6.0" } -calyx-opt = { path = "calyx-opt", version = "0.6.0" } -calyx-backend = { path = "calyx-backend", version = "0.6.0" } +calyx-utils = { path = "calyx-utils", version = "0.6.1" } +calyx-ir = { path = "calyx-ir", version = "0.6.1" } +calyx-frontend = { path = "calyx-frontend", version = "0.6.1" } +calyx-opt = { path = "calyx-opt", version = "0.6.1" } +calyx-backend = { path = "calyx-backend", version = "0.6.1" } [workspace.dependencies.petgraph] version = "0.6" @@ -81,7 +81,7 @@ default = [] serialize = ["calyx-ir/serialize", "serde/rc", "calyx-backend/sexp"] [build-dependencies] -calyx-stdlib = { path = "calyx-stdlib", version = "0.6.0" } +calyx-stdlib = { path = "calyx-stdlib", version = "0.6.1" } [dependencies] atty.workspace = true diff --git a/calyx-utils/Cargo.toml b/calyx-utils/Cargo.toml index b8e445d91..da438c0d4 100644 --- a/calyx-utils/Cargo.toml +++ b/calyx-utils/Cargo.toml @@ -10,7 +10,6 @@ repository.workspace = true homepage.workspace = true categories.workspace = true readme.workspace = true -serde_json.workspace = true [features] default = [] From 266c1bf4599f6ff09ac9946639714c2faecd8c45 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:44:29 -0400 Subject: [PATCH 080/189] Static Systolic Array (#1740) * added static option for systolic array * flake8 * tests don't duplicate data * reformat test --- .../systolic-lang/gen_array_component.py | 90 ++-- .../systolic-lang/systolic_arg_parser.py | 28 ++ runt.toml | 73 ++- .../systolic/mmult-expect/array-2-3-4.expect | 44 ++ .../systolic/mmult-expect/array-8.expect | 242 ++++++++++ .../array-2-3-4.data} | 0 .../array-2-3-4.data_dynamic.systolic} | 0 .../array-2-3-4.data_static.systolic | 7 + .../array-8.data} | 0 .../array-8.data_dynamic.systolic} | 0 .../mmult-inputs/array-8.data_static.systolic | 7 + .../systolic/output/array-2-3-4.expect | 47 -- .../systolic/output/array-8.expect | 245 ---------- .../systolic/relu-dynamic/array-2-3-4.expect | 47 -- .../systolic/relu-dynamic/array-8.expect | 245 ---------- .../systolic/relu-expect/array-2-3-4.expect | 44 ++ .../systolic/relu-expect/array-8.expect | 242 ++++++++++ .../array-2-3-4.data} | 0 .../array-2-3-4.data_dynamic.systolic} | 0 .../array-2-3-4.data_static.systolic} | 0 .../array-8.data} | 0 .../array-8.data_dynamic.systolic} | 0 .../array-8.data_static.systolic} | 0 .../systolic/relu/array-2-3-4.expect | 47 -- .../systolic/relu/array-2-3-4.systolic.data | 108 ----- .../correctness/systolic/relu/array-8.expect | 245 ---------- .../systolic/relu/array-8.systolic.data | 434 ------------------ 27 files changed, 738 insertions(+), 1457 deletions(-) create mode 100644 tests/correctness/systolic/mmult-expect/array-2-3-4.expect create mode 100644 tests/correctness/systolic/mmult-expect/array-8.expect rename tests/correctness/systolic/{output/array-2-3-4.systolic.data => mmult-inputs/array-2-3-4.data} (100%) rename tests/correctness/systolic/{output/array-2-3-4.systolic => mmult-inputs/array-2-3-4.data_dynamic.systolic} (100%) create mode 100644 tests/correctness/systolic/mmult-inputs/array-2-3-4.data_static.systolic rename tests/correctness/systolic/{output/array-8.systolic.data => mmult-inputs/array-8.data} (100%) rename tests/correctness/systolic/{output/array-8.systolic => mmult-inputs/array-8.data_dynamic.systolic} (100%) create mode 100644 tests/correctness/systolic/mmult-inputs/array-8.data_static.systolic delete mode 100644 tests/correctness/systolic/output/array-2-3-4.expect delete mode 100644 tests/correctness/systolic/output/array-8.expect delete mode 100644 tests/correctness/systolic/relu-dynamic/array-2-3-4.expect delete mode 100644 tests/correctness/systolic/relu-dynamic/array-8.expect create mode 100644 tests/correctness/systolic/relu-expect/array-2-3-4.expect create mode 100644 tests/correctness/systolic/relu-expect/array-8.expect rename tests/correctness/systolic/{relu-dynamic/array-2-3-4.systolic.data => relu-inputs/array-2-3-4.data} (100%) rename tests/correctness/systolic/{relu-dynamic/array-2-3-4.systolic => relu-inputs/array-2-3-4.data_dynamic.systolic} (100%) rename tests/correctness/systolic/{relu/array-2-3-4.systolic => relu-inputs/array-2-3-4.data_static.systolic} (100%) rename tests/correctness/systolic/{relu-dynamic/array-8.systolic.data => relu-inputs/array-8.data} (100%) rename tests/correctness/systolic/{relu-dynamic/array-8.systolic => relu-inputs/array-8.data_dynamic.systolic} (100%) rename tests/correctness/systolic/{relu/array-8.systolic => relu-inputs/array-8.data_static.systolic} (100%) delete mode 100644 tests/correctness/systolic/relu/array-2-3-4.expect delete mode 100644 tests/correctness/systolic/relu/array-2-3-4.systolic.data delete mode 100644 tests/correctness/systolic/relu/array-8.expect delete mode 100644 tests/correctness/systolic/relu/array-8.systolic.data diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index ab2ca39b3..a3f9070f9 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -246,23 +246,28 @@ def get_pe_invoke(r, c, mul_ready): ) -def init_iter_limit(comp: cb.ComponentBuilder, depth_port, partial_iter_limit): +def init_iter_limit( + comp: cb.ComponentBuilder, depth_port, config: SystolicConfiguration +): """ Builds group that instantiates the dynamic/runtime values for the systolic array: its depth and iteration limit/count (since its iteration limit depends on its depth). iteration limit = depth + partial_iter_limit """ - iter_limit = comp.reg("iter_limit", BITWIDTH) - iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") - with comp.static_group("init_iter_limit", 1): - iter_limit_add.left = partial_iter_limit - iter_limit_add.right = depth_port - iter_limit.in_ = iter_limit_add.out - iter_limit.write_en = 1 + # Only need to initalize this group if + if not config.static: + partial_iter_limit = config.top_length + config.left_length + 4 + iter_limit = comp.reg("iter_limit", BITWIDTH) + iter_limit_add = comp.add(BITWIDTH, "iter_limit_add") + with comp.static_group("init_iter_limit", 1): + iter_limit_add.left = partial_iter_limit + iter_limit_add.right = depth_port + iter_limit.in_ = iter_limit_add.out + iter_limit.write_en = 1 -def instantiate_idx_groups(comp: cb.ComponentBuilder): +def instantiate_idx_groups(comp: cb.ComponentBuilder, config: SystolicConfiguration): """ Builds groups that instantiate idx to 0 and increment idx. Also builds groups that set cond_reg to 1 (runs before the while loop) @@ -270,8 +275,6 @@ def instantiate_idx_groups(comp: cb.ComponentBuilder): """ idx = comp.reg("idx", BITWIDTH) add = comp.add(BITWIDTH, "idx_add") - iter_limit = comp.get_cell("iter_limit") - lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") with comp.static_group("init_idx", 1): idx.in_ = 0 @@ -281,9 +284,12 @@ def instantiate_idx_groups(comp: cb.ComponentBuilder): add.right = 1 idx.in_ = add.out idx.write_en = 1 - with comp.continuous: - lt_iter_limit.left = idx.out - lt_iter_limit.right = iter_limit.out + if not config.static: + iter_limit = comp.get_cell("iter_limit") + lt_iter_limit = comp.lt(BITWIDTH, "lt_iter_limit") + with comp.continuous: + lt_iter_limit.left = idx.out + lt_iter_limit.right = iter_limit.out def instantiate_calyx_adds(comp, nec_ranges) -> list: @@ -396,8 +402,22 @@ def gen_schedules( `pe_write_sched` contains when to "write" the PE value into the output ports (e.g., this.r0_valid) """ + + def depth_plus_const(const: int): + """ + Returns depth + const. If config.static, then this is an int. + Otherwise, we need to perform a Calyx addition to figure this out. + """ + if config.static: + # return an int + return config.get_contraction_dimension() + const + else: + # return a CalyxAdd object, whose value is determined after generation + depth_port = comp.this().depth + return CalyxAdd(depth_port, const) + left_length, top_length = config.left_length, config.top_length - depth_port = comp.this().depth + schedules = {} update_sched = np.zeros((left_length, top_length), dtype=object) pe_fill_sched = np.zeros((left_length, top_length), dtype=object) @@ -407,13 +427,13 @@ def gen_schedules( for row in range(0, left_length): for col in range(0, top_length): pos = row + col - update_sched[row][col] = (pos, CalyxAdd(depth_port, pos)) + update_sched[row][col] = (pos, depth_plus_const(pos)) pe_fill_sched[row][col] = (pos + 1, pos + 5) - pe_accum_sched[row][col] = (pos + 5, CalyxAdd(depth_port, pos + 5)) - pe_move_sched[row][col] = (pos + 1, CalyxAdd(depth_port, pos + 1)) + pe_accum_sched[row][col] = (pos + 5, depth_plus_const(pos + 5)) + pe_move_sched[row][col] = (pos + 1, depth_plus_const(pos + 1)) pe_write_sched[row][col] = ( - CalyxAdd(depth_port, pos + 5), - CalyxAdd(depth_port, pos + 6), + depth_plus_const(pos + 5), + depth_plus_const(pos + 6), ) schedules["update_sched"] = update_sched schedules["fill_sched"] = pe_fill_sched @@ -458,15 +478,12 @@ def generate_control( control = [] top_length, left_length = config.top_length, config.left_length - # Initialize all memories. - control.append( - py_ast.StaticParComp( - [ - py_ast.Enable("init_idx"), - py_ast.Enable("init_iter_limit"), - ] - ) - ) + # Initialize the idx and iteration_limit. + # We only need to initialize iteration_limit for dynamic configurations + init_groups = [py_ast.Enable("init_idx")] + if not config.static: + init_groups += [py_ast.Enable("init_iter_limit")] + control.append(py_ast.StaticParComp(init_groups)) # source_pos metadata init init_tag = 0 @@ -532,11 +549,16 @@ def counter(): while_body = py_ast.StaticParComp(while_body_stmts) # build the while loop with condition cond_reg. - cond_reg_port = comp.get_cell("lt_iter_limit").port("out") - while_loop = cb.while_(cond_reg_port, while_body) + if config.static: + while_loop = cb.static_repeat(config.get_iteration_count(), while_body) + else: + cond_reg_port = comp.get_cell("lt_iter_limit").port("out") + while_loop = cb.while_(cond_reg_port, while_body) control.append(while_loop) + if config.static: + return py_ast.StaticSeqComp(stmts=control), source_map return py_ast.SeqComp(stmts=control), source_map @@ -551,9 +573,7 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): computational_unit = prog.component(SYSTOLIC_ARRAY_COMP) depth_port = computational_unit.input("depth", BITWIDTH) # initialize the iteration limit to top_length + left_length + depth + 4 - init_iter_limit( - computational_unit, depth_port, config.top_length + config.left_length + 4 - ) + init_iter_limit(computational_unit, depth_port, config) schedules = gen_schedules(config, computational_unit) nec_ranges = set() @@ -562,7 +582,7 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): instantiate_calyx_adds(computational_unit, nec_ranges) # instantiate groups that handles the idx variables - instantiate_idx_groups(computational_unit) + instantiate_idx_groups(computational_unit, config) list1, list2 = zip(*nec_ranges) nec_ranges_beg = set(list1) nec_ranges_end = set(list2) diff --git a/frontends/systolic-lang/systolic_arg_parser.py b/frontends/systolic-lang/systolic_arg_parser.py index c2461e2f1..0e30d601c 100644 --- a/frontends/systolic-lang/systolic_arg_parser.py +++ b/frontends/systolic-lang/systolic_arg_parser.py @@ -27,6 +27,7 @@ def parse_arguments(self): parser.add_argument("-ll", "--left-length", type=int) parser.add_argument("-ld", "--left-depth", type=int) parser.add_argument("-p", "--post-op", type=str, default=None) + parser.add_argument("-s", "--static", action="store_true") args = parser.parse_args() @@ -37,6 +38,7 @@ def parse_arguments(self): self.left_length = args.left_length self.left_depth = args.left_depth self.post_op = args.post_op + self.static = args.static elif args.file is not None: with open(args.file, "r") as f: spec = json.load(f) @@ -46,6 +48,8 @@ def parse_arguments(self): self.left_depth = spec["left_depth"] # default to not perform leaky_relu self.post_op = spec.get("post_op", None) + # default to non-static (i.e., dynamic contraction dimension) + self.static = spec.get("static", False) else: parser.error( "Need to pass either `FILE` or all of `" @@ -63,3 +67,27 @@ def get_output_dimensions(self): of num_rows x num_cols) """ return (self.left_length, self.top_length) + + def get_contraction_dimension(self): + """ + Returns the contraction dimension + """ + assert ( + self.left_depth == self.top_depth + ), "left_depth and top_depth should be same" + # Could have also returend self.top_depth + return self.left_depth + + def get_iteration_count(self): + """ + Returns the iteration count if self.static + Otherwise throws an error + """ + # Could have also returend self.top_depth + if self.static: + (num_out_rows, num_out_cols) = self.get_output_dimensions() + return self.get_contraction_dimension() + num_out_rows + num_out_cols + 4 + raise Exception( + "Cannot get iteration count for systolic array with dynamic \ + contraction dimension" + ) diff --git a/runt.toml b/runt.toml index 7ba72defc..ca25f45b2 100644 --- a/runt.toml +++ b/runt.toml @@ -263,12 +263,77 @@ fud e --from systolic --to jq \ """ [[tests]] -name = "[frontend] systolic array output correctness" +name = "[frontend] systolic array mmult static correctness" +paths = [ + "tests/correctness/systolic/mmult-inputs/*.data" +] +cmd = """ +fud e --from systolic --to jq \ + --through verilog \ + --through dat \ + -s verilog.data {} \ + -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + {}_static.systolic -q +""" +expect_dir="tests/correctness/systolic/mmult-expect" + +[[tests]] +name = "[frontend] systolic array mmult dynamic correctness" +paths = [ + "tests/correctness/systolic/mmult-inputs/*.data" +] +cmd = """ +fud e --from systolic --to jq \ + --through verilog \ + --through dat \ + -s verilog.data {} \ + -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + {}_dynamic.systolic -q +""" +expect_dir="tests/correctness/systolic/mmult-expect" + +[[tests]] +name = "[frontend] systolic array relu static correctness" +paths = [ + "tests/correctness/systolic/relu-inputs/*.data" +] +cmd = """ +fud e --from systolic --to jq \ + --through verilog \ + --through dat \ + -s verilog.data {} \ + -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + {}_static.systolic -q +""" +expect_dir="tests/correctness/systolic/relu-expect" + +[[tests]] +name = "[frontend] systolic array relu dynamic correctness" +paths = [ + "tests/correctness/systolic/relu-inputs/*.data" +] +cmd = """ +fud e --from systolic --to jq \ + --through verilog \ + --through dat \ + -s verilog.data {} \ + -s calyx.exec './target/debug/calyx' \ + -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + {}_dynamic.systolic -q +""" +expect_dir="tests/correctness/systolic/relu-expect" + +[[tests]] +name = "[frontend] systolic array leaky relu correctness" paths = [ - "tests/correctness/systolic/output/*.systolic", "tests/correctness/systolic/leaky-relu/*.systolic", - "tests/correctness/systolic/relu/*.systolic", - "tests/correctness/systolic/relu-dynamic/*.systolic", ] cmd = """ fud e --from systolic --to dat \ diff --git a/tests/correctness/systolic/mmult-expect/array-2-3-4.expect b/tests/correctness/systolic/mmult-expect/array-2-3-4.expect new file mode 100644 index 000000000..95f7bf1c2 --- /dev/null +++ b/tests/correctness/systolic/mmult-expect/array-2-3-4.expect @@ -0,0 +1,44 @@ +{ + "l0": [ + "-1.5258636474609375", + "1.37969970703125", + "3.964019775390625" + ], + "l1": [ + "-4.90814208984375", + "1.1556854248046875", + "0.088134765625" + ], + "out_mem_0": [ + "17.829559326171875", + "-14.9852752685546875", + "-0.7954864501953125", + "-15.9398193359375" + ], + "out_mem_1": [ + "13.2156982421875", + "-5.021575927734375", + "20.450347900390625", + "-28.945556640625" + ], + "t0": [ + "-3.7752532958984375", + "-4.9618072509765625", + "4.771636962890625" + ], + "t1": [ + "0.8634185791015625", + "-0.4265594482421875", + "-3.29949951171875" + ], + "t2": [ + "-3.8273162841796875", + "1.6114501953125", + "-2.2347869873046875" + ], + "t3": [ + "4.7815093994140625", + "-4.69775390625", + "-0.545501708984375" + ] +} diff --git a/tests/correctness/systolic/mmult-expect/array-8.expect b/tests/correctness/systolic/mmult-expect/array-8.expect new file mode 100644 index 000000000..7730da720 --- /dev/null +++ b/tests/correctness/systolic/mmult-expect/array-8.expect @@ -0,0 +1,242 @@ +{ + "l0": [ + "3.3614654541015625", + "3.7810211181640625", + "-0.6595458984375", + "-2.00933837890625", + "-1.07269287109375", + "-1.7359161376953125", + "-2.23175048828125", + "3.242584228515625" + ], + "l1": [ + "-3.66552734375", + "1.862274169921875", + "-4.5985107421875", + "1.737396240234375", + "1.5211181640625", + "2.481170654296875", + "4.3662261962890625", + "-4.712066650390625" + ], + "l2": [ + "-0.1986236572265625", + "3.6620941162109375", + "-3.45025634765625", + "1.60711669921875", + "-4.554595947265625", + "1.3513336181640625", + "-3.6712799072265625", + "-1.1727142333984375" + ], + "l3": [ + "-4.38427734375", + "3.6719970703125", + "4.325927734375", + "3.3654632568359375", + "-3.818634033203125", + "2.7002716064453125", + "0.1087799072265625", + "-1.949493408203125" + ], + "l4": [ + "3.2269439697265625", + "-2.69219970703125", + "-3.09112548828125", + "-2.3430938720703125", + "2.85382080078125", + "1.8892059326171875", + "-0.634521484375", + "2.381866455078125" + ], + "l5": [ + "0.4718017578125", + "0.8296356201171875", + "1.4714813232421875", + "3.4707183837890625", + "1.939208984375", + "-0.3958892822265625", + "-4.3639373779296875", + "0.86492919921875" + ], + "l6": [ + "3.718292236328125", + "3.1377716064453125", + "1.5491790771484375", + "0.18115234375", + "-1.0565185546875", + "3.2894439697265625", + "-1.6756744384765625", + "-3.32159423828125" + ], + "l7": [ + "0.4992523193359375", + "2.626922607421875", + "3.8421630859375", + "1.6167449951171875", + "0.4383544921875", + "2.735015869140625", + "4.4162750244140625", + "-0.7459259033203125" + ], + "out_mem_0": [ + "-5.020233154296875", + "-17.630950927734375", + "-11.7227935791015625", + "-23.94586181640625", + "-20.5061187744140625", + "-18.622161865234375", + "19.1900177001953125", + "3.65228271484375" + ], + "out_mem_1": [ + "21.97125244140625", + "47.741729736328125", + "5.975616455078125", + "-11.5402069091796875", + "24.655303955078125", + "10.3508758544921875", + "-7.2060546875", + "-35.2868194580078125" + ], + "out_mem_2": [ + "-8.005645751953125", + "0.7089080810546875", + "-29.03765869140625", + "10.0974273681640625", + "-4.3226776123046875", + "-9.4420166015625", + "13.7893524169921875", + "-26.162811279296875" + ], + "out_mem_3": [ + "-36.066314697265625", + "36.6315155029296875", + "-54.45623779296875", + "23.7673797607421875", + "55.8004302978515625", + "-17.01385498046875", + "-30.425079345703125", + "-36.1455841064453125" + ], + "out_mem_4": [ + "11.5760345458984375", + "-43.1614990234375", + "32.2516937255859375", + "0.053802490234375", + "-51.6582183837890625", + "28.627716064453125", + "14.7799530029296875", + "31.807220458984375" + ], + "out_mem_5": [ + "-2.5281982421875", + "19.660186767578125", + "-6.4005126953125", + "-3.746063232421875", + "-2.146728515625", + "7.682373046875", + "-15.31072998046875", + "-21.81353759765625" + ], + "out_mem_6": [ + "-25.15228271484375", + "-9.1671295166015625", + "-17.158233642578125", + "-8.20404052734375", + "-3.4250640869140625", + "-17.01971435546875", + "19.3945770263671875", + "-2.08734130859375" + ], + "out_mem_7": [ + "-16.15911865234375", + "17.7563323974609375", + "-19.4623260498046875", + "-7.7472381591796875", + "41.1004180908203125", + "-1.3080902099609375", + "-21.5960693359375", + "0.1708831787109375" + ], + "t0": [ + "0.6451263427734375", + "-1.3166961669921875", + "-4.3086700439453125", + "2.2447357177734375", + "2.0837249755859375", + "-3.5662689208984375", + "1.9752197265625", + "-0.027435302734375" + ], + "t1": [ + "-4.8111724853515625", + "4.71002197265625", + "0.4647674560546875", + "4.4236602783203125", + "3.9444732666015625", + "-3.5243377685546875", + "1.02667236328125", + "-2.981353759765625" + ], + "t2": [ + "1.919586181640625", + "-4.0710296630859375", + "-2.6121063232421875", + "-0.96337890625", + "3.7477874755859375", + "-1.58636474609375", + "0.8641815185546875", + "-1.0011138916015625" + ], + "t3": [ + "-2.434356689453125", + "-4.969268798828125", + "0.7401275634765625", + "1.02825927734375", + "-4.4361114501953125", + "3.98602294921875", + "-1.322235107421875", + "1.4773101806640625" + ], + "t4": [ + "-2.4996795654296875", + "2.352020263671875", + "3.4475860595703125", + "4.74420166015625", + "-1.9682464599609375", + "-1.969635009765625", + "4.6419525146484375", + "-1.3448333740234375" + ], + "t5": [ + "0.34259033203125", + "-3.76025390625", + "-2.579803466796875", + "3.9580230712890625", + "1.7683563232421875", + "3.40496826171875", + "0.968505859375", + "3.2888946533203125" + ], + "t6": [ + "3.338348388671875", + "0.1703338623046875", + "-2.088653564453125", + "-4.548828125", + "-1.3649749755859375", + "-1.196014404296875", + "-1.540008544921875", + "-3.1365966796875" + ], + "t7": [ + "4.767669677734375", + "-4.9486083984375", + "0.883941650390625", + "-2.3918609619140625", + "-2.087799072265625", + "1.2293701171875", + "2.376678466796875", + "2.2551116943359375" + ] +} diff --git a/tests/correctness/systolic/output/array-2-3-4.systolic.data b/tests/correctness/systolic/mmult-inputs/array-2-3-4.data similarity index 100% rename from tests/correctness/systolic/output/array-2-3-4.systolic.data rename to tests/correctness/systolic/mmult-inputs/array-2-3-4.data diff --git a/tests/correctness/systolic/output/array-2-3-4.systolic b/tests/correctness/systolic/mmult-inputs/array-2-3-4.data_dynamic.systolic similarity index 100% rename from tests/correctness/systolic/output/array-2-3-4.systolic rename to tests/correctness/systolic/mmult-inputs/array-2-3-4.data_dynamic.systolic diff --git a/tests/correctness/systolic/mmult-inputs/array-2-3-4.data_static.systolic b/tests/correctness/systolic/mmult-inputs/array-2-3-4.data_static.systolic new file mode 100644 index 000000000..3a7624bf8 --- /dev/null +++ b/tests/correctness/systolic/mmult-inputs/array-2-3-4.data_static.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 4, + "top_depth": 3, + "left_length": 2, + "left_depth": 3, + "static": true +} \ No newline at end of file diff --git a/tests/correctness/systolic/output/array-8.systolic.data b/tests/correctness/systolic/mmult-inputs/array-8.data similarity index 100% rename from tests/correctness/systolic/output/array-8.systolic.data rename to tests/correctness/systolic/mmult-inputs/array-8.data diff --git a/tests/correctness/systolic/output/array-8.systolic b/tests/correctness/systolic/mmult-inputs/array-8.data_dynamic.systolic similarity index 100% rename from tests/correctness/systolic/output/array-8.systolic rename to tests/correctness/systolic/mmult-inputs/array-8.data_dynamic.systolic diff --git a/tests/correctness/systolic/mmult-inputs/array-8.data_static.systolic b/tests/correctness/systolic/mmult-inputs/array-8.data_static.systolic new file mode 100644 index 000000000..86724f7bb --- /dev/null +++ b/tests/correctness/systolic/mmult-inputs/array-8.data_static.systolic @@ -0,0 +1,7 @@ +{ + "top_length": 8, + "top_depth": 8, + "left_length": 8, + "left_depth": 8, + "static": true +} \ No newline at end of file diff --git a/tests/correctness/systolic/output/array-2-3-4.expect b/tests/correctness/systolic/output/array-2-3-4.expect deleted file mode 100644 index ca505ef07..000000000 --- a/tests/correctness/systolic/output/array-2-3-4.expect +++ /dev/null @@ -1,47 +0,0 @@ -{ - "cycles": 15, - "memories": { - "l0": [ - "-1.5258636474609375", - "1.37969970703125", - "3.964019775390625" - ], - "l1": [ - "-4.90814208984375", - "1.1556854248046875", - "0.088134765625" - ], - "out_mem_0": [ - "17.829559326171875", - "-14.9852752685546875", - "-0.7954864501953125", - "-15.9398193359375" - ], - "out_mem_1": [ - "13.2156982421875", - "-5.021575927734375", - "20.450347900390625", - "-28.945556640625" - ], - "t0": [ - "-3.7752532958984375", - "-4.9618072509765625", - "4.771636962890625" - ], - "t1": [ - "0.8634185791015625", - "-0.4265594482421875", - "-3.29949951171875" - ], - "t2": [ - "-3.8273162841796875", - "1.6114501953125", - "-2.2347869873046875" - ], - "t3": [ - "4.7815093994140625", - "-4.69775390625", - "-0.545501708984375" - ] - } -} diff --git a/tests/correctness/systolic/output/array-8.expect b/tests/correctness/systolic/output/array-8.expect deleted file mode 100644 index 24be67b10..000000000 --- a/tests/correctness/systolic/output/array-8.expect +++ /dev/null @@ -1,245 +0,0 @@ -{ - "cycles": 30, - "memories": { - "l0": [ - "3.3614654541015625", - "3.7810211181640625", - "-0.6595458984375", - "-2.00933837890625", - "-1.07269287109375", - "-1.7359161376953125", - "-2.23175048828125", - "3.242584228515625" - ], - "l1": [ - "-3.66552734375", - "1.862274169921875", - "-4.5985107421875", - "1.737396240234375", - "1.5211181640625", - "2.481170654296875", - "4.3662261962890625", - "-4.712066650390625" - ], - "l2": [ - "-0.1986236572265625", - "3.6620941162109375", - "-3.45025634765625", - "1.60711669921875", - "-4.554595947265625", - "1.3513336181640625", - "-3.6712799072265625", - "-1.1727142333984375" - ], - "l3": [ - "-4.38427734375", - "3.6719970703125", - "4.325927734375", - "3.3654632568359375", - "-3.818634033203125", - "2.7002716064453125", - "0.1087799072265625", - "-1.949493408203125" - ], - "l4": [ - "3.2269439697265625", - "-2.69219970703125", - "-3.09112548828125", - "-2.3430938720703125", - "2.85382080078125", - "1.8892059326171875", - "-0.634521484375", - "2.381866455078125" - ], - "l5": [ - "0.4718017578125", - "0.8296356201171875", - "1.4714813232421875", - "3.4707183837890625", - "1.939208984375", - "-0.3958892822265625", - "-4.3639373779296875", - "0.86492919921875" - ], - "l6": [ - "3.718292236328125", - "3.1377716064453125", - "1.5491790771484375", - "0.18115234375", - "-1.0565185546875", - "3.2894439697265625", - "-1.6756744384765625", - "-3.32159423828125" - ], - "l7": [ - "0.4992523193359375", - "2.626922607421875", - "3.8421630859375", - "1.6167449951171875", - "0.4383544921875", - "2.735015869140625", - "4.4162750244140625", - "-0.7459259033203125" - ], - "out_mem_0": [ - "-5.020233154296875", - "-17.630950927734375", - "-11.7227935791015625", - "-23.94586181640625", - "-20.5061187744140625", - "-18.622161865234375", - "19.1900177001953125", - "3.65228271484375" - ], - "out_mem_1": [ - "21.97125244140625", - "47.741729736328125", - "5.975616455078125", - "-11.5402069091796875", - "24.655303955078125", - "10.3508758544921875", - "-7.2060546875", - "-35.2868194580078125" - ], - "out_mem_2": [ - "-8.005645751953125", - "0.7089080810546875", - "-29.03765869140625", - "10.0974273681640625", - "-4.3226776123046875", - "-9.4420166015625", - "13.7893524169921875", - "-26.162811279296875" - ], - "out_mem_3": [ - "-36.066314697265625", - "36.6315155029296875", - "-54.45623779296875", - "23.7673797607421875", - "55.8004302978515625", - "-17.01385498046875", - "-30.425079345703125", - "-36.1455841064453125" - ], - "out_mem_4": [ - "11.5760345458984375", - "-43.1614990234375", - "32.2516937255859375", - "0.053802490234375", - "-51.6582183837890625", - "28.627716064453125", - "14.7799530029296875", - "31.807220458984375" - ], - "out_mem_5": [ - "-2.5281982421875", - "19.660186767578125", - "-6.4005126953125", - "-3.746063232421875", - "-2.146728515625", - "7.682373046875", - "-15.31072998046875", - "-21.81353759765625" - ], - "out_mem_6": [ - "-25.15228271484375", - "-9.1671295166015625", - "-17.158233642578125", - "-8.20404052734375", - "-3.4250640869140625", - "-17.01971435546875", - "19.3945770263671875", - "-2.08734130859375" - ], - "out_mem_7": [ - "-16.15911865234375", - "17.7563323974609375", - "-19.4623260498046875", - "-7.7472381591796875", - "41.1004180908203125", - "-1.3080902099609375", - "-21.5960693359375", - "0.1708831787109375" - ], - "t0": [ - "0.6451263427734375", - "-1.3166961669921875", - "-4.3086700439453125", - "2.2447357177734375", - "2.0837249755859375", - "-3.5662689208984375", - "1.9752197265625", - "-0.027435302734375" - ], - "t1": [ - "-4.8111724853515625", - "4.71002197265625", - "0.4647674560546875", - "4.4236602783203125", - "3.9444732666015625", - "-3.5243377685546875", - "1.02667236328125", - "-2.981353759765625" - ], - "t2": [ - "1.919586181640625", - "-4.0710296630859375", - "-2.6121063232421875", - "-0.96337890625", - "3.7477874755859375", - "-1.58636474609375", - "0.8641815185546875", - "-1.0011138916015625" - ], - "t3": [ - "-2.434356689453125", - "-4.969268798828125", - "0.7401275634765625", - "1.02825927734375", - "-4.4361114501953125", - "3.98602294921875", - "-1.322235107421875", - "1.4773101806640625" - ], - "t4": [ - "-2.4996795654296875", - "2.352020263671875", - "3.4475860595703125", - "4.74420166015625", - "-1.9682464599609375", - "-1.969635009765625", - "4.6419525146484375", - "-1.3448333740234375" - ], - "t5": [ - "0.34259033203125", - "-3.76025390625", - "-2.579803466796875", - "3.9580230712890625", - "1.7683563232421875", - "3.40496826171875", - "0.968505859375", - "3.2888946533203125" - ], - "t6": [ - "3.338348388671875", - "0.1703338623046875", - "-2.088653564453125", - "-4.548828125", - "-1.3649749755859375", - "-1.196014404296875", - "-1.540008544921875", - "-3.1365966796875" - ], - "t7": [ - "4.767669677734375", - "-4.9486083984375", - "0.883941650390625", - "-2.3918609619140625", - "-2.087799072265625", - "1.2293701171875", - "2.376678466796875", - "2.2551116943359375" - ] - } -} diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect b/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect deleted file mode 100644 index f642045e3..000000000 --- a/tests/correctness/systolic/relu-dynamic/array-2-3-4.expect +++ /dev/null @@ -1,47 +0,0 @@ -{ - "cycles": 19, - "memories": { - "l0": [ - "3.349822998046875", - "3.6539764404296875", - "0.0511016845703125" - ], - "l1": [ - "-0.1660003662109375", - "3.43817138671875", - "0.1073760986328125" - ], - "out_mem_0": [ - "12.569793701171875", - "0", - "1.2611541748046875", - "8.012969970703125" - ], - "out_mem_1": [ - "0", - "0", - "0.964019775390625", - "1.9193878173828125" - ], - "t0": [ - "4.0580596923828125", - "-0.2537078857421875", - "-1.896697998046875" - ], - "t1": [ - "-1.2882843017578125", - "-3.0372772216796875", - "3.0884552001953125" - ], - "t2": [ - "0.073028564453125", - "0.2735595703125", - "0.3317718505859375" - ], - "t3": [ - "1.702178955078125", - "0.6259765625", - "0.4635009765625" - ] - } -} diff --git a/tests/correctness/systolic/relu-dynamic/array-8.expect b/tests/correctness/systolic/relu-dynamic/array-8.expect deleted file mode 100644 index d8627be63..000000000 --- a/tests/correctness/systolic/relu-dynamic/array-8.expect +++ /dev/null @@ -1,245 +0,0 @@ -{ - "cycles": 38, - "memories": { - "l0": [ - "-1.49566650390625", - "-0.9142608642578125", - "-2.6135711669921875", - "1.4980010986328125", - "-3.4720001220703125", - "3.4763031005859375", - "-0.016571044921875", - "-2.989044189453125" - ], - "l1": [ - "-1.33184814453125", - "2.9468841552734375", - "1.7263946533203125", - "-1.7017974853515625", - "-1.13458251953125", - "-4.711273193359375", - "-0.290771484375", - "-4.2563934326171875" - ], - "l2": [ - "1.1874237060546875", - "-3.408599853515625", - "-1.801544189453125", - "1.1929931640625", - "-1.8954010009765625", - "-3.1168060302734375", - "0.3030242919921875", - "-1.095611572265625" - ], - "l3": [ - "-2.2605743408203125", - "-4.778472900390625", - "4.631988525390625", - "-2.366485595703125", - "2.2865142822265625", - "-1.9458465576171875", - "2.51043701171875", - "-0.420989990234375" - ], - "l4": [ - "2.081451416015625", - "-2.0117034912109375", - "-3.0953369140625", - "0.8167266845703125", - "-0.9581451416015625", - "-2.253204345703125", - "3.2512359619140625", - "0.8149871826171875" - ], - "l5": [ - "4.9659271240234375", - "-4.0330352783203125", - "0.3494110107421875", - "0.9843292236328125", - "-1.1136932373046875", - "-0.161285400390625", - "3.5453338623046875", - "-4.283843994140625" - ], - "l6": [ - "3.9283294677734375", - "1.32122802734375", - "-0.6650543212890625", - "4.8896026611328125", - "2.450042724609375", - "2.7947235107421875", - "1.7928314208984375", - "-1.518035888671875" - ], - "l7": [ - "-4.6738739013671875", - "-4.4643096923828125", - "0.1487274169921875", - "-3.4300994873046875", - "2.415863037109375", - "-3.8175506591796875", - "3.8909149169921875", - "-0.361236572265625" - ], - "out_mem_0": [ - "0", - "0", - "0", - "23.335174560546875", - "5.11322021484375", - "0", - "0.1280364990234375", - "0" - ], - "out_mem_1": [ - "0", - "1.920379638671875", - "0", - "45.25958251953125", - "32.78094482421875", - "0", - "0", - "33.4017333984375" - ], - "out_mem_2": [ - "0", - "0", - "0", - "29.5540618896484375", - "23.58514404296875", - "0", - "0.9548797607421875", - "0" - ], - "out_mem_3": [ - "21.81707763671875", - "0", - "0", - "5.942596435546875", - "19.353363037109375", - "0", - "6.6043853759765625", - "21.3936614990234375" - ], - "out_mem_4": [ - "0", - "1.3929443359375", - "0", - "16.4472808837890625", - "16.946075439453125", - "0", - "21.7616119384765625", - "0" - ], - "out_mem_5": [ - "29.9978179931640625", - "0", - "0", - "18.637359619140625", - "42.1724090576171875", - "0", - "6.4488067626953125", - "4.316436767578125" - ], - "out_mem_6": [ - "34.8578338623046875", - "18.028961181640625", - "23.9514617919921875", - "0", - "16.2915496826171875", - "2.3678436279296875", - "15.6302032470703125", - "0" - ], - "out_mem_7": [ - "0", - "0", - "0", - "27.7047271728515625", - "18.578521728515625", - "0", - "14.9741973876953125", - "10.2684478759765625" - ], - "t0": [ - "4.9021759033203125", - "-2.5044708251953125", - "4.5919189453125", - "0.601043701171875", - "2.68255615234375", - "4.476806640625", - "1.82684326171875", - "2.19659423828125" - ], - "t1": [ - "3.4096832275390625", - "4.9857330322265625", - "-3.820037841796875", - "-0.70623779296875", - "4.9615936279296875", - "-2.083038330078125", - "-2.567901611328125", - "1.8252105712890625" - ], - "t2": [ - "-0.772216796875", - "4.754638671875", - "-0.936676025390625", - "2.935699462890625", - "2.22613525390625", - "1.5690155029296875", - "-1.6681365966796875", - "0.73956298828125" - ], - "t3": [ - "-3.9584503173828125", - "0.05987548828125", - "-0.902618408203125", - "3.788360595703125", - "-3.4463958740234375", - "-4.98907470703125", - "2.5916900634765625", - "-4.97015380859375" - ], - "t4": [ - "0.08782958984375", - "-0.653778076171875", - "1.889984130859375", - "3.657745361328125", - "-1.1245880126953125", - "-3.8535003662109375", - "3.775634765625", - "-4.5704193115234375" - ], - "t5": [ - "-0.3739166259765625", - "1.5081634521484375", - "0.3743133544921875", - "3.133514404296875", - "-1.101104736328125", - "0.3949737548828125", - "-3.9834136962890625", - "2.9597930908203125" - ], - "t6": [ - "1.1507720947265625", - "-4.7238922119140625", - "-3.618682861328125", - "-0.121856689453125", - "3.2436065673828125", - "3.9204864501953125", - "2.1115570068359375", - "4.709442138671875" - ], - "t7": [ - "0.51519775390625", - "2.701629638671875", - "4.22308349609375", - "-3.078399658203125", - "0.3193511962890625", - "-1.3680877685546875", - "1.766815185546875", - "-1.8860321044921875" - ] - } -} diff --git a/tests/correctness/systolic/relu-expect/array-2-3-4.expect b/tests/correctness/systolic/relu-expect/array-2-3-4.expect new file mode 100644 index 000000000..b2f7962df --- /dev/null +++ b/tests/correctness/systolic/relu-expect/array-2-3-4.expect @@ -0,0 +1,44 @@ +{ + "l0": [ + "3.349822998046875", + "3.6539764404296875", + "0.0511016845703125" + ], + "l1": [ + "-0.1660003662109375", + "3.43817138671875", + "0.1073760986328125" + ], + "out_mem_0": [ + "12.569793701171875", + "0", + "1.2611541748046875", + "8.012969970703125" + ], + "out_mem_1": [ + "0", + "0", + "0.964019775390625", + "1.9193878173828125" + ], + "t0": [ + "4.0580596923828125", + "-0.2537078857421875", + "-1.896697998046875" + ], + "t1": [ + "-1.2882843017578125", + "-3.0372772216796875", + "3.0884552001953125" + ], + "t2": [ + "0.073028564453125", + "0.2735595703125", + "0.3317718505859375" + ], + "t3": [ + "1.702178955078125", + "0.6259765625", + "0.4635009765625" + ] +} diff --git a/tests/correctness/systolic/relu-expect/array-8.expect b/tests/correctness/systolic/relu-expect/array-8.expect new file mode 100644 index 000000000..d5f45df77 --- /dev/null +++ b/tests/correctness/systolic/relu-expect/array-8.expect @@ -0,0 +1,242 @@ +{ + "l0": [ + "-1.49566650390625", + "-0.9142608642578125", + "-2.6135711669921875", + "1.4980010986328125", + "-3.4720001220703125", + "3.4763031005859375", + "-0.016571044921875", + "-2.989044189453125" + ], + "l1": [ + "-1.33184814453125", + "2.9468841552734375", + "1.7263946533203125", + "-1.7017974853515625", + "-1.13458251953125", + "-4.711273193359375", + "-0.290771484375", + "-4.2563934326171875" + ], + "l2": [ + "1.1874237060546875", + "-3.408599853515625", + "-1.801544189453125", + "1.1929931640625", + "-1.8954010009765625", + "-3.1168060302734375", + "0.3030242919921875", + "-1.095611572265625" + ], + "l3": [ + "-2.2605743408203125", + "-4.778472900390625", + "4.631988525390625", + "-2.366485595703125", + "2.2865142822265625", + "-1.9458465576171875", + "2.51043701171875", + "-0.420989990234375" + ], + "l4": [ + "2.081451416015625", + "-2.0117034912109375", + "-3.0953369140625", + "0.8167266845703125", + "-0.9581451416015625", + "-2.253204345703125", + "3.2512359619140625", + "0.8149871826171875" + ], + "l5": [ + "4.9659271240234375", + "-4.0330352783203125", + "0.3494110107421875", + "0.9843292236328125", + "-1.1136932373046875", + "-0.161285400390625", + "3.5453338623046875", + "-4.283843994140625" + ], + "l6": [ + "3.9283294677734375", + "1.32122802734375", + "-0.6650543212890625", + "4.8896026611328125", + "2.450042724609375", + "2.7947235107421875", + "1.7928314208984375", + "-1.518035888671875" + ], + "l7": [ + "-4.6738739013671875", + "-4.4643096923828125", + "0.1487274169921875", + "-3.4300994873046875", + "2.415863037109375", + "-3.8175506591796875", + "3.8909149169921875", + "-0.361236572265625" + ], + "out_mem_0": [ + "0", + "0", + "0", + "23.335174560546875", + "5.11322021484375", + "0", + "0.1280364990234375", + "0" + ], + "out_mem_1": [ + "0", + "1.920379638671875", + "0", + "45.25958251953125", + "32.78094482421875", + "0", + "0", + "33.4017333984375" + ], + "out_mem_2": [ + "0", + "0", + "0", + "29.5540618896484375", + "23.58514404296875", + "0", + "0.9548797607421875", + "0" + ], + "out_mem_3": [ + "21.81707763671875", + "0", + "0", + "5.942596435546875", + "19.353363037109375", + "0", + "6.6043853759765625", + "21.3936614990234375" + ], + "out_mem_4": [ + "0", + "1.3929443359375", + "0", + "16.4472808837890625", + "16.946075439453125", + "0", + "21.7616119384765625", + "0" + ], + "out_mem_5": [ + "29.9978179931640625", + "0", + "0", + "18.637359619140625", + "42.1724090576171875", + "0", + "6.4488067626953125", + "4.316436767578125" + ], + "out_mem_6": [ + "34.8578338623046875", + "18.028961181640625", + "23.9514617919921875", + "0", + "16.2915496826171875", + "2.3678436279296875", + "15.6302032470703125", + "0" + ], + "out_mem_7": [ + "0", + "0", + "0", + "27.7047271728515625", + "18.578521728515625", + "0", + "14.9741973876953125", + "10.2684478759765625" + ], + "t0": [ + "4.9021759033203125", + "-2.5044708251953125", + "4.5919189453125", + "0.601043701171875", + "2.68255615234375", + "4.476806640625", + "1.82684326171875", + "2.19659423828125" + ], + "t1": [ + "3.4096832275390625", + "4.9857330322265625", + "-3.820037841796875", + "-0.70623779296875", + "4.9615936279296875", + "-2.083038330078125", + "-2.567901611328125", + "1.8252105712890625" + ], + "t2": [ + "-0.772216796875", + "4.754638671875", + "-0.936676025390625", + "2.935699462890625", + "2.22613525390625", + "1.5690155029296875", + "-1.6681365966796875", + "0.73956298828125" + ], + "t3": [ + "-3.9584503173828125", + "0.05987548828125", + "-0.902618408203125", + "3.788360595703125", + "-3.4463958740234375", + "-4.98907470703125", + "2.5916900634765625", + "-4.97015380859375" + ], + "t4": [ + "0.08782958984375", + "-0.653778076171875", + "1.889984130859375", + "3.657745361328125", + "-1.1245880126953125", + "-3.8535003662109375", + "3.775634765625", + "-4.5704193115234375" + ], + "t5": [ + "-0.3739166259765625", + "1.5081634521484375", + "0.3743133544921875", + "3.133514404296875", + "-1.101104736328125", + "0.3949737548828125", + "-3.9834136962890625", + "2.9597930908203125" + ], + "t6": [ + "1.1507720947265625", + "-4.7238922119140625", + "-3.618682861328125", + "-0.121856689453125", + "3.2436065673828125", + "3.9204864501953125", + "2.1115570068359375", + "4.709442138671875" + ], + "t7": [ + "0.51519775390625", + "2.701629638671875", + "4.22308349609375", + "-3.078399658203125", + "0.3193511962890625", + "-1.3680877685546875", + "1.766815185546875", + "-1.8860321044921875" + ] +} diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data b/tests/correctness/systolic/relu-inputs/array-2-3-4.data similarity index 100% rename from tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic.data rename to tests/correctness/systolic/relu-inputs/array-2-3-4.data diff --git a/tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic b/tests/correctness/systolic/relu-inputs/array-2-3-4.data_dynamic.systolic similarity index 100% rename from tests/correctness/systolic/relu-dynamic/array-2-3-4.systolic rename to tests/correctness/systolic/relu-inputs/array-2-3-4.data_dynamic.systolic diff --git a/tests/correctness/systolic/relu/array-2-3-4.systolic b/tests/correctness/systolic/relu-inputs/array-2-3-4.data_static.systolic similarity index 100% rename from tests/correctness/systolic/relu/array-2-3-4.systolic rename to tests/correctness/systolic/relu-inputs/array-2-3-4.data_static.systolic diff --git a/tests/correctness/systolic/relu-dynamic/array-8.systolic.data b/tests/correctness/systolic/relu-inputs/array-8.data similarity index 100% rename from tests/correctness/systolic/relu-dynamic/array-8.systolic.data rename to tests/correctness/systolic/relu-inputs/array-8.data diff --git a/tests/correctness/systolic/relu-dynamic/array-8.systolic b/tests/correctness/systolic/relu-inputs/array-8.data_dynamic.systolic similarity index 100% rename from tests/correctness/systolic/relu-dynamic/array-8.systolic rename to tests/correctness/systolic/relu-inputs/array-8.data_dynamic.systolic diff --git a/tests/correctness/systolic/relu/array-8.systolic b/tests/correctness/systolic/relu-inputs/array-8.data_static.systolic similarity index 100% rename from tests/correctness/systolic/relu/array-8.systolic rename to tests/correctness/systolic/relu-inputs/array-8.data_static.systolic diff --git a/tests/correctness/systolic/relu/array-2-3-4.expect b/tests/correctness/systolic/relu/array-2-3-4.expect deleted file mode 100644 index 63064e7a8..000000000 --- a/tests/correctness/systolic/relu/array-2-3-4.expect +++ /dev/null @@ -1,47 +0,0 @@ -{ - "cycles": 15, - "memories": { - "l0": [ - "3.349822998046875", - "3.6539764404296875", - "0.0511016845703125" - ], - "l1": [ - "-0.1660003662109375", - "3.43817138671875", - "0.1073760986328125" - ], - "out_mem_0": [ - "12.569793701171875", - "0", - "1.2611541748046875", - "8.012969970703125" - ], - "out_mem_1": [ - "0", - "0", - "0.964019775390625", - "1.9193878173828125" - ], - "t0": [ - "4.0580596923828125", - "-0.2537078857421875", - "-1.896697998046875" - ], - "t1": [ - "-1.2882843017578125", - "-3.0372772216796875", - "3.0884552001953125" - ], - "t2": [ - "0.073028564453125", - "0.2735595703125", - "0.3317718505859375" - ], - "t3": [ - "1.702178955078125", - "0.6259765625", - "0.4635009765625" - ] - } -} diff --git a/tests/correctness/systolic/relu/array-2-3-4.systolic.data b/tests/correctness/systolic/relu/array-2-3-4.systolic.data deleted file mode 100644 index 823b904b4..000000000 --- a/tests/correctness/systolic/relu/array-2-3-4.systolic.data +++ /dev/null @@ -1,108 +0,0 @@ -{ - "l0": { - "data": [ - 3.349827766418457, - 3.6539793014526367, - 0.05110502243041992 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l1": { - "data": [ - -0.16600513458251953, - 3.4381656646728516, - 0.1073751449584961 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_0": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_1": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t0": { - "data": [ - 4.058065414428711, - -0.2537107467651367, - -1.8967020511627197 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t1": { - "data": [ - -1.2882888317108154, - -3.0372798442840576, - 3.0884532928466797 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t2": { - "data": [ - 0.07303619384765625, - 0.27355289459228516, - 0.3317680358886719 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t3": { - "data": [ - 1.702174186706543, - 0.6259689331054688, - 0.4635009765625 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - } -} \ No newline at end of file diff --git a/tests/correctness/systolic/relu/array-8.expect b/tests/correctness/systolic/relu/array-8.expect deleted file mode 100644 index c7ae4dd1f..000000000 --- a/tests/correctness/systolic/relu/array-8.expect +++ /dev/null @@ -1,245 +0,0 @@ -{ - "cycles": 30, - "memories": { - "l0": [ - "-1.49566650390625", - "-0.9142608642578125", - "-2.6135711669921875", - "1.4980010986328125", - "-3.4720001220703125", - "3.4763031005859375", - "-0.016571044921875", - "-2.989044189453125" - ], - "l1": [ - "-1.33184814453125", - "2.9468841552734375", - "1.7263946533203125", - "-1.7017974853515625", - "-1.13458251953125", - "-4.711273193359375", - "-0.290771484375", - "-4.2563934326171875" - ], - "l2": [ - "1.1874237060546875", - "-3.408599853515625", - "-1.801544189453125", - "1.1929931640625", - "-1.8954010009765625", - "-3.1168060302734375", - "0.3030242919921875", - "-1.095611572265625" - ], - "l3": [ - "-2.2605743408203125", - "-4.778472900390625", - "4.631988525390625", - "-2.366485595703125", - "2.2865142822265625", - "-1.9458465576171875", - "2.51043701171875", - "-0.420989990234375" - ], - "l4": [ - "2.081451416015625", - "-2.0117034912109375", - "-3.0953369140625", - "0.8167266845703125", - "-0.9581451416015625", - "-2.253204345703125", - "3.2512359619140625", - "0.8149871826171875" - ], - "l5": [ - "4.9659271240234375", - "-4.0330352783203125", - "0.3494110107421875", - "0.9843292236328125", - "-1.1136932373046875", - "-0.161285400390625", - "3.5453338623046875", - "-4.283843994140625" - ], - "l6": [ - "3.9283294677734375", - "1.32122802734375", - "-0.6650543212890625", - "4.8896026611328125", - "2.450042724609375", - "2.7947235107421875", - "1.7928314208984375", - "-1.518035888671875" - ], - "l7": [ - "-4.6738739013671875", - "-4.4643096923828125", - "0.1487274169921875", - "-3.4300994873046875", - "2.415863037109375", - "-3.8175506591796875", - "3.8909149169921875", - "-0.361236572265625" - ], - "out_mem_0": [ - "0", - "0", - "0", - "23.335174560546875", - "5.11322021484375", - "0", - "0.1280364990234375", - "0" - ], - "out_mem_1": [ - "0", - "1.920379638671875", - "0", - "45.25958251953125", - "32.78094482421875", - "0", - "0", - "33.4017333984375" - ], - "out_mem_2": [ - "0", - "0", - "0", - "29.5540618896484375", - "23.58514404296875", - "0", - "0.9548797607421875", - "0" - ], - "out_mem_3": [ - "21.81707763671875", - "0", - "0", - "5.942596435546875", - "19.353363037109375", - "0", - "6.6043853759765625", - "21.3936614990234375" - ], - "out_mem_4": [ - "0", - "1.3929443359375", - "0", - "16.4472808837890625", - "16.946075439453125", - "0", - "21.7616119384765625", - "0" - ], - "out_mem_5": [ - "29.9978179931640625", - "0", - "0", - "18.637359619140625", - "42.1724090576171875", - "0", - "6.4488067626953125", - "4.316436767578125" - ], - "out_mem_6": [ - "34.8578338623046875", - "18.028961181640625", - "23.9514617919921875", - "0", - "16.2915496826171875", - "2.3678436279296875", - "15.6302032470703125", - "0" - ], - "out_mem_7": [ - "0", - "0", - "0", - "27.7047271728515625", - "18.578521728515625", - "0", - "14.9741973876953125", - "10.2684478759765625" - ], - "t0": [ - "4.9021759033203125", - "-2.5044708251953125", - "4.5919189453125", - "0.601043701171875", - "2.68255615234375", - "4.476806640625", - "1.82684326171875", - "2.19659423828125" - ], - "t1": [ - "3.4096832275390625", - "4.9857330322265625", - "-3.820037841796875", - "-0.70623779296875", - "4.9615936279296875", - "-2.083038330078125", - "-2.567901611328125", - "1.8252105712890625" - ], - "t2": [ - "-0.772216796875", - "4.754638671875", - "-0.936676025390625", - "2.935699462890625", - "2.22613525390625", - "1.5690155029296875", - "-1.6681365966796875", - "0.73956298828125" - ], - "t3": [ - "-3.9584503173828125", - "0.05987548828125", - "-0.902618408203125", - "3.788360595703125", - "-3.4463958740234375", - "-4.98907470703125", - "2.5916900634765625", - "-4.97015380859375" - ], - "t4": [ - "0.08782958984375", - "-0.653778076171875", - "1.889984130859375", - "3.657745361328125", - "-1.1245880126953125", - "-3.8535003662109375", - "3.775634765625", - "-4.5704193115234375" - ], - "t5": [ - "-0.3739166259765625", - "1.5081634521484375", - "0.3743133544921875", - "3.133514404296875", - "-1.101104736328125", - "0.3949737548828125", - "-3.9834136962890625", - "2.9597930908203125" - ], - "t6": [ - "1.1507720947265625", - "-4.7238922119140625", - "-3.618682861328125", - "-0.121856689453125", - "3.2436065673828125", - "3.9204864501953125", - "2.1115570068359375", - "4.709442138671875" - ], - "t7": [ - "0.51519775390625", - "2.701629638671875", - "4.22308349609375", - "-3.078399658203125", - "0.3193511962890625", - "-1.3680877685546875", - "1.766815185546875", - "-1.8860321044921875" - ] - } -} diff --git a/tests/correctness/systolic/relu/array-8.systolic.data b/tests/correctness/systolic/relu/array-8.systolic.data deleted file mode 100644 index 34b867727..000000000 --- a/tests/correctness/systolic/relu/array-8.systolic.data +++ /dev/null @@ -1,434 +0,0 @@ -{ - "l0": { - "data": [ - -1.4956629276275635, - -0.9142565727233887, - -2.6135730743408203, - 1.4980006217956543, - -3.472006320953369, - 3.476308822631836, - -0.016571044921875, - -2.989037036895752 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l1": { - "data": [ - -1.3318490982055664, - 2.9468870162963867, - 1.726388931274414, - -1.7017900943756104, - -1.1345791816711426, - -4.711271286010742, - -0.2907705307006836, - -4.256398677825928 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l2": { - "data": [ - 1.187424659729004, - -3.408595323562622, - -1.801539659500122, - 1.1929893493652344, - -1.8953990936279297, - -3.116804361343384, - 0.3030214309692383, - -1.0956144332885742 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l3": { - "data": [ - -2.2605812549591064, - -4.778478145599365, - 4.631991386413574, - -2.3664891719818115, - 2.2865095138549805, - -1.9458460807800293, - 2.51043701171875, - -0.42099571228027344 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l4": { - "data": [ - 2.0814504623413086, - -2.011702060699463, - -3.095329999923706, - 0.8167314529418945, - -0.9581432342529297, - -2.253211736679077, - 3.2512292861938477, - 0.8149852752685547 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l5": { - "data": [ - 4.965932846069336, - -4.033029079437256, - 0.34941768646240234, - 0.9843292236328125, - -1.1136901378631592, - -0.16128921508789062, - 3.5453338623046875, - -4.283846855163574 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l6": { - "data": [ - 3.9283323287963867, - 1.3212251663208008, - -0.6650471687316895, - 4.8896074295043945, - 2.45003604888916, - 2.7947306632995605, - 1.7928242683410645, - -1.5180349349975586 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "l7": { - "data": [ - -4.673877716064453, - -4.464309215545654, - 0.14873123168945312, - -3.4300994873046875, - 2.415858268737793, - -3.8175439834594727, - 3.890915870666504, - -0.36124229431152344 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_0": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_1": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_2": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_3": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_4": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_5": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_6": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "out_mem_7": { - "data": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t0": { - "data": [ - 4.902173042297363, - -2.5044643878936768, - 4.591917037963867, - 0.601048469543457, - 2.6825523376464844, - 4.476808547973633, - 1.8268499374389648, - 2.1965885162353516 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t1": { - "data": [ - 3.4096832275390625, - 4.9857330322265625, - -3.8200438022613525, - -0.706233024597168, - 4.961596488952637, - -2.0830368995666504, - -2.5678956508636475, - 1.825209617614746 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t2": { - "data": [ - -0.7722148895263672, - 4.754638671875, - -0.9366703033447266, - 2.935696601867676, - 2.2261343002319336, - 1.569009780883789, - -1.6681408882141113, - 0.7395687103271484 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t3": { - "data": [ - -3.9584505558013916, - 0.05988121032714844, - -0.9026155471801758, - 3.7883644104003906, - -3.446394205093384, - -4.989075660705566, - 2.5916852951049805, - -4.970152378082275 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t4": { - "data": [ - 0.08782482147216797, - -0.6537842750549316, - 1.8899774551391602, - 3.6577377319335938, - -1.1245930194854736, - -3.853501081466675, - 3.7756290435791016, - -4.57042121887207 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t5": { - "data": [ - -0.3739175796508789, - 1.5081634521484375, - 0.3743171691894531, - 3.1335086822509766, - -1.1011040210723877, - 0.39496898651123047, - -3.983415365219116, - 2.9597973823547363 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t6": { - "data": [ - 1.1507759094238281, - -4.7238874435424805, - -3.618685007095337, - -0.12185335159301758, - 3.2436037063598633, - 3.9204845428466797, - 2.1115517616271973, - 4.709440231323242 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - }, - "t7": { - "data": [ - 0.5151915550231934, - 2.7016282081604004, - 4.223084449768066, - -3.078404664993286, - 0.31935787200927734, - -1.3680875301361084, - 1.7668190002441406, - -1.8860268592834473 - ], - "format": { - "frac_width": 16, - "is_signed": true, - "numeric_type": "fixed_point", - "width": 32 - } - } -} \ No newline at end of file From 77adcc21da0eaca149c128158b43946e7a68c5c6 Mon Sep 17 00:00:00 2001 From: Matt Hofmann <47065711+matth2k@users.noreply.github.com> Date: Fri, 20 Oct 2023 15:27:15 -0400 Subject: [PATCH 081/189] Add width parameter to `pipelined_mult` primitive (#1748) * add newest iteration of mul primitives * revert old primitive changes * remove std_mult_pipe in favor of std_mult_seq * Revert mult_pipe name change for now * Update binary_operators.sv * add pipelined_mult parameter to regression tests --------- Co-authored-by: Andrew Butt --- primitives/binary_operators.futil | 1 - primitives/binary_operators.sv | 2 +- primitives/pipelined.futil | 11 +++++----- primitives/pipelined.sv | 22 +++++++++---------- .../static-mult-dot-product.futil | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 473f8abfe..7672dc726 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -86,7 +86,6 @@ extern "binary_operators.sv" { /// =================== Unsigned, Bitnum ========================= /// Other unsigned bitnum primitives are found in the core library, /// since they're required for FSM encoding. - primitive std_mult_pipe<"state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, diff --git a/primitives/binary_operators.sv b/primitives/binary_operators.sv index ec8bbb3a1..e2ede4b34 100644 --- a/primitives/binary_operators.sv +++ b/primitives/binary_operators.sv @@ -762,4 +762,4 @@ module std_signext #( ); end `endif -endmodule \ No newline at end of file +endmodule diff --git a/primitives/pipelined.futil b/primitives/pipelined.futil index b3436d613..9715aca20 100644 --- a/primitives/pipelined.futil +++ b/primitives/pipelined.futil @@ -1,12 +1,12 @@ extern "pipelined.sv" { // A latency-sensitive multiplier that takes 4 cycles to compute its result. - static<4> primitive pipelined_mult ( + static<4> primitive pipelined_mult[WIDTH] ( @clk clk: 1, @reset reset: 1, - left: 32, - right: 32 + left: WIDTH, + right: WIDTH ) -> ( - out: 32 + out: WIDTH ); // A latency-sensitive multiplier that takes 4 cycles to compute its result. @@ -20,4 +20,5 @@ extern "pipelined.sv" { ) -> ( out: WIDTH ); -} \ No newline at end of file + +} diff --git a/primitives/pipelined.sv b/primitives/pipelined.sv index 086bcaeea..af7677d72 100644 --- a/primitives/pipelined.sv +++ b/primitives/pipelined.sv @@ -1,34 +1,34 @@ /// This is mostly used for testing the static guarantees currently. /// A realistic implementation would probably take four cycles. -module pipelined_mult ( +module pipelined_mult #( + parameter WIDTH = 32 +) ( input wire clk, input wire reset, // inputs - input wire [31:0] left, - input wire [31:0] right, + input wire [WIDTH-1:0] left, + input wire [WIDTH-1:0] right, // The input has been committed - output wire [31:0] out + output wire [WIDTH-1:0] out ); -logic [31:0] lt, rt, buff0, buff1, buff2, tmp_prod; +logic [WIDTH-1:0] buff0, buff1, buff2, buff3, tmp_prod; -assign out = buff2; -assign tmp_prod = lt * rt; +assign out = buff3; +assign tmp_prod = left * right; always_ff @(posedge clk) begin if (reset) begin - lt <= 0; - rt <= 0; buff0 <= 0; buff1 <= 0; buff2 <= 0; + buff3 <= 0; end else begin - lt <= left; - rt <= right; buff0 <= tmp_prod; buff1 <= buff0; buff2 <= buff1; + buff3 <= buff2; end end diff --git a/tests/correctness/static-control/static-mult-dot-product.futil b/tests/correctness/static-control/static-mult-dot-product.futil index 19fb64ca2..bdbdd54b2 100644 --- a/tests/correctness/static-control/static-mult-dot-product.futil +++ b/tests/correctness/static-control/static-mult-dot-product.futil @@ -3,7 +3,7 @@ import "primitives/pipelined.futil"; component main() -> () { cells { - mul = pipelined_mult(); + mul = pipelined_mult(32); @external left = std_mem_d1(32, 10, 4); @external right = std_mem_d1(32, 10, 4); @external out = std_mem_d1(32, 10, 4); From 89e3e7f8fd3ffec40b4f04dd4a7ab40ba7a737ed Mon Sep 17 00:00:00 2001 From: Justin Ngai <57964367+NgaiJustin@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:06:24 -0400 Subject: [PATCH 082/189] Automate SystemVerilog to BTOR conversion for Calyx Primitives (#1757) * Migrate changes from NgaiJustin/calyx for sv to btor2 conversion * Update sv2btor.md --- docs/tools/sv2btor.md | 18 + tools/btor2/core/std_add.btor | 7 + tools/btor2/core/std_and.btor | 7 + tools/btor2/core/std_cat.btor | 8 + tools/btor2/core/std_eq.btor | 8 + tools/btor2/core/std_ge.btor | 8 + tools/btor2/core/std_gt.btor | 8 + tools/btor2/core/std_le.btor | 8 + tools/btor2/core/std_lsh.btor | 7 + tools/btor2/core/std_lt.btor | 8 + tools/btor2/core/std_mem_d1.btor | 97 +++++ tools/btor2/core/std_mem_d2.btor | 104 +++++ tools/btor2/core/std_mem_d3.btor | 112 +++++ tools/btor2/core/std_mem_d4.btor | 117 ++++++ tools/btor2/core/std_mux.btor | 9 + tools/btor2/core/std_neq.btor | 8 + tools/btor2/core/std_not.btor | 6 + tools/btor2/core/std_or.btor | 7 + tools/btor2/core/std_pad.btor | 5 + tools/btor2/core/std_reg.btor | 21 + tools/btor2/core/std_rsh.btor | 7 + tools/btor2/core/std_slice.btor | 5 + tools/btor2/core/std_sub.btor | 7 + tools/btor2/core/std_xor.btor | 7 + tools/btor2/sv2btor.py | 166 ++++++++ tools/btor2/sync/std_sync_reg.btor | 108 +++++ tools/btor2/verible_verilog_syntax.py | 580 ++++++++++++++++++++++++++ 27 files changed, 1453 insertions(+) create mode 100644 docs/tools/sv2btor.md create mode 100644 tools/btor2/core/std_add.btor create mode 100644 tools/btor2/core/std_and.btor create mode 100644 tools/btor2/core/std_cat.btor create mode 100644 tools/btor2/core/std_eq.btor create mode 100644 tools/btor2/core/std_ge.btor create mode 100644 tools/btor2/core/std_gt.btor create mode 100644 tools/btor2/core/std_le.btor create mode 100644 tools/btor2/core/std_lsh.btor create mode 100644 tools/btor2/core/std_lt.btor create mode 100644 tools/btor2/core/std_mem_d1.btor create mode 100644 tools/btor2/core/std_mem_d2.btor create mode 100644 tools/btor2/core/std_mem_d3.btor create mode 100644 tools/btor2/core/std_mem_d4.btor create mode 100644 tools/btor2/core/std_mux.btor create mode 100644 tools/btor2/core/std_neq.btor create mode 100644 tools/btor2/core/std_not.btor create mode 100644 tools/btor2/core/std_or.btor create mode 100644 tools/btor2/core/std_pad.btor create mode 100644 tools/btor2/core/std_reg.btor create mode 100644 tools/btor2/core/std_rsh.btor create mode 100644 tools/btor2/core/std_slice.btor create mode 100644 tools/btor2/core/std_sub.btor create mode 100644 tools/btor2/core/std_xor.btor create mode 100644 tools/btor2/sv2btor.py create mode 100644 tools/btor2/sync/std_sync_reg.btor create mode 100644 tools/btor2/verible_verilog_syntax.py diff --git a/docs/tools/sv2btor.md b/docs/tools/sv2btor.md new file mode 100644 index 000000000..4544aaa21 --- /dev/null +++ b/docs/tools/sv2btor.md @@ -0,0 +1,18 @@ +# `sv2btor` + +The `sv2btor` tool is a tool that leverages `yosys` and +`verible` to translate the SystemVerilog files into BTOR2. + +# Usage + +```bash +Usage: sv2btor.py +``` + +# Installation +To run this tool, you need to have `yosys` and `verible-verilog-syntax` installed. You will also need the `anytree` python package. + +- You can install `yosys` by following the instructions [here](https://github.com/YosysHQ/yosys). +- You can install `verible-verilog-syntax` by following the instructions [here](https://github.com/chipsalliance/verible). Note that we only need the standalone `verible-verilog-syntax` executable, the rest of the tools are optional. +- You can install `anytree` by running `pip install anytree`. + diff --git a/tools/btor2/core/std_add.btor b/tools/btor2/core/std_add.btor new file mode 100644 index 000000000..c76e54845 --- /dev/null +++ b/tools/btor2/core/std_add.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_add. +1 sort bitvec 32 +2 input 1 left ; temp.sv:5.35-5.39 +3 input 1 right ; temp.sv:6.35-6.40 +4 add 1 2 3 +5 output 4 out ; temp.sv:7.35-7.38 +; end of yosys output diff --git a/tools/btor2/core/std_and.btor b/tools/btor2/core/std_and.btor new file mode 100644 index 000000000..7097df75a --- /dev/null +++ b/tools/btor2/core/std_and.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_and. +1 sort bitvec 32 +2 input 1 left ; core.sv:97.35-97.39 +3 input 1 right ; core.sv:98.35-98.40 +4 and 1 2 3 +5 output 4 out ; core.sv:99.35-99.38 +; end of yosys output diff --git a/tools/btor2/core/std_cat.btor b/tools/btor2/core/std_cat.btor new file mode 100644 index 000000000..56847207b --- /dev/null +++ b/tools/btor2/core/std_cat.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_cat. +1 sort bitvec 32 +2 input 1 left ; core.sv:63.39-63.43 +3 input 1 right ; core.sv:64.40-64.45 +4 sort bitvec 64 +5 concat 4 2 3 +6 output 5 out ; core.sv:65.34-65.37 +; end of yosys output diff --git a/tools/btor2/core/std_eq.btor b/tools/btor2/core/std_eq.btor new file mode 100644 index 000000000..1b4e39b47 --- /dev/null +++ b/tools/btor2/core/std_eq.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_eq. +1 sort bitvec 32 +2 input 1 left ; core.sv:157.34-157.38 +3 input 1 right ; core.sv:158.34-158.39 +4 sort bitvec 1 +5 eq 4 2 3 +6 output 5 out ; core.sv:159.18-159.21 +; end of yosys output diff --git a/tools/btor2/core/std_ge.btor b/tools/btor2/core/std_ge.btor new file mode 100644 index 000000000..9e55d2f14 --- /dev/null +++ b/tools/btor2/core/std_ge.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_ge. +1 sort bitvec 32 +2 input 1 left ; core.sv:177.34-177.38 +3 input 1 right ; core.sv:178.34-178.39 +4 sort bitvec 1 +5 ugte 4 2 3 +6 output 5 out ; core.sv:179.18-179.21 +; end of yosys output diff --git a/tools/btor2/core/std_gt.btor b/tools/btor2/core/std_gt.btor new file mode 100644 index 000000000..9fd09e4a4 --- /dev/null +++ b/tools/btor2/core/std_gt.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_gt. +1 sort bitvec 32 +2 input 1 left ; core.sv:137.34-137.38 +3 input 1 right ; core.sv:138.34-138.39 +4 sort bitvec 1 +5 ugt 4 2 3 +6 output 5 out ; core.sv:139.18-139.21 +; end of yosys output diff --git a/tools/btor2/core/std_le.btor b/tools/btor2/core/std_le.btor new file mode 100644 index 000000000..c0c936991 --- /dev/null +++ b/tools/btor2/core/std_le.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_le. +1 sort bitvec 32 +2 input 1 left ; core.sv:187.34-187.38 +3 input 1 right ; core.sv:188.34-188.39 +4 sort bitvec 1 +5 ulte 4 2 3 +6 output 5 out ; core.sv:189.18-189.21 +; end of yosys output diff --git a/tools/btor2/core/std_lsh.btor b/tools/btor2/core/std_lsh.btor new file mode 100644 index 000000000..fa84191dc --- /dev/null +++ b/tools/btor2/core/std_lsh.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_lsh. +1 sort bitvec 32 +2 input 1 left ; core.sv:197.35-197.39 +3 input 1 right ; core.sv:198.35-198.40 +4 sll 1 2 3 +5 output 4 out ; core.sv:199.35-199.38 +; end of yosys output diff --git a/tools/btor2/core/std_lt.btor b/tools/btor2/core/std_lt.btor new file mode 100644 index 000000000..fcc942c6e --- /dev/null +++ b/tools/btor2/core/std_lt.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_lt. +1 sort bitvec 32 +2 input 1 left ; core.sv:147.34-147.38 +3 input 1 right ; core.sv:148.34-148.39 +4 sort bitvec 1 +5 ult 4 2 3 +6 output 5 out ; core.sv:149.18-149.21 +; end of yosys output diff --git a/tools/btor2/core/std_mem_d1.btor b/tools/btor2/core/std_mem_d1.btor new file mode 100644 index 000000000..93d0096b8 --- /dev/null +++ b/tools/btor2/core/std_mem_d1.btor @@ -0,0 +1,97 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d1. +1 sort bitvec 4 +2 input 1 addr0 ; core.sv:232.38-232.43 +3 sort bitvec 1 +4 input 3 clk ; core.sv:235.38-235.41 +5 input 3 reset ; core.sv:236.38-236.43 +6 sort bitvec 32 +7 input 6 write_data ; core.sv:233.38-233.48 +8 input 3 write_en ; core.sv:234.38-234.46 +9 state 3 +10 output 9 done ; core.sv:238.38-238.42 +11 sort array 1 6 +12 state 11 mem +13 read 6 12 2 +14 output 13 read_data ; core.sv:237.38-237.47 +15 const 3 0 +16 const 3 1 +17 ite 3 8 16 15 +18 ite 3 5 15 17 +19 next 3 9 18 +20 input 1 +21 not 3 5 +22 and 3 21 8 +23 ite 1 22 2 20 +24 input 6 +25 ite 6 22 7 24 +26 ite 3 22 16 15 +27 sort bitvec 2 +28 concat 27 26 26 +29 sort bitvec 3 +30 concat 29 26 28 +31 concat 1 26 30 +32 sort bitvec 5 +33 concat 32 26 31 +34 sort bitvec 6 +35 concat 34 26 33 +36 sort bitvec 7 +37 concat 36 26 35 +38 sort bitvec 8 +39 concat 38 26 37 +40 sort bitvec 9 +41 concat 40 26 39 +42 sort bitvec 10 +43 concat 42 26 41 +44 sort bitvec 11 +45 concat 44 26 43 +46 sort bitvec 12 +47 concat 46 26 45 +48 sort bitvec 13 +49 concat 48 26 47 +50 sort bitvec 14 +51 concat 50 26 49 +52 sort bitvec 15 +53 concat 52 26 51 +54 sort bitvec 16 +55 concat 54 26 53 +56 sort bitvec 17 +57 concat 56 26 55 +58 sort bitvec 18 +59 concat 58 26 57 +60 sort bitvec 19 +61 concat 60 26 59 +62 sort bitvec 20 +63 concat 62 26 61 +64 sort bitvec 21 +65 concat 64 26 63 +66 sort bitvec 22 +67 concat 66 26 65 +68 sort bitvec 23 +69 concat 68 26 67 +70 sort bitvec 24 +71 concat 70 26 69 +72 sort bitvec 25 +73 concat 72 26 71 +74 sort bitvec 26 +75 concat 74 26 73 +76 sort bitvec 27 +77 concat 76 26 75 +78 sort bitvec 28 +79 concat 78 26 77 +80 sort bitvec 29 +81 concat 80 26 79 +82 sort bitvec 30 +83 concat 82 26 81 +84 sort bitvec 31 +85 concat 84 26 83 +86 concat 6 26 85 +87 read 6 12 23 +88 not 6 86 +89 and 6 87 88 +90 and 6 25 86 +91 or 6 90 89 +92 write 11 12 23 91 +93 redor 3 86 +94 ite 11 93 92 12 +95 next 11 12 94 mem ; core.sv:241.21-241.24 +; end of yosys output diff --git a/tools/btor2/core/std_mem_d2.btor b/tools/btor2/core/std_mem_d2.btor new file mode 100644 index 000000000..f6e415d6f --- /dev/null +++ b/tools/btor2/core/std_mem_d2.btor @@ -0,0 +1,104 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d2. +1 sort bitvec 4 +2 input 1 addr0 ; core.sv:272.41-272.46 +3 input 1 addr1 ; core.sv:273.41-273.46 +4 sort bitvec 1 +5 input 4 clk ; core.sv:276.41-276.44 +6 input 4 reset ; core.sv:277.41-277.46 +7 sort bitvec 32 +8 input 7 write_data ; core.sv:274.41-274.51 +9 input 4 write_en ; core.sv:275.41-275.49 +10 state 4 +11 output 10 done ; core.sv:279.41-279.45 +12 sort bitvec 8 +13 sort array 12 7 +14 state 13 mem +15 uext 12 2 4 +16 sort bitvec 5 +17 const 16 10000 +18 uext 12 17 3 +19 mul 12 15 18 +20 uext 12 3 4 +21 add 12 19 20 +22 read 7 14 21 +23 output 22 read_data ; core.sv:278.41-278.50 +24 const 4 0 +25 const 4 1 +26 ite 4 9 25 24 +27 ite 4 6 24 26 +28 next 4 10 27 +29 input 12 +30 not 4 6 +31 and 4 30 9 +32 ite 12 31 21 29 +33 input 7 +34 ite 7 31 8 33 +35 ite 4 31 25 24 +36 sort bitvec 2 +37 concat 36 35 35 +38 sort bitvec 3 +39 concat 38 35 37 +40 concat 1 35 39 +41 concat 16 35 40 +42 sort bitvec 6 +43 concat 42 35 41 +44 sort bitvec 7 +45 concat 44 35 43 +46 concat 12 35 45 +47 sort bitvec 9 +48 concat 47 35 46 +49 sort bitvec 10 +50 concat 49 35 48 +51 sort bitvec 11 +52 concat 51 35 50 +53 sort bitvec 12 +54 concat 53 35 52 +55 sort bitvec 13 +56 concat 55 35 54 +57 sort bitvec 14 +58 concat 57 35 56 +59 sort bitvec 15 +60 concat 59 35 58 +61 sort bitvec 16 +62 concat 61 35 60 +63 sort bitvec 17 +64 concat 63 35 62 +65 sort bitvec 18 +66 concat 65 35 64 +67 sort bitvec 19 +68 concat 67 35 66 +69 sort bitvec 20 +70 concat 69 35 68 +71 sort bitvec 21 +72 concat 71 35 70 +73 sort bitvec 22 +74 concat 73 35 72 +75 sort bitvec 23 +76 concat 75 35 74 +77 sort bitvec 24 +78 concat 77 35 76 +79 sort bitvec 25 +80 concat 79 35 78 +81 sort bitvec 26 +82 concat 81 35 80 +83 sort bitvec 27 +84 concat 83 35 82 +85 sort bitvec 28 +86 concat 85 35 84 +87 sort bitvec 29 +88 concat 87 35 86 +89 sort bitvec 30 +90 concat 89 35 88 +91 sort bitvec 31 +92 concat 91 35 90 +93 concat 7 35 92 +94 read 7 14 32 +95 not 7 93 +96 and 7 94 95 +97 and 7 34 93 +98 or 7 97 96 +99 write 13 14 32 98 +100 redor 4 93 +101 ite 13 100 99 14 +102 next 13 14 101 mem ; core.sv:283.21-283.24 +; end of yosys output diff --git a/tools/btor2/core/std_mem_d3.btor b/tools/btor2/core/std_mem_d3.btor new file mode 100644 index 000000000..e6377b484 --- /dev/null +++ b/tools/btor2/core/std_mem_d3.btor @@ -0,0 +1,112 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d3. +1 sort bitvec 4 +2 input 1 addr0 ; core.sv:317.41-317.46 +3 input 1 addr1 ; core.sv:318.41-318.46 +4 input 1 addr2 ; core.sv:319.41-319.46 +5 sort bitvec 1 +6 input 5 clk ; core.sv:322.41-322.44 +7 input 5 reset ; core.sv:323.41-323.46 +8 sort bitvec 32 +9 input 8 write_data ; core.sv:320.41-320.51 +10 input 5 write_en ; core.sv:321.41-321.49 +11 state 5 +12 output 11 done ; core.sv:325.41-325.45 +13 sort bitvec 12 +14 sort array 13 8 +15 state 14 mem +16 sort bitvec 9 +17 uext 16 2 5 +18 sort bitvec 5 +19 const 18 10000 +20 uext 16 19 4 +21 mul 16 17 20 +22 sort bitvec 23 +23 const 22 00000000000000000000000 +24 concat 8 23 21 +25 uext 8 3 28 +26 add 8 24 25 +27 uext 8 19 27 +28 mul 8 26 27 +29 slice 13 28 11 0 +30 uext 13 4 8 +31 add 13 29 30 +32 read 8 15 31 +33 output 32 read_data ; core.sv:324.41-324.50 +34 const 5 0 +35 const 5 1 +36 ite 5 10 35 34 +37 ite 5 7 34 36 +38 next 5 11 37 +39 input 13 +40 not 5 7 +41 and 5 40 10 +42 ite 13 41 31 39 +43 input 8 +44 ite 8 41 9 43 +45 ite 5 41 35 34 +46 sort bitvec 2 +47 concat 46 45 45 +48 sort bitvec 3 +49 concat 48 45 47 +50 concat 1 45 49 +51 concat 18 45 50 +52 sort bitvec 6 +53 concat 52 45 51 +54 sort bitvec 7 +55 concat 54 45 53 +56 sort bitvec 8 +57 concat 56 45 55 +58 concat 16 45 57 +59 sort bitvec 10 +60 concat 59 45 58 +61 sort bitvec 11 +62 concat 61 45 60 +63 concat 13 45 62 +64 sort bitvec 13 +65 concat 64 45 63 +66 sort bitvec 14 +67 concat 66 45 65 +68 sort bitvec 15 +69 concat 68 45 67 +70 sort bitvec 16 +71 concat 70 45 69 +72 sort bitvec 17 +73 concat 72 45 71 +74 sort bitvec 18 +75 concat 74 45 73 +76 sort bitvec 19 +77 concat 76 45 75 +78 sort bitvec 20 +79 concat 78 45 77 +80 sort bitvec 21 +81 concat 80 45 79 +82 sort bitvec 22 +83 concat 82 45 81 +84 concat 22 45 83 +85 sort bitvec 24 +86 concat 85 45 84 +87 sort bitvec 25 +88 concat 87 45 86 +89 sort bitvec 26 +90 concat 89 45 88 +91 sort bitvec 27 +92 concat 91 45 90 +93 sort bitvec 28 +94 concat 93 45 92 +95 sort bitvec 29 +96 concat 95 45 94 +97 sort bitvec 30 +98 concat 97 45 96 +99 sort bitvec 31 +100 concat 99 45 98 +101 concat 8 45 100 +102 read 8 15 42 +103 not 8 101 +104 and 8 102 103 +105 and 8 44 101 +106 or 8 105 104 +107 write 14 15 42 106 +108 redor 5 101 +109 ite 14 108 107 15 +110 next 14 15 109 mem ; core.sv:329.21-329.24 +; end of yosys output diff --git a/tools/btor2/core/std_mem_d4.btor b/tools/btor2/core/std_mem_d4.btor new file mode 100644 index 000000000..03079b834 --- /dev/null +++ b/tools/btor2/core/std_mem_d4.btor @@ -0,0 +1,117 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d4. +1 sort bitvec 4 +2 input 1 addr0 ; core.sv:367.41-367.46 +3 input 1 addr1 ; core.sv:368.41-368.46 +4 input 1 addr2 ; core.sv:369.41-369.46 +5 input 1 addr3 ; core.sv:370.41-370.46 +6 sort bitvec 1 +7 input 6 clk ; core.sv:373.41-373.44 +8 input 6 reset ; core.sv:374.41-374.46 +9 sort bitvec 32 +10 input 9 write_data ; core.sv:371.41-371.51 +11 input 6 write_en ; core.sv:372.41-372.49 +12 state 6 +13 output 12 done ; core.sv:376.41-376.45 +14 sort bitvec 16 +15 sort array 14 9 +16 state 15 mem +17 sort bitvec 9 +18 uext 17 2 5 +19 sort bitvec 5 +20 const 19 10000 +21 uext 17 20 4 +22 mul 17 18 21 +23 sort bitvec 23 +24 const 23 00000000000000000000000 +25 concat 9 24 22 +26 uext 9 3 28 +27 add 9 25 26 +28 uext 9 20 27 +29 mul 9 27 28 +30 uext 9 4 28 +31 add 9 29 30 +32 uext 9 20 27 +33 mul 9 31 32 +34 slice 14 33 15 0 +35 uext 14 5 12 +36 add 14 34 35 +37 read 9 16 36 +38 output 37 read_data ; core.sv:375.41-375.50 +39 const 6 0 +40 const 6 1 +41 ite 6 11 40 39 +42 ite 6 8 39 41 +43 next 6 12 42 +44 input 14 +45 not 6 8 +46 and 6 45 11 +47 ite 14 46 36 44 +48 input 9 +49 ite 9 46 10 48 +50 ite 6 46 40 39 +51 sort bitvec 2 +52 concat 51 50 50 +53 sort bitvec 3 +54 concat 53 50 52 +55 concat 1 50 54 +56 concat 19 50 55 +57 sort bitvec 6 +58 concat 57 50 56 +59 sort bitvec 7 +60 concat 59 50 58 +61 sort bitvec 8 +62 concat 61 50 60 +63 concat 17 50 62 +64 sort bitvec 10 +65 concat 64 50 63 +66 sort bitvec 11 +67 concat 66 50 65 +68 sort bitvec 12 +69 concat 68 50 67 +70 sort bitvec 13 +71 concat 70 50 69 +72 sort bitvec 14 +73 concat 72 50 71 +74 sort bitvec 15 +75 concat 74 50 73 +76 concat 14 50 75 +77 sort bitvec 17 +78 concat 77 50 76 +79 sort bitvec 18 +80 concat 79 50 78 +81 sort bitvec 19 +82 concat 81 50 80 +83 sort bitvec 20 +84 concat 83 50 82 +85 sort bitvec 21 +86 concat 85 50 84 +87 sort bitvec 22 +88 concat 87 50 86 +89 concat 23 50 88 +90 sort bitvec 24 +91 concat 90 50 89 +92 sort bitvec 25 +93 concat 92 50 91 +94 sort bitvec 26 +95 concat 94 50 93 +96 sort bitvec 27 +97 concat 96 50 95 +98 sort bitvec 28 +99 concat 98 50 97 +100 sort bitvec 29 +101 concat 100 50 99 +102 sort bitvec 30 +103 concat 102 50 101 +104 sort bitvec 31 +105 concat 104 50 103 +106 concat 9 50 105 +107 read 9 16 47 +108 not 9 106 +109 and 9 107 108 +110 and 9 49 106 +111 or 9 110 109 +112 write 15 16 47 111 +113 redor 6 106 +114 ite 15 113 112 16 +115 next 15 16 114 mem ; core.sv:380.21-380.24 +; end of yosys output diff --git a/tools/btor2/core/std_mux.btor b/tools/btor2/core/std_mux.btor new file mode 100644 index 000000000..995a6f394 --- /dev/null +++ b/tools/btor2/core/std_mux.btor @@ -0,0 +1,9 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mux. +1 sort bitvec 1 +2 input 1 cond ; core.sv:219.35-219.39 +3 sort bitvec 32 +4 input 3 fal ; core.sv:221.35-221.38 +5 input 3 tru ; core.sv:220.35-220.38 +6 ite 3 2 5 4 +7 output 6 out ; core.sv:222.35-222.38 +; end of yosys output diff --git a/tools/btor2/core/std_neq.btor b/tools/btor2/core/std_neq.btor new file mode 100644 index 000000000..a69d28725 --- /dev/null +++ b/tools/btor2/core/std_neq.btor @@ -0,0 +1,8 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_neq. +1 sort bitvec 32 +2 input 1 left ; core.sv:167.34-167.38 +3 input 1 right ; core.sv:168.34-168.39 +4 sort bitvec 1 +5 neq 4 2 3 +6 output 5 out ; core.sv:169.18-169.21 +; end of yosys output diff --git a/tools/btor2/core/std_not.btor b/tools/btor2/core/std_not.btor new file mode 100644 index 000000000..a27bcf1ba --- /dev/null +++ b/tools/btor2/core/std_not.btor @@ -0,0 +1,6 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_not. +1 sort bitvec 32 +2 input 1 in ; core.sv:88.35-88.37 +3 not 1 2 +4 output 3 out ; core.sv:89.35-89.38 +; end of yosys output diff --git a/tools/btor2/core/std_or.btor b/tools/btor2/core/std_or.btor new file mode 100644 index 000000000..1b8787e35 --- /dev/null +++ b/tools/btor2/core/std_or.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_or. +1 sort bitvec 32 +2 input 1 left ; core.sv:107.35-107.39 +3 input 1 right ; core.sv:108.35-108.40 +4 or 1 2 3 +5 output 4 out ; core.sv:109.35-109.38 +; end of yosys output diff --git a/tools/btor2/core/std_pad.btor b/tools/btor2/core/std_pad.btor new file mode 100644 index 000000000..f4a988eeb --- /dev/null +++ b/tools/btor2/core/std_pad.btor @@ -0,0 +1,5 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_pad. +1 sort bitvec 32 +2 input 1 in ; core.sv:38.39-38.41 +3 output 2 out ; core.sv:39.39-39.42 +; end of yosys output diff --git a/tools/btor2/core/std_reg.btor b/tools/btor2/core/std_reg.btor new file mode 100644 index 000000000..98a6b9ebe --- /dev/null +++ b/tools/btor2/core/std_reg.btor @@ -0,0 +1,21 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_reg. +1 sort bitvec 1 +2 input 1 clk ; temp.sv:7.31-7.34 +3 sort bitvec 32 +4 input 3 in ; temp.sv:5.31-5.33 +5 input 1 reset ; temp.sv:8.31-8.36 +6 input 1 write_en ; temp.sv:6.31-6.39 +7 state 1 +8 output 7 done ; temp.sv:11.31-11.35 +9 state 3 +10 output 9 out ; temp.sv:10.31-10.34 +11 const 1 0 +12 const 1 1 +13 ite 1 6 12 11 +14 ite 1 5 11 13 +15 next 1 7 14 +16 ite 3 6 4 9 ; input if write_en else existing 9 state val +17 const 3 00000000000000000000000000000000 +18 ite 3 5 17 16 ; 32 bit 0 if reset else 16 +19 next 3 9 18 +; end of yosys output diff --git a/tools/btor2/core/std_rsh.btor b/tools/btor2/core/std_rsh.btor new file mode 100644 index 000000000..fd7ac517c --- /dev/null +++ b/tools/btor2/core/std_rsh.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_rsh. +1 sort bitvec 32 +2 input 1 left ; core.sv:207.35-207.39 +3 input 1 right ; core.sv:208.35-208.40 +4 srl 1 2 3 +5 output 4 out ; core.sv:209.35-209.38 +; end of yosys output diff --git a/tools/btor2/core/std_slice.btor b/tools/btor2/core/std_slice.btor new file mode 100644 index 000000000..4fc219734 --- /dev/null +++ b/tools/btor2/core/std_slice.btor @@ -0,0 +1,5 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_slice. +1 sort bitvec 32 +2 input 1 in ; core.sv:15.39-15.41 +3 output 2 out ; core.sv:16.39-16.42 +; end of yosys output diff --git a/tools/btor2/core/std_sub.btor b/tools/btor2/core/std_sub.btor new file mode 100644 index 000000000..e3c8c5cf8 --- /dev/null +++ b/tools/btor2/core/std_sub.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_sub. +1 sort bitvec 32 +2 input 1 left ; core.sv:127.35-127.39 +3 input 1 right ; core.sv:128.35-128.40 +4 sub 1 2 3 +5 output 4 out ; core.sv:129.35-129.38 +; end of yosys output diff --git a/tools/btor2/core/std_xor.btor b/tools/btor2/core/std_xor.btor new file mode 100644 index 000000000..a6d9e663b --- /dev/null +++ b/tools/btor2/core/std_xor.btor @@ -0,0 +1,7 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_xor. +1 sort bitvec 32 +2 input 1 left ; core.sv:117.35-117.39 +3 input 1 right ; core.sv:118.35-118.40 +4 xor 1 2 3 +5 output 4 out ; core.sv:119.35-119.38 +; end of yosys output diff --git a/tools/btor2/sv2btor.py b/tools/btor2/sv2btor.py new file mode 100644 index 000000000..8f0636c86 --- /dev/null +++ b/tools/btor2/sv2btor.py @@ -0,0 +1,166 @@ +""" +Generates a .btor file for each module in each .sv file in the current directory +""" +import os +import json +import subprocess +import sys +import anytree +import tempfile +import verible_verilog_syntax + + +# Adapted from verible examples: +# https://github.com/chipsalliance/verible/blob/e76eb275b8e6739e9c9edc9e35032b193e0ce187/verilog/tools/syntax/export_json_examples/print_modules.py +def process_file_data(path: str, data: verible_verilog_syntax.SyntaxData): + """Print information about modules found in SystemVerilog file. + + This function uses verible_verilog_syntax.Node methods to find module + declarations and specific tokens containing following information: + + * module name + * module port names + * module parameter names + * module imports + * module header code + + Args: + path: Path to source file (used only for informational purposes) + data: Parsing results returned by one of VeribleVerilogSyntax' parse_* + methods. + """ + if not data.tree: + return + + modules_info = [] + + # Collect information about each module declaration in the file + for module in data.tree.iter_find_all({"tag": "kModuleDeclaration"}): + module_info = { + "header_text": "", + "name": "", + "ports": [], + "parameters": [], + "imports": [], + } + + # Find module header + header = module.find({"tag": "kModuleHeader"}) + if not header: + continue + module_info["header_text"] = header.text + + # Find module name + name = header.find( + {"tag": ["SymbolIdentifier", "EscapedIdentifier"]}, + iter_=anytree.PreOrderIter, + ) + if not name: + continue + module_info["name"] = name.text + + # Get the list of ports + for port in header.iter_find_all({"tag": ["kPortDeclaration", "kPort"]}): + port_id = port.find({"tag": ["SymbolIdentifier", "EscapedIdentifier"]}) + module_info["ports"].append(port_id.text) + + # Get the list of parameters + for param in header.iter_find_all({"tag": ["kParamDeclaration"]}): + param_id = param.find({"tag": ["SymbolIdentifier", "EscapedIdentifier"]}) + module_info["parameters"].append(param_id.text) + + # Get the list of imports + for pkg in module.iter_find_all({"tag": ["kPackageImportItem"]}): + module_info["imports"].append(pkg.text) + + modules_info.append(module_info) + + return modules_info + + +def gen_btor(yosys_executable, sv_filename, modules_info, out_dir="."): + """ + Generates a .btor file for each module in the given .sv file + """ + # create a temporary file (.ys) for the synthesis script + _, synthesis_script_path = tempfile.mkstemp(suffix=".ys") + + # modify the synthesis script with a different prep -top for each module + for module_info in modules_info: + with open(synthesis_script_path, "w") as f: + f.write(f"read -sv {sv_filename}\n") + f.write(f"prep -top {module_info['name']}\n") + f.write( + f"write_btor -s {os.path.join(out_dir, module_info['name'])}.btor\n" + ) + f.close() + + # print contents of synthesis script + # with open(synthesis_script_path, "r") as f: + # print(f.read()) + + # run yosys + conversion_process = subprocess.Popen( + [yosys_executable, synthesis_script_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + btor_out, btor_err = conversion_process.communicate() + if btor_err: + print(btor_err.decode("utf-8")) + return 1 + + +def main(): + if len(sys.argv) < 5: + args_desc = [ + "PATH_TO_YOSYS_EXECUTABLE", + "PATH_TO_VERIBLE_VERILOG_SYNTAX", + "OUTPUT_DIR", + "VERILOG_FILE [VERILOG_FILE [...]]", + ] + print(f"Usage: {sys.argv[0]} {' '.join(args_desc)}") + return 1 + + yosys_path = sys.argv[1] + parser_path = sys.argv[2] + output_dir = sys.argv[3] + file_paths = sys.argv[4:] + + # validate + if not os.path.exists(yosys_path): + print(f"Error: {yosys_path} does not exist") + return 1 + if not os.path.exists(parser_path): + print(f"Error: {parser_path} does not exist") + return 1 + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + # if the output directory is not empty, warn the user that it will be overwritten and confirm + if os.listdir(output_dir): + print(f"Warning: {output_dir} is not empty, and will be overwritten") + print("Continue? [y/N]") + if input().lower() != "y": + return 1 + + # clear the output directory + for f in os.listdir(output_dir): + os.remove(os.path.join(output_dir, f)) + + # parse the files + parser = verible_verilog_syntax.VeribleVerilogSyntax(executable=parser_path) + data = parser.parse_files(file_paths) + + for file_path, file_data in data.items(): + modules_info = process_file_data(file_path, file_data) + gen_btor( + yosys_path, + file_path, + modules_info, + output_dir, + ) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/btor2/sync/std_sync_reg.btor b/tools/btor2/sync/std_sync_reg.btor new file mode 100644 index 000000000..c66be0f4f --- /dev/null +++ b/tools/btor2/sync/std_sync_reg.btor @@ -0,0 +1,108 @@ +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_sync_reg. +1 sort bitvec 1 +2 input 1 clk ; sync.sv:22.31-22.34 +3 sort bitvec 32 +4 input 3 in_0 ; sync.sv:16.31-16.35 +5 input 3 in_1 ; sync.sv:17.31-17.35 +6 input 1 read_en_0 ; sync.sv:18.31-18.40 +7 input 1 read_en_1 ; sync.sv:19.31-19.40 +8 input 1 reset ; sync.sv:23.31-23.36 +9 input 1 write_en_0 ; sync.sv:20.31-20.41 +10 input 1 write_en_1 ; sync.sv:21.31-21.41 +11 state 3 +12 output 11 out_0 ; sync.sv:25.31-25.36 +13 state 3 +14 output 13 out_1 ; sync.sv:26.31-26.36 +15 state 3 +16 output 15 peek ; sync.sv:31.31-31.35 +17 state 1 +18 output 17 read_done_0 ; sync.sv:29.31-29.42 +19 state 1 +20 output 19 read_done_1 ; sync.sv:30.31-30.42 +21 state 1 +22 output 21 write_done_0 ; sync.sv:27.31-27.43 +23 state 1 +24 output 23 write_done_1 ; sync.sv:28.31-28.43 +25 state 1 is_full +26 xor 1 6 7 +27 and 1 25 26 +28 and 1 27 6 +29 and 1 6 7 +30 and 1 25 29 +31 state 1 arbiter_r +32 not 1 31 +33 and 1 30 32 +34 or 1 28 33 +35 uext 1 34 0 READ_0 ; sync.sv:40.79-40.85 +36 and 1 27 7 +37 and 1 30 31 +38 or 1 36 37 +39 uext 1 38 0 READ_1 ; sync.sv:40.87-40.93 +40 uext 1 30 0 READ_MULT ; sync.sv:40.23-40.32 +41 uext 1 27 0 READ_ONE_HOT ; sync.sv:40.9-40.21 +42 not 1 25 +43 xor 1 9 10 +44 and 1 42 43 +45 and 1 44 9 +46 and 1 9 10 +47 and 1 42 46 +48 state 1 arbiter_w +49 not 1 48 +50 and 1 47 49 +51 or 1 45 50 +52 uext 1 51 0 WRITE_0 ; sync.sv:40.61-40.68 +53 and 1 44 10 +54 and 1 47 48 +55 or 1 53 54 +56 uext 1 55 0 WRITE_1 ; sync.sv:40.70-40.77 +57 uext 1 47 0 WRITE_MULT ; sync.sv:40.49-40.59 +58 uext 1 44 0 WRITE_ONE_HOT ; sync.sv:40.34-40.47 +59 state 3 state +60 input 3 +61 ite 3 34 59 60 +62 const 3 00000000000000000000000000000000 +63 ite 3 8 62 61 +64 next 3 11 63 +65 input 3 +66 ite 3 38 59 65 +67 ite 3 8 62 66 +68 next 3 13 67 +69 ite 3 55 5 15 +70 ite 3 51 4 69 +71 ite 3 8 62 70 +72 next 3 15 71 +73 const 1 0 +74 const 1 1 +75 ite 1 34 74 73 +76 ite 1 8 73 75 +77 next 1 17 76 +78 ite 1 38 74 73 +79 ite 1 8 73 78 +80 next 1 19 79 +81 ite 1 51 74 73 +82 ite 1 8 73 81 +83 next 1 21 82 +84 ite 1 55 74 73 +85 ite 1 8 73 84 +86 next 1 23 85 +87 or 1 27 30 +88 ite 1 87 73 25 +89 or 1 44 47 +90 ite 1 89 74 88 +91 ite 1 8 73 90 +92 next 1 25 91 +93 ite 1 37 73 31 +94 ite 1 33 74 93 +95 ite 1 8 73 94 +96 next 1 31 95 +97 ite 1 54 73 48 +98 ite 1 50 74 97 +99 ite 1 8 73 98 +100 next 1 48 99 +101 input 3 +102 ite 3 87 101 59 +103 ite 3 55 5 102 +104 ite 3 51 4 103 +105 ite 3 8 62 104 +106 next 3 59 105 +; end of yosys output diff --git a/tools/btor2/verible_verilog_syntax.py b/tools/btor2/verible_verilog_syntax.py new file mode 100644 index 000000000..06332297b --- /dev/null +++ b/tools/btor2/verible_verilog_syntax.py @@ -0,0 +1,580 @@ +# Copyright 2017-2020 The Verible Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Wrapper for ``verible-verilog-syntax --export_json``""" + +import collections +import json +import re +import subprocess +from typing import Any, Callable, Dict, Iterable, List, Optional, Union + +import anytree +import dataclasses + +_CSI_SEQUENCE = re.compile("\033\\[.*?m") + + +def _colorize(formats: List[str], strings: List[str]) -> str: + result = "" + fi = 0 + for s in strings: + result += f"\033[{formats[fi]}m{s}\033[0m" + fi = (fi + 1) % len(formats) + return result + + +# Type aliases + +CallableFilter = Callable[["Node"], bool] +KeyValueFilter = Dict[str, Union[str, List[str]]] +TreeIterator = Union["_TreeIteratorBase", anytree.iterators.AbstractIter] + + +# Custom tree iterators with an option for reverse children iteration + + +class _TreeIteratorBase: + def __init__( + self, + tree: "Node", + filter_: Optional[CallableFilter] = None, + reverse_children: bool = False, + ): + self.tree = tree + self.reverse_children = reverse_children + self.filter_ = filter_ if filter_ else lambda n: True + + def __iter__(self) -> Iterable["Node"]: + yield from self._iter_tree(self.tree) + + def _iter_children(self, tree: Optional["Node"]) -> Iterable["Node"]: + if not tree or not hasattr(tree, "children"): + return [] + return tree.children if not self.reverse_children else reversed(tree.children) + + def _iter_tree(self, tree: Optional["Node"]) -> Iterable["Node"]: + raise NotImplementedError("Subclass must implement '_iter_tree' method") + + +class PreOrderTreeIterator(_TreeIteratorBase): + def _iter_tree(self, tree: Optional["Node"]) -> Iterable["Node"]: + if self.filter_(tree): + yield tree + for child in self._iter_children(tree): + yield from self._iter_tree(child) + + +class PostOrderTreeIterator(_TreeIteratorBase): + def _iter_tree(self, tree: Optional["Node"]) -> Iterable["Node"]: + for child in self._iter_children(tree): + yield from self._iter_tree(child) + if self.filter_(tree): + yield tree + + +class LevelOrderTreeIterator(_TreeIteratorBase): + def _iter_tree(self, tree: Optional["Node"]) -> Iterable["Node"]: + queue = collections.deque([tree]) + while len(queue) > 0: + n = queue.popleft() + if self.filter_(n): + yield n + queue.extend(self._iter_children(n)) + + +class Node(anytree.NodeMixin): + """Base VeribleVerilogSyntax syntax tree node. + + Attributes: + parent (Optional[Node]): Parent node. + """ + + def __init__(self, parent: Optional["Node"] = None): + self.parent = parent + + @property + def syntax_data(self) -> Optional["SyntaxData"]: + """Parent SyntaxData""" + return self.parent.syntax_data if self.parent else None + + @property + def start(self) -> Optional[int]: + """Byte offset of node's first character in source text""" + raise NotImplementedError("Subclass must implement 'start' property") + + @property + def end(self) -> Optional[int]: + """Byte offset of a character just past the node in source text.""" + raise NotImplementedError("Subclass must implement 'end' property") + + @property + def text(self) -> str: + """Source code fragment spanning all tokens in a node.""" + start = self.start + end = self.end + sd = self.syntax_data + if ( + (start is not None) + and (end is not None) + and sd + and sd.source_code + and end <= len(sd.source_code) + ): + return sd.source_code[start:end].decode("utf-8") + return "" + + def __repr__(self) -> str: + return _CSI_SEQUENCE.sub("", self.to_formatted_string()) + + def to_formatted_string(self) -> str: + """Print node representation formatted for printing in terminal.""" + return super().__repr__() + + +class BranchNode(Node): + """Syntax tree branch node + + Attributes: + tag (str): Node tag. + children (Optional[Node]): Child nodes. + """ + + def __init__( + self, + tag: str, + parent: Optional[Node] = None, + children: Optional[List[Node]] = None, + ): + super().__init__(parent) + self.tag = tag + self.children = children if children is not None else [] + + @property + def start(self) -> Optional[int]: + first_token = self.find( + lambda n: isinstance(n, TokenNode), iter_=PostOrderTreeIterator + ) + return first_token.start if first_token else None + + @property + def end(self) -> Optional[int]: + last_token = self.find( + lambda n: isinstance(n, TokenNode), + iter_=PostOrderTreeIterator, + reverse_children=True, + ) + return last_token.end if last_token else None + + def iter_find_all( + self, + filter_: Union[CallableFilter, KeyValueFilter, None], + max_count: int = 0, + iter_: TreeIterator = LevelOrderTreeIterator, + **kwargs, + ) -> Iterable[Node]: + """Iterate all nodes matching specified filter. + + Args: + filter_: Describes what to search for. Might be: + * Callable taking Node as an argument and returning True for accepted + nodes. + * Dict mapping Node attribute names to searched value or list of + searched values. + max_count: Stop searching after finding that many matching nodes. + iter_: Tree iterator. Decides in what order nodes are visited. + + Yields: + Nodes matching specified filter. + """ + + def as_list(v): + return v if isinstance(v, list) else [v] + + if filter_ and not callable(filter_): + filters = filter_ + + def f(node): + for attr, value in filters.items(): + if not hasattr(node, attr): + return False + if getattr(node, attr) not in as_list(value): + return False + return True + + filter_ = f + + for node in iter_(self, filter_, **kwargs): + yield node + max_count -= 1 + if max_count == 0: + break + + def find( + self, + filter_: Union[CallableFilter, KeyValueFilter, None], + iter_: TreeIterator = LevelOrderTreeIterator, + **kwargs, + ) -> Optional[Node]: + """Find node matching specified filter. + + Args: + filter_: Describes what to search for. Might be: + * Callable taking Node as an argument and returning True for accepted + node. + * Dict mapping Node attribute names to searched value or list of + searched values. + iter_: Tree iterator. Decides in what order nodes are visited. + + Returns: + First Node matching filter. + """ + return next( + self.iter_find_all(filter_, max_count=1, iter_=iter_, **kwargs), None + ) + + def find_all( + self, + filter_: Union[CallableFilter, KeyValueFilter, None], + max_count: int = 0, + iter_: TreeIterator = LevelOrderTreeIterator, + **kwargs, + ) -> List[Node]: + """Find all nodes matching specified filter. + + Args: + filter_: Describes what to search for. Might be: + * Callable taking Node as an argument and returning True for accepted + nodes. + * Dict mapping Node attribute names to searched value or list of + searched values. + max_count: Stop searching after finding that many matching nodes. + iter_: Tree iterator. Decides in what order nodes are visited. + + Returns: + List of nodes matching specified filter. + """ + return list( + self.iter_find_all(filter_, max_count=max_count, iter_=iter_, **kwargs) + ) + + def to_formatted_string(self) -> str: + tag = self.tag if self.tag == repr(self.tag)[1:-1] else repr(self.tag) + return _colorize(["37", "1;97"], ["[", tag, "]"]) + + +class RootNode(BranchNode): + """Syntax tree root node.""" + + def __init__( + self, + tag: str, + syntax_data: Optional["SyntaxData"] = None, + children: Optional[List[Node]] = None, + ): + super().__init__(tag, None, children) + self._syntax_data = syntax_data + + @property + def syntax_data(self) -> Optional["SyntaxData"]: + return self._syntax_data + + +class LeafNode(Node): + """Syntax tree leaf node. + + This specific class is used for null nodes. + """ + + @property + def start(self) -> None: + """Byte offset of token's first character in source text""" + return None + + @property + def end(self) -> None: + """Byte offset of a character just past the token in source text.""" + return None + + def to_formatted_string(self) -> str: + return _colorize(["90"], ["null"]) + + +class TokenNode(LeafNode): + """Tree node with token data + + Represents single token in a syntax tree. + + Attributes: + tag (str): Token tag. + """ + + def __init__(self, tag: str, start: int, end: int, parent: Optional[Node] = None): + super().__init__(parent) + self.tag = tag + self._start = start + self._end = end + + @property + def start(self) -> int: + return self._start + + @property + def end(self) -> int: + return self._end + + def to_formatted_string(self) -> str: + tag = self.tag if self.tag == repr(self.tag)[1:-1] else repr(self.tag) + parts = [ + _colorize(["37", "1;97"], ["[", tag, "]"]), + _colorize(["33", "93"], ["@(", self.start, "-", self.end, ")"]), + ] + text = self.text + if self.tag != text: + parts.append(_colorize(["32", "92"], ["'", repr(text)[1:-1], "'"])) + return " ".join(parts) + + +class Token: + """Token data + + Represents single token in tokens and rawtokens lists. + + Attributes: + tag (str): Token tag. + start (int): Byte offset of token's first character in source text. + end (int): Byte offset of a character just past the token in source text. + syntax_data (Optional["SyntaxData"]): Parent SyntaxData. + """ + + def __init__( + self, tag: str, start: int, end: int, syntax_data: Optional["SyntaxData"] = None + ): + self.tag = tag + self.start = start + self.end = end + self.syntax_data = syntax_data + + @property + def text(self) -> str: + """Token text in source code.""" + sd = self.syntax_data + if sd and sd.source_code and self.end <= len(sd.source_code): + return sd.source_code[self.start : self.end].decode("utf-8") + return "" + + def __repr__(self) -> str: + return _CSI_SEQUENCE.sub("", self.to_formatted_string()) + + def to_formatted_string(self) -> str: + tag = self.tag if self.tag == repr(self.tag)[1:-1] else repr(self.tag) + parts = [ + _colorize(["37", "1;97"], ["[", tag, "]"]), + _colorize(["33", "93"], ["@(", self.start, "-", self.end, ")"]), + _colorize(["32", "92"], ["'", repr(self.text)[1:-1], "'"]), + ] + return " ".join(parts) + + +@dataclasses.dataclass +class Error: + line: int + column: int + phase: str + message: str = "" + + +@dataclasses.dataclass +class SyntaxData: + source_code: Optional[str] = None + tree: Optional[RootNode] = None + tokens: Optional[List[Token]] = None + rawtokens: Optional[List[Token]] = None + errors: Optional[List[Error]] = None + + +class VeribleVerilogSyntax: + """``verible-verilog-syntax`` wrapper. + + This class provides methods for running ``verible-verilog-syntax`` and + transforming its output into Python data structures. + + Args: + executable: path to ``verible-verilog-syntax`` binary. + """ + + def __init__(self, executable: str = "verible-verilog-syntax"): + self.executable = executable + + @staticmethod + def _transform_tree(tree, data: SyntaxData, skip_null: bool) -> RootNode: + def transform(tree): + if tree is None: + return None + if "children" in tree: + children = [ + transform(child) or LeafNode() + for child in tree["children"] + if not (skip_null and child is None) + ] + tag = tree["tag"] + return BranchNode(tag, children=children) + tag = tree["tag"] + start = tree["start"] + end = tree["end"] + return TokenNode(tag, start, end) + + if "children" not in tree: + return None + + children = [ + transform(child) or LeafNode() + for child in tree["children"] + if not (skip_null and child is None) + ] + tag = tree["tag"] + return RootNode(tag, syntax_data=data, children=children) + + @staticmethod + def _transform_tokens(tokens, data: SyntaxData) -> List[Token]: + return [Token(t["tag"], t["start"], t["end"], data) for t in tokens] + + @staticmethod + def _transform_errors(tokens) -> List[Error]: + return [ + Error(t["line"], t["column"], t["phase"], t.get("message", None)) + for t in tokens + ] + + def _parse( + self, paths: List[str], input_: str = None, options: Dict[str, Any] = None + ) -> Dict[str, SyntaxData]: + """Common implementation of parse_* methods""" + options = { + "gen_tree": True, + "skip_null": False, + "gen_tokens": False, + "gen_rawtokens": False, + **(options or {}), + } + + args = ["-export_json"] + if options["gen_tree"]: + args.append("-printtree") + if options["gen_tokens"]: + args.append("-printtokens") + if options["gen_rawtokens"]: + args.append("-printrawtokens") + + proc = subprocess.run( + [self.executable, *args, *paths], + stdout=subprocess.PIPE, + input=input_, + encoding="utf-8", + check=False, + ) + + json_data = json.loads(proc.stdout) + data = {} + for file_path, file_json in json_data.items(): + file_data = SyntaxData() + + if file_path == "-": + file_data.source_code = input_.encode("utf-8") + else: + with open(file_path, "rb") as f: + file_data.source_code = f.read() + + if "tree" in file_json: + file_data.tree = VeribleVerilogSyntax._transform_tree( + file_json["tree"], file_data, options["skip_null"] + ) + + if "tokens" in file_json: + file_data.tokens = VeribleVerilogSyntax._transform_tokens( + file_json["tokens"], file_data + ) + + if "rawtokens" in file_json: + file_data.rawtokens = VeribleVerilogSyntax._transform_tokens( + file_json["rawtokens"], file_data + ) + + if "errors" in file_json: + file_data.errors = VeribleVerilogSyntax._transform_errors( + file_json["errors"] + ) + + data[file_path] = file_data + + return data + + def parse_files( + self, paths: List[str], options: Dict[str, Any] = None + ) -> Dict[str, SyntaxData]: + """Parse multiple SystemVerilog files. + + Args: + paths: list of paths to files to parse. + options: dict with parsing options. + Available options: + gen_tree (boolean): whether to generate syntax tree. + skip_null (boolean): null nodes won't be stored in a tree if True. + gen_tokens (boolean): whether to generate tokens list. + gen_rawtokens (boolean): whether to generate raw token list. + By default only ``gen_tree`` is True. + + Returns: + A dict that maps file names to their parsing results in SyntaxData object. + """ + return self._parse(paths, options=options) + + def parse_file( + self, path: str, options: Dict[str, Any] = None + ) -> Optional[SyntaxData]: + """Parse single SystemVerilog file. + + Args: + path: path to a file to parse. + options: dict with parsing options. + Available options: + gen_tree (boolean): whether to generate syntax tree. + skip_null (boolean): null nodes won't be stored in a tree if True. + gen_tokens (boolean): whether to generate tokens list. + gen_rawtokens (boolean): whether to generate raw token list. + By default only ``gen_tree`` is True. + + Returns: + Parsing results in SyntaxData object. + """ + return self._parse([path], options=options).get(path, None) + + def parse_string( + self, string: str, options: Dict[str, Any] = None + ) -> Optional[SyntaxData]: + """Parse a string with SystemVerilog code. + + Args: + string: SystemVerilog code to parse. + options: dict with parsing options. + Available options: + gen_tree (boolean): whether to generate syntax tree. + skip_null (boolean): null nodes won't be stored in a tree if True. + gen_tokens (boolean): whether to generate tokens list. + gen_rawtokens (boolean): whether to generate raw token list. + By default only ``gen_tree`` is True. + + Returns: + Parsing results in SyntaxData object. + """ + return self._parse(["-"], input_=string, options=options).get("-", None) From cb30eada5242b0b5d57f334c4a80d5c1a178b603 Mon Sep 17 00:00:00 2001 From: bcarlet <8906114+bcarlet@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:10:40 -0400 Subject: [PATCH 083/189] Share cells in more situations (#1753) * Sharing fixes * `is_some_and` not stable in 1.67 * Suggested changes * Treat all invokes as writes * Test empty invokes --- calyx-opt/src/analysis/live_range_analysis.rs | 24 ++----- calyx-opt/src/default_passes.rs | 5 +- calyx-opt/src/passes/dead_cell_removal.rs | 56 ++++++++++++---- tests/passes/cell-share/empty-invoke.expect | 58 ++++++++++++++++ tests/passes/cell-share/empty-invoke.futil | 33 ++++++++++ tests/passes/cell-share/inline.expect | 66 +++++++++++++++++++ tests/passes/cell-share/inline.futil | 32 +++++++++ tests/passes/cell-share/ref-share.expect | 2 + 8 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 tests/passes/cell-share/empty-invoke.expect create mode 100644 tests/passes/cell-share/empty-invoke.futil create mode 100644 tests/passes/cell-share/inline.expect create mode 100644 tests/passes/cell-share/inline.futil diff --git a/calyx-opt/src/analysis/live_range_analysis.rs b/calyx-opt/src/analysis/live_range_analysis.rs index c1552ebc8..76b4f2c95 100644 --- a/calyx-opt/src/analysis/live_range_analysis.rs +++ b/calyx-opt/src/analysis/live_range_analysis.rs @@ -853,8 +853,8 @@ impl LiveRangeAnalysis { comp: &ir::RRC, shareable_components: &ShareSet, ) -> (TypeNameSet, TypeNameSet) { - // The writes of the invoke include its outputs. Also, if the input to the invoke - // is not empty, we also count the cell being invoked as being written to. + // The writes of the invoke include its outputs. Also, we count the cell + // being invoked as being written to. let mut write_set: TypeNameSet = outputs .iter() .filter_map(|(_, src)| { @@ -862,21 +862,18 @@ impl LiveRangeAnalysis { }) .collect(); - let comp_is_written = !inputs.is_empty() - && shareable_components.is_shareable_component(comp); - if comp_is_written { + if shareable_components.is_shareable_component(comp) { write_set.insert(( comp.borrow().prototype.clone(), comp.borrow().name(), )); } - // The reads of the invoke include its inputs. Also, if the outputs are - // not empty, the cell being invoked will be considered as being read from. - // One quick note: if the component is written to, there is no need to include this + // The reads of the invoke include its inputs. + // One quick note: since the component is written to, there is no need to include this // component as being read from since we know the write to the component // precedes the read from it, due to the nature of `invoke` statements. - // This is "cheating" in a sense, since the componenet is technically being + // This is "cheating" in a sense, since the component is technically being // read from. However, since we know that there is a write to the component // that that precedes the read from it within the very same invoke statement, // it "appears" to all the other control statements in the program that the @@ -887,15 +884,6 @@ impl LiveRangeAnalysis { Self::port_to_cell_name(src, shareable_components) }) .collect(); - if !outputs.is_empty() - && !comp_is_written - && shareable_components.is_shareable_component(comp) - { - read_set.insert(( - comp.borrow().prototype.clone(), - comp.borrow().name(), - )); - } if let Some(comb_group) = comb_group_info { read_set.extend( diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 72f1062d8..940d75fe3 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -89,9 +89,10 @@ impl PassManager { InferShare, ComponentInliner, CombProp, - CellShare, // LiveRangeAnalaysis should handle comb groups + DeadCellRemoval, // Clean up dead wires left by CombProp + CellShare, // LiveRangeAnalaysis should handle comb groups SimplifyWithControl, // Must run before compile-invoke - CompileInvoke, // creates dead comb groups + CompileInvoke, // creates dead comb groups AttributePromotion, StaticPromotion, ScheduleCompaction, diff --git a/calyx-opt/src/passes/dead_cell_removal.rs b/calyx-opt/src/passes/dead_cell_removal.rs index f4ceb60e2..ceefddb94 100644 --- a/calyx-opt/src/passes/dead_cell_removal.rs +++ b/calyx-opt/src/passes/dead_cell_removal.rs @@ -48,6 +48,23 @@ impl DeadCellRemoval { out } } + + fn visit_invoke( + &mut self, + comp: &ir::RRC, + inputs: &[(ir::Id, ir::RRC)], + outputs: &[(ir::Id, ir::RRC)], + ref_cells: &[(ir::Id, ir::RRC)], + ) { + let cells = inputs + .iter() + .map(|(_, p)| p) + .chain(outputs.iter().map(|(_, p)| p)) + .map(|p| p.borrow().get_parent_name()) + .chain(iter::once(comp.borrow().name())) + .chain(ref_cells.iter().map(|(_, c)| c.borrow().name())); + self.all_reads.extend(cells); + } } impl Visitor for DeadCellRemoval { @@ -62,6 +79,17 @@ impl Visitor for DeadCellRemoval { Ok(Action::Continue) } + fn start_static_if( + &mut self, + s: &mut ir::StaticIf, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + self.all_reads.insert(s.port.borrow().get_parent_name()); + Ok(Action::Continue) + } + fn start_while( &mut self, s: &mut ir::While, @@ -80,16 +108,18 @@ impl Visitor for DeadCellRemoval { _sigs: &ir::LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - let ir::Invoke { - inputs, outputs, .. - } = s; - let cells = inputs - .iter() - .map(|(_, p)| p) - .chain(outputs.iter().map(|(_, p)| p)) - .map(|p| p.borrow().get_parent_name()) - .chain(iter::once(s.comp.borrow().name())); - self.all_reads.extend(cells); + self.visit_invoke(&s.comp, &s.inputs, &s.outputs, &s.ref_cells); + Ok(Action::Continue) + } + + fn static_invoke( + &mut self, + s: &mut ir::StaticInvoke, + _comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + self.visit_invoke(&s.comp, &s.inputs, &s.outputs, &s.ref_cells); Ok(Action::Continue) } @@ -99,12 +129,14 @@ impl Visitor for DeadCellRemoval { _sigs: &ir::LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - // Add @external cells. + // Add @external cells and ref cells. self.all_reads.extend( comp.cells .iter() .filter(|c| { - c.borrow().attributes.get(ir::BoolAttr::External).is_some() + let cell = c.borrow(); + cell.attributes.get(ir::BoolAttr::External).is_some() + || cell.is_reference() }) .map(|c| c.borrow().name()), ); diff --git a/tests/passes/cell-share/empty-invoke.expect b/tests/passes/cell-share/empty-invoke.expect new file mode 100644 index 000000000..98918ce5a --- /dev/null +++ b/tests/passes/cell-share/empty-invoke.expect @@ -0,0 +1,58 @@ +import "primitives/core.futil"; +component write_one<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + @data x = std_reg(32); + } + wires { + group invoke0<"promote_static"=1> { + x.write_en = 1'd1; + invoke0[done] = x.done; + x.in = 32'd1; + } + out = x.out; + } + control { + @promote_static invoke0; + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external @data mem = std_mem_d1(32, 2, 1); + @data x = write_one(); + } + wires { + group invoke0 { + x.go = 1'd1; + invoke0[done] = x.done; + } + group invoke1 { + x.go = 1'd1; + invoke1[done] = x.done; + } + group invoke2<"promote_static"=1> { + mem.write_en = 1'd1; + invoke2[done] = mem.done; + mem.addr0 = 1'd0; + mem.write_data = x.out; + } + group invoke3 { + x.go = 1'd1; + invoke3[done] = x.done; + } + group invoke4<"promote_static"=1> { + mem.write_en = 1'd1; + invoke4[done] = mem.done; + mem.addr0 = 1'd1; + mem.write_data = x.out; + } + } + control { + seq { + invoke0; + invoke1; + @promote_static invoke2; + invoke3; + @promote_static invoke4; + } + } +} diff --git a/tests/passes/cell-share/empty-invoke.futil b/tests/passes/cell-share/empty-invoke.futil new file mode 100644 index 000000000..604f39407 --- /dev/null +++ b/tests/passes/cell-share/empty-invoke.futil @@ -0,0 +1,33 @@ +// -p pre-opt -p post-opt +import "primitives/core.futil"; + +component write_one() -> (out: 32) { + cells { + x = std_reg(32); + } + wires { + out = x.out; + } + control { + invoke x(in = 32'd1)(); + } +} + +component main() -> () { + cells { + @external mem = std_mem_d1(32, 2, 1); + // these should be shared + x = write_one(); + y = write_one(); + } + wires {} + control { + seq { + invoke x()(); + invoke y()(); // x is dead here + invoke mem(addr0 = 1'd0, write_data = y.out)(); + invoke x()(); + invoke mem(addr0 = 1'd1, write_data = x.out)(); + } + } +} diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect new file mode 100644 index 000000000..9a7e2e66b --- /dev/null +++ b/tests/passes/cell-share/inline.expect @@ -0,0 +1,66 @@ +import "primitives/core.futil"; +component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: 32, @done done: 1) { + cells { + @data r = std_reg(32); + } + wires { + group invoke0<"promote_static"=1> { + r.write_en = 1'd1; + invoke0[done] = r.done; + r.in = in; + } + out = r.out; + } + control { + @promote_static invoke0; + } +} +static<4> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external @data mem = std_mem_d1(32, 2, 1); + @generated r = std_reg(32); + } + wires { + static<1> group invoke00 { + r.write_en = 1'd1; + r.in = 32'd0; + } + static<1> group invoke10 { + mem.write_en = 1'd1; + mem.addr0 = 1'd0; + mem.write_data = r.out; + } + static<1> group invoke20 { + r.write_en = 1'd1; + r.in = 32'd1; + } + static<1> group invoke30 { + mem.write_en = 1'd1; + mem.addr0 = 1'd1; + mem.write_data = r.out; + } + static<1> group no-op { + } + static<2> group no-op0 { + } + static<3> group no-op1 { + } + } + control { + static<4> par { + invoke00; + static<2> seq { + no-op; + invoke10; + } + static<3> seq { + no-op0; + invoke20; + } + static<4> seq { + no-op1; + invoke30; + } + } + } +} diff --git a/tests/passes/cell-share/inline.futil b/tests/passes/cell-share/inline.futil new file mode 100644 index 000000000..f3ce49193 --- /dev/null +++ b/tests/passes/cell-share/inline.futil @@ -0,0 +1,32 @@ +// -p pre-opt -p post-opt +import "primitives/core.futil"; + +component my_reg<"state_share"=1>(@data in: 32) -> (@stable out: 32) { + cells { + r = std_reg(32); + } + wires { + out = r.out; + } + control { + invoke r(in = in)(); + } +} + +component main() -> () { + cells { + @external mem = std_mem_d1(32, 2, 1); + // the two `std_reg` created after inlining should be shared + @inline r0 = my_reg(); + @inline r1 = my_reg(); + } + wires {} + control { + seq { + invoke r0(in = 32'd0)(); + invoke mem(addr0 = 1'd0, write_data = r0.out)(); + invoke r1(in = 32'd1)(); + invoke mem(addr0 = 1'd1, write_data = r1.out)(); + } + } +} diff --git a/tests/passes/cell-share/ref-share.expect b/tests/passes/cell-share/ref-share.expect index fcf531a2c..055c6293d 100644 --- a/tests/passes/cell-share/ref-share.expect +++ b/tests/passes/cell-share/ref-share.expect @@ -26,6 +26,8 @@ component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { f = foo(); + r1 = std_reg(32); + r2 = std_reg(32); } wires {} control { From a0867960c7840db1b83ee24a2ae65330083d2c23 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:16:14 -0400 Subject: [PATCH 084/189] Promotion Heurisitcs (subsumes #1750) (#1758) * first attempt * added test cases * clippy * comments * no loop setting * compile repeat better * rewrite tests * support invokes * style * clippy * small change --- calyx-ir/src/control.rs | 11 + calyx-opt/src/passes/compile_repeat.rs | 8 + calyx-opt/src/passes/static_promotion.rs | 712 +++++++++++++----- tests/passes/compile-repeat/nested.expect | 8 +- tests/passes/compile-repeat/simple.expect | 4 +- .../static-promotion/no_promote_loop.expect | 39 + .../static-promotion/no_promote_loop.futil | 42 ++ .../static-promotion/promote-nested.expect | 54 ++ .../static-promotion/promote-nested.futil | 59 ++ .../passes/static-promotion/threshold.expect | 33 + tests/passes/static-promotion/threshold.futil | 36 + .../static-promotion/upgrade-bound.expect | 2 +- 12 files changed, 827 insertions(+), 181 deletions(-) create mode 100644 tests/passes/static-promotion/no_promote_loop.expect create mode 100644 tests/passes/static-promotion/no_promote_loop.futil create mode 100644 tests/passes/static-promotion/promote-nested.expect create mode 100644 tests/passes/static-promotion/promote-nested.futil create mode 100644 tests/passes/static-promotion/threshold.expect create mode 100644 tests/passes/static-promotion/threshold.futil diff --git a/calyx-ir/src/control.rs b/calyx-ir/src/control.rs index c436513e8..a64005e09 100644 --- a/calyx-ir/src/control.rs +++ b/calyx-ir/src/control.rs @@ -589,6 +589,17 @@ impl Control { let empty = Control::empty(); std::mem::replace(self, empty) } + + /// Replaces &mut self with an empty control statement, and returns StaticControl + /// of self. Note that this only works on Control that is static + pub fn take_static_control(&mut self) -> StaticControl { + let empty = Control::empty(); + let control = std::mem::replace(self, empty); + let Control::Static(static_control) = control else { + unreachable!("Called take_static_control on non-static control") + }; + static_control + } } impl StaticControl { diff --git a/calyx-opt/src/passes/compile_repeat.rs b/calyx-opt/src/passes/compile_repeat.rs index ffe707ea9..17c35ace4 100644 --- a/calyx-opt/src/passes/compile_repeat.rs +++ b/calyx-opt/src/passes/compile_repeat.rs @@ -66,6 +66,10 @@ impl Visitor for CompileRepeat { ) .to_vec(); init_group.borrow_mut().assignments = init_assigns; + init_group + .borrow_mut() + .attributes + .insert(ir::NumAttr::PromoteStatic, 1); // incr_group: // 1) writes results of idx + 1 into idx (i.e., increments idx) // 2) writes the result of (idx + 1 < num_repeats) into cond_reg, @@ -84,6 +88,10 @@ impl Visitor for CompileRepeat { ) .to_vec(); incr_group.borrow_mut().assignments = idx_incr_assigns; + incr_group + .borrow_mut() + .attributes + .insert(ir::NumAttr::PromoteStatic, 1); // create control: // init_group; while cond_reg.out {repeat_body; incr_group;} let while_body = ir::Control::seq(vec![ diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index f71a4934d..0236941a1 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -1,15 +1,19 @@ -use crate::analysis::{GraphAnalysis, IntoStatic, ReadWriteSet}; +use crate::analysis::{GraphAnalysis, ReadWriteSet}; use crate::traversal::{ Action, ConstructVisitor, Named, Order, VisResult, Visitor, }; use calyx_ir::{self as ir, LibrarySignatures, RRC}; use calyx_utils::{CalyxResult, Error}; -use ir::{GetAttributes, StaticControl}; +use ir::GetAttributes; use itertools::Itertools; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::num::NonZeroU64; use std::rc::Rc; +const APPROX_ENABLE_SIZE: u64 = 1; +const APPROX_IF_SIZE: u64 = 3; +const APPROX_WHILE_REPEAT_SIZE: u64 = 3; + /// Struct to store information about the go-done interfaces defined by a primitive. #[derive(Default, Debug)] struct GoDone { @@ -134,6 +138,12 @@ pub struct StaticPromotion { latency_data: HashMap, /// dynamic group Id -> promoted static group Id static_group_name: HashMap, + /// Maps static component names to their latencies + static_component_latencies: HashMap, + /// Threshold for promotion + threshold: u64, + /// Whether we should stop promoting when we see a loop. + stop_loop: bool, } // Override constructor to build latency_data information from the primitives @@ -167,9 +177,13 @@ impl ConstructVisitor for StaticPromotion { } latency_data.insert(prim.name, GoDone::new(go_ports)); } + let (threshold, stop_loop) = Self::get_threshold(ctx); Ok(StaticPromotion { latency_data, static_group_name: HashMap::new(), + static_component_latencies: HashMap::new(), + threshold, + stop_loop, }) } @@ -190,6 +204,54 @@ impl Named for StaticPromotion { } impl StaticPromotion { + // Looks through ctx to get the given command line threshold. + // Default threshold = 1 + fn get_threshold(ctx: &ir::Context) -> (u64, bool) + where + Self: Named, + { + let n = Self::name(); + + // getting the given opts for -x cell-share:__ + let given_opts: HashSet<_> = ctx + .extra_opts + .iter() + .filter_map(|opt| { + let mut splits = opt.split(':'); + if splits.next() == Some(n) { + splits.next() + } else { + None + } + }) + .collect(); + + let mut stop_loop = false; + given_opts.iter().for_each(|arg| { + if *arg == "stop_loop" { + stop_loop = true + } + }); + + // searching for "-x static-promotion:threshold=1" and getting back "1" + let threshold: Option<&str> = given_opts.iter().find_map(|arg| { + let split: Vec<&str> = arg.split('=').collect(); + if let Some(str) = split.first() { + if str == &"threshold" { + return Some(split[1]); + } + } + None + }); + + // Need to convert string argument into int argument + // Always default to threshold=1 + ( + threshold.unwrap_or("1").parse::().unwrap_or(1), + stop_loop, + ) + } + /// Return true if the edge (`src`, `dst`) meet one these criteria, and false otherwise: /// - `src` is an "out" port of a constant, and `dst` is a "go" port /// - `src` is a "done" port, and `dst` is a "go" port @@ -417,30 +479,45 @@ impl StaticPromotion { Some(latency_sum) } - /// if we've already constructed the static group for the `ir::Enable`, then - /// just promote `Enable` to `StaticEnable` using the constructed `static group` - /// if not, then first construct `static group` and then promote `Enable` to - /// `StaticEnable` - fn construct_static_enable( + /// Gets the inferred latency, which should either be from being a static + /// control operator or the promote_static attribute. + /// Will raise an error if neither of these is true. + fn get_inferred_latency(c: &ir::Control) -> u64 { + let ir::Control::Static(sc) = c else { + let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) else { + unreachable!("Called get_latency on control that is neither static nor promotable") + }; + return latency; + }; + sc.get_latency() + } + + fn check_latencies_match(actual: u64, inferred: u64) { + assert_eq!(actual, inferred, "Inferred and Annotated Latencies do not match. Latency: {}. Inferred: {}", actual, inferred); + } + + /// Returns true if a control statement is already static, or has the static + /// attributes + fn can_be_promoted(c: &ir::Control) -> bool { + c.is_static() || c.has_attribute(ir::NumAttr::PromoteStatic) + } + + /// If we've already constructed the static group then use the already existing + /// group. Otherwise construct `static group` and then return that. + fn construct_static_group( &mut self, builder: &mut ir::Builder, - en: ir::Enable, - ) -> ir::StaticControl { - if let Some(s_name) = - self.static_group_name.get(&en.group.borrow().name()) + group: ir::RRC, + latency: u64, + ) -> ir::RRC { + if let Some(s_name) = self.static_group_name.get(&group.borrow().name()) { - ir::StaticControl::Enable(ir::StaticEnable { - group: builder.component.find_static_group(*s_name).unwrap(), - attributes: ir::Attributes::default(), - }) + builder.component.find_static_group(*s_name).unwrap() } else { - let sg = builder.add_static_group( - en.group.borrow().name(), - en.get_attributes().get(ir::NumAttr::PromoteStatic).unwrap(), - ); + let sg = builder.add_static_group(group.borrow().name(), latency); self.static_group_name - .insert(en.group.borrow().name(), sg.borrow().name()); - for assignment in en.group.borrow().assignments.iter() { + .insert(group.borrow().name(), sg.borrow().name()); + for assignment in group.borrow().assignments.iter() { if !(assignment.dst.borrow().is_hole() && assignment.dst.borrow().name == "done") { @@ -448,69 +525,271 @@ impl StaticPromotion { sg.borrow_mut().assignments.push(static_s); } } - ir::StaticControl::Enable(ir::StaticEnable { - group: Rc::clone(&sg), - attributes: ir::Attributes::default(), - }) + Rc::clone(&sg) } } - fn construct_static_seq( + /// Converts control to static control. + /// Control must already be static or have the `promote_static` attribute. + fn convert_to_static( &mut self, + c: &mut ir::Control, builder: &mut ir::Builder, - static_vec: &mut Vec, - ) -> ir::Control { - let mut latency = 0; - let mut static_seq_st: Vec = Vec::new(); - for s in std::mem::take(static_vec) { - match s { - ir::Control::Static(sc) => { - latency += sc.get_latency(); - static_seq_st.push(sc); - } - ir::Control::Enable(en) => { - let sen = self.construct_static_enable(builder, en); - latency += sen.get_latency(); - static_seq_st.push(sen); - } - _ => unreachable!("We do not insert non-static controls other than group enables with `promote_static` attribute") - } + ) -> ir::StaticControl { + assert!( + c.has_attribute(ir::NumAttr::PromoteStatic) || c.is_static(), + "Called convert_to_static control that is neither static nor promotable" + ); + // Need to get bound_attribute here, because we cannot borrow `c` within the + // pattern match. + let bound_attribute = c.get_attribute(ir::NumAttr::Bound); + // Inferred latency of entire control block. Used to double check our + // function is correct. + let inferred_latency = Self::get_inferred_latency(c); + match c { + ir::Control::Empty(_) => ir::StaticControl::empty(), + ir::Control::Enable(ir::Enable { group, attributes }) => { + // Removing the `promote_static` attribute bc we don't need it anymore. + attributes.remove(ir::NumAttr::PromoteStatic); + let enable = ir::StaticControl::Enable(ir::StaticEnable { + // upgrading group to static group + group: self.construct_static_group( + builder, + Rc::clone(group), + group + .borrow() + .get_attributes() + .unwrap() + .get(ir::NumAttr::PromoteStatic) + .unwrap(), + ), + attributes: std::mem::take(attributes), + }); + enable + } + ir::Control::Seq(ir::Seq { stmts, attributes }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // The resulting static seq should be compactable. + attributes.insert(ir::NumAttr::Compactable, 1); + let static_stmts = + self.convert_vec_to_static(builder, std::mem::take(stmts)); + let latency = + static_stmts.iter().map(|s| s.get_latency()).sum(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Seq(ir::StaticSeq { + stmts: static_stmts, + attributes: std::mem::take(attributes), + latency, + }) + } + ir::Control::Par(ir::Par { stmts, attributes }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // Convert stmts to static + let static_stmts = + self.convert_vec_to_static(builder, std::mem::take(stmts)); + // Calculate latency + let latency = static_stmts + .iter() + .map(|s| s.get_latency()) + .max() + .unwrap_or_else(|| unreachable!("Empty Par Block")); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Par(ir::StaticPar { + stmts: static_stmts, + attributes: ir::Attributes::default(), + latency, + }) + } + ir::Control::Repeat(ir::Repeat { + body, + num_repeats, + attributes, + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + let sc = self.convert_to_static(body, builder); + let latency = (*num_repeats) * sc.get_latency(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Repeat(ir::StaticRepeat { + attributes: std::mem::take(attributes), + body: Box::new(sc), + num_repeats: *num_repeats, + latency, + }) + } + ir::Control::While(ir::While { + body, attributes, .. + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // Removing the `bound` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::Bound); + let sc = self.convert_to_static(body, builder); + let num_repeats = bound_attribute.unwrap_or_else(|| unreachable!("Called convert_to_static on a while loop without a bound")); + let latency = num_repeats * sc.get_latency(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Repeat(ir::StaticRepeat { + attributes: std::mem::take(attributes), + body: Box::new(sc), + num_repeats, + latency, + }) + } + ir::Control::If(ir::If { + port, + tbranch, + fbranch, + attributes, + .. + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + let static_tbranch = self.convert_to_static(tbranch, builder); + let static_fbranch = self.convert_to_static(fbranch, builder); + let latency = std::cmp::max( + static_tbranch.get_latency(), + static_fbranch.get_latency(), + ); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::static_if( + Rc::clone(port), + Box::new(static_tbranch), + Box::new(static_fbranch), + latency, + ) + } + ir::Control::Static(_) => c.take_static_control(), + ir::Control::Invoke(ir::Invoke { + comp, + inputs, + outputs, + attributes, + comb_group, + ref_cells, + }) => { + assert!( + comb_group.is_none(), + "Shouldn't Promote to Static if there is a Comb Group", + ); + attributes.remove(ir::NumAttr::PromoteStatic); + Self::check_latencies_match(self.static_component_latencies.get( + &comp.borrow().type_name().unwrap_or_else(|| { + unreachable!( + "Already checked that comp is component" + ) + }), + ).unwrap_or_else(|| unreachable!("Called convert_to_static for static invoke that does not have a static component")).get(), inferred_latency); + let s_inv = ir::StaticInvoke { + comp: Rc::clone(comp), + inputs: std::mem::take(inputs), + outputs: std::mem::take(outputs), + latency: inferred_latency, + attributes: std::mem::take(attributes), + ref_cells: std::mem::take(ref_cells), + }; + ir::StaticControl::Invoke(s_inv) + } } - let mut attributes = ir::Attributes::default(); - attributes.insert(ir::NumAttr::Compactable, 1); - ir::Control::Static(StaticControl::Seq(ir::StaticSeq { - stmts: static_seq_st, - attributes, - latency, - })) } - fn construct_static_par( + /// Converts vec of control to vec of static control. + /// All control statements in the vec must be promotable or already static. + fn convert_vec_to_static( &mut self, builder: &mut ir::Builder, - s_stmts: &mut Vec, - ) -> ir::Control { - let mut latency = 0; - let mut static_par_st: Vec = Vec::new(); - for s in std::mem::take(s_stmts) { - match s { - ir::Control::Static(sc) => { - latency = std::cmp::max(latency, sc.get_latency()); - static_par_st.push(sc); - } - ir::Control::Enable(en) => { - let sen = self.construct_static_enable(builder, en); - latency = std::cmp::max(latency, sen.get_latency()); - static_par_st.push(sen); - } - _ => unreachable!("We do not insert non-static controls other than group enables with `promote_static` attribute") + control_vec: Vec, + ) -> Vec { + control_vec + .into_iter() + .map(|mut c| self.convert_to_static(&mut c, builder)) + .collect() + } + + /// Calculates the approximate "size" of the control statements. + /// Tries to approximate the number of dynamic FSM transitions that will occur + fn approx_size(c: &ir::Control) -> u64 { + match c { + ir::Control::Empty(_) => 0, + ir::Control::Enable(_) => APPROX_ENABLE_SIZE, + ir::Control::Seq(ir::Seq { stmts, .. }) + | ir::Control::Par(ir::Par { stmts, .. }) => { + stmts.iter().map(Self::approx_size).sum() + } + ir::Control::Repeat(ir::Repeat { body, .. }) + | ir::Control::While(ir::While { body, .. }) => { + Self::approx_size(body) + APPROX_WHILE_REPEAT_SIZE + } + ir::Control::If(ir::If { + tbranch, fbranch, .. + }) => { + Self::approx_size(tbranch) + + Self::approx_size(fbranch) + + APPROX_IF_SIZE + } + ir::Control::Static(_) => { + // static control appears as one big group to the dynamic FSM + 1 } + ir::Control::Invoke(_) => 1, } - ir::Control::Static(StaticControl::Par(ir::StaticPar { - stmts: static_par_st, - attributes: ir::Attributes::default(), - latency, - })) + } + + /// Uses `approx_size` function to sum the sizes of the control statements + /// in the given vector + fn approx_control_vec_size(v: &[ir::Control]) -> u64 { + v.iter().map(Self::approx_size).sum() + } + + /// First checks if the vec of control statements meets the self.threshold. + /// (That is, whether the combined approx_size of the static_vec is greater) + /// Than the threshold. + /// If so, converts vec of control to a static seq, and returns a vec containing + /// the static seq. + /// Otherwise, just returns the vec without changing it. + fn convert_vec_seq_if_threshold( + &mut self, + builder: &mut ir::Builder, + control_vec: Vec, + ) -> Vec { + if Self::approx_control_vec_size(&control_vec) <= self.threshold { + // Return unchanged vec + return control_vec; + } + // Convert vec to static seq + let s_seq_stmts = self.convert_vec_to_static(builder, control_vec); + let latency = s_seq_stmts.iter().map(|sc| sc.get_latency()).sum(); + let mut sseq = + ir::Control::Static(ir::StaticControl::seq(s_seq_stmts, latency)); + sseq.get_mut_attributes() + .insert(ir::NumAttr::Compactable, 1); + vec![sseq] + } + + /// First checks if the vec of control statements meets the self.threshold. + /// If so, converts vec of control to a static par, and returns a vec containing + /// the static par. + /// Otherwise, just returns the vec without changing it. + fn convert_vec_par_if_threshold( + &mut self, + builder: &mut ir::Builder, + control_vec: Vec, + ) -> Vec { + if Self::approx_control_vec_size(&control_vec) <= self.threshold { + // Return unchanged vec + return control_vec; + } + // Convert vec to static seq + let s_par_stmts = self.convert_vec_to_static(builder, control_vec); + let latency = s_par_stmts + .iter() + .map(|sc| sc.get_latency()) + .max() + .unwrap_or_else(|| unreachable!("empty par block")); + let spar = + ir::Control::Static(ir::StaticControl::par(s_par_stmts, latency)); + vec![spar] } } @@ -545,6 +824,10 @@ impl Visitor for StaticPromotion { } } } + if comp.is_static() { + self.static_component_latencies + .insert(comp.name, comp.latency.unwrap()); + } Ok(Action::Continue) } @@ -614,33 +897,16 @@ impl Visitor for StaticPromotion { s: &mut ir::Invoke, _comp: &mut ir::Component, _sigs: &LibrarySignatures, - comps: &[ir::Component], + _comps: &[ir::Component], ) -> VisResult { - if s.comp.borrow().is_component() { - let name = s.comp.borrow().type_name().unwrap(); - for c in comps { - if c.name == name && c.is_static() { - let emp = ir::Invoke { - comp: Rc::clone(&s.comp), - inputs: Vec::new(), - outputs: Vec::new(), - attributes: ir::Attributes::default(), - comb_group: None, - ref_cells: Vec::new(), - }; - let actual_invoke = std::mem::replace(s, emp); - let s_inv = ir::StaticInvoke { - comp: Rc::clone(&actual_invoke.comp), - inputs: actual_invoke.inputs, - outputs: actual_invoke.outputs, - latency: c.latency.unwrap().get(), - attributes: ir::Attributes::default(), - ref_cells: actual_invoke.ref_cells, - }; - return Ok(Action::change(ir::Control::Static( - ir::StaticControl::Invoke(s_inv), - ))); - } + // Shouldn't promote to static invoke if we have a comb group + if s.comp.borrow().is_component() && s.comb_group.is_none() { + if let Some(latency) = self + .static_component_latencies + .get(&s.comp.borrow().type_name().unwrap()) + { + s.attributes + .insert(ir::NumAttr::PromoteStatic, latency.get()); } } Ok(Action::Continue) @@ -654,45 +920,55 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); + let old_stmts = std::mem::take(&mut s.stmts); let mut new_stmts: Vec = Vec::new(); - let mut static_vec: Vec = Vec::new(); - for stmt in std::mem::take(&mut s.stmts) { - if stmt.is_static() - || stmt.has_attribute(ir::NumAttr::PromoteStatic) - { - static_vec.push(stmt); + let mut cur_vec: Vec = Vec::new(); + for stmt in old_stmts { + if Self::can_be_promoted(&stmt) { + cur_vec.push(stmt); } else { - // we do not promote if static_vec contains only 1 single enable - match static_vec.len().cmp(&1) { - std::cmp::Ordering::Equal => { - new_stmts.extend(static_vec); - } - std::cmp::Ordering::Greater => { - let sseq = self.construct_static_seq( - &mut builder, - &mut static_vec, - ); - new_stmts.push(sseq); - } - _ => {} - } + // Accumualte cur_vec into a static seq if it meets threshold + let possibly_promoted_stmts = + self.convert_vec_seq_if_threshold(&mut builder, cur_vec); + new_stmts.extend(possibly_promoted_stmts); + cur_vec = Vec::new(); + // Add the current (non-promotable) stmt new_stmts.push(stmt); - static_vec = Vec::new(); } } - if !static_vec.is_empty() { - if static_vec.len() == 1 { - new_stmts.extend(static_vec); + if new_stmts.is_empty() { + // The entire seq can be promoted + let approx_size: u64 = cur_vec.iter().map(Self::approx_size).sum(); + if approx_size > self.threshold { + // Promote entire seq to a static seq + let s_seq_stmts = + self.convert_vec_to_static(&mut builder, cur_vec); + let latency = + s_seq_stmts.iter().map(|sc| sc.get_latency()).sum(); + let mut sseq = ir::Control::Static(ir::StaticControl::seq( + s_seq_stmts, + latency, + )); + sseq.get_mut_attributes() + .insert(ir::NumAttr::Compactable, 1); + return Ok(Action::change(sseq)); } else { - let sseq = - self.construct_static_seq(&mut builder, &mut static_vec); - if new_stmts.is_empty() { - return Ok(Action::change(sseq)); - } else { - new_stmts.push(sseq); - } + // Doesn't meet threshold. + // Add attribute to seq so parent might promote it. + let inferred_latency = + cur_vec.iter().map(Self::get_inferred_latency).sum(); + s.attributes + .insert(ir::NumAttr::PromoteStatic, inferred_latency); + s.stmts = cur_vec; + return Ok(Action::Continue); } } + // Entire seq is not static, so we're only promoting the last + // bit of it if possible. + let possibly_promoted_stmts = + self.convert_vec_seq_if_threshold(&mut builder, cur_vec); + new_stmts.extend(possibly_promoted_stmts); + let new_seq = ir::Control::Seq(ir::Seq { stmts: new_stmts, attributes: ir::Attributes::default(), @@ -709,19 +985,44 @@ impl Visitor for StaticPromotion { ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); let mut new_stmts: Vec = Vec::new(); - let (mut s_stmts, d_stmts): (Vec, Vec) = + // Split the par into static and dynamic stmts + let (s_stmts, d_stmts): (Vec, Vec) = s.stmts.drain(..).partition(|s| { s.is_static() || s.get_attributes().has(ir::NumAttr::PromoteStatic) }); - if !s_stmts.is_empty() { - let s_par = self.construct_static_par(&mut builder, &mut s_stmts); - if d_stmts.is_empty() { - return Ok(Action::change(s_par)); + if d_stmts.is_empty() { + // Entire par block can be promoted to static + if Self::approx_control_vec_size(&s_stmts) > self.threshold { + // Promote entire par block to static + let static_par_stmts = + self.convert_vec_to_static(&mut builder, s_stmts); + let latency = static_par_stmts + .iter() + .map(|sc| sc.get_latency()) + .max() + .unwrap_or_else(|| unreachable!("empty par block")); + return Ok(Action::change(ir::Control::Static( + ir::StaticControl::par(static_par_stmts, latency), + ))); } else { - new_stmts.push(s_par); + // Doesn't meet threshold, but add promotion attribute since + // parent might want to promote it. + let inferred_latency = s_stmts + .iter() + .map(Self::get_inferred_latency) + .max() + .unwrap_or_else(|| unreachable!("empty par block")); + s.get_mut_attributes() + .insert(ir::NumAttr::PromoteStatic, inferred_latency); + s.stmts = s_stmts; + return Ok(Action::Continue); } } + // Otherwise just promote the par threads that we can into a static par + let s_stmts_possibly_promoted = + self.convert_vec_par_if_threshold(&mut builder, s_stmts); + new_stmts.extend(s_stmts_possibly_promoted); new_stmts.extend(d_stmts); let new_par = ir::Control::Par(ir::Par { stmts: new_stmts, @@ -733,14 +1034,46 @@ impl Visitor for StaticPromotion { fn finish_if( &mut self, s: &mut ir::If, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, + comp: &mut ir::Component, + sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if let Some(sif) = s.make_static() { - return Ok(Action::change(ir::Control::Static( - ir::StaticControl::If(sif), - ))); + let mut builder = ir::Builder::new(comp, sigs); + if Self::can_be_promoted(&s.tbranch) + && Self::can_be_promoted(&s.fbranch) + { + // Both branches can be promoted + let approx_size_if = Self::approx_size(&s.tbranch) + + Self::approx_size(&s.fbranch) + + APPROX_IF_SIZE; + if approx_size_if > self.threshold { + // Meets size threshold so promote to static + let static_tbranch = + self.convert_to_static(&mut s.tbranch, &mut builder); + let static_fbranch = + self.convert_to_static(&mut s.fbranch, &mut builder); + let latency = std::cmp::max( + static_tbranch.get_latency(), + static_fbranch.get_latency(), + ); + return Ok(Action::change(ir::Control::Static( + ir::StaticControl::static_if( + Rc::clone(&s.port), + Box::new(static_tbranch), + Box::new(static_fbranch), + latency, + ), + ))); + } else { + // Doesn't meet size threshold, so attach attribute + // so parent might be able to promote it. + let inferred_max_latency = std::cmp::max( + Self::get_inferred_latency(&s.tbranch), + Self::get_inferred_latency(&s.fbranch), + ); + s.get_mut_attributes() + .insert(ir::NumAttr::PromoteStatic, inferred_max_latency) + } } Ok(Action::Continue) } @@ -749,26 +1082,41 @@ impl Visitor for StaticPromotion { fn finish_while( &mut self, s: &mut ir::While, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, + comp: &mut ir::Component, + sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if s.body.is_static() { - // checks body is static and we have an @bound annotation - if let Some(num_repeats) = s.attributes.get(ir::NumAttr::Bound) { - let ir::Control::Static(sc) = s.body.take_control() else { - unreachable!("already checked that body is static"); - }; - let static_repeat = - ir::StaticControl::Repeat(ir::StaticRepeat { - latency: num_repeats * sc.get_latency(), - attributes: s.attributes.clone(), - body: Box::new(sc), + if self.stop_loop { + return Ok(Action::Continue); + } + let mut builder = ir::Builder::new(comp, sigs); + // First check that while loop is bounded + if let Some(num_repeats) = s.get_attributes().get(ir::NumAttr::Bound) { + // Then check that body is static/promotable + if Self::can_be_promoted(&s.body) { + let approx_size = + Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; + // Then check that it reaches the threshold + if approx_size > self.threshold { + // Turn repeat into static repeat + let sc = self.convert_to_static(&mut s.body, &mut builder); + let latency = sc.get_latency() * num_repeats; + let static_repeat = ir::StaticControl::repeat( num_repeats, - }); - return Ok(Action::Change(Box::new(ir::Control::Static( - static_repeat, - )))); + latency, + Box::new(sc), + ); + return Ok(Action::Change(Box::new(ir::Control::Static( + static_repeat, + )))); + } else { + // Attach static_promote attribute since parent control may + // want to promote + s.attributes.insert( + ir::NumAttr::PromoteStatic, + num_repeats * Self::get_inferred_latency(&s.body), + ) + } } } Ok(Action::Continue) @@ -778,23 +1126,39 @@ impl Visitor for StaticPromotion { fn finish_repeat( &mut self, s: &mut ir::Repeat, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, + comp: &mut ir::Component, + sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if s.body.is_static() { - let ir::Control::Static(sc) = s.body.take_control() else { - unreachable!("already checked that body is static"); - }; - let static_repeat = ir::StaticControl::Repeat(ir::StaticRepeat { - latency: s.num_repeats * sc.get_latency(), - attributes: s.attributes.clone(), - body: Box::new(sc), - num_repeats: s.num_repeats, - }); - return Ok(Action::Change(Box::new(ir::Control::Static( - static_repeat, - )))); + if self.stop_loop { + return Ok(Action::Continue); + } + let mut builder = ir::Builder::new(comp, sigs); + if Self::can_be_promoted(&s.body) { + // Body can be promoted + let approx_size = + Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; + if approx_size > self.threshold { + // Meets size threshold, so turn repeat into static repeat + let sc = self.convert_to_static(&mut s.body, &mut builder); + let latency = s.num_repeats * sc.get_latency(); + let static_repeat = ir::StaticControl::repeat( + s.num_repeats, + latency, + Box::new(sc), + ); + return Ok(Action::Change(Box::new(ir::Control::Static( + static_repeat, + )))); + } else { + // Doesn't meet threshold. + // Attach static_promote attribute since parent control may + // want to promote + s.attributes.insert( + ir::NumAttr::PromoteStatic, + s.num_repeats * Self::get_inferred_latency(&s.body), + ) + } } Ok(Action::Continue) } diff --git a/tests/passes/compile-repeat/nested.expect b/tests/passes/compile-repeat/nested.expect index a89f00381..fbc82c45a 100644 --- a/tests/passes/compile-repeat/nested.expect +++ b/tests/passes/compile-repeat/nested.expect @@ -17,14 +17,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r1.write_en = 1'd1; write_r1[done] = r1.done; } - group init_repeat { + group init_repeat<"promote_static"=1> { idx.write_en = 1'd1; idx.in = 2'd0; cond_reg.write_en = 1'd1; cond_reg.in = 1'd1; init_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group incr_repeat { + group incr_repeat<"promote_static"=1> { adder.left = idx.out; adder.right = 2'd1; lt.left = adder.out; @@ -35,14 +35,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { idx.in = adder.out; incr_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group init_repeat0 { + group init_repeat0<"promote_static"=1> { idx0.write_en = 1'd1; idx0.in = 3'd0; cond_reg0.write_en = 1'd1; cond_reg0.in = 1'd1; init_repeat0[done] = cond_reg0.done & idx0.done ? 1'd1; } - group incr_repeat0 { + group incr_repeat0<"promote_static"=1> { adder0.left = idx0.out; adder0.right = 3'd1; lt0.left = adder0.out; diff --git a/tests/passes/compile-repeat/simple.expect b/tests/passes/compile-repeat/simple.expect index bb0cc5644..feba5eaef 100644 --- a/tests/passes/compile-repeat/simple.expect +++ b/tests/passes/compile-repeat/simple.expect @@ -19,14 +19,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r2.write_en = 1'd1; write_r2[done] = r2.done; } - group init_repeat { + group init_repeat<"promote_static"=1> { idx.write_en = 1'd1; idx.in = 3'd0; cond_reg.write_en = 1'd1; cond_reg.in = 1'd1; init_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group incr_repeat { + group incr_repeat<"promote_static"=1> { adder.left = idx.out; adder.right = 3'd1; lt.left = adder.out; diff --git a/tests/passes/static-promotion/no_promote_loop.expect b/tests/passes/static-promotion/no_promote_loop.expect new file mode 100644 index 000000000..26a22869a --- /dev/null +++ b/tests/passes/static-promotion/no_promote_loop.expect @@ -0,0 +1,39 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + wires { + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + static<1> group C0 { + c.in = 2'd2; + c.write_en = 1'd1; + } + } + control { + seq { + repeat 10 { + @compactable static<4> seq { + A0; + B0; + C0; + C0; + } + } + @compactable static<3> seq { + A0; + B0; + C0; + } + } + } +} diff --git a/tests/passes/static-promotion/no_promote_loop.futil b/tests/passes/static-promotion/no_promote_loop.futil new file mode 100644 index 000000000..36d9575ca --- /dev/null +++ b/tests/passes/static-promotion/no_promote_loop.futil @@ -0,0 +1,42 @@ +// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:stop_loop + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + } + + control { + seq { + repeat 10 { + seq { A; B; C; C;} + } + A; + B; + C; + } + } +} diff --git a/tests/passes/static-promotion/promote-nested.expect b/tests/passes/static-promotion/promote-nested.expect new file mode 100644 index 000000000..cb4141c2a --- /dev/null +++ b/tests/passes/static-promotion/promote-nested.expect @@ -0,0 +1,54 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + cond_reg = std_reg(1); + r0 = std_reg(2); + } + wires { + group no_upgrade { + r0.write_en = 1'd1; + no_upgrade[done] = r0.done ? 1'd1; + } + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + static<1> group C0 { + c.in = 2'd2; + c.write_en = 1'd1; + } + } + control { + seq { + @compactable static<4> seq { + static<1> par { + A0; + B0; + } + @compactable static<2> seq { + C0; + C0; + } + static<1> par { + A0; + B0; + } + } + no_upgrade; + static repeat 2 { + @compactable static<3> seq { + A0; + B0; + C0; + } + } + } + } +} diff --git a/tests/passes/static-promotion/promote-nested.futil b/tests/passes/static-promotion/promote-nested.futil new file mode 100644 index 000000000..e3a49fbd5 --- /dev/null +++ b/tests/passes/static-promotion/promote-nested.futil @@ -0,0 +1,59 @@ +// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:threshold=5 + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + cond_reg = std_reg(1); + r0 = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + + group no_upgrade { + r0.write_en = 1'd1; + no_upgrade[done] = r0.done ? 1'd1; + } + } + + control { + seq { + seq { + par {A; B;} + seq {C; C;} + par {A; B;} + } + no_upgrade; + @bound(2) while cond_reg.out { + seq { + A; + B; + C; + } + } + } + + + + } +} diff --git a/tests/passes/static-promotion/threshold.expect b/tests/passes/static-promotion/threshold.expect new file mode 100644 index 000000000..976c597a7 --- /dev/null +++ b/tests/passes/static-promotion/threshold.expect @@ -0,0 +1,33 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group C<"promote_static"=1> { + c.in = 2'd2; + c.write_en = 1'd1; + C[done] = c.done; + } + } + control { + @promote_static(4) seq { + @promote_static A; + @promote_static B; + @promote_static C; + @promote_static C; + } + } +} diff --git a/tests/passes/static-promotion/threshold.futil b/tests/passes/static-promotion/threshold.futil new file mode 100644 index 000000000..10375bdec --- /dev/null +++ b/tests/passes/static-promotion/threshold.futil @@ -0,0 +1,36 @@ +// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:threshold=4 + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + } + + control { + // No promotion because size must be *greater* than the threshold + seq { A; B; C; C;} + } +} diff --git a/tests/passes/static-promotion/upgrade-bound.expect b/tests/passes/static-promotion/upgrade-bound.expect index fa3f416a1..9fc156ea6 100644 --- a/tests/passes/static-promotion/upgrade-bound.expect +++ b/tests/passes/static-promotion/upgrade-bound.expect @@ -21,7 +21,7 @@ static<15> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done don } } control { - @bound(5) static repeat 5 { + static repeat 5 { @compactable static<3> seq { A0; B0; From 9b5f23fbbc748285679c51aa6f924c66e17c0727 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Tue, 7 Nov 2023 13:08:45 -0500 Subject: [PATCH 085/189] Systolic Generation Optimization (#1760) * better systolic array * cleaner code * small chnage * metadata format * remove getters * flake8 * sort for testing * plz work * does this work * simple sort * another try * plzzzz workkk --- .../systolic-lang/gen_array_component.py | 308 +++--------------- .../systolic-lang/systolic_scheduling.py | 240 ++++++++++++++ tests/frontend/systolic/array-1.expect | 64 +--- 3 files changed, 309 insertions(+), 303 deletions(-) create mode 100644 frontends/systolic-lang/systolic_scheduling.py diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index a3f9070f9..76f09ae39 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -import numpy as np from gen_pe import pe, PE_NAME, BITWIDTH import calyx.builder as cb from calyx import py_ast from calyx.utils import bits_needed from systolic_arg_parser import SystolicConfiguration +from systolic_scheduling import gen_schedules # Global constant for the current bitwidth. DEPTH = "depth" @@ -33,44 +33,6 @@ } -class CalyxAdd: - """ - A class that represents addition in Calyx between a port and a constant - """ - - def __init__(self, port, const): - self.port = port - self.const = const - - def __eq__(self, other): - if type(other) != CalyxAdd: - return False - return ( - cb.ExprBuilder.unwrap(self.port) == cb.ExprBuilder.unwrap(other.port) - and self.const == other.const - ) - - def __hash__(self): - return hash(self.const) - - def __str__(self): - return ( - str(cb.ExprBuilder.unwrap(self.port).item.id.name) - + "_plus_" - + str(self.const) - ) - - def implement_add(self, comp: cb.ComponentBuilder) -> str: - """ - Implements the `CalyxAdd` by creating an adder that adds the two values - """ - if comp.try_get_cell(str(self)) is None: - add = comp.add(BITWIDTH, str(self)) - with comp.continuous: - add.left = self.port - add.right = self.const - - def add_systolic_output_params(comp: cb.ComponentBuilder, row_num, addr_width): """ Add output arguments to systolic array component `comp` for row `row_num`. @@ -161,21 +123,17 @@ def instantiate_data_move( from the `write` register of the PE at (row, col) to the read register of the PEs at (row+1, col) and (row, col+1) """ - name = f"pe_{row}_{col}" - if not right_edge: - group_name = NAME_SCHEME["register move right"].format(pe=name) src_reg = comp.get_cell(f"left_{row}_{col}") dst_reg = comp.get_cell(f"left_{row}_{col + 1}") - with comp.static_group(group_name, 1): + with comp.continuous: dst_reg.in_ = src_reg.out dst_reg.write_en = 1 if not down_edge: - group_name = NAME_SCHEME["register move down"].format(pe=name) src_reg = comp.get_cell(f"top_{row}_{col}") dst_reg = comp.get_cell(f"top_{row + 1}_{col}") - with comp.static_group(group_name, 1): + with comp.continuous: dst_reg.in_ = src_reg.out dst_reg.write_en = 1 @@ -211,19 +169,6 @@ def get_memory_updates(row, col): return mover_enables -def get_pe_moves(r, c, top_length, left_length): - """ - Gets the PE moves for the PE at (r,c) - """ - pe_moves = [] - if r < left_length - 1: - pe_moves.append(NAME_SCHEME["register move down"].format(pe=f"pe_{r}_{c}")) - if c < top_length - 1: - pe_moves.append(NAME_SCHEME["register move right"].format(pe=f"pe_{r}_{c}")) - pe_enables = [py_ast.Enable(name) for name in pe_moves] - return pe_enables - - def get_pe_invoke(r, c, mul_ready): """ gets the PE invokes for the PE at (r,c). mul_ready signals whether 1 or 0 @@ -239,7 +184,7 @@ def get_pe_invoke(r, c, mul_ready): ), ( "mul_ready", - py_ast.ConstantPort(1, mul_ready), + mul_ready, ), ], out_connects=[], @@ -292,158 +237,25 @@ def instantiate_idx_groups(comp: cb.ComponentBuilder, config: SystolicConfigurat lt_iter_limit.right = iter_limit.out -def instantiate_calyx_adds(comp, nec_ranges) -> list: - """ - Instantiates the CalyxAdd objects to adders and actual groups that perform the - specified add. - Returns a list of all the group names that we created. - """ - for lo, hi in nec_ranges: - if type(lo) == CalyxAdd: - lo.implement_add(comp) - if type(hi) == CalyxAdd: - hi.implement_add(comp) - - -def check_idx_lower_bound(comp: cb.ComponentBuilder, lo): - """ - Creates assignments to test if idx >= lo - """ - if type(lo) == CalyxAdd: - lo_value = comp.get_cell(str(lo)).port("out") - else: - lo_value = lo - idx = comp.get_cell("idx") - index_ge = f"index_ge_{lo}" - ge = comp.ge(BITWIDTH, index_ge) - with comp.continuous: - ge.left = idx.out - ge.right = lo_value - - -def check_idx_upper_bound(comp: cb.ComponentBuilder, hi): - """ - Creates assignments to test if idx < hi - """ - if type(hi) == CalyxAdd: - hi_value = comp.get_cell(str(hi)).port("out") - else: - hi_value = hi - idx = comp.get_cell("idx") - index_lt = f"index_lt_{hi}" - lt = comp.lt(BITWIDTH, index_lt) - with comp.continuous: - lt.left = idx.out - lt.right = hi_value - - -def check_idx_between(comp: cb.ComponentBuilder, lo, hi) -> list: - """ - Creates assignments to check whether idx is between [lo, hi). - That is, whether lo <= idx < hi. - """ - # This is the name of the combinational cell that checks the condition - idx_between_str = f"idx_between_{lo}_{hi}_comb" - lt = comp.get_cell(f"index_lt_{hi}") - # if lo == 0, then only need to check if reg < hi - if type(lo) == int and lo == 0: - # In this case, the `wire` cell is the cell checking the condition. - wire = comp.wire(idx_between_str, 1) - with comp.continuous: - wire.in_ = lt.out - # need to check if reg >= lo and reg < hi - else: - ge = comp.get_cell(f"index_ge_{lo}") - # In this case, the `and` cell is the cell checking the condition. - and_ = comp.and_(1, idx_between_str) - with comp.continuous: - and_.right = lt.out - and_.left = ge.out - - -def accum_nec_ranges(nec_ranges, schedule): - """ - Essentially creates a set that contains all of the idx ranges that - we need to check for (e.g., [1,3) [2,4)] in order to realize - the schedule - - nec_ranges is a set of tuples. - schedule is either a 2d array or 1d array with tuple (start,end) entries. - Adds all intervals (start,end) in schedule to nec_ranges if the it's - not already in nec_ranges. - """ - if schedule.ndim == 1: - for r in schedule: - nec_ranges.add(r) - elif schedule.ndim == 2: - for r in schedule: - for c in r: - nec_ranges.add(c) - else: - raise Exception("accum_nec_ranges expects only 1d or 2d arrays") - return nec_ranges - - -def gen_schedules( - config: SystolicConfiguration, - comp: cb.ComponentBuilder, -): +def execute_if_between(comp: cb.ComponentBuilder, start, end, body): """ - Generates 4 arrays that are the same size as the output (systolic) array - Each entry in the array has tuple [start, end) that indicates the cycles that - they are active - `update_sched` contains when to update the indices of the input memories and feed - them into the systolic array - `pe_fill_sched` contains when to invoke PE but not accumulate (bc the multipliers - are not ready with an output yet) - `pe_accum_sched` contains when to invoke PE and accumulate (bc the multipliers - are ready with an output) - `pe_move_sched` contains when to "move" the PE (i.e., pass data) - `pe_write_sched` contains when to "write" the PE value into the output ports - (e.g., this.r0_valid) + body is a list of control stmts + if body is empty, return an empty list + otherwise, builds an if stmt that executes body in parallel if + idx is between start and end """ - - def depth_plus_const(const: int): - """ - Returns depth + const. If config.static, then this is an int. - Otherwise, we need to perform a Calyx addition to figure this out. - """ - if config.static: - # return an int - return config.get_contraction_dimension() + const - else: - # return a CalyxAdd object, whose value is determined after generation - depth_port = comp.this().depth - return CalyxAdd(depth_port, const) - - left_length, top_length = config.left_length, config.top_length - - schedules = {} - update_sched = np.zeros((left_length, top_length), dtype=object) - pe_fill_sched = np.zeros((left_length, top_length), dtype=object) - pe_accum_sched = np.zeros((left_length, top_length), dtype=object) - pe_move_sched = np.zeros((left_length, top_length), dtype=object) - pe_write_sched = np.zeros((left_length, top_length), dtype=object) - for row in range(0, left_length): - for col in range(0, top_length): - pos = row + col - update_sched[row][col] = (pos, depth_plus_const(pos)) - pe_fill_sched[row][col] = (pos + 1, pos + 5) - pe_accum_sched[row][col] = (pos + 5, depth_plus_const(pos + 5)) - pe_move_sched[row][col] = (pos + 1, depth_plus_const(pos + 1)) - pe_write_sched[row][col] = ( - depth_plus_const(pos + 5), - depth_plus_const(pos + 6), - ) - schedules["update_sched"] = update_sched - schedules["fill_sched"] = pe_fill_sched - schedules["accum_sched"] = pe_accum_sched - schedules["move_sched"] = pe_move_sched - schedules["write_sched"] = pe_write_sched - return schedules + if not body: + return [] + if_cell = comp.get_cell(f"idx_between_{start}_{end}_comb") + return [ + cb.static_if( + if_cell.out, + py_ast.StaticParComp(body), + ) + ] -def execute_if_between(comp: cb.ComponentBuilder, start, end, body): +def execute_if_eq(comp: cb.ComponentBuilder, val, body): """ body is a list of control stmts if body is empty, return an empty list @@ -452,7 +264,7 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): """ if not body: return [] - if_cell = comp.get_cell(f"idx_between_{start}_{end}_comb") + if_cell = comp.get_cell(f"index_eq_{val}") return [ cb.static_if( if_cell.out, @@ -462,7 +274,7 @@ def execute_if_between(comp: cb.ComponentBuilder, start, end, body): def generate_control( - comp: cb.ComponentBuilder, config: SystolicConfiguration, schedules + comp: cb.ComponentBuilder, config: SystolicConfiguration, schedule ): """ Logically, control performs the following actions: @@ -500,51 +312,45 @@ def counter(): while_body_stmts = [py_ast.Enable("incr_idx")] for r in range(left_length): for c in range(top_length): - # build 4 if stmts for the 4 schedules that we need to account for + # Execute input_mem_updates = execute_if_between( comp, - schedules["update_sched"][r][c][0], - schedules["update_sched"][r][c][1], + schedule.mappings["update_sched"][r][c].i1, + schedule.mappings["update_sched"][r][c].i2, get_memory_updates(r, c), ) - pe_fills = execute_if_between( - comp, - schedules["fill_sched"][r][c][0], - schedules["fill_sched"][r][c][1], - [get_pe_invoke(r, c, 0)], - ) - pe_moves = execute_if_between( - comp, - schedules["move_sched"][r][c][0], - schedules["move_sched"][r][c][1], - get_pe_moves(r, c, top_length, left_length), + pe_accum_thresh = schedule.mappings["pe_accum_cond"][r][c].i1 + pe_accum_cond = py_ast.CompPort( + py_ast.CompVar(f"index_ge_{pe_accum_thresh}"), "out" ) - pe_accums = execute_if_between( + pe_executions = execute_if_between( comp, - schedules["accum_sched"][r][c][0], - schedules["accum_sched"][r][c][1], - [get_pe_invoke(r, c, 1)], + schedule.mappings["pe_sched"][r][c].i1, + schedule.mappings["pe_sched"][r][c].i2, + [get_pe_invoke(r, c, pe_accum_cond)], ) - output_writes = execute_if_between( + output_writes = execute_if_eq( comp, - schedules["write_sched"][r][c][0], - schedules["write_sched"][r][c][1], + schedule.mappings["pe_write_sched"][r][c].i1, [py_ast.Enable(NAME_SCHEME["out write"].format(pe=f"pe_{r}_{c}"))], ) - pe_control = ( - input_mem_updates + pe_fills + pe_moves + pe_accums + output_writes + while_body_stmts.append( + py_ast.StaticParComp(input_mem_updates + pe_executions + output_writes) ) - while_body_stmts.append(py_ast.StaticParComp(pe_control)) # providing metadata tag = counter() + boundary_fill_sched = "" + if r == 0 or c == 0: + boundary_fill_sched = f"Feeding Boundary PE: \ +[{schedule.mappings['update_sched'][r][c].i1},\ +{schedule.mappings['update_sched'][r][c].i2}) || " source_map[ tag - ] = f"pe_{r}_{c} filling: [{schedules['fill_sched'][r][c][0]},\ -{schedules['fill_sched'][r][c][1]}), \ -accumulating: [{schedules['accum_sched'][r][c][0]} \ -{schedules['accum_sched'][r][c][1]}), \ -writing: [{schedules['write_sched'][r][c][0]} \ -{schedules['write_sched'][r][c][1]})" + ] = f"pe_{r}_{c}: \ +{boundary_fill_sched}\ +Invoking PE: [{schedule.mappings['pe_sched'][r][c].i1}, \ +{schedule.mappings['pe_sched'][r][c].i2}) || \ +Writing PE Result: {schedule.mappings['pe_write_sched'][r][c].i1}" while_body = py_ast.StaticParComp(while_body_stmts) @@ -575,24 +381,16 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): # initialize the iteration limit to top_length + left_length + depth + 4 init_iter_limit(computational_unit, depth_port, config) - schedules = gen_schedules(config, computational_unit) - nec_ranges = set() - for sched in schedules.values(): - accum_nec_ranges(nec_ranges, sched) - instantiate_calyx_adds(computational_unit, nec_ranges) + # Generate the Schedule + schedule = gen_schedules(config, computational_unit) # instantiate groups that handles the idx variables instantiate_idx_groups(computational_unit, config) - list1, list2 = zip(*nec_ranges) - nec_ranges_beg = set(list1) - nec_ranges_end = set(list2) - for val in nec_ranges_beg: - check_idx_lower_bound(computational_unit, val) - for val in nec_ranges_end: - check_idx_upper_bound(computational_unit, val) - for start, end in nec_ranges: - # create the assignments that help determine if idx is in between - check_idx_between(computational_unit, start, end) + + # Generate the hardware For the schedule + schedule.build_hardware( + computational_unit, idx_reg=computational_unit.get_cell("idx") + ) for row in range(config.left_length): for col in range(config.top_length): @@ -629,6 +427,6 @@ def create_systolic_array(prog: cb.Builder, config: SystolicConfiguration): instantiate_output_move(computational_unit, row, col) # Generate the control and set the source map - control, source_map = generate_control(computational_unit, config, schedules) + control, source_map = generate_control(computational_unit, config, schedule) computational_unit.control = control prog.program.meta = source_map diff --git a/frontends/systolic-lang/systolic_scheduling.py b/frontends/systolic-lang/systolic_scheduling.py new file mode 100644 index 000000000..9e36e1d74 --- /dev/null +++ b/frontends/systolic-lang/systolic_scheduling.py @@ -0,0 +1,240 @@ +import calyx.builder as cb +from gen_pe import BITWIDTH +from enum import Enum +from systolic_arg_parser import SystolicConfiguration +import numpy as np + + +class CalyxAdd: + """ + A class that represents addition in Calyx between a port and a constant + """ + + def __init__(self, port, const): + self.port = port + self.const = const + + def __eq__(self, other): + if type(other) != CalyxAdd: + return False + return ( + cb.ExprBuilder.unwrap(self.port) == cb.ExprBuilder.unwrap(other.port) + and self.const == other.const + ) + + def __hash__(self): + return hash(self.const) + + def __str__(self): + return ( + str(cb.ExprBuilder.unwrap(self.port).item.id.name) + + "_plus_" + + str(self.const) + ) + + def implement_add(self, comp: cb.ComponentBuilder) -> str: + """ + Implements the `CalyxAdd` by creating an adder that adds the two values + """ + if comp.try_get_cell(str(self)) is None: + add = comp.add(BITWIDTH, str(self)) + with comp.continuous: + add.left = self.port + add.right = self.const + + +class ScheduleType(Enum): + GE = 1 + LT = 2 + EQ = 3 + INTERVAL = 4 + + +class ScheduleInstance: + def __init__(self, type: ScheduleType, i1, i2=None): + self.type = type + self.i1 = i1 + self.i2 = i2 + if type == ScheduleType.INTERVAL and self.i2 is None: + raise Exception("INTERVAL type must specify beginning and end") + + def __lt__(self, other): + return (self.type, self.i1, self.i2) < (other.type, other.i1, other.i2) + + +class Schedule: + def __init__(self): + # XXX(Caleb): self.instances could be a set, but I'm running into annoying + # ordering errors on tests. Python dictionaries are luckily ordered. + self.instances = {} + self.mappings = {} + + def add_instances(self, name, schedule_instances): + """ """ + self.mappings[name] = schedule_instances + for schedule_instance in schedule_instances.flatten(): + self.instances[schedule_instance] = None + + def __instantiate_calyx_adds(self, comp) -> list: + """ """ + for schedule_instance in self.instances.keys(): + if type(schedule_instance.i1) == CalyxAdd: + schedule_instance.i1.implement_add(comp) + if type(schedule_instance.i2) == CalyxAdd: + schedule_instance.i2.implement_add(comp) + + def __check_idx_eq(self, comp: cb.ComponentBuilder, idx_reg: cb.CellBuilder, eq): + """ + Creates assignments to test if idx >= lo + """ + if type(eq) == CalyxAdd: + eq_value = comp.get_cell(str(eq)).port("out") + else: + eq_value = eq + eq = comp.eq(BITWIDTH, f"index_eq_{eq}") + with comp.continuous: + eq.left = idx_reg.out + eq.right = eq_value + + def __check_idx_lower_bound( + self, comp: cb.ComponentBuilder, idx_reg: cb.CellBuilder, lo + ): + """ + Creates assignments to test if idx >= lo + """ + if type(lo) == int and lo == 0: + return + if type(lo) == CalyxAdd: + lo_value = comp.get_cell(str(lo)).port("out") + else: + lo_value = lo + ge = comp.ge(BITWIDTH, f"index_ge_{lo}") + with comp.continuous: + ge.left = idx_reg.out + ge.right = lo_value + + def __check_idx_upper_bound( + self, comp: cb.ComponentBuilder, idx_reg: cb.CellBuilder, hi + ): + """ + Creates assignments to test if idx < hi + """ + if type(hi) == CalyxAdd: + hi_value = comp.get_cell(str(hi)).port("out") + else: + hi_value = hi + lt = comp.lt(BITWIDTH, f"index_lt_{hi}") + with comp.continuous: + lt.left = idx_reg.out + lt.right = hi_value + + def __check_idx_between(self, comp: cb.ComponentBuilder, lo, hi) -> list: + """ + Creates assignments to check whether idx is between [lo, hi). + That is, whether lo <= idx < hi. + IMPORTANT: Assumes the lt and gt cells ahve already been created + """ + # This is the name of the combinational cell that checks the condition + idx_between_str = f"idx_between_{lo}_{hi}_comb" + lt = comp.get_cell(f"index_lt_{hi}") + # if lo == 0, then only need to check if reg < hi + if type(lo) == int and lo == 0: + # In this case, the `wire` cell is the cell checking the condition. + wire = comp.wire(idx_between_str, 1) + with comp.continuous: + wire.in_ = lt.out + # need to check if reg >= lo and reg < hi + else: + ge = comp.get_cell(f"index_ge_{lo}") + # In this case, the `and` cell is the cell checking the condition. + and_ = comp.and_(1, idx_between_str) + with comp.continuous: + and_.right = lt.out + and_.left = ge.out + + def build_hardware(self, comp: cb.ComponentBuilder, idx_reg: cb.CellBuilder): + """ """ + # instantiate groups that handles the idx variables + # Dictionary to keep consistent ordering. + ge_ranges = {} + lt_ranges = {} + eq_ranges = {} + interval_ranges = {} + for schedule_instance in self.instances.keys(): + sched_type = schedule_instance.type + if sched_type == ScheduleType.GE: + ge_ranges[schedule_instance.i1] = None + elif sched_type == ScheduleType.LT: + lt_ranges[schedule_instance.i1] = None + elif sched_type == ScheduleType.EQ: + eq_ranges[schedule_instance.i1] = None + elif sched_type == ScheduleType.INTERVAL: + ge_ranges[schedule_instance.i1] = None + lt_ranges[schedule_instance.i2] = None + interval_ranges[(schedule_instance.i1, schedule_instance.i2)] = None + self.__instantiate_calyx_adds(comp) + # Need to sort for testing purposes + for val in eq_ranges: + self.__check_idx_eq(comp, idx_reg, val) + for val in ge_ranges: + self.__check_idx_lower_bound(comp, idx_reg, val) + for val in lt_ranges: + self.__check_idx_upper_bound(comp, idx_reg, val) + for start, end in interval_ranges: + self.__check_idx_between(comp, start, end) + + +def gen_schedules( + config: SystolicConfiguration, + comp: cb.ComponentBuilder, +): + """ + Generates 4 arrays that are the same size as the output (systolic) array + Each entry in the array has tuple [start, end) that indicates the cycles that + they are active + `update_sched` contains when to update the indices of the input memories and feed + them into the systolic array + `pe_sched` contains when to invoke PE + `pe_accum_cond` contains when to allow the PEs to accumulate (bc the multipliers + are ready with an output) + `pe_write_sched` contains when to "write" the PE value into the output ports + (e.g., this.r0_valid) + """ + + def depth_plus_const(const: int): + """ + Returns depth + const. If config.static, then this is an int. + Otherwise, we need to perform a Calyx addition to figure this out. + """ + if config.static: + # return an int + return config.get_contraction_dimension() + const + else: + # return a CalyxAdd object, whose value is determined after generation + depth_port = comp.this().depth + return CalyxAdd(depth_port, const) + + left_length, top_length = config.left_length, config.top_length + update_sched = np.zeros((left_length, top_length), dtype=object) + pe_sched = np.zeros((left_length, top_length), dtype=object) + pe_accum_cond = np.zeros((left_length, top_length), dtype=object) + pe_write_sched = np.zeros((left_length, top_length), dtype=object) + for row in range(0, left_length): + for col in range(0, top_length): + pos = row + col + update_sched[row][col] = ScheduleInstance( + ScheduleType.INTERVAL, pos, depth_plus_const(pos) + ) + pe_sched[row][col] = ScheduleInstance( + ScheduleType.INTERVAL, pos + 1, depth_plus_const(pos + 5) + ) + pe_accum_cond[row][col] = ScheduleInstance(ScheduleType.GE, pos + 5) + pe_write_sched[row][col] = ScheduleInstance( + ScheduleType.EQ, depth_plus_const(pos + 5) + ) + schedule = Schedule() + schedule.add_instances("update_sched", update_sched) + schedule.add_instances("pe_sched", pe_sched) + schedule.add_instances("pe_accum_cond", pe_accum_cond) + schedule.add_instances("pe_write_sched", pe_write_sched) + return schedule diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 1c7b2f703..a0a53c6bf 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -31,27 +31,18 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> cells { iter_limit = std_reg(32); iter_limit_add = std_add(32); - depth_plus_5 = std_add(32); - depth_plus_0 = std_add(32); - depth_plus_1 = std_add(32); - depth_plus_6 = std_add(32); idx = std_reg(32); idx_add = std_add(32); lt_iter_limit = std_lt(32); - index_ge_0 = std_ge(32); + depth_plus_0 = std_add(32); + depth_plus_5 = std_add(32); + index_eq_depth_plus_5 = std_eq(32); index_ge_1 = std_ge(32); - index_ge_depth_plus_5 = std_ge(32); index_ge_5 = std_ge(32); index_lt_depth_plus_0 = std_lt(32); - index_lt_depth_plus_1 = std_lt(32); - index_lt_5 = std_lt(32); index_lt_depth_plus_5 = std_lt(32); - index_lt_depth_plus_6 = std_lt(32); - idx_between_5_depth_plus_5_comb = std_and(1); - idx_between_1_5_comb = std_and(1); idx_between_0_depth_plus_0_comb = std_wire(1); - idx_between_1_depth_plus_1_comb = std_and(1); - idx_between_depth_plus_5_depth_plus_6_comb = std_and(1); + idx_between_1_depth_plus_5_comb = std_and(1); pe_0_0 = mac_pe(); top_0_0 = std_reg(32); left_0_0 = std_reg(32); @@ -65,14 +56,6 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> iter_limit.in = iter_limit_add.out; iter_limit.write_en = 1'd1; } - depth_plus_5.left = depth; - depth_plus_5.right = 32'd5; - depth_plus_0.left = depth; - depth_plus_0.right = 32'd0; - depth_plus_1.left = depth; - depth_plus_1.right = 32'd1; - depth_plus_6.left = depth; - depth_plus_6.right = 32'd6; static<1> group init_idx { idx.in = 32'd0; idx.write_en = 1'd1; @@ -85,33 +68,23 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> } lt_iter_limit.left = idx.out; lt_iter_limit.right = iter_limit.out; - index_ge_0.left = idx.out; - index_ge_0.right = 32'd0; + depth_plus_0.left = depth; + depth_plus_0.right = 32'd0; + depth_plus_5.left = depth; + depth_plus_5.right = 32'd5; + index_eq_depth_plus_5.left = idx.out; + index_eq_depth_plus_5.right = depth_plus_5.out; index_ge_1.left = idx.out; index_ge_1.right = 32'd1; - index_ge_depth_plus_5.left = idx.out; - index_ge_depth_plus_5.right = depth_plus_5.out; index_ge_5.left = idx.out; index_ge_5.right = 32'd5; index_lt_depth_plus_0.left = idx.out; index_lt_depth_plus_0.right = depth_plus_0.out; - index_lt_depth_plus_1.left = idx.out; - index_lt_depth_plus_1.right = depth_plus_1.out; - index_lt_5.left = idx.out; - index_lt_5.right = 32'd5; index_lt_depth_plus_5.left = idx.out; index_lt_depth_plus_5.right = depth_plus_5.out; - index_lt_depth_plus_6.left = idx.out; - index_lt_depth_plus_6.right = depth_plus_6.out; - idx_between_5_depth_plus_5_comb.right = index_lt_depth_plus_5.out; - idx_between_5_depth_plus_5_comb.left = index_ge_5.out; - idx_between_1_5_comb.right = index_lt_5.out; - idx_between_1_5_comb.left = index_ge_1.out; idx_between_0_depth_plus_0_comb.in = index_lt_depth_plus_0.out; - idx_between_1_depth_plus_1_comb.right = index_lt_depth_plus_1.out; - idx_between_1_depth_plus_1_comb.left = index_ge_1.out; - idx_between_depth_plus_5_depth_plus_6_comb.right = index_lt_depth_plus_6.out; - idx_between_depth_plus_5_depth_plus_6_comb.left = index_ge_depth_plus_5.out; + idx_between_1_depth_plus_5_comb.right = index_lt_depth_plus_5.out; + idx_between_1_depth_plus_5_comb.left = index_ge_1.out; idx_minus_0.left = idx.out; idx_minus_0.right = 32'd0; idx_minus_0_res.in = idx_minus_0.out; @@ -147,17 +120,12 @@ component systolic_array_comp(depth: 32, t0_read_data: 32, l0_read_data: 32) -> t0_move; } } - static if idx_between_1_5_comb.out { - static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd0)(); - } - } - static if idx_between_5_depth_plus_5_comb.out { + static if idx_between_1_depth_plus_5_comb.out { static par { - static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=1'd1)(); + static invoke pe_0_0(top=top_0_0.out, left=left_0_0.out, mul_ready=index_ge_5.out)(); } } - static if idx_between_depth_plus_5_depth_plus_6_comb.out { + static if index_eq_depth_plus_5.out { static par { pe_0_0_out_write; } @@ -228,5 +196,5 @@ component main() -> () { } } metadata #{ -0: pe_0_0 filling: [1,5), accumulating: [5 depth_plus_5), writing: [depth_plus_5 depth_plus_6) +0: pe_0_0: Feeding Boundary PE: [0,depth_plus_0) || Invoking PE: [1, depth_plus_5) || Writing PE Result: depth_plus_5 }# From c56b5a08d6254b6113401012f17336cccb31e344 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:56:41 -0500 Subject: [PATCH 086/189] `fifo`: better testing (#1762) --- calyx-py/calyx/fifo_data_gen.py | 53 +++++++++++++++++++++++ calyx-py/calyx/fifo_oracle.py | 60 +++++++++++++++++++++++++++ calyx-py/test/correctness/fifo.data | 40 +++++++++--------- calyx-py/test/correctness/fifo.expect | 54 ++++++++++++------------ 4 files changed, 160 insertions(+), 47 deletions(-) create mode 100644 calyx-py/calyx/fifo_data_gen.py create mode 100644 calyx-py/calyx/fifo_oracle.py diff --git a/calyx-py/calyx/fifo_data_gen.py b/calyx-py/calyx/fifo_data_gen.py new file mode 100644 index 000000000..da07f57f4 --- /dev/null +++ b/calyx-py/calyx/fifo_data_gen.py @@ -0,0 +1,53 @@ +import random +import time +import json +from typing import Dict, Union + +MAX_CMDS = 15 +ANS_MEM_LEN = 10 + +FormatType = Dict[str, Union[bool, str, int]] + + +def format_gen(width: int) -> FormatType: + """Generates a format object for a bitvector of length `width`.""" + return {"is_signed": False, "numeric_type": "bitnum", "width": width} + + +def dump_json(): + """Prints a JSON representation of the data to stdout. + The data itself is populated randomly, following certain rules: + - It has three "memories": `commands`, `values`, and `ans_mem`. + - The `commands` memory has MAX_CMDS items, which are 0, 1, or 2. + - The `values` memory has MAX_CMDS items: random values between 0 and 100. + - The `ans_mem` memory has ANS_MEM_LEN items, all zeroes. + - Each memory has a `format` field, which is a format object for a bitvector. + """ + commands = { + "commands": { + "data": [random.randint(0, 2) for _ in range(MAX_CMDS)], + # The `commands` memory has MAX_CMDS items, which are 0, 1, or 2. + "format": format_gen(2), + } + } + values = { + "values": { + "data": [random.randint(0, 100) for _ in range(MAX_CMDS)], + # The `values` memory has MAX_CMDS items: random values between 0 and 100. + "format": format_gen(32), + } + } + ans_mem = { + "ans_mem": { + "data": [0 for _ in range(ANS_MEM_LEN)], + # The `ans_mem` memory has ANS_MEM_LEN items, all zeroes. + "format": format_gen(32), + } + } + + print(json.dumps(commands | values | ans_mem, indent=2)) + + +if __name__ == "__main__": + random.seed(5) + dump_json() diff --git a/calyx-py/calyx/fifo_oracle.py b/calyx-py/calyx/fifo_oracle.py new file mode 100644 index 000000000..6ca4fbd54 --- /dev/null +++ b/calyx-py/calyx/fifo_oracle.py @@ -0,0 +1,60 @@ +import sys +import json + + +def parse_json(): + """Effectively the opposite of `data_gen`: + Given a JSON file formatted for Calyx purposes, parse it into its two lists: + - The `commands` memory, which has MAX_CMDS items. + - The `values` memory, which has MAX_CMDS items. + Returns the two lists. + """ + + # The JSON file is piped to us in stdin. + data = json.load(sys.stdin) + commands = data["commands"]["data"] + values = data["values"]["data"] + return commands, values + + +def operate_fifo(commands, values): + """Given the three lists, operate a FIFO routine. + - Read the comammands list in order. + - When the value is 0, we "pop" the FIFO and write the value to the answer memory. + - When it is 1, we "peek" into the FIFO and write the value to the answer memory. + - When it is 2, we push the coressponding item in the `values` list to the FIFO. + + In the end, we return the answer memory. + """ + fifo = [] + ans = [] + for cmd, val in zip(commands, values): + if cmd == 0: + if len(fifo) == 0: + break + ans.append(fifo.pop(0)) + elif cmd == 1: + if len(fifo) == 0: + break + ans.append(fifo[0]) + elif cmd == 2: + fifo.append(val) + # Pad the answer memory with zeroes until it is of length ANS_MEM_LEN. + ans += [0] * (10 - len(ans)) + return ans + + +def dump_json(commands, values, ans_mem): + """Prints a JSON representation of the data to stdout.""" + payload = { + "ans_mem": ans_mem, + "commands": commands, + "values": values, + } + print(json.dumps(payload, indent=2)) + + +if __name__ == "__main__": + commands, values = parse_json() + ans = operate_fifo(commands, values) + dump_json(commands, values, ans) diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index f0c8359a9..65ab3d659 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -4,15 +4,15 @@ 2, 1, 2, - 2, - 0, - 2, - 2, + 1, 2, 2, 2, 2, 0, + 1, + 0, + 2, 0, 0, 0 @@ -25,21 +25,21 @@ }, "values": { "data": [ - 100, - 0, - 101, - 102, - 0, - 103, - 104, - 105, - 106, - 107, - 108, - 0, - 0, - 0, - 0 + 47, + 60, + 31, + 48, + 69, + 13, + 73, + 31, + 1, + 93, + 27, + 52, + 35, + 23, + 98 ], "format": { "is_signed": false, @@ -66,4 +66,4 @@ "width": 32 } } -} \ No newline at end of file +} diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index 72d5cf8bd..20595ecca 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,13 +1,13 @@ { "ans_mem": [ - 100, - 100, - 101, - 102, - 103, - 104, - 0, - 0, + 47, + 47, + 47, + 31, + 31, + 69, + 13, + 73, 0, 0 ], @@ -15,34 +15,34 @@ 2, 1, 2, - 2, - 0, - 2, - 2, + 1, 2, 2, 2, 2, 0, + 1, + 0, + 2, 0, 0, 0 ], "values": [ - 100, - 0, - 101, - 102, - 0, - 103, - 104, - 105, - 106, - 107, - 108, - 0, - 0, - 0, - 0 + 47, + 60, + 31, + 48, + 69, + 13, + 73, + 31, + 1, + 93, + 27, + 52, + 35, + 23, + 98 ] } From 13028ba6f9f7f2f39c8e01e8ed6edbb0dcbceb71 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Sat, 11 Nov 2023 17:05:46 -0500 Subject: [PATCH 087/189] Schedule Compaction Minimizes Par Threads (#1774) * modify pass ordering * more compact compaction * another small change * dumb mistake * another silly mistake * documentation * rewrite tests * rewrite test * code cleaning --- calyx-opt/src/passes/schedule_compaction.rs | 112 +++++++++++++----- examples/futil/dot-product.expect | 78 ++++++------ examples/futil/simple.expect | 32 ++--- examples/futil/vectorized-add.expect | 68 +++++------ tests/passes/cell-share/inline.expect | 23 +--- .../schedule-compaction.expect | 14 +-- 6 files changed, 177 insertions(+), 150 deletions(-) diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index 9b873eee4..b3b3b93b5 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -58,54 +58,106 @@ impl Visitor for ScheduleCompaction { if let Ok(order) = algo::toposort(&total_order, None) { let mut total_time: u64 = 0; - let mut stmts: Vec = Vec::new(); + + // First we build the schedule. for i in order { - let mut start: u64 = 0; - for node in dependency.get(&i).unwrap() { - let allow_start = schedule[node] + latency_map[node]; - if allow_start > start { - start = allow_start; - } - } + // Start time is when the latest dependency finishes + let start = dependency + .get(&i) + .unwrap() + .iter() + .map(|node| schedule[node] + latency_map[node]) + .max() + .unwrap_or(0); schedule.insert(i, start); + total_time = std::cmp::max(start + latency_map[&i], total_time); + } + // We sort the schedule by start time. + let mut sorted_schedule: Vec<(NodeIndex, u64)> = + schedule.into_iter().collect(); + sorted_schedule + .sort_by(|(k1, v1), (k2, v2)| (v1, k1).cmp(&(v2, k2))); + // Threads for the static par, where each entry is (thread, thread_latency) + let mut par_threads: Vec<(Vec, u64)> = + Vec::new(); + + // We encode the schedule attempting to minimize the number of + // par threads. + 'outer: for (i, start) in sorted_schedule { let control = total_order[i].take().unwrap(); - let mut st_seq_stmts: Vec = Vec::new(); + for (thread, thread_latency) in par_threads.iter_mut() { + if *thread_latency <= start { + if *thread_latency < start { + // Might need a no-op group so the schedule starts correctly + let no_op = builder.add_static_group( + "no-op", + start - *thread_latency, + ); + thread.push(ir::StaticControl::Enable( + ir::StaticEnable { + group: no_op, + attributes: ir::Attributes::default(), + }, + )); + *thread_latency = start; + } + thread.push(control); + *thread_latency += latency_map[&i]; + continue 'outer; + } + } + // We must create a new par thread. if start > 0 { + // If start > 0, then we must add a delay to the start of the + // group. let no_op = builder.add_static_group("no-op", start); - - st_seq_stmts.push(ir::StaticControl::Enable( - ir::StaticEnable { + let no_op_enable = + ir::StaticControl::Enable(ir::StaticEnable { group: no_op, attributes: ir::Attributes::default(), - }, + }); + par_threads.push(( + vec![no_op_enable, control], + start + latency_map[&i], )); + } else { + par_threads.push((vec![control], latency_map[&i])); } - if start + latency_map[&i] > total_time { - total_time = start + latency_map[&i]; - } + } - st_seq_stmts.push(control); - stmts.push(ir::StaticControl::Seq(ir::StaticSeq { - stmts: st_seq_stmts, + // Turn Vec -> StaticSeq + let mut par_control_threads: Vec = Vec::new(); + for (thread, thread_latency) in par_threads { + par_control_threads.push(ir::StaticControl::Seq( + ir::StaticSeq { + stmts: thread, + attributes: ir::Attributes::default(), + latency: thread_latency, + }, + )); + } + // Double checking that we have built the static par correctly. + let max = par_control_threads.iter().map(|c| c.get_latency()).max(); + assert!(max.unwrap() == total_time, "The schedule expects latency {}. The static par that was built has latency {}", total_time, max.unwrap()); + + if par_control_threads.len() == 1 { + let c = Vec::pop(&mut par_control_threads).unwrap(); + Ok(Action::static_change(c)) + } else { + let s_par = ir::StaticControl::Par(ir::StaticPar { + stmts: par_control_threads, attributes: ir::Attributes::default(), - latency: start + latency_map[&i], - })); + latency: total_time, + }); + Ok(Action::static_change(s_par)) } - - let s_par = ir::StaticControl::Par(ir::StaticPar { - stmts, - attributes: ir::Attributes::default(), - latency: total_time, - }); - return Ok(Action::static_change(s_par)); } else { - println!( + panic!( "Error when producing topo sort. Dependency graph has a cycle." ); } - Ok(Action::Continue) } fn finish_static_repeat( diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index 0bbfdc060..c5f0d0db3 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -28,92 +28,92 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_par_go = std_wire(1); - @generated early_reset_static_par_done = std_wire(1); + @generated early_reset_static_seq_go = std_wire(1); + @generated early_reset_static_seq_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_par_go = std_wire(1); - @generated while_wrapper_early_reset_static_par_done = std_wire(1); + @generated while_wrapper_early_reset_static_seq_go = std_wire(1); + @generated while_wrapper_early_reset_static_seq_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 4'd1 & early_reset_static_par_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 4'd1 & early_reset_static_seq_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 4'd1 & early_reset_static_par_go.out ? add1.out; + i0.in = fsm.out == 4'd1 & early_reset_static_seq_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 4'd1 & early_reset_static_par_go.out ? i0.out; - add1.right = fsm.out == 4'd1 & early_reset_static_par_go.out ? const3.out; + add1.left = fsm.out == 4'd1 & early_reset_static_seq_go.out ? i0.out; + add1.right = fsm.out == 4'd1 & early_reset_static_seq_go.out ? const3.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 4'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 4'd0; - fsm.in = fsm.out != 4'd7 & early_reset_static_par_go.out ? adder0.out; + fsm.in = fsm.out == 4'd0 & early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? 4'd0; + fsm.in = fsm.out != 4'd7 & early_reset_static_seq_go.out ? adder0.out; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 4'd1; - add0.left = fsm.out == 4'd6 & early_reset_static_par_go.out ? v0.read_data; - add0.right = fsm.out == 4'd6 & early_reset_static_par_go.out ? B_read0_0.out; - v0.write_en = fsm.out == 4'd6 & early_reset_static_par_go.out ? 1'd1; + add0.left = fsm.out == 4'd6 & early_reset_static_seq_go.out ? v0.read_data; + add0.right = fsm.out == 4'd6 & early_reset_static_seq_go.out ? B_read0_0.out; + v0.write_en = fsm.out == 4'd6 & early_reset_static_seq_go.out ? 1'd1; v0.clk = clk; - v0.addr0 = fsm.out == 4'd6 & early_reset_static_par_go.out ? const2.out; + v0.addr0 = fsm.out == 4'd6 & early_reset_static_seq_go.out ? const2.out; v0.reset = reset; - v0.write_data = fsm.out == 4'd6 & early_reset_static_par_go.out ? add0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? 1'd1; + v0.write_data = fsm.out == 4'd6 & early_reset_static_seq_go.out ? add0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; - while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; + A0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; A0.reset = reset; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; mult_pipe0.clk = clk; - mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? A_read0_0.out; - mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? 1'd1; + mult_pipe0.left = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? A_read0_0.out; + mult_pipe0.go = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? 1'd1; mult_pipe0.reset = reset; - mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_par_go.out ? B_read0_0.out; - adder0.left = early_reset_static_par_go.out ? fsm.out; - adder0.right = early_reset_static_par_go.out ? 4'd1; + mult_pipe0.right = fsm.out >= 4'd1 & fsm.out < 4'd4 & early_reset_static_seq_go.out ? B_read0_0.out; + adder0.left = early_reset_static_seq_go.out ? fsm.out; + adder0.right = early_reset_static_seq_go.out ? 4'd1; invoke0_done.in = i0.done; - early_reset_static_par_done.in = ud0.out; - le0.left = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_par_go.out ? const1.out; + early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; + le0.left = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 4'd7 & early_reset_static_seq_go.out ? const1.out; signal_reg.write_en = fsm.out == 4'd0 & signal_reg.out | fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 4'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 4'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 4'd0 & early_reset_static_par_go.out ? i0.out; + B0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5 & fsm.out < 4'd6) & early_reset_static_par_go.out ? 1'd1; + B_read0_0.write_en = (fsm.out == 4'd0 & fsm.out < 4'd7 | fsm.out == 4'd5 & fsm.out < 4'd7) & early_reset_static_seq_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? B0.read_data; - B_read0_0.in = fsm.out == 4'd5 & early_reset_static_par_go.out ? A_read0_0.out; + B_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 4'd5 & early_reset_static_seq_go.out ? A_read0_0.out; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 4'd0 & signal_reg.out ? 1'd1; + early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; - A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4 & fsm.out >= 4'd1 & fsm.out < 4'd5 & fsm.out < 4'd5) & early_reset_static_par_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; + A_read0_0.write_en = (fsm.out == 4'd0 & fsm.out < 4'd7 | fsm.out == 4'd4 & fsm.out < 4'd7) & early_reset_static_seq_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 4'd0 & early_reset_static_par_go.out ? A0.read_data; - A_read0_0.in = fsm.out == 4'd4 & early_reset_static_par_go.out ? mult_pipe0.out; + A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; } control {} } diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 16a037543..4f61bc431 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -6,29 +6,29 @@ static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done @generated ud = undef(1); @generated adder = std_add(3); @generated signal_reg = std_reg(1); - @generated early_reset_static_par_go = std_wire(1); - @generated early_reset_static_par_done = std_wire(1); - @generated wrapper_early_reset_static_par_go = std_wire(1); - @generated wrapper_early_reset_static_par_done = std_wire(1); + @generated early_reset_static_seq_go = std_wire(1); + @generated early_reset_static_seq_done = std_wire(1); + @generated wrapper_early_reset_static_seq_go = std_wire(1); + @generated wrapper_early_reset_static_seq_done = std_wire(1); } wires { - done = wrapper_early_reset_static_par_done.out ? 1'd1; - fsm.write_en = early_reset_static_par_go.out ? 1'd1; + done = wrapper_early_reset_static_seq_done.out ? 1'd1; + fsm.write_en = early_reset_static_seq_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; - fsm.in = fsm.out != 3'd4 & early_reset_static_par_go.out ? adder.out; - fsm.in = fsm.out == 3'd4 & early_reset_static_par_go.out ? 3'd0; - adder.left = early_reset_static_par_go.out ? fsm.out; - adder.right = early_reset_static_par_go.out ? 3'd1; - wrapper_early_reset_static_par_go.in = go; - wrapper_early_reset_static_par_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; - early_reset_static_par_done.in = ud.out; - signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; + fsm.in = fsm.out != 3'd4 & early_reset_static_seq_go.out ? adder.out; + fsm.in = fsm.out == 3'd4 & early_reset_static_seq_go.out ? 3'd0; + adder.left = early_reset_static_seq_go.out ? fsm.out; + adder.right = early_reset_static_seq_go.out ? 3'd1; + wrapper_early_reset_static_seq_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; + early_reset_static_seq_go.in = wrapper_early_reset_static_seq_go.out ? 1'd1; + signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; - signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_par_go.out ? 1'd1; + signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_static_seq_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; - early_reset_static_par_go.in = wrapper_early_reset_static_par_go.out ? 1'd1; + early_reset_static_seq_done.in = ud.out; + wrapper_early_reset_static_seq_go.in = go; } control {} } diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index 507224343..005c8bc0f 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -25,85 +25,85 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated invoke0_done = std_wire(1); @generated early_reset_cond00_go = std_wire(1); @generated early_reset_cond00_done = std_wire(1); - @generated early_reset_static_par_go = std_wire(1); - @generated early_reset_static_par_done = std_wire(1); + @generated early_reset_static_seq_go = std_wire(1); + @generated early_reset_static_seq_done = std_wire(1); @generated wrapper_early_reset_cond00_go = std_wire(1); @generated wrapper_early_reset_cond00_done = std_wire(1); - @generated while_wrapper_early_reset_static_par_go = std_wire(1); - @generated while_wrapper_early_reset_static_par_done = std_wire(1); + @generated while_wrapper_early_reset_static_seq_go = std_wire(1); + @generated while_wrapper_early_reset_static_seq_done = std_wire(1); @generated tdcc_go = std_wire(1); @generated tdcc_done = std_wire(1); } wires { - i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_par_go.out ? 1'd1; + i0.write_en = invoke0_go.out | fsm.out == 3'd2 & early_reset_static_seq_go.out ? 1'd1; i0.clk = clk; i0.reset = reset; - i0.in = fsm.out == 3'd2 & early_reset_static_par_go.out ? add1.out; + i0.in = fsm.out == 3'd2 & early_reset_static_seq_go.out ? add1.out; i0.in = invoke0_go.out ? const0.out; early_reset_cond00_go.in = wrapper_early_reset_cond00_go.out ? 1'd1; - add1.left = fsm.out == 3'd2 & early_reset_static_par_go.out ? i0.out; - add1.right = fsm.out == 3'd2 & early_reset_static_par_go.out ? const2.out; + add1.left = fsm.out == 3'd2 & early_reset_static_seq_go.out ? i0.out; + add1.right = fsm.out == 3'd2 & early_reset_static_seq_go.out ? const2.out; done = tdcc_done.out ? 1'd1; - fsm.write_en = early_reset_cond00_go.out | early_reset_static_par_go.out ? 1'd1; + fsm.write_en = early_reset_cond00_go.out | early_reset_static_seq_go.out ? 1'd1; fsm.clk = clk; fsm.reset = reset; fsm.in = fsm.out != 3'd0 & early_reset_cond00_go.out ? adder.out; - fsm.in = fsm.out != 3'd3 & early_reset_static_par_go.out ? adder0.out; - fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 3'd0; + fsm.in = fsm.out != 3'd3 & early_reset_static_seq_go.out ? adder0.out; + fsm.in = fsm.out == 3'd0 & early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 3'd0; adder.left = early_reset_cond00_go.out ? fsm.out; adder.right = early_reset_cond00_go.out ? 3'd1; - add0.left = fsm.out == 3'd1 & early_reset_static_par_go.out ? A_read0_0.out; - add0.right = fsm.out == 3'd1 & early_reset_static_par_go.out ? B_read0_0.out; - comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? 1'd1; + add0.left = fsm.out == 3'd1 & early_reset_static_seq_go.out ? A_read0_0.out; + add0.right = fsm.out == 3'd1 & early_reset_static_seq_go.out ? B_read0_0.out; + comb_reg.write_en = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? 1'd1; comb_reg.clk = clk; comb_reg.reset = reset; - comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? le0.out; + comb_reg.in = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? le0.out; early_reset_cond00_done.in = ud.out; - while_wrapper_early_reset_static_par_go.in = !while_wrapper_early_reset_static_par_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_go.in = !while_wrapper_early_reset_static_seq_done.out & fsm0.out == 2'd2 & tdcc_go.out ? 1'd1; invoke0_go.in = !invoke0_done.out & fsm0.out == 2'd0 & tdcc_go.out ? 1'd1; - while_wrapper_early_reset_static_par_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; tdcc_go.in = go; A0.clk = clk; - A0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; + A0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; A0.reset = reset; - Sum0.write_en = fsm.out == 3'd1 & early_reset_static_par_go.out ? 1'd1; + Sum0.write_en = fsm.out == 3'd1 & early_reset_static_seq_go.out ? 1'd1; Sum0.clk = clk; - Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_par_go.out ? i0.out; + Sum0.addr0 = fsm.out == 3'd1 & early_reset_static_seq_go.out ? i0.out; Sum0.reset = reset; - Sum0.write_data = fsm.out == 3'd1 & early_reset_static_par_go.out ? add0.out; - fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 1'd1; + Sum0.write_data = fsm.out == 3'd1 & early_reset_static_seq_go.out ? add0.out; + fsm0.write_en = fsm0.out == 2'd3 | fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out | fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out | fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 1'd1; fsm0.clk = clk; fsm0.reset = reset; fsm0.in = fsm0.out == 2'd0 & invoke0_done.out & tdcc_go.out ? 2'd1; fsm0.in = fsm0.out == 2'd3 ? 2'd0; - fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_par_done.out & tdcc_go.out ? 2'd3; + fsm0.in = fsm0.out == 2'd2 & while_wrapper_early_reset_static_seq_done.out & tdcc_go.out ? 2'd3; fsm0.in = fsm0.out == 2'd1 & wrapper_early_reset_cond00_done.out & tdcc_go.out ? 2'd2; - adder0.left = early_reset_static_par_go.out ? fsm.out; - adder0.right = early_reset_static_par_go.out ? 3'd1; + adder0.left = early_reset_static_seq_go.out ? fsm.out; + adder0.right = early_reset_static_seq_go.out ? 3'd1; invoke0_done.in = i0.done; - early_reset_static_par_done.in = ud0.out; - le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? i0.out; - le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_par_go.out ? const1.out; + early_reset_static_seq_go.in = while_wrapper_early_reset_static_seq_go.out ? 1'd1; + le0.left = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? i0.out; + le0.right = early_reset_cond00_go.out | fsm.out == 3'd3 & early_reset_static_seq_go.out ? const1.out; signal_reg.write_en = fsm.out == 3'd0 & signal_reg.out | fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.clk = clk; signal_reg.reset = reset; signal_reg.in = fsm.out == 3'd0 & !signal_reg.out & wrapper_early_reset_cond00_go.out ? 1'd1; signal_reg.in = fsm.out == 3'd0 & signal_reg.out ? 1'd0; B0.clk = clk; - B0.addr0 = fsm.out == 3'd0 & early_reset_static_par_go.out ? i0.out; + B0.addr0 = fsm.out == 3'd0 & early_reset_static_seq_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; + B_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; - B_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? B0.read_data; + B_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? B0.read_data; wrapper_early_reset_cond00_go.in = !wrapper_early_reset_cond00_done.out & fsm0.out == 2'd1 & tdcc_go.out ? 1'd1; wrapper_early_reset_cond00_done.in = fsm.out == 3'd0 & signal_reg.out ? 1'd1; + early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; - early_reset_static_par_go.in = while_wrapper_early_reset_static_par_go.out ? 1'd1; - A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_par_go.out ? 1'd1; + while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 3'd0 ? 1'd1; + A_read0_0.write_en = fsm.out == 3'd0 & early_reset_static_seq_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; - A_read0_0.in = fsm.out == 3'd0 & early_reset_static_par_go.out ? A0.read_data; + A_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; } control {} } diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect index 9a7e2e66b..73fbadbca 100644 --- a/tests/passes/cell-share/inline.expect +++ b/tests/passes/cell-share/inline.expect @@ -39,28 +39,13 @@ static<4> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done mem.addr0 = 1'd1; mem.write_data = r.out; } - static<1> group no-op { - } - static<2> group no-op0 { - } - static<3> group no-op1 { - } } control { - static<4> par { + static<4> seq { invoke00; - static<2> seq { - no-op; - invoke10; - } - static<3> seq { - no-op0; - invoke20; - } - static<4> seq { - no-op1; - invoke30; - } + invoke10; + invoke20; + invoke30; } } } diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect index bf7291c5c..855907b6b 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.expect +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -26,25 +26,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { d_reg.write_en = %0 ? 1'd1; d_reg.in = a_reg.out; } - static<1> group no-op { - } - static<10> group no-op0 { - } } control { static<11> par { - static<10> seq { - C; - } - static<1> seq { - A; - } static<11> seq { - no-op; + A; D; } static<11> seq { - no-op0; + C; B; } } From 51c54cd8946fc07033871fcd3fc6fd49563bf411 Mon Sep 17 00:00:00 2001 From: paili0628 <92661158+paili0628@users.noreply.github.com> Date: Sun, 12 Nov 2023 18:46:58 -0500 Subject: [PATCH 088/189] Static interface (#1759) * implemented static interface * fmt * clippy * fmt * added implementation for one-cycle static interface and avoid promoting main component * fmt * clippy * change order of compile-invoke * change pass ordering * restore pass ordering * changes * change pass ordering * clippy * fmt * clippy * add test cases * restore pass ordering * fmt * fix test cases --- calyx-frontend/src/ast.rs | 2 + calyx-frontend/src/attribute.rs | 3 + calyx-frontend/src/parser.rs | 12 +- calyx-frontend/src/syntax.pest | 2 +- calyx-ir/src/control.rs | 3 + calyx-ir/src/from_ast.rs | 263 +++++++++----- calyx-ir/src/printer.rs | 4 + calyx-opt/src/default_passes.rs | 12 +- calyx-opt/src/passes/add_guard.rs | 44 +++ calyx-opt/src/passes/compile_invoke.rs | 22 +- calyx-opt/src/passes/compile_static.rs | 76 +++- .../src/passes/compile_static_interface.rs | 339 ++++++++++++++++++ calyx-opt/src/passes/dead_group_removal.rs | 8 + calyx-opt/src/passes/mod.rs | 4 + calyx-opt/src/passes/static_promotion.rs | 8 +- calyx-opt/src/passes/wire_inliner.rs | 54 +-- examples/futil/simple.expect | 2 +- runt.toml | 4 +- ...static-interface-promoted-one-cycle.expect | 5 + .../static-interface-promoted-one-cycle.futil | 44 +++ ...ic-interface-promoted-one-cycle.futil.data | 12 + .../static-interface-promoted.expect | 5 + .../static-interface-promoted.futil | 50 +++ .../static-interface-promoted.futil.data | 12 + .../static-interface-repeat.expect | 5 + .../static-interface-repeat.futil | 56 +++ .../static-interface-repeat.futil.data | 12 + .../static-interface/static-interface.expect | 5 + .../static-interface/static-interface.futil | 50 +++ .../static-interface.futil.data | 12 + tests/passes/cell-share/inline.expect | 2 +- .../compile-static-invoke.expect | 2 +- tests/passes/compile-invoke/static-ref.expect | 2 +- .../compile-static-interface-one-cycle.expect | 31 ++ .../compile-static-interface-one-cycle.futil | 32 ++ .../compile-static-interface-repeat.expect | 55 +++ .../compile-static-interface-repeat.futil | 44 +++ tests/passes/compile-static-interface.expect | 55 +++ tests/passes/compile-static-interface.futil | 39 ++ .../passes/static-promotion/component.expect | 2 +- tests/passes/static-promotion/invoke.expect | 7 +- .../static-promotion/multi-static.expect | 7 +- .../static-promotion/upgrade-bound.expect | 2 +- 43 files changed, 1252 insertions(+), 158 deletions(-) create mode 100644 calyx-opt/src/passes/add_guard.rs create mode 100644 calyx-opt/src/passes/compile_static_interface.rs create mode 100644 tests/correctness/static-interface/static-interface-promoted-one-cycle.expect create mode 100644 tests/correctness/static-interface/static-interface-promoted-one-cycle.futil create mode 100644 tests/correctness/static-interface/static-interface-promoted-one-cycle.futil.data create mode 100644 tests/correctness/static-interface/static-interface-promoted.expect create mode 100644 tests/correctness/static-interface/static-interface-promoted.futil create mode 100644 tests/correctness/static-interface/static-interface-promoted.futil.data create mode 100644 tests/correctness/static-interface/static-interface-repeat.expect create mode 100644 tests/correctness/static-interface/static-interface-repeat.futil create mode 100644 tests/correctness/static-interface/static-interface-repeat.futil.data create mode 100644 tests/correctness/static-interface/static-interface.expect create mode 100644 tests/correctness/static-interface/static-interface.futil create mode 100644 tests/correctness/static-interface/static-interface.futil.data create mode 100644 tests/passes/compile-static-interface-one-cycle.expect create mode 100644 tests/passes/compile-static-interface-one-cycle.futil create mode 100644 tests/passes/compile-static-interface-repeat.expect create mode 100644 tests/passes/compile-static-interface-repeat.futil create mode 100644 tests/passes/compile-static-interface.expect create mode 100644 tests/passes/compile-static-interface.futil diff --git a/calyx-frontend/src/ast.rs b/calyx-frontend/src/ast.rs index 488bc94d0..8217da409 100644 --- a/calyx-frontend/src/ast.rs +++ b/calyx-frontend/src/ast.rs @@ -376,6 +376,8 @@ pub enum Control { attributes: Attributes, /// External cells that may execute with this invoke. ref_cells: Vec<(Id, Id)>, + /// Combinational group that may execute with this invoke. + comb_group: Option, /// (optional) latency. Latency can be inferred if not given. latency: Option, }, diff --git a/calyx-frontend/src/attribute.rs b/calyx-frontend/src/attribute.rs index 76cdb57e5..242b0a01f 100644 --- a/calyx-frontend/src/attribute.rs +++ b/calyx-frontend/src/attribute.rs @@ -61,6 +61,9 @@ pub enum BoolAttr { #[strum(serialize = "inline")] /// Inline this subcomponent Inline, + #[strum(serialize = "promoted")] + /// denotes a static component promoted from dynamic + Promoted, } impl From for Attribute { fn from(attr: BoolAttr) -> Self { diff --git a/calyx-frontend/src/parser.rs b/calyx-frontend/src/parser.rs index b6088ddae..63d680d71 100644 --- a/calyx-frontend/src/parser.rs +++ b/calyx-frontend/src/parser.rs @@ -10,7 +10,6 @@ use calyx_utils::{self, CalyxResult, Id}; use calyx_utils::{FileIdx, GPosIdx, GlobalPositionTable}; use pest::pratt_parser::{Assoc, Op, PrattParser}; use pest_consume::{match_nodes, Error, Parser}; -use std::convert::TryInto; use std::fs; use std::io::Read; use std::path::Path; @@ -865,6 +864,17 @@ impl CalyxParser { attributes: attrs.add_span(span), ref_cells: cells, latency, + comb_group: None, + }, + [at_attributes(attrs), static_optional_latency(latency), identifier(comp), invoke_ref_args(cells),invoke_args(inputs), invoke_args(outputs), identifier(group)] => + ast::Control::StaticInvoke { + comp, + inputs, + outputs, + attributes: attrs.add_span(span), + ref_cells: cells, + latency, + comb_group: Some(group), }, )) } diff --git a/calyx-frontend/src/syntax.pest b/calyx-frontend/src/syntax.pest index bbf99dec5..90b85263f 100644 --- a/calyx-frontend/src/syntax.pest +++ b/calyx-frontend/src/syntax.pest @@ -294,7 +294,7 @@ invoke_args = { (invoke_arg ~ ("," ~ invoke_arg)*)? } invoke_ref_arg = {identifier ~ "=" ~ identifier} invoke_ref_args = {("[" ~ (invoke_ref_arg ~ ("," ~ invoke_ref_arg)*)? ~ "]")?} invoke = { at_attributes ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ("with" ~ identifier)? ~ ";" } -static_invoke = { at_attributes ~ static_optional_latency ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ";" } +static_invoke = { at_attributes ~ static_optional_latency ~ "invoke" ~ identifier ~ invoke_ref_args ~ "(" ~ invoke_args ~ ")" ~ "(" ~ invoke_args ~ ")" ~ ("with" ~ identifier)? ~ ";" } seq = { at_attributes ~ "seq" ~ "{" diff --git a/calyx-ir/src/control.rs b/calyx-ir/src/control.rs index a64005e09..7f4dc719e 100644 --- a/calyx-ir/src/control.rs +++ b/calyx-ir/src/control.rs @@ -302,6 +302,8 @@ pub struct StaticInvoke { pub attributes: Attributes, /// Mapping from name of external cell in 'comp' to the cell connected to it. pub ref_cells: CellMap, + /// Optional combinational group that is active when the invoke is active. + pub comb_group: Option>, } impl GetAttributes for StaticInvoke { fn get_attributes(&self) -> &Attributes { @@ -818,6 +820,7 @@ impl Cloner { outputs: i.outputs.clone(), attributes: i.attributes.clone(), ref_cells: i.ref_cells.clone(), + comb_group: i.comb_group.clone(), } } diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index 0a4ab9da7..619c5ab31 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -5,7 +5,7 @@ use super::{ RESERVED_NAMES, RRC, }; use crate::{Nothing, PortComp, StaticTiming}; -use calyx_frontend::{ast, ast::Atom, BoolAttr, Workspace}; +use calyx_frontend::{ast, BoolAttr, Workspace}; use calyx_utils::{CalyxResult, Error, GPosIdx, WithPos}; use itertools::Itertools; @@ -13,8 +13,6 @@ use std::collections::{HashMap, HashSet}; use std::num::NonZeroU64; use std::rc::Rc; -type InvokePortMap = Vec<(Id, Atom)>; - /// Context to store the signature information for all defined primitives and /// components. #[derive(Default)] @@ -696,82 +694,6 @@ fn build_static_if( Ok(con) } -// builds a static invoke from the given information -fn build_static_invoke( - builder: &mut Builder, - component: Id, - (inputs, outputs): (InvokePortMap, InvokePortMap), - attributes: Attributes, - ref_cells: Vec<(Id, Id)>, - given_latency: Option, - sig_ctx: &SigCtx, -) -> CalyxResult { - let cell = Rc::clone(&builder.component.find_cell(component).ok_or_else( - || { - Error::undefined(component, "cell".to_string()) - .with_pos(&attributes) - }, - )?); - let comp_name = cell - .borrow() - .type_name() - .unwrap_or_else(|| unreachable!("invoked component without a name")); - let latency = get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?; - let unwrapped_latency = if let Some(v) = latency { - v - } else { - return Err(Error::malformed_control(format!( - "non-static component {} is statically invoked", - comp_name - )) - .with_pos(&attributes)); - }; - assert_latencies_eq(given_latency, unwrapped_latency.into()); - - let inputs = inputs - .into_iter() - .map(|(id, port)| { - // checking that comp_name.id exists on comp's signature - check_valid_port(Rc::clone(&cell), &id, &attributes, sig_ctx)?; - atom_to_port(port, builder) - .and_then(|pr| ensure_direction(pr, Direction::Output)) - .map(|p| (id, p)) - }) - .collect::>()?; - let outputs = outputs - .into_iter() - .map(|(id, port)| { - // checking that comp_name.id exists on comp's signature - check_valid_port(Rc::clone(&cell), &id, &attributes, sig_ctx)?; - atom_to_port(port, builder) - .and_then(|pr| ensure_direction(pr, Direction::Input)) - .map(|p| (id, p)) - }) - .collect::>()?; - let mut inv = StaticInvoke { - comp: cell, - inputs, - outputs, - attributes: Attributes::default(), - ref_cells: Vec::new(), - latency: unwrapped_latency.into(), - }; - if !ref_cells.is_empty() { - let mut ext_cell_tuples = Vec::new(); - for (outcell, incell) in ref_cells { - let ext_cell_ref = builder - .component - .find_cell(incell) - .ok_or_else(|| Error::undefined(incell, "cell".to_string()))?; - ext_cell_tuples.push((outcell, ext_cell_ref)); - } - inv.ref_cells = ext_cell_tuples; - } - let mut con = StaticControl::Invoke(inv); - *con.get_mut_attributes() = attributes; - Ok(con) -} - fn build_static_repeat( num_repeats: u64, body: ast::Control, @@ -823,16 +745,91 @@ fn build_static_control( attributes, ref_cells, latency, + comb_group, } => { - return build_static_invoke( - builder, - comp, - (inputs, outputs), - attributes, - ref_cells, - latency, - sig_ctx, + let cell = Rc::clone( + &builder.component.find_cell(comp).ok_or_else(|| { + Error::undefined(comp, "cell".to_string()) + .with_pos(&attributes) + })?, ); + let comp_name = cell.borrow().type_name().unwrap_or_else(|| { + unreachable!("invoked component without a name") + }); + let c_latency = + get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?; + let unwrapped_latency = if let Some(v) = c_latency { + v + } else { + return Err(Error::malformed_control(format!( + "non-static component {} is statically invoked", + comp_name + )) + .with_pos(&attributes)); + }; + assert_latencies_eq(latency, unwrapped_latency.into()); + + let inputs = inputs + .into_iter() + .map(|(id, port)| { + // checking that comp_name.id exists on comp's signature + check_valid_port( + Rc::clone(&cell), + &id, + &attributes, + sig_ctx, + )?; + atom_to_port(port, builder) + .and_then(|pr| ensure_direction(pr, Direction::Output)) + .map(|p| (id, p)) + }) + .collect::>()?; + let outputs = outputs + .into_iter() + .map(|(id, port)| { + // checking that comp_name.id exists on comp's signature + check_valid_port( + Rc::clone(&cell), + &id, + &attributes, + sig_ctx, + )?; + atom_to_port(port, builder) + .and_then(|pr| ensure_direction(pr, Direction::Input)) + .map(|p| (id, p)) + }) + .collect::>()?; + let mut inv = StaticInvoke { + comp: cell, + inputs, + outputs, + attributes: Attributes::default(), + ref_cells: Vec::new(), + latency: unwrapped_latency.into(), + comb_group: None, + }; + if !ref_cells.is_empty() { + let mut ext_cell_tuples = Vec::new(); + for (outcell, incell) in ref_cells { + let ext_cell_ref = + builder.component.find_cell(incell).ok_or_else( + || Error::undefined(incell, "cell".to_string()), + )?; + ext_cell_tuples.push((outcell, ext_cell_ref)); + } + inv.ref_cells = ext_cell_tuples; + } + if let Some(cg) = comb_group { + let cg_ref = + builder.component.find_comb_group(cg).ok_or_else(|| { + Error::undefined(cg, "combinational group".to_string()) + .with_pos(&inv.attributes) + })?; + inv.comb_group = Some(cg_ref); + } + let mut con = StaticControl::Invoke(inv); + *con.get_mut_attributes() = attributes; + return Ok(con); } ast::Control::StaticSeq { stmts, @@ -933,17 +930,91 @@ fn build_control( attributes, ref_cells, latency, + comb_group, } => { - let i = build_static_invoke( - builder, - comp, - (inputs, outputs), - attributes, - ref_cells, - latency, - sig_ctx, + let cell = Rc::clone( + &builder.component.find_cell(comp).ok_or_else(|| { + Error::undefined(comp, "cell".to_string()) + .with_pos(&attributes) + })?, ); - Control::Static(i?) + let comp_name = cell.borrow().type_name().unwrap_or_else(|| { + unreachable!("invoked component without a name") + }); + let c_latency = + get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)?; + let unwrapped_latency = if let Some(v) = c_latency { + v + } else { + return Err(Error::malformed_control(format!( + "non-static component {} is statically invoked", + comp_name + )) + .with_pos(&attributes)); + }; + assert_latencies_eq(latency, unwrapped_latency.into()); + + let inputs = inputs + .into_iter() + .map(|(id, port)| { + // checking that comp_name.id exists on comp's signature + check_valid_port( + Rc::clone(&cell), + &id, + &attributes, + sig_ctx, + )?; + atom_to_port(port, builder) + .and_then(|pr| ensure_direction(pr, Direction::Output)) + .map(|p| (id, p)) + }) + .collect::>()?; + let outputs = outputs + .into_iter() + .map(|(id, port)| { + // checking that comp_name.id exists on comp's signature + check_valid_port( + Rc::clone(&cell), + &id, + &attributes, + sig_ctx, + )?; + atom_to_port(port, builder) + .and_then(|pr| ensure_direction(pr, Direction::Input)) + .map(|p| (id, p)) + }) + .collect::>()?; + let mut inv = StaticInvoke { + comp: cell, + inputs, + outputs, + attributes: Attributes::default(), + ref_cells: Vec::new(), + latency: unwrapped_latency.into(), + comb_group: None, + }; + if !ref_cells.is_empty() { + let mut ext_cell_tuples = Vec::new(); + for (outcell, incell) in ref_cells { + let ext_cell_ref = + builder.component.find_cell(incell).ok_or_else( + || Error::undefined(incell, "cell".to_string()), + )?; + ext_cell_tuples.push((outcell, ext_cell_ref)); + } + inv.ref_cells = ext_cell_tuples; + } + if let Some(cg) = comb_group { + let cg_ref = + builder.component.find_comb_group(cg).ok_or_else(|| { + Error::undefined(cg, "combinational group".to_string()) + .with_pos(&inv.attributes) + })?; + inv.comb_group = Some(cg_ref); + } + let mut con = StaticControl::Invoke(inv); + *con.get_mut_attributes() = attributes; + Control::Static(con) } ast::Control::Invoke { comp: component, diff --git a/calyx-ir/src/printer.rs b/calyx-ir/src/printer.rs index 6c881506d..88c488f7b 100644 --- a/calyx-ir/src/printer.rs +++ b/calyx-ir/src/printer.rs @@ -503,6 +503,7 @@ impl Printer { outputs, attributes, ref_cells, + comb_group, }) => { write!(f, "{}", Self::format_at_attributes(attributes))?; write!( @@ -552,6 +553,9 @@ impl Printer { } if outputs.is_empty() { write!(f, ")")?; + } + if let Some(group) = comb_group { + writeln!(f, " with {};", group.borrow().name)?; } else { write!(f, "\n{})", " ".repeat(indent_level))?; } diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 940d75fe3..f082493b3 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -1,8 +1,9 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ - AttributePromotion, Canonicalize, CellShare, ClkInsertion, CollapseControl, - CombProp, CompileEmpty, CompileInvoke, CompileRepeat, CompileStatic, - CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, + AddGuard, AttributePromotion, Canonicalize, CellShare, ClkInsertion, + CollapseControl, CombProp, CompileEmpty, CompileInvoke, CompileRepeat, + CompileStatic, CompileStaticInterface, CompileSync, + CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, @@ -52,6 +53,8 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; + pm.register_pass::()?; // Lowering passes pm.register_pass::()?; @@ -109,6 +112,9 @@ impl PassManager { MergeAssign, // Static inliner generates lots of assigns DeadGroupRemoval, // Static inliner generates lots of dead groups SimplifyStaticGuards, + AddGuard, + CompileStaticInterface, + DeadGroupRemoval, CompileStatic, TopDownStaticTiming, TopDownCompileControl diff --git a/calyx-opt/src/passes/add_guard.rs b/calyx-opt/src/passes/add_guard.rs new file mode 100644 index 000000000..8e7abc63a --- /dev/null +++ b/calyx-opt/src/passes/add_guard.rs @@ -0,0 +1,44 @@ +use crate::traversal::{Action, Named, VisResult, Visitor}; +use calyx_ir as ir; + +#[derive(Default)] +pub struct AddGuard; + +impl Named for AddGuard { + fn name() -> &'static str { + "add-guard" + } + + fn description() -> &'static str { + "add guard %[0: n] where n is latency of static component for each assignment in the static enable of static component." + } +} + +impl Visitor for AddGuard { + fn start_static_control( + &mut self, + s: &mut ir::StaticControl, + comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + if comp.is_static() { + let latency = s.get_latency(); + if let ir::StaticControl::Enable(sen) = s { + for assign in sen.group.borrow_mut().assignments.iter_mut() { + let g = + ir::Guard::Info(ir::StaticTiming::new((0, latency))); + let new_g = ir::Guard::And( + Box::new(g), + std::mem::replace( + &mut assign.guard, + Box::new(ir::Guard::True), + ), + ); + assign.guard = Box::new(new_g); + } + } + } + Ok(Action::Continue) + } +} diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 92b26a45c..09becaf60 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -4,7 +4,7 @@ use crate::traversal::{ use calyx_ir::structure; use calyx_ir::{self as ir, Attributes, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; -use ir::{RRC, WRC}; +use ir::{Assignment, RRC, WRC}; use itertools::Itertools; use std::collections::HashMap; use std::rc::Rc; @@ -373,13 +373,12 @@ impl Visitor for CompileInvoke { // Get the go port let go_port = get_go_port(Rc::clone(&s.comp))?; + // define first cycle guard + let first_cycle = ir::Guard::Info(ir::StaticTiming::new((0, 1))); + // Build assignemnts let go_assign: ir::Assignment = builder - .build_assignment( - go_port, - one.borrow().get("out"), - ir::Guard::True, - ); + .build_assignment(go_port, one.borrow().get("out"), first_cycle); invoke_group.borrow_mut().assignments.push(go_assign); // Generate argument assignments @@ -392,6 +391,17 @@ impl Visitor for CompileInvoke { ); invoke_group.borrow_mut().assignments.extend(assigns); + if let Some(cgr) = &s.comb_group { + let cg = &*cgr.borrow(); + invoke_group.borrow_mut().assignments.extend( + cg.assignments + .iter() + .cloned() + .map(Assignment::from) + .collect_vec(), + ); + } + let en = ir::StaticEnable { group: invoke_group, attributes: Attributes::default(), diff --git a/calyx-opt/src/passes/compile_static.rs b/calyx-opt/src/passes/compile_static.rs index 23a0cf32b..ba2a86c64 100644 --- a/calyx-opt/src/passes/compile_static.rs +++ b/calyx-opt/src/passes/compile_static.rs @@ -39,29 +39,72 @@ impl Named for CompileStatic { // The only thing that actually changes is the Guard::Info case // We need to turn static_timing to dynamic guards using `fsm`. // E.g.: %[2:3] gets turned into fsm.out >= 2 & fsm.out < 3 -fn make_guard_dyn( +pub(super) fn make_guard_dyn( guard: ir::Guard, fsm: &ir::RRC, fsm_size: u64, builder: &mut ir::Builder, + is_static_comp: bool, + comp_sig: Option>, ) -> Box> { match guard { ir::Guard::Or(l, r) => Box::new(ir::Guard::Or( - make_guard_dyn(*l, fsm, fsm_size, builder), - make_guard_dyn(*r, fsm, fsm_size, builder), + make_guard_dyn( + *l, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig.clone(), + ), + make_guard_dyn( + *r, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig, + ), )), ir::Guard::And(l, r) => Box::new(ir::Guard::And( - make_guard_dyn(*l, fsm, fsm_size, builder), - make_guard_dyn(*r, fsm, fsm_size, builder), + make_guard_dyn( + *l, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig.clone(), + ), + make_guard_dyn( + *r, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig, + ), )), - ir::Guard::Not(g) => { - Box::new(ir::Guard::Not(make_guard_dyn(*g, fsm, fsm_size, builder))) - } + ir::Guard::Not(g) => Box::new(ir::Guard::Not(make_guard_dyn( + *g, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig, + ))), ir::Guard::CompOp(op, l, r) => Box::new(ir::Guard::CompOp(op, l, r)), ir::Guard::Port(p) => Box::new(ir::Guard::Port(p)), ir::Guard::True => Box::new(ir::Guard::True), ir::Guard::Info(static_timing) => { let (beg, end) = static_timing.get_interval(); + if is_static_comp && beg == 0 && end == 1 { + let interval_const = builder.add_constant(0, fsm_size); + let sig = comp_sig.unwrap(); + let g1 = guard!(sig["go"]); + let g2 = guard!(fsm["out"] == interval_const["out"]); + let g = ir::Guard::And(Box::new(g1), Box::new(g2)); + return Box::new(g); + } if beg + 1 == end { // if beg + 1 == end then we only need to check if fsm == beg let interval_const = builder.add_constant(beg, fsm_size); @@ -92,17 +135,26 @@ fn make_guard_dyn( // Takes in static assignment `assign` and returns a dynamic assignments // Mainly transforms the guards such that fsm.out >= 2 & fsm.out <= 3 -fn make_assign_dyn( +pub(super) fn make_assign_dyn( assign: ir::Assignment, fsm: &ir::RRC, fsm_size: u64, builder: &mut ir::Builder, + is_static_comp: bool, + comp_sig: Option>, ) -> ir::Assignment { ir::Assignment { src: assign.src, dst: assign.dst, attributes: assign.attributes, - guard: make_guard_dyn(*assign.guard, fsm, fsm_size, builder), + guard: make_guard_dyn( + *assign.guard, + fsm, + fsm_size, + builder, + is_static_comp, + comp_sig, + ), } } @@ -177,7 +229,9 @@ impl CompileStatic { // converting static assignments to dynamic assignments let mut assigns = sgroup_assigns .drain(..) - .map(|assign| make_assign_dyn(assign, &fsm, fsm_size, builder)) + .map(|assign| { + make_assign_dyn(assign, &fsm, fsm_size, builder, false, None) + }) .collect_vec(); // assignments to increment the fsm let not_penultimate_state_guard: ir::Guard = diff --git a/calyx-opt/src/passes/compile_static_interface.rs b/calyx-opt/src/passes/compile_static_interface.rs new file mode 100644 index 000000000..cb884123e --- /dev/null +++ b/calyx-opt/src/passes/compile_static_interface.rs @@ -0,0 +1,339 @@ +use super::compile_static::make_assign_dyn; +use crate::passes::math_utilities::get_bit_width_from; +use crate::traversal::{Action, Named, VisResult, Visitor}; +use calyx_ir as ir; +use ir::{ + build_assignments, guard, structure, Attributes, Guard, Nothing, + StaticTiming, RRC, +}; +use itertools::Itertools; +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Default)] +pub struct CompileStaticInterface; + +impl Named for CompileStaticInterface { + fn name() -> &'static str { + "compile-static-interface" + } + + fn description() -> &'static str { + "Compiles Static Component Interface" + } +} + +fn separate_first_cycle( + guard: ir::Guard, +) -> ir::Guard { + match guard { + ir::Guard::Info(st) => { + let (beg, end) = st.get_interval(); + if beg == 0 && end != 1 { + let first_cycle = + ir::Guard::Info(ir::StaticTiming::new((0, 1))); + let after = ir::Guard::Info(ir::StaticTiming::new((1, end))); + let cong = ir::Guard::or(first_cycle, after); + return cong; + } + guard + } + ir::Guard::And(l, r) => { + let left = separate_first_cycle(*l); + let right = separate_first_cycle(*r); + ir::Guard::and(left, right) + } + ir::Guard::Or(l, r) => { + let left = separate_first_cycle(*l); + let right = separate_first_cycle(*r); + ir::Guard::or(left, right) + } + ir::Guard::Not(g) => { + let a = separate_first_cycle(*g); + ir::Guard::Not(Box::new(a)) + } + _ => guard, + } +} + +fn separate_first_cycle_assign( + assign: ir::Assignment, +) -> ir::Assignment { + ir::Assignment { + src: assign.src, + dst: assign.dst, + attributes: assign.attributes, + guard: Box::new(separate_first_cycle(*assign.guard)), + } +} + +fn make_guard_dyn_one_cycle_static_comp( + guard: ir::Guard, + comp_sig: RRC, +) -> ir::Guard { + match guard { + ir::Guard::Or(l, r) => { + let left = + make_guard_dyn_one_cycle_static_comp(*l, Rc::clone(&comp_sig)); + let right = + make_guard_dyn_one_cycle_static_comp(*r, Rc::clone(&comp_sig)); + ir::Guard::or(left, right) + } + ir::Guard::And(l, r) => { + let left = + make_guard_dyn_one_cycle_static_comp(*l, Rc::clone(&comp_sig)); + let right = + make_guard_dyn_one_cycle_static_comp(*r, Rc::clone(&comp_sig)); + ir::Guard::and(left, right) + } + ir::Guard::Not(g) => { + let f = + make_guard_dyn_one_cycle_static_comp(*g, Rc::clone(&comp_sig)); + ir::Guard::Not(Box::new(f)) + } + ir::Guard::Info(t) => { + let (beg, end) = t.get_interval(); + if beg != 0 || end != 1 { + unreachable!("This function is implemented for 1 cycle static components, only %0 can exist as timing guard") + } else { + let g = guard!(comp_sig["go"]); + g + } + } + ir::Guard::CompOp(op, l, r) => ir::Guard::CompOp(op, l, r), + ir::Guard::Port(p) => ir::Guard::Port(p), + ir::Guard::True => ir::Guard::True, + } +} + +fn make_assign_dyn_one_cycle_static_comp( + assign: ir::Assignment, + comp_sig: RRC, +) -> ir::Assignment { + ir::Assignment { + src: assign.src, + dst: assign.dst, + attributes: assign.attributes, + guard: Box::new(make_guard_dyn_one_cycle_static_comp( + *assign.guard, + comp_sig, + )), + } +} + +impl CompileStaticInterface { + fn make_early_reset_assigns_static_component( + &mut self, + sgroup_assigns: &mut Vec>, + latency: u64, + fsm: ir::RRC, + builder: &mut ir::Builder, + comp_sig: RRC, + ) -> Vec> { + let fsm_name = fsm.borrow().name(); + let fsm_size = fsm + .borrow() + .find("out") + .unwrap_or_else(|| unreachable!("no `out` port on {fsm_name}")) + .borrow() + .width; + let mut assigns = sgroup_assigns + .drain(..) + .map(separate_first_cycle_assign) + .collect_vec(); + let mut dyn_assigns = assigns + .drain(..) + .map(|assign| { + make_assign_dyn( + assign, + &fsm, + fsm_size, + builder, + true, + Some(Rc::clone(&comp_sig)), + ) + }) + .collect_vec(); + let this = Rc::clone(&comp_sig); + structure!( builder; + // done hole will be undefined bc of early reset + let signal_on = constant(1,1); + let adder = prim std_add(fsm_size); + let const_one = constant(1, fsm_size); + let first_state = constant(0, fsm_size); + let penultimate_state = constant(latency-1, fsm_size); + ); + let g1: Guard = guard!(this["go"]); + let g2: Guard = guard!(fsm["out"] == first_state["out"]); + let trigger_guard = ir::Guard::and(g1, g2); + let g3: Guard = guard!(fsm["out"] != first_state["out"]); + let g4: Guard = guard!(fsm["out"] != penultimate_state["out"]); + let incr_guard = ir::Guard::and(g3, g4); + let stop_guard: Guard = + guard!(fsm["out"] == penultimate_state["out"]); + let fsm_incr_assigns = build_assignments!( + builder; + // increments the fsm + adder["left"] = ? fsm["out"]; + adder["right"] = ? const_one["out"]; + fsm["write_en"] = ? signal_on["out"]; + fsm["in"] = trigger_guard ? const_one["out"]; + fsm["in"] = incr_guard ? adder["out"]; + // resets the fsm early + fsm["in"] = stop_guard ? first_state["out"]; + ); + dyn_assigns.extend(fsm_incr_assigns); + + dyn_assigns + } + + fn make_done_signal_for_promoted_component( + &mut self, + fsm: ir::RRC, + builder: &mut ir::Builder, + comp_sig: RRC, + ) -> Vec> { + let fsm_size = fsm + .borrow() + .find("out") + .unwrap_or_else(|| { + unreachable!("no `out` port on {}", fsm.borrow().name()) + }) + .borrow() + .width; + structure!(builder; + let sig_reg = prim std_reg(1); + let one = constant(1, 1); + let zero = constant(0, 1); + let first_state = constant(0, fsm_size); + ); + let go_guard = guard!(comp_sig["go"]); + let done_guard = guard!(comp_sig["done"]); + let on_guard = go_guard & !done_guard; + let first_state_guard = guard!(fsm["out"] == first_state["out"]); + let signal_on_guard = guard!(sig_reg["out"]); + let comp_done_guard = first_state_guard & signal_on_guard; + let done_guard_2 = guard!(comp_sig["done"]); + let assigns = build_assignments!(builder; + sig_reg["in"] = on_guard ? one["out"]; + sig_reg["write_en"] = on_guard ? one["out"]; + comp_sig["done"] = comp_done_guard ? one["out"]; + sig_reg["in"] = done_guard_2 ? zero["out"]; + sig_reg["write_en"] = done_guard_2 ? one["out"]; + ); + assigns.to_vec() + } + + fn make_done_signal_for_promoted_component_one_cycle( + &mut self, + builder: &mut ir::Builder, + comp_sig: RRC, + ) -> Vec> { + structure!(builder; + let sig_reg = prim std_reg(1); + let one = constant(1, 1); + let zero = constant(0, 1); + ); + let go_guard = guard!(comp_sig["go"]); + let done_guard = guard!(comp_sig["done"]); + let on_guard = go_guard & !done_guard; + let signal_on_guard = guard!(sig_reg["out"]); + let done_guard_2 = guard!(comp_sig["done"]); + let assigns = build_assignments!(builder; + sig_reg["in"] = on_guard ? one["out"]; + sig_reg["write_en"] = on_guard ? one["out"]; + comp_sig["done"] = signal_on_guard ? one["out"]; + sig_reg["in"] = done_guard_2 ? zero["out"]; + sig_reg["write_en"] = done_guard_2 ? one["out"]; + ); + assigns.to_vec() + } +} + +impl Visitor for CompileStaticInterface { + fn start_static_control( + &mut self, + s: &mut ir::StaticControl, + comp: &mut ir::Component, + sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + if comp.is_static() && s.get_latency() > 1 { + let latency = s.get_latency(); + if let ir::StaticControl::Enable(sen) = s { + let mut builder = ir::Builder::new(comp, sigs); + let fsm_size = get_bit_width_from(latency + 1); + structure!( builder; + let fsm = prim std_reg(fsm_size); + ); + let mut assignments = + std::mem::take(&mut sen.group.borrow_mut().assignments); + let comp_sig = Rc::clone(&builder.component.signature); + let dyn_assigns = self + .make_early_reset_assigns_static_component( + &mut assignments, + s.get_latency(), + Rc::clone(&fsm), + &mut builder, + Rc::clone(&comp_sig), + ); + builder.component.continuous_assignments.extend(dyn_assigns); + if builder.component.attributes.has(ir::BoolAttr::Promoted) { + let done_assigns = self + .make_done_signal_for_promoted_component( + Rc::clone(&fsm), + &mut builder, + Rc::clone(&comp_sig), + ); + builder + .component + .continuous_assignments + .extend(done_assigns); + } + } + } else if comp.is_static() && s.get_latency() == 1 { + if let ir::StaticControl::Enable(sen) = s { + let assignments = + std::mem::take(&mut sen.group.borrow_mut().assignments); + for assign in assignments { + let comp_sig = Rc::clone(&comp.signature); + comp.continuous_assignments.push( + make_assign_dyn_one_cycle_static_comp(assign, comp_sig), + ); + } + if comp.attributes.has(ir::BoolAttr::Promoted) { + let mut builder = ir::Builder::new(comp, sigs); + let comp_sig = Rc::clone(&builder.component.signature); + let done_assigns = self + .make_done_signal_for_promoted_component_one_cycle( + &mut builder, + comp_sig, + ); + builder + .component + .continuous_assignments + .extend(done_assigns); + } + } + } + Ok(Action::Continue) + } + + fn finish( + &mut self, + comp: &mut ir::Component, + _sigs: &ir::LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + if comp.is_static() { + //let _c = std::mem::replace(&mut comp.control, Rc::new(RefCell::new(ir::Control::Static(ir::StaticControl::Empty(ir::Empty{attributes:Attributes::default()}))))); + let _c = std::mem::replace( + &mut comp.control, + Rc::new(RefCell::new(ir::Control::Empty(ir::Empty { + attributes: Attributes::default(), + }))), + ); + } + Ok(Action::Stop) + } +} diff --git a/calyx-opt/src/passes/dead_group_removal.rs b/calyx-opt/src/passes/dead_group_removal.rs index 798e88291..9e58841e2 100644 --- a/calyx-opt/src/passes/dead_group_removal.rs +++ b/calyx-opt/src/passes/dead_group_removal.rs @@ -100,6 +100,14 @@ impl Visitor for DeadGroupRemoval { } } } + + for assign in &comp.continuous_assignments { + let dst = assign.dst.borrow(); + if dst.is_hole() && dst.name == "go" { + self.used_groups.insert(dst.get_parent_name()); + } + } + for group in comp.get_static_groups().iter() { for assign in &group.borrow().assignments { let dst = assign.dst.borrow(); diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index cf9d261a3..414870fdf 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -34,6 +34,8 @@ mod static_inliner; mod static_promotion; mod sync; // mod simplify_guards; +mod add_guard; +mod compile_static_interface; mod data_path_infer; mod discover_external; mod simplify_with_control; @@ -82,6 +84,8 @@ pub use static_promotion::StaticPromotion; pub use sync::CompileSync; pub use sync::CompileSyncWithoutSyncReg; // pub use simplify_guards::SimplifyGuards; +pub use add_guard::AddGuard; +pub use compile_static_interface::CompileStaticInterface; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; pub use top_down_static_timing::TopDownStaticTiming; diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 0236941a1..7e95df3cf 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -688,6 +688,7 @@ impl StaticPromotion { latency: inferred_latency, attributes: std::mem::take(attributes), ref_cells: std::mem::take(ref_cells), + comb_group: std::mem::take(comb_group), }; ir::StaticControl::Invoke(s_inv) } @@ -806,8 +807,11 @@ impl Visitor for StaticPromotion { _lib: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if comp.control.borrow().is_static() { + if comp.name != "main" && comp.control.borrow().is_static() { if let Some(lat) = comp.control.borrow().get_latency() { + if !comp.is_static() { + comp.attributes.insert(ir::BoolAttr::Promoted, 1); + } comp.latency = Some(NonZeroU64::new(lat).unwrap()); let comp_sig = comp.signature.borrow(); let mut done_ports: Vec<_> = @@ -900,7 +904,7 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { // Shouldn't promote to static invoke if we have a comb group - if s.comp.borrow().is_component() && s.comb_group.is_none() { + if s.comp.borrow().is_component() { if let Some(latency) = self .static_component_latencies .get(&s.comp.borrow().type_name().unwrap()) diff --git a/calyx-opt/src/passes/wire_inliner.rs b/calyx-opt/src/passes/wire_inliner.rs index c3e8fde59..c730ccf94 100644 --- a/calyx-opt/src/passes/wire_inliner.rs +++ b/calyx-opt/src/passes/wire_inliner.rs @@ -54,29 +54,33 @@ impl Visitor for WireInliner { let control_ref = Rc::clone(&comp.control); let control = control_ref.borrow(); // Don't compile if the control program is empty - if let ir::Control::Empty(..) = &*control { - return Ok(Action::Stop); - } + // if let ir::Control::Empty(..) = &*control { + // return Ok(Action::Stop); + // } - if let ir::Control::Enable(data) = &*control { - let this = Rc::clone(&comp.signature); - let mut builder = ir::Builder::new(comp, sigs); - let group = &data.group; + match &*control { + ir::Control::Enable(data) => { + let this = Rc::clone(&comp.signature); + let mut builder = ir::Builder::new(comp, sigs); + let group = &data.group; - structure!(builder; - let one = constant(1, 1); - ); - let group_done = guard!(group["done"]); - let assigns = build_assignments!(builder; - group["go"] = ? this["go"]; - this["done"] = group_done ? one["out"]; - ); - comp.continuous_assignments.extend(assigns); - } else { - return Err(calyx_utils::Error::malformed_control(format!( - "{}: Structure has more than one group", - Self::name() - ))); + structure!(builder; + let one = constant(1, 1); + ); + let group_done = guard!(group["done"]); + let assigns = build_assignments!(builder; + group["go"] = ? this["go"]; + this["done"] = group_done ? one["out"]; + ); + comp.continuous_assignments.extend(assigns); + } + ir::Control::Empty(_) => {} + _ => { + return Err(calyx_utils::Error::malformed_control(format!( + "{}: Structure has more than one group", + Self::name() + ))); + } } // assume static groups is empty @@ -115,15 +119,15 @@ impl Visitor for WireInliner { gr.borrow_mut().assignments = assigns; }); + comp.continuous_assignments + .iter_mut() + .for_each(|assign| rewrite_assign(&hole_map, assign)); + let mut group_assigns = groups .into_iter() .flat_map(|g| g.borrow_mut().assignments.drain(..).collect_vec()) .collect_vec(); - comp.continuous_assignments - .iter_mut() - .for_each(|assign| rewrite_assign(&hole_map, assign)); - comp.continuous_assignments.append(&mut group_assigns); // remove group from control diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 4f61bc431..27bcdd76d 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -1,6 +1,6 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; -static<5> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @generated fsm = std_reg(3); @generated ud = undef(1); diff --git a/runt.toml b/runt.toml index ca25f45b2..fc4b140d3 100644 --- a/runt.toml +++ b/runt.toml @@ -124,6 +124,7 @@ paths = [ "tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil", "tests/correctness/sync/*.futil", + "tests/correctness/static-interface/*.futil", ] cmd = """ fud exec --from calyx --to jq \ @@ -140,7 +141,8 @@ timeout = 120 [[tests]] name = "correctness static timing" -paths = ["tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil"] +paths = ["tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil", +"tests/correctness/static-interface/*.futil" ] cmd = """ fud exec --from calyx --to jq \ --through verilog \ diff --git a/tests/correctness/static-interface/static-interface-promoted-one-cycle.expect b/tests/correctness/static-interface/static-interface-promoted-one-cycle.expect new file mode 100644 index 000000000..9b844adf4 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted-one-cycle.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 11 + ] +} diff --git a/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil new file mode 100644 index 000000000..be82a5a5e --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil @@ -0,0 +1,44 @@ +import "primitives/core.futil"; + +component do_add(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + out = r.out; + } + control { + a; + } + +} + +component main () -> () { + cells { + a = do_add(); + @external out = std_mem_d1(32, 1, 1); + } + wires { + group inv_a { + a.go = 1'd1; + a.left = 32'd5; + a.right = 32'd6; + out.write_data = a.done ? a.out; + out.write_en = a.done ? 1'd1; + out.addr0 = a.done ? 1'd0; + inv_a[done] = out.done; + } + } + + control { + inv_a; + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil.data b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface-promoted.expect b/tests/correctness/static-interface/static-interface-promoted.expect new file mode 100644 index 000000000..767b6e753 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 17 + ] +} diff --git a/tests/correctness/static-interface/static-interface-promoted.futil b/tests/correctness/static-interface/static-interface-promoted.futil new file mode 100644 index 000000000..f978950df --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted.futil @@ -0,0 +1,50 @@ +import "primitives/core.futil"; + +component do_add(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + static<1> group b { + add.left = r.out; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + out = r.out; + } + control { + static seq {a; b;} + } + +} + +component main () -> () { + cells { + a = do_add(); + @external out = std_mem_d1(32, 1, 1); + } + wires { + group inv_a { + a.go = 1'd1; + a.left = 32'd5; + a.right = 32'd6; + out.write_data = a.done ? a.out; + out.write_en = a.done ? 1'd1; + out.addr0 = a.done ? 1'd0; + inv_a[done] = out.done; + } + } + + control { + inv_a; + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface-promoted.futil.data b/tests/correctness/static-interface/static-interface-promoted.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-promoted.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface-repeat.expect b/tests/correctness/static-interface/static-interface-repeat.expect new file mode 100644 index 000000000..3309ff34b --- /dev/null +++ b/tests/correctness/static-interface/static-interface-repeat.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 41 + ] +} diff --git a/tests/correctness/static-interface/static-interface-repeat.futil b/tests/correctness/static-interface/static-interface-repeat.futil new file mode 100644 index 000000000..c4c6d9b43 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-repeat.futil @@ -0,0 +1,56 @@ +// -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface +import "primitives/core.futil"; + +static<6> component do_add(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = r.out; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + static<1> group b { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + out = r.out; + } + control { + static seq { + b; + static repeat 5 { + a; + } + } + } + +} + +component main () -> () { + cells { + a = do_add(); + @external out = std_mem_d1(32, 1, 1); + } + wires { + group a_to_out { + out.write_data = a.out; + out.write_en = 1'd1; + out.addr0 = 1'd0; + a_to_out[done] = out.done; + } + } + + control { + seq { + static invoke a(left=32'd5, right=32'd6)(); + a_to_out; + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface-repeat.futil.data b/tests/correctness/static-interface/static-interface-repeat.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/static-interface-repeat.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface.expect b/tests/correctness/static-interface/static-interface.expect new file mode 100644 index 000000000..767b6e753 --- /dev/null +++ b/tests/correctness/static-interface/static-interface.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 17 + ] +} diff --git a/tests/correctness/static-interface/static-interface.futil b/tests/correctness/static-interface/static-interface.futil new file mode 100644 index 000000000..73d0c71ac --- /dev/null +++ b/tests/correctness/static-interface/static-interface.futil @@ -0,0 +1,50 @@ +import "primitives/core.futil"; + +static<2> component do_add(left: 32, right: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + static<1> group b { + add.left = r.out; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + out = r.out; + } + control { + static seq {a; b;} + } + +} + +component main () -> () { + cells { + a = do_add(); + @external out = std_mem_d1(32, 1, 1); + } + wires { + group a_to_out { + out.write_data = a.out; + out.write_en = 1'd1; + out.addr0 = 1'd0; + a_to_out[done] = out.done; + } + } + + control { + seq { + static invoke a(left=32'd5, right=32'd6)(); + a_to_out; + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/static-interface.futil.data b/tests/correctness/static-interface/static-interface.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/static-interface.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect index 73fbadbca..d9269453e 100644 --- a/tests/passes/cell-share/inline.expect +++ b/tests/passes/cell-share/inline.expect @@ -15,7 +15,7 @@ component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset r @promote_static invoke0; } } -static<4> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @external @data mem = std_mem_d1(32, 2, 1); @generated r = std_reg(32); diff --git a/tests/passes/compile-invoke/compile-static-invoke.expect b/tests/passes/compile-invoke/compile-static-invoke.expect index b78e25044..91fb7a0e1 100644 --- a/tests/passes/compile-invoke/compile-static-invoke.expect +++ b/tests/passes/compile-invoke/compile-static-invoke.expect @@ -20,7 +20,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<4> group static_invoke { - exp0.go = 1'd1; + exp0.go = %0 ? 1'd1; exp0.base = r.out; exp0.exp = 4'd3; } diff --git a/tests/passes/compile-invoke/static-ref.expect b/tests/passes/compile-invoke/static-ref.expect index e81780ca0..d6547a511 100644 --- a/tests/passes/compile-invoke/static-ref.expect +++ b/tests/passes/compile-invoke/static-ref.expect @@ -52,7 +52,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { mem.write_en = adder.out_write_en; adder.out_read_data = mem.read_data; adder.out_done = mem.done; - adder.go = 1'd1; + adder.go = %0 ? 1'd1; } } control { diff --git a/tests/passes/compile-static-interface-one-cycle.expect b/tests/passes/compile-static-interface-one-cycle.expect new file mode 100644 index 000000000..fec73d83a --- /dev/null +++ b/tests/passes/compile-static-interface-one-cycle.expect @@ -0,0 +1,31 @@ +import "primitives/core.futil"; +static<1> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + } + r.write_en = go ? 1'd1; + add.right = go ? right; + add.left = go ? left; + r.in = go ? add.out; + } + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = do_add(); + } + wires { + static<1> group static_invoke { + a.go = %0 ? 1'd1; + a.left = 32'd5; + a.right = 32'd6; + } + } + control { + static_invoke; + } +} diff --git a/tests/passes/compile-static-interface-one-cycle.futil b/tests/passes/compile-static-interface-one-cycle.futil new file mode 100644 index 000000000..d58915b95 --- /dev/null +++ b/tests/passes/compile-static-interface-one-cycle.futil @@ -0,0 +1,32 @@ +// -p validate -p compile-invoke -p static-inline -p add-guard -p compile-static-interface +import "primitives/core.futil"; + +static<1> component do_add(left: 32, right: 32) -> () { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + } + control { + a; + } + +} + +component main () -> () { + cells { + a = do_add(); + } + wires {} + + control { + static invoke a(left=32'd5, right=32'd6)(); + } +} \ No newline at end of file diff --git a/tests/passes/compile-static-interface-repeat.expect b/tests/passes/compile-static-interface-repeat.expect new file mode 100644 index 000000000..718af6314 --- /dev/null +++ b/tests/passes/compile-static-interface-repeat.expect @@ -0,0 +1,55 @@ +import "primitives/core.futil"; +static<6> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add = std_add(32); + r = std_reg(32); + @generated fsm = std_reg(3); + @generated adder = std_add(3); + } + wires { + static<1> group a { + r.write_en = 1'd1; + add.right = right; + add.left = r.out; + r.in = add.out; + } + static<1> group b { + r.write_en = 1'd1; + add.right = right; + add.left = left; + r.in = add.out; + } + static<6> group static_seq { + } + static<5> group static_repeat { + a[go] = 1'd1; + } + r.write_en = go & fsm.out == 3'd0 ? 1'd1; + add.right = go & fsm.out == 3'd0 ? right; + add.left = go & fsm.out == 3'd0 ? left; + r.in = go & fsm.out == 3'd0 ? add.out; + a[go] = fsm.out >= 3'd1 & fsm.out < 3'd6 ? 1'd1; + adder.left = fsm.out; + adder.right = 3'd1; + fsm.write_en = 1'd1; + fsm.in = go & fsm.out == 3'd0 ? 3'd1; + fsm.in = fsm.out != 3'd0 & fsm.out != 3'd5 ? adder.out; + fsm.in = fsm.out == 3'd5 ? 3'd0; + } + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = do_add(); + } + wires { + static<6> group static_invoke { + a.go = %0 ? 1'd1; + a.left = 32'd5; + a.right = 32'd6; + } + } + control { + static_invoke; + } +} diff --git a/tests/passes/compile-static-interface-repeat.futil b/tests/passes/compile-static-interface-repeat.futil new file mode 100644 index 000000000..f3e0f7da6 --- /dev/null +++ b/tests/passes/compile-static-interface-repeat.futil @@ -0,0 +1,44 @@ +// -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface +import "primitives/core.futil"; + +static<6> component do_add(left: 32, right: 32) -> () { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = r.out; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + static<1> group b { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + } + control { + static seq { + b; + static repeat 5 { + a; + } + } + } + +} + +component main () -> () { + cells { + a = do_add(); + } + wires {} + + control { + static invoke a(left=32'd5, right = 32'd6)(); + } +} \ No newline at end of file diff --git a/tests/passes/compile-static-interface.expect b/tests/passes/compile-static-interface.expect new file mode 100644 index 000000000..05f01bd8d --- /dev/null +++ b/tests/passes/compile-static-interface.expect @@ -0,0 +1,55 @@ +import "primitives/core.futil"; +static<2> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + add = std_add(32); + r = std_reg(32); + @generated fsm = std_reg(2); + @generated adder = std_add(2); + } + wires { + static<1> group a { + r.write_en = 1'd1; + add.right = right; + add.left = left; + r.in = add.out; + } + static<1> group b { + r.write_en = 1'd1; + add.right = right; + add.left = r.out; + r.in = add.out; + } + static<2> group static_seq { + } + r.write_en = go & fsm.out == 2'd0 ? 1'd1; + add.right = go & fsm.out == 2'd0 ? right; + add.left = go & fsm.out == 2'd0 ? left; + r.in = go & fsm.out == 2'd0 ? add.out; + r.write_en = fsm.out == 2'd1 ? 1'd1; + add.right = fsm.out == 2'd1 ? right; + add.left = fsm.out == 2'd1 ? r.out; + r.in = fsm.out == 2'd1 ? add.out; + adder.left = fsm.out; + adder.right = 2'd1; + fsm.write_en = 1'd1; + fsm.in = go & fsm.out == 2'd0 ? 2'd1; + fsm.in = fsm.out != 2'd0 & fsm.out != 2'd1 ? adder.out; + fsm.in = fsm.out == 2'd1 ? 2'd0; + } + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = do_add(); + } + wires { + static<2> group static_invoke { + a.go = %0 ? 1'd1; + a.left = 32'd5; + a.right = 32'd6; + } + } + control { + static_invoke; + } +} diff --git a/tests/passes/compile-static-interface.futil b/tests/passes/compile-static-interface.futil new file mode 100644 index 000000000..a9cf82aac --- /dev/null +++ b/tests/passes/compile-static-interface.futil @@ -0,0 +1,39 @@ +// -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface +import "primitives/core.futil"; + +static<2> component do_add(left: 32, right: 32) -> () { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = left; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + + static<1> group b { + add.left = r.out; + add.right = right; + r.in = add.out; + r.write_en = 1'd1; + } + } + control { + static seq {a; b;} + } + +} + +component main () -> () { + cells { + a = do_add(); + } + wires {} + + control { + static invoke a(left=32'd5, right=32'd6)(); + } +} \ No newline at end of file diff --git a/tests/passes/static-promotion/component.expect b/tests/passes/static-promotion/component.expect index 5515c1b23..e311382bc 100644 --- a/tests/passes/static-promotion/component.expect +++ b/tests/passes/static-promotion/component.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); b = std_reg(2); diff --git a/tests/passes/static-promotion/invoke.expect b/tests/passes/static-promotion/invoke.expect index cb0f4671b..ccbd7e55a 100644 --- a/tests/passes/static-promotion/invoke.expect +++ b/tests/passes/static-promotion/invoke.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); exp0 = exponent(); @@ -16,11 +16,12 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done static<2> invoke exp0( base = r.out, exp = r.out - )(); + )() + ); } } } -static<2> component exponent(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-promotion/multi-static.expect b/tests/passes/static-promotion/multi-static.expect index 5413970bf..ee0ef2e7d 100644 --- a/tests/passes/static-promotion/multi-static.expect +++ b/tests/passes/static-promotion/multi-static.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); exp0 = exponent(); @@ -16,11 +16,12 @@ static<3> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done static<2> invoke exp0( base = r.out, exp = r.out - )(); + )() + ); } } } -static<2> component exponent(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-promotion/upgrade-bound.expect b/tests/passes/static-promotion/upgrade-bound.expect index 9fc156ea6..18962c3e1 100644 --- a/tests/passes/static-promotion/upgrade-bound.expect +++ b/tests/passes/static-promotion/upgrade-bound.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -static<15> component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); b = std_reg(2); From 38f3449c9e725b1e3418cffc860089adc8145394 Mon Sep 17 00:00:00 2001 From: bcarlet <8906114+bcarlet@users.noreply.github.com> Date: Sun, 12 Nov 2023 20:11:11 -0500 Subject: [PATCH 089/189] `fud` stages for HLS place and route (#1773) * Stages for HLS place and route * tclargs doesn't allow flags * Add missing description * Documentation --- fud/fud/main.py | 2 + fud/fud/stages/vivado/__init__.py | 4 ++ fud/fud/stages/vivado/extract.py | 47 ++++++++++------ fud/fud/stages/vivado/stage.py | 91 ++++++++++++++++++++++++++++--- fud/synth/hls.tcl | 38 ++++++++++++- 5 files changed, 156 insertions(+), 26 deletions(-) diff --git a/fud/fud/main.py b/fud/fud/main.py index 59c0f07e9..5b89d86bc 100644 --- a/fud/fud/main.py +++ b/fud/fud/main.py @@ -135,6 +135,8 @@ def register_stages(registry): registry.register(vivado.VivadoExtractStage()) registry.register(vivado.VivadoHLSStage()) registry.register(vivado.VivadoHLSExtractStage()) + registry.register(vivado.VivadoHLSPlaceAndRouteStage()) + registry.register(vivado.VivadoHLSPlaceAndRouteExtractStage()) # Vcdump registry.register(vcdump.VcdumpStage()) diff --git a/fud/fud/stages/vivado/__init__.py b/fud/fud/stages/vivado/__init__.py index 3f46c0a87..e041f517d 100644 --- a/fud/fud/stages/vivado/__init__.py +++ b/fud/fud/stages/vivado/__init__.py @@ -3,6 +3,8 @@ VivadoExtractStage, VivadoHLSStage, VivadoHLSExtractStage, + VivadoHLSPlaceAndRouteStage, + VivadoHLSPlaceAndRouteExtractStage, ) __all__ = [ @@ -10,4 +12,6 @@ "VivadoExtractStage", "VivadoHLSStage", "VivadoHLSExtractStage", + "VivadoHLSPlaceAndRouteStage", + "VivadoHLSPlaceAndRouteExtractStage", ] diff --git a/fud/fud/stages/vivado/extract.py b/fud/fud/stages/vivado/extract.py index bb0cc0d23..964e95ee2 100644 --- a/fud/fud/stages/vivado/extract.py +++ b/fud/fud/stages/vivado/extract.py @@ -1,6 +1,6 @@ import json import os -from pathlib import Path +from pathlib import Path, PurePath import re import traceback import logging as log @@ -37,9 +37,9 @@ def file_contains(regex, filename): return len(strings) == 0 -def rtl_component_extract(directory, name): +def rtl_component_extract(file: Path, name: str): try: - with (directory / "synth_1" / "runme.log").open() as f: + with file.open() as f: log = f.read() comp_usage = re.search( r"Start RTL Component Statistics(.*?)Finished RTL", log, re.DOTALL @@ -52,21 +52,30 @@ def rtl_component_extract(directory, name): return 0 -def futil_extract(directory): - # Search for directory named FutilBuild.runs +def place_and_route_extract( + directory: Path, + files_root: str, + utilization_file: PurePath, + timing_file: PurePath, + synthesis_file: PurePath, +): + # Search for the given root directory for root, dirs, _ in os.walk(directory): for d in dirs: - if d == "FutilBuild.runs": + if d == files_root: directory = Path(os.path.join(root, d)) break + util_file = directory / utilization_file + synth_file = directory / synthesis_file + timing_file = directory / timing_file + # The resource information is extracted first for the implementation files, and # then for the synthesis files. This is done separately in case users want to # solely use one or the other. resource_info = {} # Extract utilization information - util_file = directory / "impl_1" / "main_utilization_placed.rpt" try: if util_file.exists(): impl_parser = rpt.RPTParser(util_file) @@ -87,8 +96,8 @@ def futil_extract(directory): find_row(slice_logic, "Site Type", "CLB LUTs")["Used"] ), "dsp": to_int(find_row(dsp_table, "Site Type", "DSPs")["Used"]), - "registers": rtl_component_extract(directory, "Registers"), - "muxes": rtl_component_extract(directory, "Muxes"), + "registers": rtl_component_extract(synth_file, "Registers"), + "muxes": rtl_component_extract(synth_file, "Muxes"), "clb_registers": clb_reg, "carry8": carry8, "f7_muxes": f7_muxes, @@ -105,7 +114,6 @@ def futil_extract(directory): log.error("Failed to extract utilization information") # Get timing information - timing_file = directory / "impl_1" / "main_timing_summary_routed.rpt" if not timing_file.exists(): log.error(f"Timing file {timing_file} is missing") else: @@ -132,7 +140,6 @@ def futil_extract(directory): ) # Extraction for synthesis files. - synth_file = directory / "synth_1" / "runme.log" try: if not synth_file.exists(): log.error(f"Synthesis file {synth_file} is missing") @@ -169,18 +176,26 @@ def futil_extract(directory): return json.dumps(resource_info, indent=2) -def hls_extract(directory): - directory = directory / "benchmark.prj" / "solution1" +def hls_extract(directory: Path, top: str): + # Search for directory named benchmark.prj + for root, dirs, _ in os.walk(directory): + for d in dirs: + if d == "benchmark.prj": + directory = Path(os.path.join(root, d)) + break + + directory = directory / "solution1" + try: - parser = rpt.RPTParser(directory / "syn" / "report" / "kernel_csynth.rpt") + parser = rpt.RPTParser(directory / "syn" / "report" / f"{top}_csynth.rpt") summary_table = parser.get_table(re.compile(r"== Utilization Estimates"), 2) instance_table = parser.get_table(re.compile(r"\* Instance:"), 0) solution_data = json.load((directory / "solution1_data.json").open()) - latency = solution_data["ModuleInfo"]["Metrics"]["kernel"]["Latency"] + latency = solution_data["ModuleInfo"]["Metrics"][top]["Latency"] total_row = find_row(summary_table, "Name", "Total") - s_axi_row = find_row(instance_table, "Instance", "kernel_control_s_axi_U") + s_axi_row = find_row(instance_table, "Instance", f"{top}_control_s_axi_U") return json.dumps( { diff --git a/fud/fud/stages/vivado/stage.py b/fud/fud/stages/vivado/stage.py index 4256ef919..775f5436c 100644 --- a/fud/fud/stages/vivado/stage.py +++ b/fud/fud/stages/vivado/stage.py @@ -1,5 +1,5 @@ import shutil -from pathlib import Path +from pathlib import Path, PurePath import os from fud.stages import SourceType, Stage @@ -7,7 +7,7 @@ from fud.utils import TmpDir, shell from fud import config as cfg -from .extract import futil_extract, hls_extract +from .extract import hls_extract, place_and_route_extract class VivadoBaseStage(Stage): @@ -42,12 +42,19 @@ def device_files(self, config): """ pass + def extra_flags(self, config): + """ + Extra flags to append to the command. + """ + return "" + def _define_steps(self, verilog_path, builder, config): use_ssh = bool(config.get(["stages", self.name, "remote"])) + flags = f"{self.flags} {self.extra_flags(config)}" if use_ssh: - cmd = f"{config['stages', self.name, 'exec']} {self.flags}" + cmd = f"{config['stages', self.name, 'exec']} {flags}" else: - cmd = f"{self.remote_exec} {self.flags}" + cmd = f"{self.remote_exec} {flags}" # Steps and schedule local_tmpdir = self.setup_environment(verilog_path, builder, config) @@ -149,10 +156,39 @@ def __init__(self): def device_files(self, config): root = Path(config["global", cfg.ROOT]) return [ - str(root / "fud" / "synth" / "hls.tcl"), - str(root / "fud" / "synth" / "fxp_sqrt.h"), + root / "fud" / "synth" / "hls.tcl", + root / "fud" / "synth" / "fxp_sqrt.h", + ] + + def extra_flags(self, config): + top = config.get(["stages", self.name, "top"]) + return f"-tclargs top {top}" if top else "" + + +class VivadoHLSPlaceAndRouteStage(VivadoBaseStage): + name = "vivado-hls" + + def __init__(self): + super().__init__( + "vivado-hls", + "hls-files-routed", + "Performs placement and routing of RTL generated by Vivado HLS", + target_name="kernel.cpp", + remote_exec="vivado_hls", + flags="-f hls.tcl -tclargs impl", + ) + + def device_files(self, config): + root = Path(config["global", cfg.ROOT]) + return [ + root / "fud" / "synth" / "hls.tcl", + root / "fud" / "synth" / "fxp_sqrt.h", ] + def extra_flags(self, config): + top = config.get(["stages", self.name, "top"]) + return f"top {top}" if top else "" + class VivadoExtractStage(Stage): name = "synth-files" @@ -172,7 +208,13 @@ def extract(directory: SourceType.Directory) -> SourceType.String: """ Extract relevant data from Vivado synthesis files. """ - return futil_extract(Path(directory.name)) + return place_and_route_extract( + Path(directory.name), + "FutilBuild.runs", + PurePath("impl_1", "main_utilization_placed.rpt"), + PurePath("impl_1", "main_timing_summary_routed.rpt"), + PurePath("synth_1", "runme.log"), + ) return extract(input) @@ -195,6 +237,39 @@ def extract(directory: SourceType.Directory) -> SourceType.String: """ Extract relevant data from Vivado synthesis files. """ - return hls_extract(Path(directory.name)) + top = config.get(["stages", self.name, "top"]) or "kernel" + return hls_extract(Path(directory.name), top) + + return extract(input) + + +class VivadoHLSPlaceAndRouteExtractStage(Stage): + name = "hls-files-routed" + + def __init__(self): + super().__init__( + src_state="hls-files-routed", + target_state="hls-detailed-estimate", + input_type=SourceType.Directory, + output_type=SourceType.String, + description="Extracts information from Vivado HLS synthesis files", + ) + + def _define_steps(self, input, builder, config): + @builder.step() + def extract(directory: SourceType.Directory) -> SourceType.String: + """ + Extract relevant data from Vivado synthesis files. + """ + top = config.get(["stages", self.name, "top"]) or "kernel" + verilog_dir = PurePath("solution1", "impl", "verilog") + + return place_and_route_extract( + Path(directory.name), + "benchmark.prj", + verilog_dir / "report" / f"{top}_utilization_routed.rpt", + verilog_dir / "report" / f"{top}_timing_routed.rpt", + verilog_dir / "project.runs" / "bd_0_hls_inst_0_synth_1" / "runme.log", + ) return extract(input) diff --git a/fud/synth/hls.tcl b/fud/synth/hls.tcl index a99576340..561c5d08f 100644 --- a/fud/synth/hls.tcl +++ b/fud/synth/hls.tcl @@ -1,7 +1,32 @@ +# Usage: vivado_hls -f hls.tcl -tclargs [impl] [top ] + +proc lshift listVar { + upvar 1 $listVar l + set r [lindex $l 0] + set l [lreplace $l [set l 0] 0] + return $r +} + +set impl 0 +set top kernel set hls_prj benchmark.prj + +while {[llength $argv]} { + set flag [lshift argv] + switch -exact -- $flag { + impl { + set impl 1 + } + top { + set top [lshift argv] + } + } +} + open_project ${hls_prj} -reset -set_top kernel; # The name of the hardware function. -add_files [glob ./*.cpp] -cflags "-std=c++11 -DVHLS" ; # HLS source files. +set_top $top; # The name of the hardware function. +add_files [glob ./*.cpp] -cflags "-std=c++11 -DVHLS"; # HLS source files. + open_solution "solution1" set_part xczu3eg-sbva484-1-e create_clock -period 7 @@ -9,4 +34,13 @@ create_clock -period 7 # Actions we can take include csim_design, csynth_design, or cosim_design. csynth_design +if {$impl} { + # Exporting the design gives us a convenient way to run place and route via + # the `-flow impl` option. Another option is `-flow syn` if you only need to + # run RTL synthesis. + # The packaging options don't matter for our purposes, but we set the version + # to 1.1.0 to circumvent this bug: https://support.xilinx.com/s/article/76960 + export_design -format ip_catalog -version 1.1.0 -flow impl +} + exit From b2c990abfbd9b8546c6275829198fc633551ed02 Mon Sep 17 00:00:00 2001 From: Elias Castro <127804425+eliascxstro@users.noreply.github.com> Date: Mon, 13 Nov 2023 22:08:12 -0500 Subject: [PATCH 090/189] Cider-dap changes (#1768) * Cleaned up UnhandledCommandError * Added the SetBreakPoints command to the debugger * Added SetExceptionBreakpoints * Cleaned up code and added threads command, debugger now runs * PR revisions --------- Co-authored-by: root --- cider-dap/src/adapter.rs | 83 +++++++++++++++++++++++++++++++++++++++- cider-dap/src/error.rs | 5 ++- cider-dap/src/main.rs | 49 ++++++++++++++++++++++-- 3 files changed, 129 insertions(+), 8 deletions(-) diff --git a/cider-dap/src/adapter.rs b/cider-dap/src/adapter.rs index 78a09a5e9..9b0837c35 100644 --- a/cider-dap/src/adapter.rs +++ b/cider-dap/src/adapter.rs @@ -1,12 +1,91 @@ +use dap::types::{Breakpoint, Source, SourceBreakpoint, Thread}; use std::fs::File; pub struct MyAdapter { #[allow(dead_code)] file: File, - // Other fields of the struct + breakpoints: Vec<(Source, i64)>, //This field is a placeholder + break_count: Counter, + threads: Vec, //This field is a placeholder } impl MyAdapter { pub fn new(file: File) -> Self { - MyAdapter { file } + MyAdapter { + file, + breakpoints: Vec::new(), + break_count: Counter::new(), + threads: Vec::new(), + } + } + + ///Set breakpoints for adapter + pub fn set_breakpoint( + &mut self, + path: Source, + source: &Vec, + ) -> Vec { + //Keep all the new breakpoints made + let mut out_vec: Vec = vec![]; + + //Loop over all breakpoints + for source_point in source { + self.breakpoints.push((path.clone(), source_point.line)); + //Create new Breakpoint instance + let breakpoint = make_breakpoint( + self.break_count.increment().into(), + true, + Some(path.clone()), + ); + + out_vec.push(breakpoint); + } + + out_vec + } + + /// Clone threads + pub fn clone_threads(&self) -> Vec { + self.threads.clone() + } +} + +/// Simple struct used to keep an index of the breakpoints used. +pub struct Counter { + value: i64, +} + +impl Counter { + pub fn new() -> Self { + Counter { value: 0 } + } + + /// Increment the counter by 1 and return the OLD value + pub fn increment(&mut self) -> i64 { + let out = self.value; + self.value += 1; + out + } +} + +/// Returns a Breakpoint object. +/// +/// This function takes in relevant fields in Breakpoint that are used +/// by the adapter. This is subject to change. +pub fn make_breakpoint( + id: Option, + verified: bool, + source: Option, +) -> Breakpoint { + Breakpoint { + id, + verified, + message: None, + source, + line: None, + column: None, + end_line: None, + end_column: None, + instruction_reference: None, + offset: None, } } diff --git a/cider-dap/src/error.rs b/cider-dap/src/error.rs index 70bc5e439..81c2b41c0 100644 --- a/cider-dap/src/error.rs +++ b/cider-dap/src/error.rs @@ -1,11 +1,12 @@ use dap::errors::ServerError; +use dap::requests::Command; #[allow(dead_code)] // remove this later #[derive(thiserror::Error, Debug)] pub enum MyAdapterError { /// Represents an unhandled command error. - #[error("Unhandled command")] - UnhandledCommandError, + #[error("Unhandled command: {0:?}")] + UnhandledCommandError(Command), /// Represents an error when unable to parse the file. #[error("Unable to parse the file: {0}")] diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index 3bb2b1657..1681ec3c3 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -2,6 +2,9 @@ mod adapter; mod error; use adapter::MyAdapter; +use dap::responses::{ + SetBreakpointsResponse, SetExceptionBreakpointsResponse, ThreadsResponse, +}; use error::MyAdapterError; use dap::prelude::*; @@ -81,7 +84,12 @@ where server.respond(rsp)?; server.send_event(Event::Initialized)?; } - _ => return Err(MyAdapterError::UnhandledCommandError), + + unknown_command => { + return Err(MyAdapterError::UnhandledCommandError( + unknown_command.clone(), + )); + } } // handle the second request (Launch) @@ -119,7 +127,7 @@ where fn run_server( server: &mut Server, - _adapter: MyAdapter, + mut adapter: MyAdapter, ) -> AdapterResult<()> { loop { // Start looping here @@ -132,13 +140,46 @@ fn run_server( let rsp = req.success(ResponseBody::Launch); server.respond(rsp)?; } + + Command::SetBreakpoints(args) => { + //Add breakpoints + if let Some(breakpoint) = &args.breakpoints { + let out = + adapter.set_breakpoint(args.source.clone(), breakpoint); + + //Success + let rsp = req.success(ResponseBody::SetBreakpoints( + SetBreakpointsResponse { breakpoints: (out) }, + )); + server.respond(rsp)?; + } + } + + //TODO: Implement this request fully when adapter becomes functional + Command::SetExceptionBreakpoints(_) => { + let rsp = req.success(ResponseBody::SetExceptionBreakpoints( + SetExceptionBreakpointsResponse { + breakpoints: (None), + }, + )); + server.respond(rsp)?; + } + + //Retrieve a list of all threads + Command::Threads => { + let rsp = req.success(ResponseBody::Threads(ThreadsResponse { + threads: adapter.clone_threads(), + })); + server.respond(rsp)?; + } // Here, can add a match pattern for a disconnect or exit command // to break out of the loop and close the server. // Command::Disconnect(_) => break, // ... unknown_command => { - eprintln!("Unknown_command: {:?}", unknown_command); - return Err(MyAdapterError::UnhandledCommandError); + return Err(MyAdapterError::UnhandledCommandError( + unknown_command.clone(), + )); } } } From cf6bea2d8f982d4219a7305e2b4ca748110aba93 Mon Sep 17 00:00:00 2001 From: kadenlei <95266101+kadenlei@users.noreply.github.com> Date: Tue, 14 Nov 2023 21:11:10 -0500 Subject: [PATCH 091/189] Converted extension.js to typescript (#1772) * Started working on ts conversion * Worked on ts file * Deleted accidentally committed files * Converted to ts and made ports and path configurable * Edited README * deleted extension.js --- cider-dap/README.md | 97 ++++++++++++------- .../calyxDebug/{extension.js => extension.ts} | 74 +++++++++----- cider-dap/calyxDebug/package.json | 88 ++++++++++------- 3 files changed, 165 insertions(+), 94 deletions(-) rename cider-dap/calyxDebug/{extension.js => extension.ts} (65%) diff --git a/cider-dap/README.md b/cider-dap/README.md index 672f1ee1b..44b371a7a 100644 --- a/cider-dap/README.md +++ b/cider-dap/README.md @@ -1,9 +1,12 @@ # Cider Debug Adapter + ## Installing the extension + Navigate to your vscode extension directory `~/.vscode/extensions` for local -installations. For WSL users, you need to use the *server's* extension folder not +installations. For WSL users, you need to use the _server's_ extension folder not the normal installation in windows. Once in the appropriate folder create a symlink for the extension + ``` ln -s /cider-dap/calyxDebug cider.cider-dap-0.0.1 ``` @@ -11,115 +14,139 @@ ln -s /cider-dap/calyxDebug cider.cider-dap-0.0.1 Once vscode is reloaded, the extension should be active and viewable in the `Cider dap` tab of the output panel. You will also need to create a symlink for the cider-dap binary somewhere on your path. From some directory on your PATH: + ``` ln -s /target/debug/cider-dap ``` -You can then launch the adapter with the Launch Program (Multi Session) action +You will have to configure user settings of cider-dap in VSCode and input your cider binary path and port number. You can then launch the adapter with the Launch Program (Multi Session) action ## Known issues - * The launch action can sometimes attempt a connection before the server is - ready and will cause a failure, subsequent attempts will work until the - server closes. Ideally the extension would wait until the server has fully launched. +- The launch action can sometimes attempt a connection before the server is + ready and will cause a failure, subsequent attempts will work until the + server closes. Ideally the extension would wait until the server has fully launched. ## Project Overview: + Cider-dap is a debug adapter protocol implementation using Rust, which aids in debugging processes. It interfaces with IDEs or other tools using the Debug Adapter Protocol. This project primarily leverages the Debug Adapter Protocol (DAP) for its functionality. The structure is organized into different directories and files which encapsulate the functionalities:
+
1.`cider-dap` directory: The main directory which contains the following sub-directories and files:
-1.``` cider-dap ``` directory: The main directory which contains the following sub-directories and files: -
-        ```calyxDebug```: Contains the file responsible for debugging extensions and related utilities. So it is a dedicated directory for VSCode debugging extensions. It establishes the bridge between your Rust codebase and the VSCode debugging environment.
-        ```src```: Houses the Rust source files for the project. It contains the project's core functionalities, logic, and structures.
-        ```cargo.lock``` & ```cargo.toml```: Standard Rust project files detailing dependencies and project metadata.
-3. ```src``` directory:
-        ```adapter.rs```: Defines the primary adapter structure for the project and its associated functionalities. Not just any adapter, this file structures the fundamental protocols, handling the translation of high-level debugging commands into actionable, low-level instructions.
-        ```error.rs```: Contains custom error definitions and types for better error handling.
-        ```main.rs```: The entry point for the project, it integrates functionalities from the other source files and provides the main execution logic.
-4. ```calyxDebug``` directory:
-        ```extension.js```: JavaScript file for VSCode extension integration. It provides functions to interface between the VSCode environment and the Rust backend.
+        `calyxDebug`: Contains the file responsible for debugging extensions and related utilities. So it is a dedicated directory for VSCode debugging extensions. It establishes the bridge between your Rust codebase and the VSCode debugging environment.
+        `src`: Houses the Rust source files for the project. It contains the project's core functionalities, logic, and structures.
+        `cargo.lock` & `cargo.toml`: Standard Rust project files detailing dependencies and project metadata.
3. `src` directory:
+        `adapter.rs`: Defines the primary adapter structure for the project and its associated functionalities. Not just any adapter, this file structures the fundamental protocols, handling the translation of high-level debugging commands into actionable, low-level instructions.
+        `error.rs`: Contains custom error definitions and types for better error handling.
+        `main.rs`: The entry point for the project, it integrates functionalities from the other source files and provides the main execution logic.
4. `calyxDebug` directory:
+        `extension.js`: JavaScript file for VSCode extension integration. It provides functions to interface between the VSCode environment and the Rust backend.
### About main.rs: the Main File -In ``` main.rs ```, our program is set up to accommodate both single and multi-session debugging. It defines the entry point of our application and orchestrates how the server is run based on user-provided arguments. + +In `main.rs`, our program is set up to accommodate both single and multi-session debugging. It defines the entry point of our application and orchestrates how the server is run based on user-provided arguments. #### Initialization: -At the start of the ```main()``` function: + +At the start of the `main()` function: - The Opts struct captures command-line arguments. This struct contains an optional file path, a switch to determine if the application runs in multi-session mode, and a port number (with a default of 8080). -- ```argh::from_env()``` processes the command-line arguments based on the defined struct. The use of argh simplifies command-line parsing, allowing you to focus on the main logic without getting bogged down in argument processing. +- `argh::from_env()` processes the command-line arguments based on the defined struct. The use of argh simplifies command-line parsing, allowing you to focus on the main logic without getting bogged down in argument processing. #### Single vs. Multi-Session Decision: -Depending on whether the ```is_multi_session flag``` is set: + +Depending on whether the `is_multi_session flag` is set: ##### Multi-Session: + -         A TCP listener is set up, which will listen for incoming debugger connections. -         On accepting a connection, the streams are buffered for efficient I/O operations. -         The multi_session_init function gets the adapter configured for the session, handling initial handshakes like the Initialize and Launch commands. -         The run_server function then takes over, orchestrating the actual debugging session with the given adapter. + ##### Single-Session: + -         Directly reads from standard input and writes to standard output. -         Instead of expecting and processing initial handshakes, the function simply sets up the adapter with the provided file and begins the server loop. This dual mode is valuable: the single-session approach allows for streamlined debugging in local environments or for simpler setups, while the multi-session setup allows for more advanced scenarios, perhaps remote debugging or handling multiple debugger sessions. -#### ```multi_session_init``` +#### `multi_session_init` + This function sets up an adapter for a multi-session environment. Here's a step-by-step breakdown: + ##### 1. Initial Handshake: + - It first waits for and processes an Initialize request. This is fundamental in the DAP as it establishes the initial connection between the debugger client and server. - After successfully processing this request, it sends an Initialized event to notify the client that the server is ready for subsequent commands. ##### 2. Setup: + - The next expected command is a Launch command. This command contains additional information (like the path to the program being debugged). This path is extracted and checked for validity. - The program is then opened and used to construct the MyAdapter instance. -The purpose of this function is to perform the initial setup necessary to start a debugging session. By separating it from the run_server function, the code remains modular, allowing for easier debugging, testing, and modification. + The purpose of this function is to perform the initial setup necessary to start a debugging session. By separating it from the run_server function, the code remains modular, allowing for easier debugging, testing, and modification. + +#### run_server : -#### run_server : The heart of the debugger's runtime: ##### Core Loop : The function continuously polls for requests from the client. + - Upon receiving a Launch command, it sends a successful response back to the client. This indicates that the server is ready to begin debugging. - The loop can be expanded to handle other DAP commands as needed. For example, handling a Disconnect command could cleanly terminate the loop and close the server. ##### Command Processing: + - The only command being actively handled right now is the Launch command. Upon receiving this command, the server simply responds with a success message, indicating that it's ready to commence debugging. - The loop is designed with extensibility in mind. Comments suggest places where commands like Disconnect can be incorporated to handle disconnection events, allowing the server to terminate gracefully. ##### Error Handling : + - If an unknown command is received, it's printed to the error output and the server terminates with an UnhandledCommandError. - This is a robust approach, ensuring that only expected commands are processed and any anomalies are immediately flagged. ### Dependencies + The following dependencies have been added to the project as specified in the cargo.toml:
-- ```dap```: Rust DAP implementation. At its core, this Rust DAP implementation is what powers cider-dap. It's the backbone that ensures all debugging actions are in line with the protocol's standards.
-- ```thiserror```: Used for ergonomic error handling. Enhancing error handling by providing more contextual feedback and streamlined debugging.
-- ```serde_json``` & ```serde```: Serialization and deserialization of data. Essential for data communication. They ensure that data structures are efficiently serialized and deserialized between different parts of the system.
-- ```owo-colors```: For colored console output. So it elevates user experience by introducing color-coded outputs, making console interactions more intuitive.
-- ```argh```: For command line argument parsing. It simplifies command line interactions, ensuring that user inputs are effectively parsed and processed.
+ +- `dap`: Rust DAP implementation. At its core, this Rust DAP implementation is what powers cider-dap. It's the backbone that ensures all debugging actions are in line with the protocol's standards.
+- `thiserror`: Used for ergonomic error handling. Enhancing error handling by providing more contextual feedback and streamlined debugging.
+- `serde_json` & `serde`: Serialization and deserialization of data. Essential for data communication. They ensure that data structures are efficiently serialized and deserialized between different parts of the system.
+- `owo-colors`: For colored console output. So it elevates user experience by introducing color-coded outputs, making console interactions more intuitive.
+- `argh`: For command line argument parsing. It simplifies command line interactions, ensuring that user inputs are effectively parsed and processed.
### Running the Project + 1. Ensure you have the necessary dependencies installed. If not, you can install them using cargo: - ```cargo install ``` -3. To run the main project: -```cargo run ``` + `cargo install ` +2. To run the main project: + `cargo run ` ### Next Steps 1. Advanced Error Handling: Utilize the structures in error.rs to provide detailed insights, potentially integrating with external error databases or logs. 2. Command Enhancements: Augment the DAP commands and responses in main.rs, exploring beyond traditional debugging actions. 3. There are changes needed to be done inside run_server: + ### Additional Command Handling: + - Incorporate command handlers for other DAP commands: -- ```Disconnect ```: Handle disconnect commands gracefully, ensuring any necessary cleanup is done before closing the server. -- ```Breakpoint ```: Implement functionality to pause execution at specific points. -- ```StepOver ```, ```StepInto ```, ```StepOut ```: Allow fine-grained control over the debugging process, allowing users to inspect code step-by-step. -- ```Evaluate ```: Handle evaluation requests from the debugger, returning values as needed. +- `Disconnect `: Handle disconnect commands gracefully, ensuring any necessary cleanup is done before closing the server. +- `Breakpoint `: Implement functionality to pause execution at specific points. +- `StepOver `, `StepInto `, `StepOut `: Allow fine-grained control over the debugging process, allowing users to inspect code step-by-step. +- `Evaluate `: Handle evaluation requests from the debugger, returning values as needed. + ### Refined Error Handling: + - Instead of immediate termination on an unknown command, consider logging these events or sending specific error messages back to the client. This provides a more user-friendly debugging experience. + ### Enhanced Logging: + - Implement more detailed logging to provide insights into server operations. This would be especially useful in identifying issues or understanding the flow of commands and responses. + ### Asynchronous Processing: + - Consider incorporating asynchronous command processing. This would allow the server to handle multiple requests concurrently, offering faster response times and smoother user experiences, especially in complex debugging scenarios. diff --git a/cider-dap/calyxDebug/extension.js b/cider-dap/calyxDebug/extension.ts similarity index 65% rename from cider-dap/calyxDebug/extension.js rename to cider-dap/calyxDebug/extension.ts index 43cfb9c31..10fb8144e 100644 --- a/cider-dap/calyxDebug/extension.js +++ b/cider-dap/calyxDebug/extension.ts @@ -1,6 +1,6 @@ -const vscode = require('vscode'); -const cp = require('child_process'); -const net = require('net'); +import * as vscode from "vscode"; +import cp = require("child_process"); +import net = require("net"); // Hold the debug adapter instance let debugAdapter = null; @@ -16,14 +16,18 @@ function logToPanel(message) { // Function to get the program name from the user async function getProgramName() { const fileName = await vscode.window.showInputBox({ - placeHolder: 'Please enter the name of a futil file in the workspace folder', - value: 'default.futil' + placeHolder: + "Please enter the name of a futil file in the workspace folder", + value: "default.futil", }); if (fileName) { - if (!fileName.startsWith('/')) { - const path = require('path'); - return path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, fileName); + if (!fileName.startsWith("/")) { + const path = require("path"); + return path.join( + vscode.workspace.workspaceFolders[0].uri.fsPath, + fileName + ); } return fileName; } else { @@ -32,6 +36,11 @@ async function getProgramName() { } class CiderDebugAdapterDescriptorFactory { + adapter: CiderDebugAdapter; + adapterPath: string; + workspace: string; + outputChannel: object; + constructor(adapterPath, workspace, outputChannel) { logToPanel("inside constructor"); this.adapter = new CiderDebugAdapter(adapterPath, workspace, outputChannel); @@ -49,8 +58,8 @@ class CiderDebugAdapterDescriptorFactory { _startDebugServer(session) { logToPanel("start of startDebugServer"); - const port = 8888; // This is the default value - + // default port: 8888 + const port = vscode.workspace.getConfiguration("cider-dap").port; if (!this.adapter.isServerRunning()) { logToPanel("server is not running"); this.adapter.start(port); @@ -62,6 +71,12 @@ class CiderDebugAdapterDescriptorFactory { } } class CiderDebugAdapter { + adapterPath: string; + outputChannel: object; + cwd: string; + adapterProcess: cp.ChildProcessWithoutNullStreams | null; + isRunning: boolean; + constructor(adapterPath, cwd, outputChannel) { logToPanel("inside CiderDebugAdapter"); this.adapterPath = adapterPath; @@ -76,26 +91,29 @@ class CiderDebugAdapter { } // Start the debug adapter process start(port) { - logToPanel('beginning of start'); + logToPanel("beginning of start"); // Spawn a new child process for the debug adapter // Include the port as a command line argument - this.adapterProcess = cp.spawn(this.adapterPath, [programName, '--port', port, "--tcp"], { cwd: this.cwd }); + this.adapterProcess = cp.spawn( + this.adapterPath, + [programName, "--port", port, "--tcp"], + { cwd: this.cwd } + ); // Attach event listener to capture standard output of the adapter process and log it to the output channel - this.adapterProcess.stdout.on('data', (data) => { + this.adapterProcess.stdout.on("data", (data) => { logToPanel(data.toString()); }); // Attach event listener to capture standard error of the adapter process and log it to the output channel - this.adapterProcess.stderr.on('data', (data) => { + this.adapterProcess.stderr.on("data", (data) => { logToPanel(data.toString()); }); - this.adapterProcess.on('spawn', () => { - logToPanel('Debugger started on port ' + port + '!'); + this.adapterProcess.on("spawn", () => { + logToPanel("Debugger started on port " + port + "!"); }); - } stop() { @@ -103,19 +121,25 @@ class CiderDebugAdapter { this.adapterProcess.kill(); this.adapterProcess = null; this.isRunning = false; - logToPanel('Debugger stopped.'); + logToPanel("Debugger stopped."); } else { - logToPanel('No running debug adapter to stop.'); + logToPanel("No running debug adapter to stop."); } } } function activate(context) { - logToPanel('Extension activated!'); + logToPanel("Extension activated!"); // Start the debug server explicitly - const factory = new CiderDebugAdapterDescriptorFactory('cider-dap', vscode.workspace.rootPath, outputChannel); - context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('cider-dap', factory)); + const factory = new CiderDebugAdapterDescriptorFactory( + vscode.workspace.getConfiguration("cider-dap").path, + vscode.workspace.rootPath, + outputChannel + ); + context.subscriptions.push( + vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory) + ); logToPanel("after start server"); // Update the adapter path with the serverPort and use it for starting the debug adapter @@ -123,14 +147,14 @@ function activate(context) { /* context.subscriptions.push(vscode.commands.registerCommand('cider.startDebugging', startDebugging)); context.subscriptions.push(vscode.commands.registerCommand('cider.stopDebugging', stopDebugging)); */ - logToPanel('Hello, your extension is now activated!'); + logToPanel("Hello, your extension is now activated!"); } function stopDebugging() { if (debugAdapter) { debugAdapter.stop(); } else { - logToPanel('No running debug adapter to stop.'); + logToPanel("No running debug adapter to stop."); } } @@ -140,5 +164,5 @@ function deactivate() { module.exports = { activate, - deactivate + deactivate, }; diff --git a/cider-dap/calyxDebug/package.json b/cider-dap/calyxDebug/package.json index b011db3e3..dbc2c936e 100644 --- a/cider-dap/calyxDebug/package.json +++ b/cider-dap/calyxDebug/package.json @@ -1,37 +1,57 @@ { - "name": "cider-dap", - "displayName": "Cider", - "version": "0.0.1", - "publisher": "Cider", - "description": "A debug adapter for Calyx files", - "author": { - "name": "...", - "email": "..." - }, - "engines": { - "vscode": "^1.54.0" - }, - "icon": "", - "categories": [ - "Debuggers" + "name": "cider-dap", + "displayName": "Cider", + "version": "0.0.1", + "publisher": "Cider", + "description": "A debug adapter for Calyx files", + "author": { + "name": "...", + "email": "..." + }, + "engines": { + "vscode": "^1.54.0" + }, + "icon": "", + "categories": [ + "Debuggers" + ], + "main": "./built/extension.js", + "contributes": { + "breakpoints": [ + { + "language": "calyx" + } ], - "main": "./extension.js", - "contributes": { - "breakpoints": [ - { - "language": "calyx" - } - ], - "debuggers": [ - { - "type": "cider-dap", - "label": "Cider Debug", - "configurationAttributes": {} - } - ] - }, - "activationEvents": [ - "onDebug", - "onLanguage:calyx" - ] + "debuggers": [ + { + "type": "cider-dap", + "label": "Cider Debug", + "configurationAttributes": {} + } + ], + "configuration": { + "title": "cider-dap", + "properties": { + "cider-dap.path": { + "type": "string", + "scope": "machine", + "default": "cider-dap", + "description": "Cider Binary Path" + }, + "cider-dap.port": { + "type": "number", + "scope": "machine", + "default": 8888, + "description": "Port number" + } + } + } + }, + "activationEvents": [ + "onDebug", + "onLanguage:calyx" + ], + "scripts": { + "vscode:prepublish": "npx tsc" + } } From 51acaaf68f0033f90a97a8ea5fb4fbdacb0a5110 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Wed, 15 Nov 2023 14:21:32 -0500 Subject: [PATCH 092/189] [Cider 2.0] random grab bag of stuff (#1778) * move some of the env stuff * very rough stab at the next code * add the missing seq processing * typo * rearrange * checkpoint with semi-functional std memories * add the stdmem to the primitive builder * unfinished but i don't wanna stash rn * some refactoring shennanigans * flesh out the par portion of the descent * dubious checkpoint * remove all the frills from Value * clippy cleanup * clippy's wrath * remove import * minor cleanup * sketch of new value construct * environment is a module now. this code doesn't work * checkpoint --- interp/src/flatten/flat_ir/base.rs | 44 +- .../src/flatten/flat_ir/control/structures.rs | 2 +- interp/src/flatten/mod.rs | 7 +- interp/src/flatten/primitives/builder.rs | 62 +- interp/src/flatten/primitives/macros.rs | 13 + .../src/flatten/primitives/stateful/math.rs | 1 + .../flatten/primitives/stateful/memories.rs | 356 +++++++- interp/src/flatten/primitives/stateful/mod.rs | 1 + interp/src/flatten/structures/environment.rs | 386 --------- .../src/flatten/structures/environment/mod.rs | 773 ++++++++++++++++++ .../structures/environment/program_counter.rs | 301 +++++++ interp/src/flatten/structures/mod.rs | 1 + interp/src/flatten/structures/values.rs | 30 + interp/src/structures/values.rs | 147 +--- interp/src/tests/values.rs | 8 +- 15 files changed, 1598 insertions(+), 534 deletions(-) create mode 100644 interp/src/flatten/primitives/stateful/math.rs delete mode 100644 interp/src/flatten/structures/environment.rs create mode 100644 interp/src/flatten/structures/environment/mod.rs create mode 100644 interp/src/flatten/structures/environment/program_counter.rs create mode 100644 interp/src/flatten/structures/values.rs diff --git a/interp/src/flatten/flat_ir/base.rs b/interp/src/flatten/flat_ir/base.rs index 1c05794bb..6745bd6d8 100644 --- a/interp/src/flatten/flat_ir/base.rs +++ b/interp/src/flatten/flat_ir/base.rs @@ -85,7 +85,9 @@ impl_index!(LocalCellOffset); pub struct LocalRefCellOffset(u32); impl_index!(LocalRefCellOffset); -/// Enum used in assignments to encapsulate the different types of port references +/// Enum used in assignments to encapsulate the different types of port +/// references these are always relative to a component's base-point and must be +/// converted to global references when used. #[derive(Debug, Copy, Clone)] pub enum PortRef { /// A port belonging to a non-ref cell/group in the current component or the @@ -135,6 +137,46 @@ impl From for PortRef { } } +/// This is the global analogue to [PortRef] and contains global identifiers +/// after the relative offsets have been transformed via a component base location +pub enum GlobalPortRef { + /// A non-ref port with an exact address + Port(GlobalPortId), + /// A reference port + Ref(GlobalRefPortId), +} + +impl From for GlobalPortRef { + fn from(v: GlobalRefPortId) -> Self { + Self::Ref(v) + } +} + +impl From for GlobalPortRef { + fn from(v: GlobalPortId) -> Self { + Self::Port(v) + } +} + +impl GlobalPortRef { + #[must_use] + pub fn as_port(&self) -> Option<&GlobalPortId> { + if let Self::Port(v) = self { + Some(v) + } else { + None + } + } + + #[must_use] + pub fn as_ref(&self) -> Option<&GlobalRefPortId> { + if let Self::Ref(v) = self { + Some(v) + } else { + None + } + } +} /// An enum wrapping the two different types of port definitions (ref/local) pub enum PortDefinitionRef { Local(PortDefinitionIdx), diff --git a/interp/src/flatten/flat_ir/control/structures.rs b/interp/src/flatten/flat_ir/control/structures.rs index e16a9a3ca..beb839775 100644 --- a/interp/src/flatten/flat_ir/control/structures.rs +++ b/interp/src/flatten/flat_ir/control/structures.rs @@ -5,7 +5,7 @@ use crate::flatten::{ structures::{index_trait::impl_index, indexed_map::IndexedMap}, }; -#[derive(Debug, Eq, Copy, Clone, PartialEq, Hash)] +#[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd)] pub struct ControlIdx(u32); impl_index!(ControlIdx); diff --git a/interp/src/flatten/mod.rs b/interp/src/flatten/mod.rs index 8f70fbdd5..1cdb5ed86 100644 --- a/interp/src/flatten/mod.rs +++ b/interp/src/flatten/mod.rs @@ -5,13 +5,14 @@ pub(crate) mod text_utils; use structures::environment::Environment; +use self::structures::environment::Simulator; + pub fn flat_main(ctx: &calyx_ir::Context) { let i_ctx = flat_ir::control::translator::translate(ctx); i_ctx.printer().print_program(); let env = Environment::new(&i_ctx); - env.print_env_stats(); - env.print_env(); - env.print_pc() + let mut sim = Simulator::new(env); + sim._main_test() } diff --git a/interp/src/flatten/primitives/builder.rs b/interp/src/flatten/primitives/builder.rs index 181d4ecba..522694573 100644 --- a/interp/src/flatten/primitives/builder.rs +++ b/interp/src/flatten/primitives/builder.rs @@ -1,7 +1,7 @@ use crate::{ flatten::{ flat_ir::{ - cell_prototype::{CellPrototype, PrimType1}, + cell_prototype::{CellPrototype, MemType, PrimType1}, prelude::{CellInfo, GlobalPortId}, }, structures::environment::Environment, @@ -9,8 +9,8 @@ use crate::{ values::Value, }; -use super::stateful::*; use super::{combinational::*, Primitive}; +use super::{prim_trait::DummyPrimitive, stateful::*}; pub fn build_primitive( env: &mut Environment, @@ -59,7 +59,7 @@ pub fn build_primitive( PrimType1::SignedLe => Box::new(StdSle::new(base_port)), PrimType1::SignedLsh => Box::new(StdSlsh::new(base_port)), PrimType1::SignedRsh => Box::new(StdSrsh::new(base_port)), - PrimType1::MultPipe => todo!(), + PrimType1::MultPipe => Box::new(DummyPrimitive), PrimType1::SignedMultPipe => todo!(), PrimType1::DivPipe => todo!(), PrimType1::SignedDivPipe => todo!(), @@ -103,41 +103,53 @@ pub fn build_primitive( out: _, } => todo!(), CellPrototype::MemD1 { - mem_type: _, - width: _, - size: _, + mem_type, + width, + size, idx_size: _, - } => todo!(), + } => match mem_type { + MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), + MemType::Std => Box::new(StdMemD1::new(base_port, *width, false, *size as usize)) + }, CellPrototype::MemD2 { - mem_type: _, - width: _, - d0_size: _, - d1_size: _, + mem_type, + width, + d0_size, + d1_size, d0_idx_size: _, d1_idx_size: _, - } => todo!(), + } => match mem_type { + MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), + MemType::Std => Box::new(StdMemD2::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize))), + }, CellPrototype::MemD3 { - mem_type: _, - width: _, - d0_size: _, - d1_size: _, - d2_size: _, + mem_type, + width, + d0_size, + d1_size, + d2_size, d0_idx_size: _, d1_idx_size: _, d2_idx_size: _, - } => todo!(), + } => match mem_type { + MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), + MemType::Std => Box::new(StdMemD3::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize))), + }, CellPrototype::MemD4 { - mem_type: _, - width: _, - d0_size: _, - d1_size: _, - d2_size: _, - d3_size: _, + mem_type, + width, + d0_size, + d1_size, + d2_size, + d3_size, d0_idx_size: _, d1_idx_size: _, d2_idx_size: _, d3_idx_size: _, - } => todo!(), + }=> match mem_type { + MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), + MemType::Std => Box::new(StdMemD4::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize, *d3_size as usize))), + }, CellPrototype::Unknown(_, _) => todo!(), } } diff --git a/interp/src/flatten/primitives/macros.rs b/interp/src/flatten/primitives/macros.rs index 0f4159bd3..0c068d7b8 100644 --- a/interp/src/flatten/primitives/macros.rs +++ b/interp/src/flatten/primitives/macros.rs @@ -20,7 +20,20 @@ macro_rules! output { } } +macro_rules! make_getters { + ($base:ident; $( $port:ident : $offset:expr ),+ ) => { + $( + #[inline] + fn $port(&self) -> $crate::flatten::flat_ir::prelude::GlobalPortId { + ($crate::flatten::structures::index_trait::IndexRef::index(&self.$base) + $offset).into() + } + )+ + + } +} + pub(crate) use declare_ports; +pub(crate) use make_getters; pub(crate) use output; pub(crate) use ports; diff --git a/interp/src/flatten/primitives/stateful/math.rs b/interp/src/flatten/primitives/stateful/math.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/interp/src/flatten/primitives/stateful/math.rs @@ -0,0 +1 @@ + diff --git a/interp/src/flatten/primitives/stateful/memories.rs b/interp/src/flatten/primitives/stateful/memories.rs index 11d95c0e1..a6b127af6 100644 --- a/interp/src/flatten/primitives/stateful/memories.rs +++ b/interp/src/flatten/primitives/stateful/memories.rs @@ -2,7 +2,8 @@ use crate::{ flatten::{ flat_ir::prelude::GlobalPortId, primitives::{ - declare_ports, output, ports, prim_trait::Results, Primitive, + declare_ports, make_getters, output, ports, prim_trait::Results, + Primitive, }, structures::environment::PortMap, }, @@ -73,3 +74,356 @@ impl Primitive for StdReg { true } } + +pub trait MemAddresser { + const NON_ADDRESS_BASE: usize; + + fn calculate_addr( + &self, + port_map: &PortMap, + base_port: GlobalPortId, + ) -> usize; +} + +pub struct MemD1; + +impl MemAddresser for MemD1 { + fn calculate_addr( + &self, + port_map: &PortMap, + base_port: GlobalPortId, + ) -> usize { + let addr0 = if SEQ { + ports![&base_port; addr0: Self::SEQ_ADDR0]; + addr0 + } else { + ports![&base_port; addr0: Self::COMB_ADDR0]; + addr0 + }; + + port_map[addr0].as_usize() + } + + const NON_ADDRESS_BASE: usize = if SEQ { + Self::SEQ_ADDR0 + 1 + } else { + Self::COMB_ADDR0 + 1 + }; +} + +impl MemD1 { + declare_ports![SEQ_ADDR0: 2, COMB_ADDR0: 0]; +} + +pub struct MemD2 { + d1_size: usize, +} + +impl MemD2 { + declare_ports![SEQ_ADDR0: 2, COMB_ADDR0: 0, SEQ_ADDR1: 3, COMB_ADDR1: 1]; +} + +impl MemAddresser for MemD2 { + fn calculate_addr( + &self, + port_map: &PortMap, + base_port: GlobalPortId, + ) -> usize { + let (addr0, addr1) = if SEQ { + ports![&base_port; + addr0: Self::SEQ_ADDR0, + addr1: Self::SEQ_ADDR1]; + (addr0, addr1) + } else { + ports![&base_port; + addr0: Self::COMB_ADDR0, + addr1: Self::COMB_ADDR1]; + (addr0, addr1) + }; + + let a0 = port_map[addr0].as_usize(); + let a1 = port_map[addr1].as_usize(); + + a0 * self.d1_size + a1 + } + + const NON_ADDRESS_BASE: usize = if SEQ { + Self::SEQ_ADDR1 + 1 + } else { + Self::COMB_ADDR1 + 1 + }; +} + +pub struct MemD3 { + d1_size: usize, + d2_size: usize, +} + +impl MemD3 { + declare_ports![SEQ_ADDR0: 2, COMB_ADDR0: 0, + SEQ_ADDR1: 3, COMB_ADDR1: 1, + SEQ_ADDR2: 4, COMB_ADDR2: 2]; +} + +impl MemAddresser for MemD3 { + fn calculate_addr( + &self, + port_map: &PortMap, + base_port: GlobalPortId, + ) -> usize { + let (addr0, addr1, addr2) = if SEQ { + ports![&base_port; + addr0: Self::SEQ_ADDR0, + addr1: Self::SEQ_ADDR1, + addr2: Self::SEQ_ADDR2 + ]; + (addr0, addr1, addr2) + } else { + ports![&base_port; + addr0: Self::COMB_ADDR0, + addr1: Self::COMB_ADDR1, + addr2: Self::COMB_ADDR2 + ]; + + (addr0, addr1, addr2) + }; + + let a0 = port_map[addr0].as_usize(); + let a1 = port_map[addr1].as_usize(); + let a2 = port_map[addr2].as_usize(); + + a0 * (self.d1_size * self.d2_size) + a1 * self.d2_size + a2 + } + + const NON_ADDRESS_BASE: usize = if SEQ { + Self::SEQ_ADDR2 + 1 + } else { + Self::COMB_ADDR2 + 1 + }; +} + +pub struct MemD4 { + d1_size: usize, + d2_size: usize, + d3_size: usize, +} + +impl MemD4 { + declare_ports![ + SEQ_ADDR0: 2, COMB_ADDR0: 0, + SEQ_ADDR1: 3, COMB_ADDR1: 1, + SEQ_ADDR2: 4, COMB_ADDR2: 2, + SEQ_ADDR3: 5, COMB_ADDR3: 3 + ]; +} + +impl MemAddresser for MemD4 { + fn calculate_addr( + &self, + port_map: &PortMap, + base_port: GlobalPortId, + ) -> usize { + let (addr0, addr1, addr2, addr3) = if SEQ { + ports![&base_port; + addr0: Self::SEQ_ADDR0, + addr1: Self::SEQ_ADDR1, + addr2: Self::SEQ_ADDR2, + addr3: Self::SEQ_ADDR3 + ]; + (addr0, addr1, addr2, addr3) + } else { + ports![&base_port; + addr0: Self::COMB_ADDR0, + addr1: Self::COMB_ADDR1, + addr2: Self::COMB_ADDR2, + addr3: Self::COMB_ADDR3 + ]; + + (addr0, addr1, addr2, addr3) + }; + + let a0 = port_map[addr0].as_usize(); + let a1 = port_map[addr1].as_usize(); + let a2 = port_map[addr2].as_usize(); + let a3 = port_map[addr3].as_usize(); + + a0 * (self.d1_size * self.d2_size * self.d3_size) + + a1 * (self.d2_size * self.d3_size) + + a2 * self.d3_size + + a3 + } + + const NON_ADDRESS_BASE: usize = if SEQ { + Self::SEQ_ADDR3 + 1 + } else { + Self::COMB_ADDR3 + 1 + }; +} + +pub struct StdMem { + base_port: GlobalPortId, + internal_state: Vec, + allow_invalid_access: bool, + width: u32, + addresser: M, +} + +impl StdMem { + declare_ports![ + WRITE_DATA: M::NON_ADDRESS_BASE + 1, + WRITE_EN: M::NON_ADDRESS_BASE + 2, + CLK: M::NON_ADDRESS_BASE + 3, + RESET: M::NON_ADDRESS_BASE + 4, + READ_DATA: M::NON_ADDRESS_BASE + 5, + DONE: M::NON_ADDRESS_BASE + 6 + ]; + + make_getters![base_port; + write_data: Self::WRITE_DATA, + write_en: Self::WRITE_EN, + reset_port: Self::RESET, + read_data: Self::READ_DATA, + done: Self::DONE + ]; +} + +impl Primitive for StdMem { + fn exec_comb(&self, port_map: &PortMap) -> Results { + let addr = self.addresser.calculate_addr(port_map, self.base_port); + let read_data = self.read_data(); + if addr < self.internal_state.len() { + Ok(output![read_data: self.internal_state[addr].clone()]) + } else { + // throw error on cycle boundary rather than here + Ok(output![read_data: Value::zeroes(self.width)]) + } + } + + fn exec_cycle(&mut self, port_map: &PortMap) -> Results { + let reset = port_map[self.reset_port()].as_bool(); + let write_en = port_map[self.write_en()].as_bool(); + let addr = self.addresser.calculate_addr(port_map, self.base_port); + let (read_data, done) = (self.read_data(), self.done()); + + if write_en && !reset { + let write_data = port_map[self.write_data()].clone(); + self.internal_state[addr] = write_data; + Ok( + output![read_data: self.internal_state[addr].clone(), done: Value::bit_high()], + ) + } else { + Ok( + output![read_data: self.internal_state[addr].clone(), done: Value::bit_low()], + ) + } + } + + fn reset(&mut self, _port_map: &PortMap) -> Results { + let (read_data, done) = (self.read_data(), self.done()); + Ok( + output![read_data: Value::zeroes(self.width), done: Value::bit_low()], + ) + } + + fn serialize( + &self, + _code: Option, + ) -> Serializable { + todo!("StdMemD1::serialize") + } + + fn has_serializable_state(&self) -> bool { + true + } +} + +// type aliases +pub type StdMemD1 = StdMem>; +pub type StdMemD2 = StdMem>; +pub type StdMemD3 = StdMem>; +pub type StdMemD4 = StdMem>; + +impl StdMemD1 { + pub fn new( + base: GlobalPortId, + width: u32, + allow_invalid: bool, + size: usize, + ) -> Self { + let internal_state = vec![Value::zeroes(width); size]; + + Self { + base_port: base, + internal_state, + allow_invalid_access: allow_invalid, + width, + addresser: MemD1::, + } + } +} + +impl StdMemD2 { + pub fn new( + base: GlobalPortId, + width: u32, + allow_invalid: bool, + size: (usize, usize), + ) -> Self { + let internal_state = vec![Value::zeroes(width); size.0 * size.1]; + + Self { + base_port: base, + internal_state, + allow_invalid_access: allow_invalid, + width, + addresser: MemD2:: { d1_size: size.1 }, + } + } +} + +impl StdMemD3 { + pub fn new( + base: GlobalPortId, + width: u32, + allow_invalid: bool, + size: (usize, usize, usize), + ) -> Self { + let internal_state = + vec![Value::zeroes(width); size.0 * size.1 * size.2]; + + Self { + base_port: base, + internal_state, + allow_invalid_access: allow_invalid, + width, + addresser: MemD3:: { + d1_size: size.1, + d2_size: size.2, + }, + } + } +} + +impl StdMemD4 { + pub fn new( + base: GlobalPortId, + width: u32, + allow_invalid: bool, + size: (usize, usize, usize, usize), + ) -> Self { + let internal_state = + vec![Value::zeroes(width); size.0 * size.1 * size.2 * size.3]; + + Self { + base_port: base, + internal_state, + allow_invalid_access: allow_invalid, + width, + addresser: MemD4:: { + d1_size: size.1, + d2_size: size.2, + d3_size: size.3, + }, + } + } +} diff --git a/interp/src/flatten/primitives/stateful/mod.rs b/interp/src/flatten/primitives/stateful/mod.rs index 66aaf7520..d21b3caaf 100644 --- a/interp/src/flatten/primitives/stateful/mod.rs +++ b/interp/src/flatten/primitives/stateful/mod.rs @@ -1,3 +1,4 @@ +pub mod math; pub mod memories; pub use memories::*; diff --git a/interp/src/flatten/structures/environment.rs b/interp/src/flatten/structures/environment.rs deleted file mode 100644 index 81d1ae039..000000000 --- a/interp/src/flatten/structures/environment.rs +++ /dev/null @@ -1,386 +0,0 @@ -use ahash::{HashMap, HashMapExt}; -use itertools::Itertools; -use smallvec::SmallVec; - -use super::{context::Context, indexed_map::IndexedMap}; -use crate::{ - flatten::{ - flat_ir::prelude::{ - BaseIndices, ComponentIdx, ControlIdx, ControlNode, GlobalCellId, - GlobalPortId, GlobalRefCellId, GlobalRefPortId, - }, - primitives::{self, Primitive}, - structures::index_trait::IndexRef, - }, - values::Value, -}; -use std::fmt::Debug; - -pub(crate) type PortMap = IndexedMap; -pub(crate) type CellMap = IndexedMap; -pub(crate) type RefCellMap = IndexedMap>; -pub(crate) type RefPortMap = IndexedMap>; - -pub(crate) struct ComponentLedger { - pub(crate) index_bases: BaseIndices, - pub(crate) comp_id: ComponentIdx, -} - -pub(crate) enum CellLedger { - Primitive { - // wish there was a better option with this one - cell_dyn: Box, - }, - Component(ComponentLedger), -} - -impl CellLedger { - fn comp(idx: ComponentIdx, env: &Environment) -> Self { - Self::Component(ComponentLedger { - index_bases: BaseIndices::new( - env.ports.peek_next_idx(), - (env.cells.peek_next_idx().index() + 1).into(), - env.ref_cells.peek_next_idx(), - env.ref_ports.peek_next_idx(), - ), - comp_id: idx, - }) - } - - pub fn as_comp(&self) -> Option<&ComponentLedger> { - match self { - Self::Component(comp) => Some(comp), - _ => None, - } - } -} - -impl Debug for CellLedger { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Primitive { .. } => f.debug_struct("Primitive").finish(), - Self::Component(ComponentLedger { - index_bases, - comp_id, - }) => f - .debug_struct("Component") - .field("index_bases", index_bases) - .field("comp_id", comp_id) - .finish(), - } - } -} - -/// Simple struct containing both the component instance and the active leaf -/// node in the component -#[derive(Debug)] -pub struct ControlPoint { - pub comp: GlobalCellId, - pub control_leaf: ControlIdx, -} - -impl ControlPoint { - pub fn new(comp: GlobalCellId, control_leaf: ControlIdx) -> Self { - Self { comp, control_leaf } - } -} - -/// The number of control points to preallocate for the program counter. -/// Using 1 for now, as this is the same size as using a vec, but this can -/// change in the future and probably should. -const CONTROL_POINT_PREALLOCATE: usize = 1; - -/// The program counter for the whole program execution. Wraps over a vector of -/// the active leaf statements for each component instance. -#[derive(Debug, Default)] -pub(crate) struct ProgramCounter { - vec: SmallVec<[ControlPoint; CONTROL_POINT_PREALLOCATE]>, -} - -impl ProgramCounter { - pub fn new(ctx: &Context) -> Self { - let root = ctx.entry_point; - // TODO: this relies on the fact that we construct the root cell-ledger - // as the first possible cell in the program. If that changes this will break. - let root_cell = GlobalCellId::new(0); - - let mut vec = SmallVec::new(); - if let Some(current) = ctx.primary[root].control { - let mut work_queue: Vec = Vec::from([current]); - let mut backtrack_map = HashMap::new(); - - while let Some(current) = work_queue.pop() { - match &ctx.primary[current] { - ControlNode::Empty(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Enable(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Seq(s) => match s - .stms() - .iter() - .find(|&x| !backtrack_map.contains_key(x)) - { - Some(n) => { - backtrack_map.insert(*n, current); - work_queue.push(*n); - } - None => { - if let Some(b) = backtrack_map.get(¤t) { - work_queue.push(*b) - } - } - }, - ControlNode::Par(p) => { - for node in p.stms() { - work_queue.push(*node); - } - } - ControlNode::If(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::While(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Invoke(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - } - } - } else { - todo!( - "Flat interpreter does not support control-less components yet" - ) - } - - Self { vec } - } - - pub fn iter(&self) -> std::slice::Iter<'_, ControlPoint> { - self.vec.iter() - } - - pub fn is_done(&self) -> bool { - self.vec.is_empty() - } -} - -impl<'a> IntoIterator for &'a ProgramCounter { - type Item = &'a ControlPoint; - - type IntoIter = std::slice::Iter<'a, ControlPoint>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -#[derive(Debug)] -pub struct Environment<'a> { - /// A map from global port IDs to their current values. - pub(crate) ports: PortMap, - /// A map from global cell IDs to their current state and execution info. - cells: CellMap, - /// A map from global ref cell IDs to the cell they reference, if any. - ref_cells: RefCellMap, - /// A map from global ref port IDs to the port they reference, if any. - ref_ports: RefPortMap, - - /// The program counter for the whole program execution. - pcs: ProgramCounter, - - /// The immutable context. This is retained for ease of use. - ctx: &'a Context, -} - -impl<'a> Environment<'a> { - pub fn new(ctx: &'a Context) -> Self { - let root = ctx.entry_point; - let aux = &ctx.secondary[root]; - - let mut env = Self { - ports: PortMap::with_capacity(aux.port_offset_map.count()), - cells: CellMap::with_capacity(aux.cell_offset_map.count()), - ref_cells: RefCellMap::with_capacity( - aux.ref_cell_offset_map.count(), - ), - ref_ports: RefPortMap::with_capacity( - aux.ref_port_offset_map.count(), - ), - pcs: ProgramCounter::new(ctx), - ctx, - }; - - let root_node = CellLedger::comp(root, &env); - let root = env.cells.push(root_node); - env.layout_component(root); - - env - } - - fn layout_component(&mut self, comp: GlobalCellId) { - let ComponentLedger { - index_bases, - comp_id, - } = self.cells[comp] - .as_comp() - .expect("Called layout component with a non-component cell."); - let comp_aux = &self.ctx.secondary[*comp_id]; - - let comp_id = *comp_id; - - // first layout the signature - for sig_port in comp_aux.signature.iter() { - let width = self.ctx.lookup_port_def(&comp_id, sig_port).width; - let idx = self.ports.push(Value::zeroes(width)); - debug_assert_eq!(index_bases + sig_port, idx); - } - // second group ports - for group_idx in comp_aux.definitions.groups() { - // TODO Griffin: The sanity checks here are assuming that go & done - // are defined in that order. This could break if the IR changes the - // order on hole ports in groups. - - //go - let go = self.ports.push(Value::bit_low()); - debug_assert_eq!(go, index_bases + self.ctx.primary[group_idx].go); - - //done - let done = self.ports.push(Value::bit_low()); - debug_assert_eq!( - done, - index_bases + self.ctx.primary[group_idx].done - ); - } - - for (cell_off, def_idx) in comp_aux.cell_offset_map.iter() { - let info = &self.ctx.secondary[*def_idx]; - if !info.prototype.is_component() { - let port_base = self.ports.peek_next_idx(); - for port in info.ports.iter() { - let width = self.ctx.lookup_port_def(&comp_id, port).width; - let idx = self.ports.push(Value::zeroes(width)); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + port, - idx - ); - } - let cell_dyn = - primitives::build_primitive(self, info, port_base); - let cell = self.cells.push(CellLedger::Primitive { cell_dyn }); - - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + cell_off, - cell - ); - } else { - let child_comp = info.prototype.as_component().unwrap(); - let child_comp = CellLedger::comp(*child_comp, self); - - let cell = self.cells.push(child_comp); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + cell_off, - cell - ); - - self.layout_component(cell); - } - } - - // ref cells and ports are initialized to None - for (ref_cell, def_idx) in comp_aux.ref_cell_offset_map.iter() { - let info = &self.ctx.secondary[*def_idx]; - for port_idx in info.ports.iter() { - let port_actual = self.ref_ports.push(None); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + port_idx, - port_actual - ) - } - let cell_actual = self.ref_cells.push(None); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + ref_cell, - cell_actual - ) - } - } - - pub fn print_env(&self) { - let root_idx = GlobalCellId::new(0); - let mut hierarchy = Vec::new(); - self.print_component(root_idx, &mut hierarchy) - } - - fn print_component( - &self, - target: GlobalCellId, - hierarchy: &mut Vec, - ) { - let info = self.cells[target].as_comp().unwrap(); - let comp = &self.ctx.secondary[info.comp_id]; - hierarchy.push(target); - - // This funky iterator chain first pulls the first element (the - // entrypoint) and extracts its name. Subsequent element are pairs of - // global offsets produced by a staggered iteration, yielding `(root, - // child)` then `(child, grandchild)` and so on. All the strings are - // finally collected and concatenated with a `.` separator to produce - // the fully qualified name prefix for the given component instance. - let name_prefix = hierarchy - .first() - .iter() - .map(|x| { - let info = self.cells[**x].as_comp().unwrap(); - let prior_comp = &self.ctx.secondary[info.comp_id]; - &self.ctx.secondary[prior_comp.name] - }) - .chain(hierarchy.iter().zip(hierarchy.iter().skip(1)).map( - |(l, r)| { - let info = self.cells[*l].as_comp().unwrap(); - let prior_comp = &self.ctx.secondary[info.comp_id]; - let local_target = r - (&info.index_bases); - - let def_idx = &prior_comp.cell_offset_map[local_target]; - - let id = &self.ctx.secondary[*def_idx]; - &self.ctx.secondary[id.name] - }, - )) - .join("."); - - for (cell_off, def_idx) in comp.cell_offset_map.iter() { - let definition = &self.ctx.secondary[*def_idx]; - - println!("{}.{}", name_prefix, self.ctx.secondary[definition.name]); - for port in definition.ports.iter() { - let definition = - &self.ctx.secondary[comp.port_offset_map[port]]; - println!( - " {}: {}", - self.ctx.secondary[definition.name], - self.ports[&info.index_bases + port] - ); - } - - if definition.prototype.is_component() { - let child_target = &info.index_bases + cell_off; - self.print_component(child_target, hierarchy); - } - } - - hierarchy.pop(); - } - - pub fn print_env_stats(&self) { - println!("Environment Stats:"); - println!(" Ports: {}", self.ports.len()); - println!(" Cells: {}", self.cells.len()); - println!(" Ref Cells: {}", self.ref_cells.len()); - println!(" Ref Ports: {}", self.ref_ports.len()); - } - - pub fn print_pc(&self) { - println!("{:?}", self.pcs) - } -} diff --git a/interp/src/flatten/structures/environment/mod.rs b/interp/src/flatten/structures/environment/mod.rs new file mode 100644 index 000000000..781456769 --- /dev/null +++ b/interp/src/flatten/structures/environment/mod.rs @@ -0,0 +1,773 @@ +mod program_counter; + +use itertools::Itertools; + +use self::program_counter::ProgramCounter; + +use super::{ + context::Context, index_trait::IndexRange, indexed_map::IndexedMap, +}; +use crate::{ + errors::InterpreterResult, + flatten::{ + flat_ir::{ + prelude::{ + Assignment, AssignmentIdx, BaseIndices, ComponentIdx, + ControlIdx, ControlNode, GlobalCellId, GlobalPortId, + GlobalPortRef, GlobalRefCellId, GlobalRefPortId, GuardIdx, + PortRef, + }, + wires::guards::Guard, + }, + primitives::{self, Primitive}, + structures::index_trait::IndexRef, + }, + values::Value, +}; +use std::{collections::VecDeque, fmt::Debug}; + +pub(crate) type PortMap = IndexedMap; +pub(crate) type CellMap = IndexedMap; +pub(crate) type RefCellMap = IndexedMap>; +pub(crate) type RefPortMap = IndexedMap>; +type AssignmentRange = IndexRange; + +pub(crate) struct ComponentLedger { + pub(crate) index_bases: BaseIndices, + pub(crate) comp_id: ComponentIdx, +} + +impl ComponentLedger { + /// Convert a relative offset to a global one. Perhaps should take an owned + /// value rather than a pointer + pub fn convert_to_global(&self, port: &PortRef) -> GlobalPortRef { + match port { + PortRef::Local(l) => (&self.index_bases + l).into(), + PortRef::Ref(r) => (&self.index_bases + r).into(), + } + } +} + +/// An enum encapsulating cell functionality. It is either a pointer to a +/// primitive or information about a calyx component instance +pub(crate) enum CellLedger { + Primitive { + // wish there was a better option with this one + cell_dyn: Box, + }, + Component(ComponentLedger), +} + +impl CellLedger { + fn new_comp(idx: ComponentIdx, env: &Environment) -> Self { + Self::Component(ComponentLedger { + index_bases: BaseIndices::new( + env.ports.peek_next_idx(), + (env.cells.peek_next_idx().index() + 1).into(), + env.ref_cells.peek_next_idx(), + env.ref_ports.peek_next_idx(), + ), + comp_id: idx, + }) + } + + pub fn as_comp(&self) -> Option<&ComponentLedger> { + match self { + Self::Component(comp) => Some(comp), + _ => None, + } + } + + #[inline] + pub fn unwrap_comp(&self) -> &ComponentLedger { + self.as_comp() + .expect("Unwrapped cell ledger as component but received primitive") + } +} + +impl Debug for CellLedger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Primitive { .. } => f.debug_struct("Primitive").finish(), + Self::Component(ComponentLedger { + index_bases, + comp_id, + }) => f + .debug_struct("Component") + .field("index_bases", index_bases) + .field("comp_id", comp_id) + .finish(), + } + } +} + +#[derive(Debug)] +pub struct Environment<'a> { + /// A map from global port IDs to their current values. + pub(crate) ports: PortMap, + /// A map from global cell IDs to their current state and execution info. + cells: CellMap, + /// A map from global ref cell IDs to the cell they reference, if any. + ref_cells: RefCellMap, + /// A map from global ref port IDs to the port they reference, if any. + ref_ports: RefPortMap, + + /// The program counter for the whole program execution. + pc: ProgramCounter, + + /// The immutable context. This is retained for ease of use. + ctx: &'a Context, +} + +impl<'a> Environment<'a> { + pub fn new(ctx: &'a Context) -> Self { + let root = ctx.entry_point; + let aux = &ctx.secondary[root]; + + let mut env = Self { + ports: PortMap::with_capacity(aux.port_offset_map.count()), + cells: CellMap::with_capacity(aux.cell_offset_map.count()), + ref_cells: RefCellMap::with_capacity( + aux.ref_cell_offset_map.count(), + ), + ref_ports: RefPortMap::with_capacity( + aux.ref_port_offset_map.count(), + ), + pc: ProgramCounter::new(ctx), + ctx, + }; + + let root_node = CellLedger::new_comp(root, &env); + let root = env.cells.push(root_node); + env.layout_component(root); + + env + } + + /// Internal function used to layout a given component from a cell id + /// + /// Layout is handled in the following order: + /// 1. component signature (input/output) + /// 2. group hole ports + /// 3. cells + ports, primitive + /// 4. sub-components + /// 5. ref-cells & ports + fn layout_component(&mut self, comp: GlobalCellId) { + let ComponentLedger { + index_bases, + comp_id, + } = self.cells[comp] + .as_comp() + .expect("Called layout component with a non-component cell."); + let comp_aux = &self.ctx.secondary[*comp_id]; + + let comp_id = *comp_id; + + // first layout the signature + for sig_port in comp_aux.signature.iter() { + let width = self.ctx.lookup_port_def(&comp_id, sig_port).width; + let idx = self.ports.push(Value::zeroes(width)); + debug_assert_eq!(index_bases + sig_port, idx); + } + // second group ports + for group_idx in comp_aux.definitions.groups() { + //go + let go = self.ports.push(Value::bit_low()); + + //done + let done = self.ports.push(Value::bit_low()); + + // quick sanity check asserts + let go_actual = index_bases + self.ctx.primary[group_idx].go; + let done_actual = index_bases + self.ctx.primary[group_idx].done; + // Case 1 - Go defined before done + if self.ctx.primary[group_idx].go < self.ctx.primary[group_idx].done + { + debug_assert_eq!(done, done_actual); + debug_assert_eq!(go, go_actual); + } + // Case 2 - Done defined before go + else { + // in this case go is defined after done, so our variable names + // are backward, but this is not a problem since they are + // initialized to the same value + debug_assert_eq!(go, done_actual); + debug_assert_eq!(done, go_actual); + } + } + + for (cell_off, def_idx) in comp_aux.cell_offset_map.iter() { + let info = &self.ctx.secondary[*def_idx]; + if !info.prototype.is_component() { + let port_base = self.ports.peek_next_idx(); + for port in info.ports.iter() { + let width = self.ctx.lookup_port_def(&comp_id, port).width; + let idx = self.ports.push(Value::zeroes(width)); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + port, + idx + ); + } + let cell_dyn = + primitives::build_primitive(self, info, port_base); + let cell = self.cells.push(CellLedger::Primitive { cell_dyn }); + + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + cell_off, + cell + ); + } else { + let child_comp = info.prototype.as_component().unwrap(); + let child_comp = CellLedger::new_comp(*child_comp, self); + + let cell = self.cells.push(child_comp); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + cell_off, + cell + ); + + self.layout_component(cell); + } + } + + // ref cells and ports are initialized to None + for (ref_cell, def_idx) in comp_aux.ref_cell_offset_map.iter() { + let info = &self.ctx.secondary[*def_idx]; + for port_idx in info.ports.iter() { + let port_actual = self.ref_ports.push(None); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + port_idx, + port_actual + ) + } + let cell_actual = self.ref_cells.push(None); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + ref_cell, + cell_actual + ) + } + } +} + +// ===================== Environment print implementations ===================== +impl<'a> Environment<'a> { + pub fn print_env(&self) { + let root_idx = GlobalCellId::new(0); + let mut hierarchy = Vec::new(); + self.print_component(root_idx, &mut hierarchy) + } + + fn print_component( + &self, + target: GlobalCellId, + hierarchy: &mut Vec, + ) { + let info = self.cells[target].as_comp().unwrap(); + let comp = &self.ctx.secondary[info.comp_id]; + hierarchy.push(target); + + // This funky iterator chain first pulls the first element (the + // entrypoint) and extracts its name. Subsequent element are pairs of + // global offsets produced by a staggered iteration, yielding `(root, + // child)` then `(child, grandchild)` and so on. All the strings are + // finally collected and concatenated with a `.` separator to produce + // the fully qualified name prefix for the given component instance. + let name_prefix = hierarchy + .first() + .iter() + .map(|x| { + let info = self.cells[**x].as_comp().unwrap(); + let prior_comp = &self.ctx.secondary[info.comp_id]; + &self.ctx.secondary[prior_comp.name] + }) + .chain(hierarchy.iter().zip(hierarchy.iter().skip(1)).map( + |(l, r)| { + let info = self.cells[*l].as_comp().unwrap(); + let prior_comp = &self.ctx.secondary[info.comp_id]; + let local_target = r - (&info.index_bases); + + let def_idx = &prior_comp.cell_offset_map[local_target]; + + let id = &self.ctx.secondary[*def_idx]; + &self.ctx.secondary[id.name] + }, + )) + .join("."); + + for (cell_off, def_idx) in comp.cell_offset_map.iter() { + let definition = &self.ctx.secondary[*def_idx]; + + println!("{}.{}", name_prefix, self.ctx.secondary[definition.name]); + for port in definition.ports.iter() { + let definition = + &self.ctx.secondary[comp.port_offset_map[port]]; + println!( + " {}: {}", + self.ctx.secondary[definition.name], + self.ports[&info.index_bases + port] + ); + } + + if definition.prototype.is_component() { + let child_target = &info.index_bases + cell_off; + self.print_component(child_target, hierarchy); + } + } + + hierarchy.pop(); + } + + pub fn print_env_stats(&self) { + println!("Environment Stats:"); + println!(" Ports: {}", self.ports.len()); + println!(" Cells: {}", self.cells.len()); + println!(" Ref Cells: {}", self.ref_cells.len()); + println!(" Ref Ports: {}", self.ref_ports.len()); + } + + pub fn print_pc(&self) { + println!("{:?}", self.pc) + } +} + +/// A wrapper struct for the environment that provides the functions used to +/// simulate the actual program +pub struct Simulator<'a> { + env: Environment<'a>, +} + +impl<'a> Simulator<'a> { + pub fn new(env: Environment<'a>) -> Self { + Self { env } + } + + pub fn print_env(&self) { + self.env.print_env() + } + + pub fn ctx(&self) -> &Context { + self.env.ctx + } +} + +// =========================== simulation functions =========================== +impl<'a> Simulator<'a> { + /// Finds the next control point from a finished control point. If there is + /// no next control point, returns None. + /// + /// If given an If/While statement this will assume the entire if/while node + /// is finished executing and will ascend to the parent context. Evaluating + /// the if/while condition and moving to the appropriate body must be + /// handled elsewhere. + // fn find_next_control_point( + // &self, + // target: &ControlPoint, + // ) -> NextControlPoint { + // let comp = target.comp; + // let comp_idx = self.env.cells[comp].as_comp().unwrap().comp_id; + // let root_ctrl = self.env.ctx.primary[comp_idx].control.expect( + // "Called `find_next_control_point` on a component with no control. This is an error, please report it", + // ); + + // // here's the goal: + // // we want to first walk the control tree for this component and find + // // the given control point and the path through the tree to get there. + // // Once we have this, we move back along the path to find the next + // // node to run (either a terminal node in an `invoke` or `enable` or a + // // non-terminal while/if condition check). Since this involves + // // backtracking, in the limit this means backtracking all the way to the + // // root of the component in which case the component has finished + // // executing. + + // let cont = self.extract_next_search(root_ctrl); + + // let mut search_stack = Vec::from([SearchNode { + // node: root_ctrl, + // next: cont, + // }]); + + // while let Some(mut node) = search_stack.pop() { + // if node.node == target.control_leaf { + // // found the node! we return it to the stack which is now the + // // path from the root to our finished node + // search_stack.push(node); + // break; + // } else if let Some(next_node) = node.next.pop_front() { + // let next_search_node = SearchNode { + // node: next_node, + // next: self.extract_next_search(next_node), + // }; + // // return the now modified original + // search_stack.push(node); + // // push the descendent next, so that the search continues + // // depth first + // search_stack.push(next_search_node); + // } else { + // // This node was not the one we wanted and none of its + // // children (if any) were either, we must return to the + // // parent which means dropping the node, i.e. doing nothing here + // } + // } + + // if search_stack.is_empty() { + // // The reason this should never happen is that this implies a + // // controlpoint was constructed for a fully-structural component + // // instance which means something went wrong with the construction + // // as such an instance could not have a control program to reference + // panic!("Could not find control point in component, this should never happen. Please report this error.") + // } + + // // phase two, backtrack to find the next node to run + + // // remove the deepest node (i.e. our target) + // search_stack.pop(); + + // let mut immediate_next_node = None; + + // while let Some(node) = search_stack.pop() { + // match &self.ctx().primary[node.node] { + // ControlNode::Seq(_) => { + // if let Some(next) = node.next.get(0) { + // // the target node will have been popped off the + // // list during the search meaning the next node left + // // over from the search is the next node to run + // immediate_next_node = Some(*next); + // // exit to descend the list + // break; + // } else { + // // no next node, go to parent context + // } + // }, + // ControlNode::Par(_) => { + // // par arm needs to wait until all arms are finished + // return NextControlPoint::FinishedParChild(ControlPoint::new(comp, node.node)); + // }, + // ControlNode::If(_) => { + // // do nothing, go to parent context + // }, + // ControlNode::While(_) => { + // // need to recheck condition so the while itself is next + // return NextControlPoint::Next(ControlPoint::new(comp, node.node)); + // }, + // // + // ControlNode::Empty(_) + // | ControlNode::Enable(_) + // | ControlNode::Invoke(_) => unreachable!("terminal nodes cannot be the parents of a node. If this happens something has gone horribly wrong and should be reported"), + // } + // } + + // // phase 3, take the immediate next node and descend to find its leaf + + // if let Some(node) = immediate_next_node { + // // we reuse the existing search stack without resetting it to allow + // // backtracking further if the immediate next node has no actual + // // leaves under it, e.g. a seq of empty seqs + // // TODO Griffin: double check this aspect later as it might + // // complicate things or introduce errors + // self.descend_to_leaf(node, &mut search_stack, comp) + // } else { + // // if we exit without finding the next node then it does not exist + // NextControlPoint::None + // } + // } + + /// pull out the next nodes to search when + fn extract_next_search(&self, idx: ControlIdx) -> VecDeque { + match &self.env.ctx.primary[idx] { + ControlNode::Seq(s) => s.stms().iter().copied().collect(), + ControlNode::Par(p) => p.stms().iter().copied().collect(), + ControlNode::If(i) => vec![i.tbranch(), i.fbranch()].into(), + ControlNode::While(w) => vec![w.body()].into(), + _ => VecDeque::new(), + } + } + + fn lookup_global_port_id(&self, port: GlobalPortRef) -> GlobalPortId { + match port { + GlobalPortRef::Port(p) => p, + // TODO Griffin: Please make sure this error message is correct with + // respect to the compiler + GlobalPortRef::Ref(r) => self.env.ref_ports[r].expect("A ref port is being queried without a supplied ref-cell. This is an error?"), + } + } + + fn get_global_idx( + &self, + port: &PortRef, + comp: GlobalCellId, + ) -> GlobalPortId { + let ledger = self.env.cells[comp].unwrap_comp(); + self.lookup_global_port_id(ledger.convert_to_global(port)) + } + + fn get_value(&self, port: &PortRef, comp: GlobalCellId) -> &Value { + let port_idx = self.get_global_idx(port, comp); + &self.env.ports[port_idx] + } + + // fn descend_to_leaf( + // &self, + // // the node (possibly terminal) which we want to start evaluating + // immediate_next_node: ControlIdx, + // search_stack: &mut Vec, + // comp: GlobalCellId, + // ) -> NextControlPoint { + // search_stack.push(SearchNode { + // node: immediate_next_node, + // next: self.extract_next_search(immediate_next_node), + // }); + + // while let Some(mut node) = search_stack.pop() { + // match &self.ctx().primary[node.node] { + // ControlNode::Seq(_) => { + // if let Some(next) = node.next.pop_front() { + // search_stack.push(node); + // let next_search_node = SearchNode { + // node: next, + // next: self.extract_next_search(next), + // }; + // search_stack.push(next_search_node); + // } else { + // // this seq does not contain any more nodes. + // // Currently only possible if the seq is empty + // } + // }, + + // ControlNode::Par(p) => { + // let mut ctrl_points = vec![]; + // let mut pars_activated = vec![]; + + // let mut this_par = (ControlPoint::new(comp, node.node), p.stms().len() as u32); + + // // TODO Griffin: Maybe consider making this not + // // recursive in the future + // for arm in p.stms().iter().map( |x| { + // self.descend_to_leaf(*x, &mut vec![], comp) + // }) { + // match arm { + // NextControlPoint::None => { + // this_par.1 -= 1; + // }, + // NextControlPoint::Next(c) => ctrl_points.push(c), + // NextControlPoint::FinishedParChild(_) => unreachable!("I think this impossible"), + // NextControlPoint::StartedParChild(nodes, pars) => { + // ctrl_points.extend(nodes); + // pars_activated.extend(pars); + // }, + // } + // } + + // if this_par.1 != 0 { + // pars_activated.push(this_par); + // return NextControlPoint::StartedParChild(ctrl_points, pars_activated) + // } else { + // // there were no next nodes under this par, so we + // // ascend the search tree and continue + // } + // } + + // // functionally terminals for the purposes of needing to be + // // seen in the control program and given extra treatment + // ControlNode::If(_) + // | ControlNode::While(_) + // // actual terminals + // | ControlNode::Invoke(_) + // | ControlNode::Enable(_) + // // might not want this here in the future, but makes sense + // // if we think about annotations on empty groups. + // | ControlNode::Empty(_)=> { + // return NextControlPoint::Next(ControlPoint::new(comp, node.node)) + // } + // } + // } + // NextControlPoint::None + // } + + // may want to make this iterate directly if it turns out that the vec + // allocation is too expensive in this context + fn get_assignments(&self) -> AssignmentBundle { + // maybe should give this a capacity equivalent to the number of + // elements in the program counter? It would be a bit of an over + // approximation + let mut out = AssignmentBundle::new(); + for node in self.env.pc.iter() { + match &self.ctx().primary[node.control_leaf] { + ControlNode::Empty(_) => { + // don't need to add any assignments here + } + ControlNode::Enable(e) => { + out.assigns.push((node.comp, self.ctx().primary[e.group()].assignments)) + } + + ControlNode::Invoke(_) => todo!("invokes not yet implemented"), + // The reason this shouldn't happen is that the program counter + // should've processed these nodes into their children and + // stored the needed auxillary data for par structures + ControlNode::If(_) | ControlNode::While(_) => panic!("If/While nodes are present in the control program when `get_assignments` is called. This is an error, please report it."), + ControlNode::Seq(_) | ControlNode::Par(_) => unreachable!(), + } + } + + out + } + + pub fn step(&mut self) -> InterpreterResult<()> { + // place to keep track of what groups we need to conclude at the end of + // this step. These are indices into the program counter + + // we want to iterate through all the nodes present in the program counter + + // first we need to check for conditional control nodes + + self.simulate_combinational(); + + todo!() + } + + fn evaluate_guard(&self, guard: GuardIdx, comp: GlobalCellId) -> bool { + let guard = &self.ctx().primary[guard]; + match guard { + Guard::True => true, + Guard::Or(a, b) => { + self.evaluate_guard(*a, comp) || self.evaluate_guard(*b, comp) + } + Guard::And(a, b) => { + self.evaluate_guard(*a, comp) || self.evaluate_guard(*b, comp) + } + Guard::Not(n) => !self.evaluate_guard(*n, comp), + Guard::Comp(c, a, b) => { + let comp_v = self.env.cells[comp].unwrap_comp(); + + let a = self.lookup_global_port_id(comp_v.convert_to_global(a)); + let b = self.lookup_global_port_id(comp_v.convert_to_global(b)); + + let a_val = &self.env.ports[a]; + let b_val = &self.env.ports[b]; + match c { + calyx_ir::PortComp::Eq => a_val == b_val, + calyx_ir::PortComp::Neq => a_val != b_val, + calyx_ir::PortComp::Gt => a_val > b_val, + calyx_ir::PortComp::Lt => a_val < b_val, + calyx_ir::PortComp::Geq => a_val >= b_val, + calyx_ir::PortComp::Leq => a_val <= b_val, + } + } + Guard::Port(p) => { + let comp_v = self.env.cells[comp].unwrap_comp(); + let p_idx = + self.lookup_global_port_id(comp_v.convert_to_global(p)); + self.env.ports[p_idx].as_bool() + } + } + } + + fn simulate_combinational(&mut self) { + let assigns = self.get_assignments(); + let mut has_changed = true; + + // This is an upper-bound, i.e. if every assignment succeeds then there + // will be this many entries + let mut updates_vec: Vec<(GlobalPortId, Value)> = + Vec::with_capacity(assigns.len()); + + while has_changed { + let updates = assigns.iter_over_assignments(self.ctx()).filter_map( + |(comp_idx, assign)| { + if self.evaluate_guard(assign.guard, comp_idx) { + let val = self.get_value(&assign.src, comp_idx); + Some(( + self.get_global_idx(&assign.dst, comp_idx), + val.clone(), + )) + } else { + None + } + }, + ); + + // want to buffer all updates before committing. It's not ideal to + // be doing this in a tight loop. + updates_vec.extend(updates); + + for (dest, val) in updates_vec.drain(..) { + if self.env.ports[dest] != val { + has_changed = true + } + self.env.ports[dest] = val; + } + } + } + + pub fn _main_test(&mut self) { + self.env.print_pc(); + for _x in self.env.pc.iter() { + // println!("{:?} next {:?}", x, self.find_next_control_point(x)) + } + println!("{:?}", self.get_assignments()) + } +} + +/// A collection of assignments represented using a series of half-open ranges +/// via [AssignmentRange] +#[derive(Debug)] +struct AssignmentBundle { + assigns: Vec<(GlobalCellId, AssignmentRange)>, +} + +impl AssignmentBundle { + fn new() -> Self { + Self { + assigns: Vec::new(), + } + } + + fn with_capacity(size: usize) -> Self { + Self { + assigns: Vec::with_capacity(size), + } + } + + #[inline] + pub fn push(&mut self, value: (GlobalCellId, AssignmentRange)) { + self.assigns.push(value) + } + + pub fn iter( + &self, + ) -> impl Iterator { + self.assigns.iter() + } + + pub fn iter_over_indices( + &self, + ) -> impl Iterator + '_ { + self.assigns + .iter() + .flat_map(|(c, x)| x.iter().map(|y| (*c, y))) + } + + pub fn iter_over_assignments<'a>( + &'a self, + ctx: &'a Context, + ) -> impl Iterator { + self.iter_over_indices() + .map(|(c, idx)| (c, &ctx.primary[idx])) + } + + /// The total number of assignments. Not the total number of index ranges! + pub fn len(&self) -> usize { + self.assigns + .iter() + .fold(0, |acc, (_, range)| acc + range.size()) + } +} + +impl FromIterator<(GlobalCellId, AssignmentRange)> for AssignmentBundle { + fn from_iter>( + iter: T, + ) -> Self { + Self { + assigns: iter.into_iter().collect(), + } + } +} diff --git a/interp/src/flatten/structures/environment/program_counter.rs b/interp/src/flatten/structures/environment/program_counter.rs new file mode 100644 index 000000000..190e78936 --- /dev/null +++ b/interp/src/flatten/structures/environment/program_counter.rs @@ -0,0 +1,301 @@ +use std::num::NonZeroU32; + +use ahash::{HashMap, HashMapExt}; + +use super::super::context::Context; +use crate::flatten::{ + flat_ir::prelude::{ControlIdx, ControlNode, GlobalCellId}, + structures::index_trait::{impl_index_nonzero, IndexRef}, +}; + +use itertools::{FoldWhile, Itertools}; + +/// Simple struct containing both the component instance and the active leaf +/// node in the component +#[derive(Debug, Hash, Eq, PartialEq)] +pub struct ControlPoint { + pub comp: GlobalCellId, + pub control_leaf: ControlIdx, +} + +impl ControlPoint { + pub fn new(comp: GlobalCellId, control_leaf: ControlIdx) -> Self { + Self { comp, control_leaf } + } +} + +#[derive(Debug)] +enum NextControlPoint { + /// no + None, + /// This is the node to run next. The nice friendly singular case + Next(ControlPoint), + /// We just finished the child of this par block and need to decrement its + /// count + FinishedParChild(ControlPoint), + /// We passed through one or more par nodes to reach this leaf (or leaves) + StartedParChild(Vec, Vec<(ControlPoint, u32)>), +} + +/// An index for searching up and down a tree. This is used to index into +/// various control nodes. For If blocks the true branch is denoted by 0 and +/// the false by 1. The same is true for while blocks. For seq and par blocks, +/// it represents the current index into their statement vector. It is not +/// meaningful for other control types. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SearchIndex(NonZeroU32); +impl_index_nonzero!(SearchIndex); + +pub struct SearchNode { + pub node: ControlIdx, + pub search_index: Option, +} + +impl SearchIndex { + const TRUE_BRANCH: usize = 0; + const FALSE_BRANCH: usize = 1; + + /// Returns the next index, i.e. the current index incremented by 1 + fn next(&self) -> Self { + Self::new(self.index() + 1) + } + + fn is_true_branch(&self) -> bool { + self.index() == Self::TRUE_BRANCH + } + + fn is_false_branch(&self) -> bool { + self.index() == Self::FALSE_BRANCH + } +} + +/// A path from a control node (usually root) to some descendent node/leaf in the control tree +pub struct SearchPath { + path: Vec, +} + +impl SearchPath { + fn new() -> Self { + SearchPath { path: vec![] } + } + + pub fn source_node(&self) -> Option<&SearchNode> { + self.path.get(0) + } + + pub fn len(&self) -> usize { + self.path.len() + } + + pub fn is_empty(&self) -> bool { + self.path.is_empty() + } + + pub fn find_path_to_node( + start: ControlIdx, + target: ControlIdx, + context: &Context, + ) -> Self { + let mut current_path = Self::new(); + current_path.path.push(SearchNode { + node: start, + search_index: None, + }); + + while let Some(node) = current_path.path.last_mut() { + if node.node == target { + break; + } + + match &context.primary.control[node.node] { + ControlNode::Empty(_) + | ControlNode::Enable(_) + | ControlNode::Invoke(_) => { + // in this case we reached a terminal node which was not the + // target since we did not break in the above case. So we + // simply remove the current lowest node and ascend the + // stack to continue the DFS. + current_path.path.pop(); + } + ControlNode::Seq(s) => { + if let Some(idx) = &mut node.search_index { + if idx.index() < (s.stms().len() - 1) { + *idx = idx.next(); + } else { + current_path.path.pop(); + continue; + } + } else if !s.stms().is_empty() { + let new_idx = SearchIndex::new(0); + node.search_index = Some(new_idx); + } else { + current_path.path.pop(); + continue; + } + + // unwrap is safe since by this point it has been forced to + // be a Some variant + let new_node = s.stms()[node.search_index.unwrap().index()]; + current_path.path.push(SearchNode { + node: new_node, + search_index: None, + }) + } + // TODO Griffin: figure out how to deduplicate these arms + ControlNode::Par(p) => { + if let Some(idx) = &mut node.search_index { + if idx.index() < (p.stms().len() - 1) { + *idx = idx.next(); + } else { + current_path.path.pop(); + continue; + } + } else if !p.stms().is_empty() { + let new_idx = SearchIndex::new(0); + node.search_index = Some(new_idx); + } else { + current_path.path.pop(); + continue; + } + + // unwrap is safe since by this point it has been forced to + // be a Some variant + let new_node = p.stms()[node.search_index.unwrap().index()]; + current_path.path.push(SearchNode { + node: new_node, + search_index: None, + }) + } + ControlNode::If(_) => todo!(), + ControlNode::While(_) => todo!(), + } + } + + current_path + } + + pub fn find_path_from_root(target: ControlIdx, context: &Context) -> Self { + let root = context + .primary + .components + .iter() + .fold_while(ControlIdx::new(0), |current_root, (_, comp_info)| { + if let Some(index) = comp_info.control { + if index >= current_root && index < target { + FoldWhile::Continue(index) + } else { + FoldWhile::Done(current_root) + } + } else { + FoldWhile::Continue(current_root) + } + }) + .into_inner(); + + Self::find_path_to_node(root, target, context) + } +} + +/// The number of control points to preallocate for the program counter. +const CONTROL_POINT_PREALLOCATE: usize = 16; + +/// The number of children that have yet to finish for a given par arm. I have +/// this a u16 at the moment which is hopefully fine? More than 65,535 parallel +/// children would be a lot. +pub type ChildCount = u16; + +/// The program counter for the whole program execution. Wraps over a vector of +/// the active leaf statements for each component instance. +#[derive(Debug, Default)] +pub(crate) struct ProgramCounter { + vec: Vec, + par_map: HashMap, +} + +// we need a few things from the program counter + +impl ProgramCounter { + pub fn new(ctx: &Context) -> Self { + let root = ctx.entry_point; + // this relies on the fact that we construct the root cell-ledger + // as the first possible cell in the program. If that changes this will break. + let root_cell = GlobalCellId::new(0); + let mut par_map: HashMap = HashMap::new(); + + let mut vec = Vec::with_capacity(CONTROL_POINT_PREALLOCATE); + if let Some(current) = ctx.primary[root].control { + let mut work_queue: Vec = Vec::from([current]); + let mut backtrack_map = HashMap::new(); + + while let Some(current) = work_queue.pop() { + match &ctx.primary[current] { + ControlNode::Empty(_) => { + vec.push(ControlPoint::new(root_cell, current)) + } + ControlNode::Enable(_) => { + vec.push(ControlPoint::new(root_cell, current)) + } + ControlNode::Seq(s) => match s + .stms() + .iter() + .find(|&x| !backtrack_map.contains_key(x)) + { + Some(n) => { + backtrack_map.insert(*n, current); + work_queue.push(*n); + } + None => { + if let Some(b) = backtrack_map.get(¤t) { + work_queue.push(*b) + } + } + }, + ControlNode::Par(p) => { + par_map.insert( + ControlPoint::new(root_cell, current), + p.stms().len().try_into().expect( + "number of par arms does not fit into the default size value. Please let us know so that we can adjust the datatype accordingly", + ), + ); + for node in p.stms() { + work_queue.push(*node); + } + } + ControlNode::If(_) => { + vec.push(ControlPoint::new(root_cell, current)) + } + ControlNode::While(_) => { + vec.push(ControlPoint::new(root_cell, current)) + } + ControlNode::Invoke(_) => { + vec.push(ControlPoint::new(root_cell, current)) + } + } + } + } else { + todo!( + "Flat interpreter does not support control-less components yet" + ) + } + + Self { vec, par_map } + } + + pub fn iter(&self) -> std::slice::Iter<'_, ControlPoint> { + self.vec.iter() + } + + pub fn is_done(&self) -> bool { + self.vec.is_empty() + } +} + +impl<'a> IntoIterator for &'a ProgramCounter { + type Item = &'a ControlPoint; + + type IntoIter = std::slice::Iter<'a, ControlPoint>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/interp/src/flatten/structures/mod.rs b/interp/src/flatten/structures/mod.rs index af7edb104..feccaf3e8 100644 --- a/interp/src/flatten/structures/mod.rs +++ b/interp/src/flatten/structures/mod.rs @@ -4,3 +4,4 @@ pub mod index_trait; pub mod indexed_map; mod printer; pub mod sparse_map; +pub mod values; diff --git a/interp/src/flatten/structures/values.rs b/interp/src/flatten/structures/values.rs new file mode 100644 index 000000000..0c4b5ee6d --- /dev/null +++ b/interp/src/flatten/structures/values.rs @@ -0,0 +1,30 @@ +use crate::values::Value as BvValue; + +pub enum Value { + /// An undefined value from which it is dangerous to read. + Undefined, + /// A defined value that can be computed with + Defined(DefinedValue), +} + +pub enum DefinedValue { + Large(BvValue), +} + +impl Value { + /// Returns `true` if the value is [`Undefined`]. + /// + /// [`Undefined`]: Value::Undefined + #[must_use] + pub fn is_undefined(&self) -> bool { + matches!(self, Self::Undefined) + } + + /// Returns `true` if the value is [`Defined`]. + /// + /// [`Defined`]: Value::Defined + #[must_use] + pub fn is_defined(&self) -> bool { + matches!(self, Self::Defined(..)) + } +} diff --git a/interp/src/structures/values.rs b/interp/src/structures/values.rs index bcebcc46f..a66e552c1 100644 --- a/interp/src/structures/values.rs +++ b/interp/src/structures/values.rs @@ -1,6 +1,5 @@ use std::ops::Not; -use std::rc::Rc; -use std::{cell::RefCell, fmt::Write, ops::Index}; +use std::{fmt::Write, ops::Index}; use bitvec::prelude::*; use fraction::Fraction; @@ -9,8 +8,6 @@ use itertools::Itertools; use serde::de::{self, Deserialize, Visitor}; use serde::Serialize; -use calyx_ir as ir; - pub type BitString = BitVec; /// Retrieves the unsigned fixed point representation of `v`. This splits the representation into @@ -256,8 +253,6 @@ impl InputNumber { } } -type Signed = Rc>>; -type Unsigned = Rc>>; #[derive(Clone, Debug)] /// The type of all inputs and outputs to all components in Calyx. /// Wraps a BitVector. @@ -265,20 +260,12 @@ pub struct Value { // Lsb0 means the 0th index contains the LSB. This is useful because // a 7-bit bitvector and 17-bit bitvector representing the number 6 have // ones in the same index. - vec: Rc, - - unsigned: Unsigned, - - signed: Signed, + vec: BitString, } impl From for Value { fn from(bv: BitString) -> Self { - Self { - vec: Rc::new(bv), - unsigned: Unsigned::default(), - signed: Signed::default(), - } + Self { vec: bv } } } @@ -307,7 +294,7 @@ impl Value { } pub fn clone_bit_vec(&self) -> BitString { - (*self.vec).clone() + self.vec.clone() } pub fn bv_ref(&self) -> &BitString { @@ -334,9 +321,7 @@ impl Value { pub fn zeroes>(bitwidth: I) -> Value { let input_num: InputNumber = bitwidth.into(); Value { - vec: Rc::new(bitvec![usize, Lsb0; 0; input_num.as_usize()]), - unsigned: ir::rrc(Some(0_u8.into())), - signed: ir::rrc(Some(0.into())), + vec: bitvec![usize, Lsb0; 0; input_num.as_usize()], } } @@ -382,34 +367,13 @@ impl Value { && !Value::unsigned_value_fits_in(&bv, width); bv.resize(width, init.is_negative()); - ( - Value { - vec: Rc::new(bv), - signed: ir::rrc(None), - unsigned: ir::rrc(None), - }, - flag, - ) + (Value { vec: bv }, flag) } #[inline] pub fn from_bv(bv: BitString) -> Self { bv.into() } - - /// Returns a Value containing a vector of length 0, effectively returning - /// a cleared vector. - // TODO (Griffin): Depricate this. - pub fn clear(&self) -> Self { - let mut vec = (*self.vec).clone(); - vec.truncate(0); - Value { - vec: Rc::new(vec), - signed: Signed::default(), - unsigned: Unsigned::default(), - } - } - /// Returns a Value truncated to length new_size. /// /// # Example @@ -418,19 +382,13 @@ impl Value { /// let val_4_4 = Value::from(4, 16).truncate(4); /// ``` pub fn truncate(&self, new_size: usize) -> Value { - let mut vec = (*self.vec).clone(); + let mut vec = self.vec.clone(); vec.truncate(new_size); - Value { - vec: Rc::new(vec), - signed: Signed::default(), - unsigned: Unsigned::default(), - } + Value { vec } } pub fn truncate_in_place(&mut self, new_size: usize) { - Rc::make_mut(&mut self.vec).truncate(new_size); - self.signed = Default::default(); - self.unsigned = Unsigned::default(); + self.vec.truncate(new_size); } /// Zero-extend the vector to length ext. @@ -441,15 +399,11 @@ impl Value { /// let val_4_16 = Value::from(4, 4).ext(16); /// ``` pub fn ext(&self, ext: usize) -> Value { - let mut vec = (*self.vec).clone(); + let mut vec = self.vec.clone(); for _x in 0..(ext - vec.len()) { vec.push(false); } - Value { - vec: Rc::new(vec), - signed: self.signed.clone(), - unsigned: self.unsigned.clone(), - } + Value { vec } } /// Sign-extend the vector to length ext. @@ -461,16 +415,12 @@ impl Value { /// let val_31_5 = Value::from(15, 4).sext(5); /// ``` pub fn sext(&self, ext: usize) -> Value { - let mut vec = (*self.vec).clone(); + let mut vec = self.vec.clone(); let sign = vec[vec.len() - 1]; for _x in 0..(ext - vec.len()) { vec.push(sign); } - Value { - vec: Rc::new(vec), - signed: Signed::default(), - unsigned: Unsigned::default(), - } + Value { vec } } /// Converts value into u64 type. @@ -628,51 +578,36 @@ impl Value { } pub fn as_signed(&self) -> IBig { - let memo_ref = self.signed.borrow(); - if let Some(v) = &*memo_ref { - v.clone() - } else { - drop(memo_ref); - let mut acc: IBig = 0.into(); - - // skip the msb for the moment - for bit in self.vec.iter().take(self.vec.len() - 1).rev() { - acc <<= 1; - let bit: IBig = (*bit).into(); - acc |= bit - } + let mut acc: IBig = 0.into(); - if let Some(bit) = self.vec.last() { - if *bit { - let neg: IBig = (-1).into(); - let two: IBig = (2).into(); + // skip the msb for the moment + for bit in self.vec.iter().take(self.vec.len() - 1).rev() { + acc <<= 1; + let bit: IBig = (*bit).into(); + acc |= bit + } - acc += neg * two.pow(self.vec.len() - 1) - } + if let Some(bit) = self.vec.last() { + if *bit { + let neg: IBig = (-1).into(); + let two: IBig = (2).into(); + + acc += neg * two.pow(self.vec.len() - 1) } - let mut memo_ref = self.signed.borrow_mut(); - *memo_ref = Some(acc.clone()); - acc } + + acc } pub fn as_unsigned(&self) -> UBig { - let memo_ref = self.unsigned.borrow(); - - if let Some(v) = &*memo_ref { - v.clone() - } else { - drop(memo_ref); - let mut acc: UBig = 0_u32.into(); - for bit in self.vec.iter().rev() { - acc <<= 1; - let bit: UBig = (*bit).into(); - acc |= bit; - } - let mut memo_ref = self.unsigned.borrow_mut(); - *memo_ref = Some(acc.clone()); - acc + let mut acc: UBig = 0_u32.into(); + for bit in self.vec.iter().rev() { + acc <<= 1; + let bit: UBig = (*bit).into(); + acc |= bit; } + + acc } /// Interprets a 1bit value as a bool, will not panic for non-1-bit values @@ -700,11 +635,7 @@ impl Value { assert!(upper_idx < self.vec.len()); let new_bv = (self.vec[lower_idx..=upper_idx]).into(); - Value { - vec: Rc::new(new_bv), - signed: Signed::default(), - unsigned: Unsigned::default(), - } + Value { vec: new_bv } } /// Returns a value containing the sliced region \[lower,upper\] @@ -713,11 +644,7 @@ impl Value { assert!(upper_idx < self.vec.len()); let new_bv = BitVec::from_bitslice(&self.vec[lower_idx..=upper_idx]); - Value { - vec: Rc::new(new_bv), - signed: Signed::default(), - unsigned: Unsigned::default(), - } + Value { vec: new_bv } } } diff --git a/interp/src/tests/values.rs b/interp/src/tests/values.rs index 72f24a424..c7e715e30 100644 --- a/interp/src/tests/values.rs +++ b/interp/src/tests/values.rs @@ -24,13 +24,7 @@ mod val_test { println!("15 with bit width 4: {}", v_15_4); assert_eq!(v_31_4.as_u64(), v_15_4.as_u64()); } - #[test] - fn clear() { - let v_15_4 = Value::from(15, 4); - let v_15_4 = v_15_4.clear(); - println!("15 with bit width 4 AFTER clear: {}", v_15_4); - assert_eq!(v_15_4.as_u64(), 0); - } + #[test] fn ext() { let v_15_4 = Value::from(15, 4); From c81a4acd8147e28faf96c07ce00b387cc61d5c60 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:10:48 -0500 Subject: [PATCH 093/189] `pifo`: better testing (#1763) --- calyx-py/calyx/fifo_oracle.py | 62 +------ calyx-py/calyx/pifo_oracle.py | 11 ++ .../{fifo_data_gen.py => queue_data_gen.py} | 7 +- calyx-py/calyx/queues.py | 171 ++++++++++++++++++ calyx-py/test/correctness/fifo.data | 28 +-- calyx-py/test/correctness/fifo.expect | 44 ++--- calyx-py/test/correctness/pifo.data | 38 ++-- calyx-py/test/correctness/pifo.expect | 54 +++--- 8 files changed, 272 insertions(+), 143 deletions(-) create mode 100644 calyx-py/calyx/pifo_oracle.py rename calyx-py/calyx/{fifo_data_gen.py => queue_data_gen.py} (93%) create mode 100644 calyx-py/calyx/queues.py diff --git a/calyx-py/calyx/fifo_oracle.py b/calyx-py/calyx/fifo_oracle.py index 6ca4fbd54..8cc4104f5 100644 --- a/calyx-py/calyx/fifo_oracle.py +++ b/calyx-py/calyx/fifo_oracle.py @@ -1,60 +1,8 @@ -import sys -import json - - -def parse_json(): - """Effectively the opposite of `data_gen`: - Given a JSON file formatted for Calyx purposes, parse it into its two lists: - - The `commands` memory, which has MAX_CMDS items. - - The `values` memory, which has MAX_CMDS items. - Returns the two lists. - """ - - # The JSON file is piped to us in stdin. - data = json.load(sys.stdin) - commands = data["commands"]["data"] - values = data["values"]["data"] - return commands, values - - -def operate_fifo(commands, values): - """Given the three lists, operate a FIFO routine. - - Read the comammands list in order. - - When the value is 0, we "pop" the FIFO and write the value to the answer memory. - - When it is 1, we "peek" into the FIFO and write the value to the answer memory. - - When it is 2, we push the coressponding item in the `values` list to the FIFO. - - In the end, we return the answer memory. - """ - fifo = [] - ans = [] - for cmd, val in zip(commands, values): - if cmd == 0: - if len(fifo) == 0: - break - ans.append(fifo.pop(0)) - elif cmd == 1: - if len(fifo) == 0: - break - ans.append(fifo[0]) - elif cmd == 2: - fifo.append(val) - # Pad the answer memory with zeroes until it is of length ANS_MEM_LEN. - ans += [0] * (10 - len(ans)) - return ans - - -def dump_json(commands, values, ans_mem): - """Prints a JSON representation of the data to stdout.""" - payload = { - "ans_mem": ans_mem, - "commands": commands, - "values": values, - } - print(json.dumps(payload, indent=2)) +import queues if __name__ == "__main__": - commands, values = parse_json() - ans = operate_fifo(commands, values) - dump_json(commands, values, ans) + commands, values = queues.parse_json() + pifo = queues.Fifo([]) + ans = queues.operate_queue(commands, values, pifo) + queues.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/pifo_oracle.py b/calyx-py/calyx/pifo_oracle.py new file mode 100644 index 000000000..55d7a81bc --- /dev/null +++ b/calyx-py/calyx/pifo_oracle.py @@ -0,0 +1,11 @@ +import queues + + +if __name__ == "__main__": + commands, values = queues.parse_json() + + # Our PIFO is simple: it just orchestrates two FIFOs. The boundary is 200. + pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200) + + ans = queues.operate_queue(commands, values, pifo) + queues.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/fifo_data_gen.py b/calyx-py/calyx/queue_data_gen.py similarity index 93% rename from calyx-py/calyx/fifo_data_gen.py rename to calyx-py/calyx/queue_data_gen.py index da07f57f4..13f5cf211 100644 --- a/calyx-py/calyx/fifo_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -1,5 +1,4 @@ import random -import time import json from typing import Dict, Union @@ -19,7 +18,7 @@ def dump_json(): The data itself is populated randomly, following certain rules: - It has three "memories": `commands`, `values`, and `ans_mem`. - The `commands` memory has MAX_CMDS items, which are 0, 1, or 2. - - The `values` memory has MAX_CMDS items: random values between 0 and 100. + - The `values` memory has MAX_CMDS items: random values between 0 and 400. - The `ans_mem` memory has ANS_MEM_LEN items, all zeroes. - Each memory has a `format` field, which is a format object for a bitvector. """ @@ -32,8 +31,8 @@ def dump_json(): } values = { "values": { - "data": [random.randint(0, 100) for _ in range(MAX_CMDS)], - # The `values` memory has MAX_CMDS items: random values between 0 and 100. + "data": [random.randint(0, 400) for _ in range(MAX_CMDS)], + # The `values` memory has MAX_CMDS items: random values between 0 and 00. "format": format_gen(32), } } diff --git a/calyx-py/calyx/queues.py b/calyx-py/calyx/queues.py new file mode 100644 index 000000000..c9c493b9e --- /dev/null +++ b/calyx-py/calyx/queues.py @@ -0,0 +1,171 @@ +import sys +import json +from dataclasses import dataclass +from typing import List + +ANS_MEM_LEN = 10 + + +@dataclass +class Fifo: + """A FIFO data structure. + Supports the operations `push`, `pop`, and `peek`. + """ + + def __init__(self, data: List[int]): + self.data = data + + def push(self, val: int): + """Pushes `val` to the FIFO.""" + self.data.append(val) + + def pop(self) -> int: + """Pops the FIFO.""" + if len(self.data) == 0: + raise IndexError("Cannot pop from empty FIFO.") + return self.data.pop(0) + + def peek(self) -> int: + """Peeks into the FIFO.""" + if len(self.data) == 0: + raise IndexError("Cannot peek into empty FIFO.") + return self.data[0] + + def __len__(self) -> int: + return len(self.data) + + +@dataclass +class Pifo: + """A PIFO data structure. + Supports the operations `push`, `pop`, and `peek`. + + We do this by maintaining two queues that are given to us at initialization. + We toggle between these queues when popping/peeking. + We have a variable called `hot` that says which queue is to be popped/peeked next. + `hot` starts at 0. + We also take at initialization a `boundary` value. + + We maintain internally a variable called `pifo_len`: + the sum of the lengths of the two queues. + + When asked to pop: + - If `pifo_len` is 0, we raise an error. + - Else, if `hot` is 0, we try to pop from queue_0. + + If it succeeds, we flip `hot` to 1 and return the value we got. + + If it fails, we pop from queue_1 and return the value we got. + We leave `hot` as it was. + - If `hot` is 1, we proceed symmetrically. + - We decrement `pifo_len` by 1. + + When asked to peek: + We do the same thing as above, except: + - We peek instead of popping. + - We don't flip `hot`. + + When asked to push: + - If the value to be pushed is less than `boundary`, we push it into queue_1. + - Else, we push it into queue_2. + - We increment `pifo_len` by 1. + """ + + def __init__(self, queue_1, queue_2, boundary): + self.data = (queue_1, queue_2) + self.hot = 0 + self.pifo_len = len(queue_1) + len(queue_2) + self.boundary = boundary + + def push(self, val: int): + """Pushes `val` to the PIFO.""" + if val < self.boundary: + self.data[0].push(val) + else: + self.data[1].push(val) + self.pifo_len += 1 + + def pop(self) -> int: + """Pops the PIFO.""" + if self.pifo_len == 0: + raise IndexError("Cannot pop from empty PIFO.") + self.pifo_len -= 1 # We decrement `pifo_len` by 1. + if self.hot == 0: + try: + self.hot = 1 + return self.data[0].pop() + except IndexError: + return self.data[1].pop() + else: + try: + self.hot = 0 + return self.data[1].pop() + except IndexError: + return self.data[0].pop() + + def peek(self) -> int: + """Peeks into the PIFO.""" + if self.pifo_len == 0: + raise IndexError("Cannot peek into empty PIFO.") + if self.hot == 0: + try: + return self.data[0].peek() + except IndexError: + return self.data[1].peek() + else: + try: + return self.data[1].peek() + except IndexError: + return self.data[0].peek() + + def __len__(self) -> int: + return self.pifo_len + + +def parse_json(): + """Effectively the opposite of `data_gen`: + Given a JSON file formatted for Calyx purposes, parse it into its two lists: + - The `commands` memory, which has MAX_CMDS items. + - The `values` memory, which has MAX_CMDS items. + Returns the two lists. + """ + + data = json.load(sys.stdin) + commands = data["commands"]["data"] + values = data["values"]["data"] + return commands, values + + +def dump_json(commands, values, ans_mem): + """Prints a JSON representation of the data to stdout.""" + payload = { + "ans_mem": ans_mem, + "commands": commands, + "values": values, + } + print(json.dumps(payload, indent=2)) + + +def operate_queue(commands, values, queue): + """Given the two lists, one of commands and one of values. + Feed these into our queue, and return the answer memory. + """ + + ans = [] + for cmd, val in zip(commands, values): + if cmd == 0: + try: + ans.append(queue.pop()) + except IndexError: + break + + elif cmd == 1: + try: + ans.append(queue.peek()) + except IndexError: + break + + elif cmd == 2: + queue.push(val) + + # Pad the answer memory with zeroes until it is of length ANS_MEM_LEN. + ans += [0] * (ANS_MEM_LEN - len(ans)) + return ans diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 65ab3d659..5f72a3db8 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -25,21 +25,21 @@ }, "values": { "data": [ - 47, - 60, - 31, - 48, - 69, - 13, - 73, - 31, - 1, - 93, - 27, + 190, + 240, + 126, + 194, + 278, 52, - 35, - 23, - 98 + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index 20595ecca..d55133390 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,13 +1,13 @@ { "ans_mem": [ - 47, - 47, - 47, - 31, - 31, - 69, - 13, - 73, + 190, + 190, + 190, + 126, + 126, + 278, + 52, + 293, 0, 0 ], @@ -29,20 +29,20 @@ 0 ], "values": [ - 47, - 60, - 31, - 48, - 69, - 13, - 73, - 31, - 1, - 93, - 27, + 190, + 240, + 126, + 194, + 278, 52, - 35, - 23, - 98 + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ] } diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index fc06886e7..5f72a3db8 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -2,19 +2,19 @@ "commands": { "data": [ 2, + 1, 2, - 0, - 0, + 1, 2, 2, 2, 2, - 1, 0, + 1, 0, + 2, 0, 0, - 2, 0 ], "format": { @@ -25,21 +25,21 @@ }, "values": { "data": [ - 101, - 102, - 0, - 0, - 103, - 104, - 201, - 202, - 0, - 0, - 0, - 0, - 0, - 105, - 0 + 190, + 240, + 126, + 194, + 278, + 52, + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index 0631155c8..e29484e3f 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -1,48 +1,48 @@ { "ans_mem": [ - 101, - 102, - 201, - 201, - 103, - 202, - 104, - 105, + 190, + 190, + 190, + 278, + 278, + 126, + 293, + 52, 0, 0 ], "commands": [ 2, + 1, 2, - 0, - 0, + 1, 2, 2, 2, 2, - 1, 0, + 1, 0, + 2, 0, 0, - 2, 0 ], "values": [ - 101, - 102, - 0, - 0, - 103, - 104, - 201, - 202, - 0, - 0, - 0, - 0, - 0, - 105, - 0 + 190, + 240, + 126, + 194, + 278, + 52, + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ] } From 44c0a6732febd195020013e85d3996a4a699de52 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:26:37 -0500 Subject: [PATCH 094/189] `pifo tree`: better testing (#1765) --- calyx-py/calyx/pifotree_oracle.py | 22 +++++++++ calyx-py/test/correctness/pifo_tree.data | 40 ++++++++-------- calyx-py/test/correctness/pifo_tree.expect | 54 +++++++++++----------- 3 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 calyx-py/calyx/pifotree_oracle.py diff --git a/calyx-py/calyx/pifotree_oracle.py b/calyx-py/calyx/pifotree_oracle.py new file mode 100644 index 000000000..9f83b83fc --- /dev/null +++ b/calyx-py/calyx/pifotree_oracle.py @@ -0,0 +1,22 @@ +import queues + + +if __name__ == "__main__": + commands, values = queues.parse_json() + + # Our PIFO is a little complicated: it is a tree of queues. + # The root has two children, which are PIFOs. + # - PIFO_red is the left child. + # + PIFO_red itself has two children, which are FIFOs. + # * FIFO_purple is the left child. + # * FIFO_tangerine is the right child. + # * The boundary for this is 100. + # - FIFO_blue is the right child. + # - The boundary for this is 200. + + pifo = queues.Pifo( + queues.Pifo(queues.Fifo([]), queues.Fifo([]), 100), queues.Fifo([]), 200 + ) + + ans = queues.operate_queue(commands, values, pifo) + queues.dump_json(commands, values, ans) diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data index 254f74da6..5f72a3db8 100644 --- a/calyx-py/test/correctness/pifo_tree.data +++ b/calyx-py/test/correctness/pifo_tree.data @@ -2,17 +2,17 @@ "commands": { "data": [ 2, + 1, 2, + 1, 2, 2, 2, 2, 0, + 1, 0, - 0, - 0, - 0, - 0, + 2, 0, 0, 0 @@ -25,21 +25,21 @@ }, "values": { "data": [ - 11, - 12, - 201, - 202, - 203, - 101, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 190, + 240, + 126, + 194, + 278, + 52, + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ], "format": { "is_signed": false, @@ -66,4 +66,4 @@ "width": 32 } } -} \ No newline at end of file +} diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect index e72076fcf..c0040e323 100644 --- a/calyx-py/test/correctness/pifo_tree.expect +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -1,48 +1,48 @@ { "ans_mem": [ - 11, - 201, - 101, - 202, - 12, - 203, - 0, - 0, + 190, + 190, + 52, + 278, + 278, + 190, + 293, + 126, 0, 0 ], "commands": [ 2, + 1, 2, + 1, 2, 2, 2, 2, 0, + 1, 0, - 0, - 0, - 0, - 0, + 2, 0, 0, 0 ], "values": [ - 11, - 12, - 201, - 202, - 203, - 101, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + 190, + 240, + 126, + 194, + 278, + 52, + 293, + 127, + 6, + 374, + 110, + 208, + 143, + 93, + 392 ] } From 3d27b0fcffa86066982ef9eee1813675470aa488 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:59:51 -0500 Subject: [PATCH 095/189] Queues: collect magic numbers, pass 100 commands (#1771) --- calyx-py/calyx/fifo_oracle.py | 12 +- calyx-py/calyx/pifo_oracle.py | 8 +- calyx-py/calyx/pifotree_oracle.py | 8 +- calyx-py/calyx/queue_call.py | 19 +- calyx-py/calyx/queue_data_gen.py | 27 +- calyx-py/calyx/queue_util.py | 29 + calyx-py/calyx/queues.py | 61 +- calyx-py/test/correctness/fifo.data | 290 ++++- calyx-py/test/correctness/fifo.expect | 306 ++++- calyx-py/test/correctness/piezo_pifotree.yx | 1197 +++++++++++++++++++ calyx-py/test/correctness/pifo.data | 290 ++++- calyx-py/test/correctness/pifo.expect | 306 ++++- calyx-py/test/correctness/pifo_tree.data | 290 ++++- calyx-py/test/correctness/pifo_tree.expect | 306 ++++- 14 files changed, 2966 insertions(+), 183 deletions(-) create mode 100644 calyx-py/calyx/queue_util.py create mode 100644 calyx-py/test/correctness/piezo_pifotree.yx diff --git a/calyx-py/calyx/fifo_oracle.py b/calyx-py/calyx/fifo_oracle.py index 8cc4104f5..68f990580 100644 --- a/calyx-py/calyx/fifo_oracle.py +++ b/calyx-py/calyx/fifo_oracle.py @@ -1,8 +1,8 @@ -import queues - +import calyx.queues as queues +import calyx.queue_util as queue_util if __name__ == "__main__": - commands, values = queues.parse_json() - pifo = queues.Fifo([]) - ans = queues.operate_queue(commands, values, pifo) - queues.dump_json(commands, values, ans) + commands, values = queue_util.parse_json() + fifo = queues.Fifo([]) + ans = queues.operate_queue(commands, values, fifo) + queue_util.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/pifo_oracle.py b/calyx-py/calyx/pifo_oracle.py index 55d7a81bc..f454a7540 100644 --- a/calyx-py/calyx/pifo_oracle.py +++ b/calyx-py/calyx/pifo_oracle.py @@ -1,11 +1,11 @@ -import queues - +import calyx.queues as queues +import calyx.queue_util as queue_util if __name__ == "__main__": - commands, values = queues.parse_json() + commands, values = queue_util.parse_json() # Our PIFO is simple: it just orchestrates two FIFOs. The boundary is 200. pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200) ans = queues.operate_queue(commands, values, pifo) - queues.dump_json(commands, values, ans) + queue_util.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/pifotree_oracle.py b/calyx-py/calyx/pifotree_oracle.py index 9f83b83fc..9ca1f2c35 100644 --- a/calyx-py/calyx/pifotree_oracle.py +++ b/calyx-py/calyx/pifotree_oracle.py @@ -1,8 +1,9 @@ -import queues +import calyx.queues as queues +import calyx.queue_util as queue_util if __name__ == "__main__": - commands, values = queues.parse_json() + commands, values = queue_util.parse_json() # Our PIFO is a little complicated: it is a tree of queues. # The root has two children, which are PIFOs. @@ -19,4 +20,5 @@ ) ans = queues.operate_queue(commands, values, pifo) - queues.dump_json(commands, values, ans) + queue_util.dump_json(commands, values, ans) + diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index e8e0ad1cc..e66b50fc7 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -1,9 +1,7 @@ # pylint: disable=import-error +import calyx.queue_util as queue_util import calyx.builder as cb -MAX_CMDS = 15 -ANS_MEM_LEN = 10 - def insert_main(prog, queue): """Inserts the component `main` into the program. @@ -33,9 +31,9 @@ def insert_main(prog, queue): # - one ref register, `ans`, into which the result of a pop or peek is written. # - one ref register, `err`, which is raised if an error occurs. - commands = main.seq_mem_d1("commands", 2, MAX_CMDS, 32, is_external=True) - values = main.seq_mem_d1("values", 32, MAX_CMDS, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True) + commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True) + values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) # The two components we'll use: queue = main.cell("myqueue", queue) @@ -79,10 +77,10 @@ def insert_main(prog, queue): loop_goes_on # Does the `err` flag say that the loop should continue? ) - update_i_neq_15, _ = main.neq_store_in_reg( + update_i_neq_max_cmds, _ = main.neq_store_in_reg( i.out, - cb.const(32, 15), - "i_neq_15", + cb.const(32, queue_util.MAX_CMDS), + "i_neq_max_cmds", 32, loop_goes_on # Does the `i` index say that the loop should continue? @@ -116,7 +114,8 @@ def insert_main(prog, queue): ], ), incr_i, # Increment the command index - update_i_neq_15, # Did this increment make us need to break? + update_i_neq_max_cmds, + # Did this increment make us need to break? ], ), ], diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index 13f5cf211..327f2d86d 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -1,9 +1,7 @@ import random import json from typing import Dict, Union - -MAX_CMDS = 15 -ANS_MEM_LEN = 10 +import calyx.queue_util as queue_util FormatType = Dict[str, Union[bool, str, int]] @@ -17,29 +15,34 @@ def dump_json(): """Prints a JSON representation of the data to stdout. The data itself is populated randomly, following certain rules: - It has three "memories": `commands`, `values`, and `ans_mem`. - - The `commands` memory has MAX_CMDS items, which are 0, 1, or 2. - - The `values` memory has MAX_CMDS items: random values between 0 and 400. - - The `ans_mem` memory has ANS_MEM_LEN items, all zeroes. + - The `commands` memory has queue_util.MAX_CMDS items, which are 0, 1, or 2. + - The `values` memory has queue_util.MAX_CMDS items: + random values between 0 and 400. + - The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes. - Each memory has a `format` field, which is a format object for a bitvector. """ commands = { "commands": { - "data": [random.randint(0, 2) for _ in range(MAX_CMDS)], - # The `commands` memory has MAX_CMDS items, which are 0, 1, or 2. + # We'll "rig" these random values a little. + # The first 5% of the commands will be 2 (push). + # The rest will be generated randomly from among 0, 1, and 2. + "data": [2] * (queue_util.MAX_CMDS // 20) + + [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS * 19 // 20)], "format": format_gen(2), } } values = { "values": { - "data": [random.randint(0, 400) for _ in range(MAX_CMDS)], - # The `values` memory has MAX_CMDS items: random values between 0 and 00. + "data": [random.randint(0, 400) for _ in range(queue_util.MAX_CMDS)], + # The `values` memory has queue_util.MAX_CMDS items: random values + # between 0 and 400. "format": format_gen(32), } } ans_mem = { "ans_mem": { - "data": [0 for _ in range(ANS_MEM_LEN)], - # The `ans_mem` memory has ANS_MEM_LEN items, all zeroes. + "data": [0 for _ in range(queue_util.MAX_CMDS)], + # The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes. "format": format_gen(32), } } diff --git a/calyx-py/calyx/queue_util.py b/calyx-py/calyx/queue_util.py new file mode 100644 index 000000000..e04380a0b --- /dev/null +++ b/calyx-py/calyx/queue_util.py @@ -0,0 +1,29 @@ +import json +import sys + +MAX_CMDS = 100 +QUEUE_SIZE = 10 + + +def parse_json(): + """Effectively the opposite of `data_gen`: + Given a JSON file formatted for Calyx purposes, parse it into its two lists: + - The `commands` memory, which has MAX_CMDS items. + - The `values` memory, which has MAX_CMDS items. + Returns the two lists. + """ + + data = json.load(sys.stdin) + commands = data["commands"]["data"] + values = data["values"]["data"] + return commands, values + + +def dump_json(commands, values, ans_mem): + """Prints a JSON representation of the data to stdout.""" + payload = { + "ans_mem": ans_mem, + "commands": commands, + "values": values, + } + print(json.dumps(payload, indent=2)) diff --git a/calyx-py/calyx/queues.py b/calyx-py/calyx/queues.py index c9c493b9e..77f2982ef 100644 --- a/calyx-py/calyx/queues.py +++ b/calyx-py/calyx/queues.py @@ -1,23 +1,26 @@ -import sys -import json from dataclasses import dataclass from typing import List - -ANS_MEM_LEN = 10 +import calyx.queue_util as queue_util @dataclass class Fifo: """A FIFO data structure. Supports the operations `push`, `pop`, and `peek`. + Inherent to the queue is its `max_len`, which is given to us at initialization + and we cannot exceed. """ - def __init__(self, data: List[int]): + def __init__(self, data: List[int], max_len: int = None): self.data = data + self.max_len = max_len or queue_util.QUEUE_SIZE def push(self, val: int): """Pushes `val` to the FIFO.""" - self.data.append(val) + if len(self.data) < self.max_len: + self.data.append(val) + else: + raise IndexError("Cannot push to full FIFO.") def pop(self) -> int: """Pops the FIFO.""" @@ -49,6 +52,10 @@ class Pifo: We maintain internally a variable called `pifo_len`: the sum of the lengths of the two queues. + Inherent to the queue is its `max_len`, which is given to us at initialization + and we cannot exceed. + + When asked to pop: - If `pifo_len` is 0, we raise an error. - Else, if `hot` is 0, we try to pop from queue_0. @@ -64,19 +71,26 @@ class Pifo: - We don't flip `hot`. When asked to push: + - If the PIFO is at length `max_len`, we raise an error. - If the value to be pushed is less than `boundary`, we push it into queue_1. - Else, we push it into queue_2. - We increment `pifo_len` by 1. """ - def __init__(self, queue_1, queue_2, boundary): + def __init__(self, queue_1, queue_2, boundary, max_len=None): self.data = (queue_1, queue_2) self.hot = 0 self.pifo_len = len(queue_1) + len(queue_2) self.boundary = boundary + self.max_len = max_len or queue_util.QUEUE_SIZE + assert ( + self.pifo_len <= self.max_len + ) # We can't be initialized with a PIFO that is too long. def push(self, val: int): """Pushes `val` to the PIFO.""" + if self.pifo_len == self.max_len: + raise IndexError("Cannot push to full PIFO.") if val < self.boundary: self.data[0].push(val) else: @@ -120,30 +134,6 @@ def __len__(self) -> int: return self.pifo_len -def parse_json(): - """Effectively the opposite of `data_gen`: - Given a JSON file formatted for Calyx purposes, parse it into its two lists: - - The `commands` memory, which has MAX_CMDS items. - - The `values` memory, which has MAX_CMDS items. - Returns the two lists. - """ - - data = json.load(sys.stdin) - commands = data["commands"]["data"] - values = data["values"]["data"] - return commands, values - - -def dump_json(commands, values, ans_mem): - """Prints a JSON representation of the data to stdout.""" - payload = { - "ans_mem": ans_mem, - "commands": commands, - "values": values, - } - print(json.dumps(payload, indent=2)) - - def operate_queue(commands, values, queue): """Given the two lists, one of commands and one of values. Feed these into our queue, and return the answer memory. @@ -164,8 +154,11 @@ def operate_queue(commands, values, queue): break elif cmd == 2: - queue.push(val) + try: + queue.push(val) + except IndexError: + break - # Pad the answer memory with zeroes until it is of length ANS_MEM_LEN. - ans += [0] * (ANS_MEM_LEN - len(ans)) + # Pad the answer memory with zeroes until it is of length MAX_CMDS. + ans += [0] * (queue_util.MAX_CMDS - len(ans)) return ans diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 5f72a3db8..7d0d68fb2 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -1,6 +1,11 @@ { "commands": { "data": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -15,7 +20,87 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "format": { "is_signed": false, @@ -25,21 +110,106 @@ }, "values": { "data": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ], "format": { "is_signed": false, @@ -49,6 +219,96 @@ }, "ans_mem": { "data": [ + 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, + 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, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index d55133390..63c85e68a 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,17 +1,112 @@ { "ans_mem": [ - 190, - 190, - 190, - 126, - 126, - 278, - 52, - 293, + 296, + 296, + 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, + 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 ], "commands": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -26,23 +121,188 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "values": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ] } diff --git a/calyx-py/test/correctness/piezo_pifotree.yx b/calyx-py/test/correctness/piezo_pifotree.yx new file mode 100644 index 000000000..c0357fc52 --- /dev/null +++ b/calyx-py/test/correctness/piezo_pifotree.yx @@ -0,0 +1,1197 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +import "primitives/memories.futil"; +component stats(flow: 1) -> (count_0: 32, count_1: 32) { + cells { + count_0_sto = std_reg(32); + count_1_sto = std_reg(32); + count_0_sto_incr = std_add(32); + count_1_sto_incr = std_add(32); + eq_1 = std_eq(1); + eq_2 = std_eq(1); + } + wires { + group count_0_sto_incr_group { + count_0_sto_incr.left = count_0_sto.out; + count_0_sto_incr.right = 32'd1; + count_0_sto.write_en = 1'd1; + count_0_sto.in = count_0_sto_incr.out; + count_0_sto_incr_group[done] = count_0_sto.done; + } + group count_1_sto_incr_group { + count_1_sto_incr.left = count_1_sto.out; + count_1_sto_incr.right = 32'd1; + count_1_sto.write_en = 1'd1; + count_1_sto.in = count_1_sto_incr.out; + count_1_sto_incr_group[done] = count_1_sto.done; + } + comb group eq_1_group { + eq_1.left = flow; + eq_1.right = 1'd0; + } + comb group eq_2_group { + eq_2.left = flow; + eq_2.right = 1'd1; + } + count_0 = count_0_sto.out; + count_1 = count_1_sto.out; + } + control { + seq { + par { + if eq_1.out with eq_1_group { + seq { + count_0_sto_incr_group; + } + } + if eq_2.out with eq_2_group { + seq { + count_1_sto_incr_group; + } + } + } + } + } +} +component fifo_purple(cmd: 2, value: 32) -> () { + cells { + mem = seq_mem_d1(32, 10, 32); + next_write = std_reg(32); + next_read = std_reg(32); + ref ans = std_reg(32); + ref err = std_reg(1); + len = std_reg(32); + eq_1 = std_eq(2); + eq_2 = std_eq(2); + eq_3 = std_eq(2); + eq_4 = std_eq(32); + eq_5 = std_eq(32); + eq_6 = std_eq(32); + eq_7 = std_eq(32); + next_write_incr = std_add(32); + next_read_incr = std_add(32); + len_incr = std_add(32); + len_decr = std_sub(32); + } + wires { + comb group eq_1_group { + eq_1.left = cmd; + eq_1.right = 2'd0; + } + comb group eq_2_group { + eq_2.left = cmd; + eq_2.right = 2'd1; + } + comb group eq_3_group { + eq_3.left = cmd; + eq_3.right = 2'd2; + } + comb group eq_4_group { + eq_4.left = next_write.out; + eq_4.right = 32'd10; + } + comb group eq_5_group { + eq_5.left = next_read.out; + eq_5.right = 32'd10; + } + comb group eq_6_group { + eq_6.left = len.out; + eq_6.right = 32'd0; + } + comb group eq_7_group { + eq_7.left = len.out; + eq_7.right = 32'd10; + } + group next_write_incr_group { + next_write_incr.left = next_write.out; + next_write_incr.right = 32'd1; + next_write.write_en = 1'd1; + next_write.in = next_write_incr.out; + next_write_incr_group[done] = next_write.done; + } + group next_read_incr_group { + next_read_incr.left = next_read.out; + next_read_incr.right = 32'd1; + next_read.write_en = 1'd1; + next_read.in = next_read_incr.out; + next_read_incr_group[done] = next_read.done; + } + group len_incr_group { + len_incr.left = len.out; + len_incr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_incr.out; + len_incr_group[done] = len.done; + } + group len_decr_group { + len_decr.left = len.out; + len_decr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_decr.out; + len_decr_group[done] = len.done; + } + group flash_write { + next_write.in = 32'd0; + next_write.write_en = 1'd1; + flash_write[done] = next_write.done; + } + group flash_read { + next_read.in = 32'd0; + next_read.write_en = 1'd1; + flash_read[done] = next_read.done; + } + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + group flash_ans { + ans.in = 32'd0; + ans.write_en = 1'd1; + flash_ans[done] = ans.done; + } + group write_payload_to_mem { + mem.addr0 = next_write.out; + mem.write_en = 1'd1; + mem.write_data = value; + write_payload_to_mem[done] = mem.write_done; + } + group read_payload_from_mem_phase1 { + mem.addr0 = next_read.out; + mem.read_en = 1'd1; + read_payload_from_mem_phase1[done] = mem.read_done; + } + group read_payload_from_mem_phase2 { + ans.write_en = 1'd1; + ans.in = mem.read_data; + read_payload_from_mem_phase2[done] = ans.done; + } + } + control { + seq { + par { + if eq_1.out with eq_1_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + next_read_incr_group; + if eq_5.out with eq_5_group { + flash_read; + } + len_decr_group; + } + } + } + if eq_2.out with eq_2_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + } + } + } + if eq_3.out with eq_3_group { + if eq_7.out with eq_7_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + write_payload_to_mem; + next_write_incr_group; + if eq_4.out with eq_4_group { + flash_write; + } + len_incr_group; + } + } + } + } + } + } +} +component fifo_tangerine(cmd: 2, value: 32) -> () { + cells { + mem = seq_mem_d1(32, 10, 32); + next_write = std_reg(32); + next_read = std_reg(32); + ref ans = std_reg(32); + ref err = std_reg(1); + len = std_reg(32); + eq_1 = std_eq(2); + eq_2 = std_eq(2); + eq_3 = std_eq(2); + eq_4 = std_eq(32); + eq_5 = std_eq(32); + eq_6 = std_eq(32); + eq_7 = std_eq(32); + next_write_incr = std_add(32); + next_read_incr = std_add(32); + len_incr = std_add(32); + len_decr = std_sub(32); + } + wires { + comb group eq_1_group { + eq_1.left = cmd; + eq_1.right = 2'd0; + } + comb group eq_2_group { + eq_2.left = cmd; + eq_2.right = 2'd1; + } + comb group eq_3_group { + eq_3.left = cmd; + eq_3.right = 2'd2; + } + comb group eq_4_group { + eq_4.left = next_write.out; + eq_4.right = 32'd10; + } + comb group eq_5_group { + eq_5.left = next_read.out; + eq_5.right = 32'd10; + } + comb group eq_6_group { + eq_6.left = len.out; + eq_6.right = 32'd0; + } + comb group eq_7_group { + eq_7.left = len.out; + eq_7.right = 32'd10; + } + group next_write_incr_group { + next_write_incr.left = next_write.out; + next_write_incr.right = 32'd1; + next_write.write_en = 1'd1; + next_write.in = next_write_incr.out; + next_write_incr_group[done] = next_write.done; + } + group next_read_incr_group { + next_read_incr.left = next_read.out; + next_read_incr.right = 32'd1; + next_read.write_en = 1'd1; + next_read.in = next_read_incr.out; + next_read_incr_group[done] = next_read.done; + } + group len_incr_group { + len_incr.left = len.out; + len_incr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_incr.out; + len_incr_group[done] = len.done; + } + group len_decr_group { + len_decr.left = len.out; + len_decr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_decr.out; + len_decr_group[done] = len.done; + } + group flash_write { + next_write.in = 32'd0; + next_write.write_en = 1'd1; + flash_write[done] = next_write.done; + } + group flash_read { + next_read.in = 32'd0; + next_read.write_en = 1'd1; + flash_read[done] = next_read.done; + } + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + group flash_ans { + ans.in = 32'd0; + ans.write_en = 1'd1; + flash_ans[done] = ans.done; + } + group write_payload_to_mem { + mem.addr0 = next_write.out; + mem.write_en = 1'd1; + mem.write_data = value; + write_payload_to_mem[done] = mem.write_done; + } + group read_payload_from_mem_phase1 { + mem.addr0 = next_read.out; + mem.read_en = 1'd1; + read_payload_from_mem_phase1[done] = mem.read_done; + } + group read_payload_from_mem_phase2 { + ans.write_en = 1'd1; + ans.in = mem.read_data; + read_payload_from_mem_phase2[done] = ans.done; + } + } + control { + seq { + par { + if eq_1.out with eq_1_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + next_read_incr_group; + if eq_5.out with eq_5_group { + flash_read; + } + len_decr_group; + } + } + } + if eq_2.out with eq_2_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + } + } + } + if eq_3.out with eq_3_group { + if eq_7.out with eq_7_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + write_payload_to_mem; + next_write_incr_group; + if eq_4.out with eq_4_group { + flash_write; + } + len_incr_group; + } + } + } + } + } + } +} +component pifo_red(cmd: 2, value: 32) -> () { + cells { + queue_l = fifo_purple(); + queue_r = fifo_tangerine(); + flow = std_reg(1); + lt_1 = std_lt(32); + ref ans = std_reg(32); + ref err = std_reg(1); + len = std_reg(32); + hot = std_reg(1); + eq_2 = std_eq(1); + eq_3 = std_eq(1); + eq_4 = std_eq(1); + eq_5 = std_eq(1); + eq_6 = std_eq(32); + eq_7 = std_eq(32); + eq_8 = std_eq(2); + eq_9 = std_eq(2); + eq_10 = std_eq(2); + eq_11 = std_eq(1); + neq_12 = std_neq(1); + hot_not = std_not(1); + len_incr = std_add(32); + len_decr = std_sub(32); + } + wires { + group infer_flow { + lt_1.left = 32'd100; + lt_1.right = value; + flow.write_en = 1'd1; + flow.in = lt_1.out; + infer_flow[done] = flow.done; + } + comb group eq_2_group { + eq_2.left = hot.out; + eq_2.right = 1'd0; + } + comb group eq_3_group { + eq_3.left = hot.out; + eq_3.right = 1'd1; + } + comb group eq_4_group { + eq_4.left = flow.out; + eq_4.right = 1'd0; + } + comb group eq_5_group { + eq_5.left = flow.out; + eq_5.right = 1'd1; + } + comb group eq_6_group { + eq_6.left = len.out; + eq_6.right = 32'd0; + } + comb group eq_7_group { + eq_7.left = len.out; + eq_7.right = 32'd10; + } + comb group eq_8_group { + eq_8.left = cmd; + eq_8.right = 2'd0; + } + comb group eq_9_group { + eq_9.left = cmd; + eq_9.right = 2'd1; + } + comb group eq_10_group { + eq_10.left = cmd; + eq_10.right = 2'd2; + } + comb group eq_11_group { + eq_11.left = err.out; + eq_11.right = 1'd0; + } + comb group neq_12_group { + neq_12.left = err.out; + neq_12.right = 1'd0; + } + group hot_not_group { + hot_not.in = hot.out; + hot.write_en = 1'd1; + hot.in = hot_not.out; + hot_not_group[done] = hot.done; + } + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + group lower_err { + err.in = 1'd0; + err.write_en = 1'd1; + lower_err[done] = err.done; + } + group flash_ans { + ans.in = 32'd0; + ans.write_en = 1'd1; + flash_ans[done] = ans.done; + } + group len_incr_group { + len_incr.left = len.out; + len_incr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_incr.out; + len_incr_group[done] = len.done; + } + group len_decr_group { + len_decr.left = len.out; + len_decr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_decr.out; + len_decr_group[done] = len.done; + } + } + control { + seq { + par { + if eq_8.out with eq_8_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + par { + if eq_2.out with eq_2_group { + seq { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + par { + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + hot_not_group; + } + } + } + } + } + if eq_3.out with eq_3_group { + seq { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + par { + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + hot_not_group; + } + } + } + } + } + } + len_decr_group; + } + } + } + if eq_9.out with eq_9_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + par { + if eq_2.out with eq_2_group { + seq { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + } + } + if eq_3.out with eq_3_group { + seq { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + } + } + } + } + } + } + if eq_10.out with eq_10_group { + if eq_7.out with eq_7_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + infer_flow; + par { + if eq_4.out with eq_4_group { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + if eq_5.out with eq_5_group { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + len_incr_group; + } + } + } + } + } + } + } + } +} +component fifo_blue(cmd: 2, value: 32) -> () { + cells { + mem = seq_mem_d1(32, 10, 32); + next_write = std_reg(32); + next_read = std_reg(32); + ref ans = std_reg(32); + ref err = std_reg(1); + len = std_reg(32); + eq_1 = std_eq(2); + eq_2 = std_eq(2); + eq_3 = std_eq(2); + eq_4 = std_eq(32); + eq_5 = std_eq(32); + eq_6 = std_eq(32); + eq_7 = std_eq(32); + next_write_incr = std_add(32); + next_read_incr = std_add(32); + len_incr = std_add(32); + len_decr = std_sub(32); + } + wires { + comb group eq_1_group { + eq_1.left = cmd; + eq_1.right = 2'd0; + } + comb group eq_2_group { + eq_2.left = cmd; + eq_2.right = 2'd1; + } + comb group eq_3_group { + eq_3.left = cmd; + eq_3.right = 2'd2; + } + comb group eq_4_group { + eq_4.left = next_write.out; + eq_4.right = 32'd10; + } + comb group eq_5_group { + eq_5.left = next_read.out; + eq_5.right = 32'd10; + } + comb group eq_6_group { + eq_6.left = len.out; + eq_6.right = 32'd0; + } + comb group eq_7_group { + eq_7.left = len.out; + eq_7.right = 32'd10; + } + group next_write_incr_group { + next_write_incr.left = next_write.out; + next_write_incr.right = 32'd1; + next_write.write_en = 1'd1; + next_write.in = next_write_incr.out; + next_write_incr_group[done] = next_write.done; + } + group next_read_incr_group { + next_read_incr.left = next_read.out; + next_read_incr.right = 32'd1; + next_read.write_en = 1'd1; + next_read.in = next_read_incr.out; + next_read_incr_group[done] = next_read.done; + } + group len_incr_group { + len_incr.left = len.out; + len_incr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_incr.out; + len_incr_group[done] = len.done; + } + group len_decr_group { + len_decr.left = len.out; + len_decr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_decr.out; + len_decr_group[done] = len.done; + } + group flash_write { + next_write.in = 32'd0; + next_write.write_en = 1'd1; + flash_write[done] = next_write.done; + } + group flash_read { + next_read.in = 32'd0; + next_read.write_en = 1'd1; + flash_read[done] = next_read.done; + } + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + group flash_ans { + ans.in = 32'd0; + ans.write_en = 1'd1; + flash_ans[done] = ans.done; + } + group write_payload_to_mem { + mem.addr0 = next_write.out; + mem.write_en = 1'd1; + mem.write_data = value; + write_payload_to_mem[done] = mem.write_done; + } + group read_payload_from_mem_phase1 { + mem.addr0 = next_read.out; + mem.read_en = 1'd1; + read_payload_from_mem_phase1[done] = mem.read_done; + } + group read_payload_from_mem_phase2 { + ans.write_en = 1'd1; + ans.in = mem.read_data; + read_payload_from_mem_phase2[done] = ans.done; + } + } + control { + seq { + par { + if eq_1.out with eq_1_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + next_read_incr_group; + if eq_5.out with eq_5_group { + flash_read; + } + len_decr_group; + } + } + } + if eq_2.out with eq_2_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + read_payload_from_mem_phase1; + read_payload_from_mem_phase2; + } + } + } + if eq_3.out with eq_3_group { + if eq_7.out with eq_7_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + write_payload_to_mem; + next_write_incr_group; + if eq_4.out with eq_4_group { + flash_write; + } + len_incr_group; + } + } + } + } + } + } +} +component pifo_root(cmd: 2, value: 32) -> () { + cells { + queue_l = pifo_red(); + queue_r = fifo_blue(); + ref stats = stats(); + flow = std_reg(1); + lt_1 = std_lt(32); + ref ans = std_reg(32); + ref err = std_reg(1); + len = std_reg(32); + hot = std_reg(1); + eq_2 = std_eq(1); + eq_3 = std_eq(1); + eq_4 = std_eq(1); + eq_5 = std_eq(1); + eq_6 = std_eq(32); + eq_7 = std_eq(32); + eq_8 = std_eq(2); + eq_9 = std_eq(2); + eq_10 = std_eq(2); + eq_11 = std_eq(1); + neq_12 = std_neq(1); + hot_not = std_not(1); + len_incr = std_add(32); + len_decr = std_sub(32); + } + wires { + group infer_flow { + lt_1.left = 32'd200; + lt_1.right = value; + flow.write_en = 1'd1; + flow.in = lt_1.out; + infer_flow[done] = flow.done; + } + comb group eq_2_group { + eq_2.left = hot.out; + eq_2.right = 1'd0; + } + comb group eq_3_group { + eq_3.left = hot.out; + eq_3.right = 1'd1; + } + comb group eq_4_group { + eq_4.left = flow.out; + eq_4.right = 1'd0; + } + comb group eq_5_group { + eq_5.left = flow.out; + eq_5.right = 1'd1; + } + comb group eq_6_group { + eq_6.left = len.out; + eq_6.right = 32'd0; + } + comb group eq_7_group { + eq_7.left = len.out; + eq_7.right = 32'd10; + } + comb group eq_8_group { + eq_8.left = cmd; + eq_8.right = 2'd0; + } + comb group eq_9_group { + eq_9.left = cmd; + eq_9.right = 2'd1; + } + comb group eq_10_group { + eq_10.left = cmd; + eq_10.right = 2'd2; + } + comb group eq_11_group { + eq_11.left = err.out; + eq_11.right = 1'd0; + } + comb group neq_12_group { + neq_12.left = err.out; + neq_12.right = 1'd0; + } + group hot_not_group { + hot_not.in = hot.out; + hot.write_en = 1'd1; + hot.in = hot_not.out; + hot_not_group[done] = hot.done; + } + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + group lower_err { + err.in = 1'd0; + err.write_en = 1'd1; + lower_err[done] = err.done; + } + group flash_ans { + ans.in = 32'd0; + ans.write_en = 1'd1; + flash_ans[done] = ans.done; + } + group len_incr_group { + len_incr.left = len.out; + len_incr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_incr.out; + len_incr_group[done] = len.done; + } + group len_decr_group { + len_decr.left = len.out; + len_decr.right = 32'd1; + len.write_en = 1'd1; + len.in = len_decr.out; + len_decr_group[done] = len.done; + } + } + control { + seq { + par { + if eq_8.out with eq_8_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + par { + if eq_2.out with eq_2_group { + seq { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + par { + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + hot_not_group; + } + } + } + } + } + if eq_3.out with eq_3_group { + seq { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + par { + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + hot_not_group; + } + } + } + } + } + } + len_decr_group; + } + } + } + if eq_9.out with eq_9_group { + if eq_6.out with eq_6_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + par { + if eq_2.out with eq_2_group { + seq { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + } + } + if eq_3.out with eq_3_group { + seq { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + if neq_12.out with neq_12_group { + seq { + lower_err; + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + } + } + } + } + } + } + if eq_10.out with eq_10_group { + if eq_7.out with eq_7_group { + seq { + raise_err; + flash_ans; + } + } else { + seq { + lower_err; + infer_flow; + par { + if eq_4.out with eq_4_group { + invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); + } + if eq_5.out with eq_5_group { + invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); + } + } + if eq_11.out with eq_11_group { + seq { + len_incr_group; + invoke stats(flow=flow.out)(); + } + } + } + } + } + } + } + } +} +component dataplane() -> () { + cells { + ref stats_runner = stats(); + myqueue = pifo_root(); + ref commands = seq_mem_d1(2, 15, 32); + ref values = seq_mem_d1(32, 15, 32); + ref has_ans = std_reg(1); + ref component_ans = std_reg(32); + ref component_err = std_reg(1); + i = std_reg(32); + command = std_reg(2); + value = std_reg(32); + i_incr = std_add(32); + le_1 = std_le(2); + not_2 = std_not(1); + i_eq_MAX_CMDS = std_eq(32); + } + wires { + group i_incr_group { + i_incr.left = i.out; + i_incr.right = 32'd1; + i.write_en = 1'd1; + i.in = i_incr.out; + i_incr_group[done] = i.done; + } + comb group le_1_group { + le_1.left = command.out; + le_1.right = 2'd1; + } + group read_cmd_phase1 { + commands.addr0 = i.out; + commands.read_en = 1'd1; + read_cmd_phase1[done] = commands.read_done; + } + group write_cmd_phase2 { + command.write_en = 1'd1; + command.in = commands.read_data; + write_cmd_phase2[done] = command.done; + } + group read_value { + values.addr0 = i.out; + values.read_en = 1'd1; + read_value[done] = values.read_done; + } + group write_value_to_reg { + value.write_en = 1'd1; + value.in = values.read_data; + write_value_to_reg[done] = value.done; + } + group raise_has_ans { + has_ans.in = 1'd1; + has_ans.write_en = 1'd1; + raise_has_ans[done] = has_ans.done; + } + group lower_has_ans { + has_ans.in = 1'd0; + has_ans.write_en = 1'd1; + lower_has_ans[done] = has_ans.done; + } + comb group not_2_group { + not_2.in = component_err.out; + } + group i_eq_MAX_CMDS_group { + i_eq_MAX_CMDS.left = i.out; + i_eq_MAX_CMDS.right = 32'd15; + component_err.write_en = 1'd1; + component_err.in = i_eq_MAX_CMDS.out; + i_eq_MAX_CMDS_group[done] = component_err.done; + } + } + control { + seq { + read_cmd_phase1; + write_cmd_phase2; + read_value; + write_value_to_reg; + invoke myqueue[ans=component_ans, err=component_err, stats=stats_runner](cmd=command.out, value=value.out)(); + if not_2.out with not_2_group { + seq { + if le_1.out with le_1_group { + seq { + raise_has_ans; + } + } else { + seq { + lower_has_ans; + } + } + i_incr_group; + i_eq_MAX_CMDS_group; + } + } + } + } +} +component controller() -> () { + cells { + ref stats_controller = stats(); + count_0 = std_reg(32); + count_1 = std_reg(32); + } + wires { + group get_data_locally { + count_0.in = stats_controller.count_0; + count_0.write_en = 1'd1; + count_1.in = stats_controller.count_1; + count_1.write_en = 1'd1; + get_data_locally[done] = count_0.done & count_1.done ? 1'd1; + } + } + control { + seq { + get_data_locally; + } + } +} +component main() -> () { + cells { + stats_main = stats(); + dataplane = dataplane(); + controller = controller(); + has_ans = std_reg(1); + dataplane_ans = std_reg(32); + dataplane_err = std_reg(1); + @external commands = seq_mem_d1(2, 15, 32); + @external values = seq_mem_d1(32, 15, 32); + @external ans_mem = seq_mem_d1(32, 10, 32); + j = std_reg(32); + j_incr = std_add(32); + eq_1 = std_eq(1); + } + wires { + group j_incr_group { + j_incr.left = j.out; + j_incr.right = 32'd1; + j.write_en = 1'd1; + j.in = j_incr.out; + j_incr_group[done] = j.done; + } + group write_ans { + ans_mem.addr0 = j.out; + ans_mem.write_en = 1'd1; + ans_mem.write_data = dataplane_ans.out; + write_ans[done] = ans_mem.write_done; + } + comb group eq_1_group { + eq_1.left = dataplane_err.out; + eq_1.right = 1'd0; + } + } + control { + seq { + while eq_1.out with eq_1_group { + seq { + invoke dataplane[commands=commands, values=values, has_ans=has_ans, component_ans=dataplane_ans, component_err=dataplane_err, stats_runner=stats_main]()(); + if has_ans.out { + seq { + write_ans; + j_incr_group; + } + } + invoke controller[stats_controller=stats_main]()(); + } + } + } + } +} diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index 5f72a3db8..7d0d68fb2 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -1,6 +1,11 @@ { "commands": { "data": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -15,7 +20,87 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "format": { "is_signed": false, @@ -25,21 +110,106 @@ }, "values": { "data": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ], "format": { "is_signed": false, @@ -49,6 +219,96 @@ }, "ans_mem": { "data": [ + 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, + 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, diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index e29484e3f..342f59873 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -1,17 +1,112 @@ { "ans_mem": [ - 190, - 190, - 190, - 278, - 278, - 126, - 293, - 52, + 4, + 4, + 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, + 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 ], "commands": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -26,23 +121,188 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "values": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ] } diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data index 5f72a3db8..7d0d68fb2 100644 --- a/calyx-py/test/correctness/pifo_tree.data +++ b/calyx-py/test/correctness/pifo_tree.data @@ -1,6 +1,11 @@ { "commands": { "data": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -15,7 +20,87 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "format": { "is_signed": false, @@ -25,21 +110,106 @@ }, "values": { "data": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ], "format": { "is_signed": false, @@ -49,6 +219,96 @@ }, "ans_mem": { "data": [ + 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, + 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, diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect index c0040e323..342f59873 100644 --- a/calyx-py/test/correctness/pifo_tree.expect +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -1,17 +1,112 @@ { "ans_mem": [ - 190, - 190, - 52, - 278, - 278, - 190, - 293, - 126, + 4, + 4, + 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, + 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 ], "commands": [ + 2, + 2, + 2, + 2, + 2, 2, 1, 2, @@ -26,23 +121,188 @@ 2, 0, 0, - 0 + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1 ], "values": [ - 190, - 240, - 126, - 194, - 278, - 52, - 293, - 127, - 6, + 296, + 4, + 231, + 23, + 362, + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, 374, - 110, - 208, - 143, - 93, - 392 + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140 ] } From 52ec28cb508df7fc042f5f0274e1355a32d39c92 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 17:35:05 -0500 Subject: [PATCH 096/189] Queues: option for no errors (#1779) --- calyx-py/calyx/builder.py | 19 ++++ calyx-py/calyx/fifo_oracle.py | 4 +- calyx-py/calyx/pifo_oracle.py | 4 +- calyx-py/calyx/pifotree_oracle.py | 4 +- calyx-py/calyx/queue_call.py | 40 ++----- calyx-py/calyx/queue_data_gen.py | 8 +- calyx-py/calyx/queues.py | 102 +++++++++++------ calyx-py/test/correctness/fifo.data | 24 ++-- calyx-py/test/correctness/fifo.expect | 122 ++++++++++----------- calyx-py/test/correctness/pifo.data | 24 ++-- calyx-py/test/correctness/pifo.expect | 122 ++++++++++----------- calyx-py/test/correctness/pifo_tree.data | 24 ++-- calyx-py/test/correctness/pifo_tree.expect | 122 ++++++++++----------- 13 files changed, 324 insertions(+), 295 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 86a2d5985..249d5e2c4 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -418,6 +418,20 @@ def fp_sop( ast.Stdlib.fixed_point_op(op_name, width, int_width, frac_width, True), ) + def unary_use(self, input, cell, groupname=None): + """Accepts a cell that performs some computation on value `input`. + Creates a combinational group that wires up the cell with this port. + Returns the cell and the combintational group. + comb group `groupname` { + `cell.name`.in = `input`; + } + Returns handles to the cell and the combinational group. + """ + groupname = groupname or f"{cell.name}_group" + with self.comb_group(groupname) as comb_group: + cell.in_ = input + return CellAndGroup(cell, comb_group) + def binary_use(self, left, right, cell, groupname=None): """Accepts a cell that performs some computation on values `left` and `right`. Creates a combinational group that wires up the cell with these ports. @@ -488,6 +502,11 @@ def sub_use(self, left, right, signed=False, cellname=None, width=None): width = self.try_infer_width(width, left, right) return self.binary_use(left, right, self.sub(width, cellname, signed)) + def not_use(self, input, cellname=None, width=None): + """Inserts wiring into `self` to compute `not input`.""" + width = self.try_infer_width(width, input, input) + return self.unary_use(input, self.not_(width, cellname)) + def bitwise_flip_reg(self, reg, cellname=None): """Inserts wiring into `self` to bitwise-flip the contents of `reg` and put the result back into `reg`. diff --git a/calyx-py/calyx/fifo_oracle.py b/calyx-py/calyx/fifo_oracle.py index 68f990580..fd943b4a1 100644 --- a/calyx-py/calyx/fifo_oracle.py +++ b/calyx-py/calyx/fifo_oracle.py @@ -1,8 +1,8 @@ import calyx.queues as queues -import calyx.queue_util as queue_util +from calyx import queue_util if __name__ == "__main__": commands, values = queue_util.parse_json() - fifo = queues.Fifo([]) + fifo = queues.Fifo([], False) ans = queues.operate_queue(commands, values, fifo) queue_util.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/pifo_oracle.py b/calyx-py/calyx/pifo_oracle.py index f454a7540..9786ffc69 100644 --- a/calyx-py/calyx/pifo_oracle.py +++ b/calyx-py/calyx/pifo_oracle.py @@ -1,11 +1,11 @@ import calyx.queues as queues -import calyx.queue_util as queue_util +from calyx import queue_util if __name__ == "__main__": commands, values = queue_util.parse_json() # Our PIFO is simple: it just orchestrates two FIFOs. The boundary is 200. - pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200) + pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200, False) ans = queues.operate_queue(commands, values, pifo) queue_util.dump_json(commands, values, ans) diff --git a/calyx-py/calyx/pifotree_oracle.py b/calyx-py/calyx/pifotree_oracle.py index 9ca1f2c35..6969f1be5 100644 --- a/calyx-py/calyx/pifotree_oracle.py +++ b/calyx-py/calyx/pifotree_oracle.py @@ -1,5 +1,5 @@ import calyx.queues as queues -import calyx.queue_util as queue_util +from calyx import queue_util if __name__ == "__main__": @@ -16,7 +16,7 @@ # - The boundary for this is 200. pifo = queues.Pifo( - queues.Pifo(queues.Fifo([]), queues.Fifo([]), 100), queues.Fifo([]), 200 + queues.Pifo(queues.Fifo([]), queues.Fifo([]), 100), queues.Fifo([]), 200, False ) ans = queues.operate_queue(commands, values, pifo) diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index e66b50fc7..8b85bf395 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -1,5 +1,5 @@ # pylint: disable=import-error -import calyx.queue_util as queue_util +from calyx import queue_util import calyx.builder as cb @@ -55,6 +55,8 @@ def insert_main(prog, queue): incr_i = main.incr(i) # i++ incr_j = main.incr(j) # j++ + lower_err = main.reg_store(err, 0, "lower_err") # err := 1 + cmd_le_1 = main.le_use(cmd.out, 1) # cmd <= 1 read_cmd = main.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") @@ -66,30 +68,12 @@ def insert_main(prog, queue): ) write_ans = main.mem_store_seq_d1(ans_mem, j.out, ans.out, "write_ans") - loop_goes_on = main.reg( - "loop_goes_on", 1 - ) # A flag to indicate whether the loop should continue - update_err_is_down, _ = main.eq_store_in_reg( - err.out, - 0, - "err_is_down", - 1, - loop_goes_on - # Does the `err` flag say that the loop should continue? - ) - update_i_neq_max_cmds, _ = main.neq_store_in_reg( - i.out, - cb.const(32, queue_util.MAX_CMDS), - "i_neq_max_cmds", - 32, - loop_goes_on - # Does the `i` index say that the loop should continue? - ) + i_lt_max_cmds = main.lt_use(i.out, queue_util.MAX_CMDS) + not_err = main.not_use(err.out) main.control += [ - update_err_is_down, - cb.while_( - loop_goes_on.out, # Run while the `err` flag is down + cb.while_with( + i_lt_max_cmds, # Run while i < MAX_CMDS [ read_cmd, write_cmd_to_reg, # `cmd := commands[i]` @@ -102,9 +86,8 @@ def insert_main(prog, queue): ref_ans=ans, ref_err=err, ), - update_err_is_down, # Does `err` say that the loop should be broken? - cb.if_( - loop_goes_on.out, # If the loop is not meant to be broken... + cb.if_with( + not_err, [ cb.if_with( cmd_le_1, # If the command was a pop or peek, @@ -113,11 +96,10 @@ def insert_main(prog, queue): incr_j, # And increment the answer index. ], ), - incr_i, # Increment the command index - update_i_neq_max_cmds, - # Did this increment make us need to break? ], ), + lower_err, # Lower the error flag + incr_i, # Increment the command index ], ), ] diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index 327f2d86d..d6fa9227c 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -1,7 +1,7 @@ import random import json from typing import Dict, Union -import calyx.queue_util as queue_util +from calyx import queue_util FormatType = Dict[str, Union[bool, str, int]] @@ -23,11 +23,7 @@ def dump_json(): """ commands = { "commands": { - # We'll "rig" these random values a little. - # The first 5% of the commands will be 2 (push). - # The rest will be generated randomly from among 0, 1, and 2. - "data": [2] * (queue_util.MAX_CMDS // 20) - + [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS * 19 // 20)], + "data": [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS)], "format": format_gen(2), } } diff --git a/calyx-py/calyx/queues.py b/calyx-py/calyx/queues.py index 77f2982ef..8d4f156bd 100644 --- a/calyx-py/calyx/queues.py +++ b/calyx-py/calyx/queues.py @@ -1,37 +1,52 @@ from dataclasses import dataclass from typing import List -import calyx.queue_util as queue_util +from typing import Optional +from calyx import queue_util + + +class QueueError(Exception): + """An error that occurs when we try to pop/peek from an empty queue,""" @dataclass class Fifo: """A FIFO data structure. Supports the operations `push`, `pop`, and `peek`. - Inherent to the queue is its `max_len`, which is given to us at initialization - and we cannot exceed. + Inherent to the queue is its `max_len`, + which is given at initialization and cannot be exceeded. + + If initialized with "error mode" turned on, the queue raises errors in case + of underflow or overflow and stops the simulation. + Otherwise, it allows those commands to fail silently but continues the simulation. """ - def __init__(self, data: List[int], max_len: int = None): + def __init__(self, data: List[int], error_mode=True, max_len: int = None): self.data = data self.max_len = max_len or queue_util.QUEUE_SIZE + self.error_mode = error_mode - def push(self, val: int): + def push(self, val: int) -> None: """Pushes `val` to the FIFO.""" - if len(self.data) < self.max_len: - self.data.append(val) - else: - raise IndexError("Cannot push to full FIFO.") + if len(self.data) == self.max_len: + if self.error_mode: + raise QueueError("Cannot push to full FIFO.") + return + self.data.append(val) - def pop(self) -> int: + def pop(self) -> Optional[int]: """Pops the FIFO.""" if len(self.data) == 0: - raise IndexError("Cannot pop from empty FIFO.") + if self.error_mode: + raise QueueError("Cannot pop from empty FIFO.") + return None return self.data.pop(0) - def peek(self) -> int: + def peek(self) -> Optional[int]: """Peeks into the FIFO.""" if len(self.data) == 0: - raise IndexError("Cannot peek into empty FIFO.") + if self.error_mode: + raise QueueError("Cannot peek into empty FIFO.") + return None return self.data[0] def __len__(self) -> int: @@ -43,9 +58,10 @@ class Pifo: """A PIFO data structure. Supports the operations `push`, `pop`, and `peek`. - We do this by maintaining two queues that are given to us at initialization. - We toggle between these queues when popping/peeking. - We have a variable called `hot` that says which queue is to be popped/peeked next. + We do this by maintaining two sub-queues that are given to us at initialization. + We toggle between these sub-queues when popping/peeking. + We have a variable called `hot` that says which sub-queue is to be + popped/peeked next. `hot` starts at 0. We also take at initialization a `boundary` value. @@ -55,9 +71,12 @@ class Pifo: Inherent to the queue is its `max_len`, which is given to us at initialization and we cannot exceed. + If initialized with "error mode" turned on, the queue raises errors in case + of underflow or overflow and stops the simulation. + Otherwise, it allows those commands to fail silently but continues the simulation. When asked to pop: - - If `pifo_len` is 0, we raise an error. + - If `pifo_len` is 0, we fail silently or raise an error. - Else, if `hot` is 0, we try to pop from queue_0. + If it succeeds, we flip `hot` to 1 and return the value we got. + If it fails, we pop from queue_1 and return the value we got. @@ -67,22 +86,23 @@ class Pifo: When asked to peek: We do the same thing as above, except: - - We peek instead of popping. + - We peek into the sub-queue instead of popping it. - We don't flip `hot`. When asked to push: - - If the PIFO is at length `max_len`, we raise an error. + - If the PIFO is at length `max_len`, we fail silently or raise an error. - If the value to be pushed is less than `boundary`, we push it into queue_1. - Else, we push it into queue_2. - We increment `pifo_len` by 1. """ - def __init__(self, queue_1, queue_2, boundary, max_len=None): + def __init__(self, queue_1, queue_2, boundary, error_mode=True, max_len=None): self.data = (queue_1, queue_2) self.hot = 0 self.pifo_len = len(queue_1) + len(queue_2) self.boundary = boundary self.max_len = max_len or queue_util.QUEUE_SIZE + self.error_mode = error_mode assert ( self.pifo_len <= self.max_len ) # We can't be initialized with a PIFO that is too long. @@ -90,44 +110,52 @@ def __init__(self, queue_1, queue_2, boundary, max_len=None): def push(self, val: int): """Pushes `val` to the PIFO.""" if self.pifo_len == self.max_len: - raise IndexError("Cannot push to full PIFO.") - if val < self.boundary: + if self.error_mode: + raise QueueError("Cannot push to full PIFO.") + return + if val <= self.boundary: self.data[0].push(val) else: self.data[1].push(val) self.pifo_len += 1 - def pop(self) -> int: + def pop(self) -> Optional[int]: """Pops the PIFO.""" if self.pifo_len == 0: - raise IndexError("Cannot pop from empty PIFO.") + if self.error_mode: + raise QueueError("Cannot pop from empty PIFO.") + return None self.pifo_len -= 1 # We decrement `pifo_len` by 1. if self.hot == 0: try: self.hot = 1 return self.data[0].pop() - except IndexError: + except QueueError: + self.hot = 0 return self.data[1].pop() else: try: self.hot = 0 return self.data[1].pop() - except IndexError: + except QueueError: + self.hot = 1 return self.data[0].pop() - def peek(self) -> int: + def peek(self) -> Optional[int]: """Peeks into the PIFO.""" if self.pifo_len == 0: - raise IndexError("Cannot peek into empty PIFO.") + if self.error_mode: + raise QueueError("Cannot peek into empty PIFO.") + return None if self.hot == 0: try: return self.data[0].peek() - except IndexError: + except QueueError: return self.data[1].peek() else: try: return self.data[1].peek() - except IndexError: + except QueueError: return self.data[0].peek() def __len__(self) -> int: @@ -143,20 +171,24 @@ def operate_queue(commands, values, queue): for cmd, val in zip(commands, values): if cmd == 0: try: - ans.append(queue.pop()) - except IndexError: + result = queue.pop() + if result: + ans.append(result) + except QueueError: break elif cmd == 1: try: - ans.append(queue.peek()) - except IndexError: + result = queue.peek() + if result: + ans.append(queue.peek()) + except QueueError: break elif cmd == 2: try: queue.push(val) - except IndexError: + except QueueError: break # Pad the answer memory with zeroes until it is of length MAX_CMDS. diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 7d0d68fb2..485b42724 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -1,11 +1,6 @@ { "commands": { "data": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -100,7 +95,12 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "format": { "is_signed": false, @@ -110,11 +110,6 @@ }, "values": { "data": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -209,7 +204,12 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index 63c85e68a..b3523a34e 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,54 +1,54 @@ { "ans_mem": [ - 296, - 296, - 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, + 92, + 92, + 92, + 100, + 100, + 386, + 125, + 236, + 176, + 176, + 176, + 128, + 128, + 151, + 221, + 174, + 47, + 47, + 159, + 368, + 24, + 41, + 207, + 207, + 207, + 16, + 252, + 252, + 106, + 106, + 106, + 106, + 106, + 106, + 66, + 66, + 66, + 374, + 222, + 222, + 150, + 150, + 150, + 267, + 267, + 267, + 267, + 373, + 373, 0, 0, 0, @@ -102,11 +102,6 @@ 0 ], "commands": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -201,14 +196,14 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "values": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -303,6 +298,11 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ] } diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index 7d0d68fb2..485b42724 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -1,11 +1,6 @@ { "commands": { "data": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -100,7 +95,12 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "format": { "is_signed": false, @@ -110,11 +110,6 @@ }, "values": { "data": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -209,7 +204,12 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index 342f59873..e13d98057 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -1,54 +1,54 @@ { "ans_mem": [ - 4, - 4, - 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, + 92, + 92, + 92, + 386, + 386, + 100, + 236, + 125, + 176, + 176, + 176, + 128, + 128, + 221, + 151, + 174, + 47, + 47, + 159, + 368, + 24, + 207, + 41, + 41, + 41, + 252, + 16, + 16, + 374, + 374, + 374, + 374, + 374, + 374, + 106, + 106, + 106, + 222, + 66, + 66, + 267, + 267, + 267, + 150, + 150, + 150, + 150, + 373, + 373, 0, 0, 0, @@ -102,11 +102,6 @@ 0 ], "commands": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -201,14 +196,14 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "values": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -303,6 +298,11 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ] } diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data index 7d0d68fb2..485b42724 100644 --- a/calyx-py/test/correctness/pifo_tree.data +++ b/calyx-py/test/correctness/pifo_tree.data @@ -1,11 +1,6 @@ { "commands": { "data": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -100,7 +95,12 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "format": { "is_signed": false, @@ -110,11 +110,6 @@ }, "values": { "data": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -209,7 +204,12 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect index 342f59873..876500088 100644 --- a/calyx-py/test/correctness/pifo_tree.expect +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -1,54 +1,54 @@ { "ans_mem": [ - 4, - 4, - 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, + 92, + 92, + 92, + 386, + 386, + 125, + 236, + 100, + 176, + 176, + 176, + 128, + 128, + 221, + 151, + 174, + 47, + 47, + 159, + 368, + 24, + 207, + 41, + 41, + 41, + 252, + 106, + 106, + 374, + 374, + 374, + 374, + 374, + 374, + 16, + 16, + 16, + 222, + 150, + 150, + 267, + 267, + 267, + 66, + 66, + 66, + 66, + 373, + 373, 0, 0, 0, @@ -102,11 +102,6 @@ 0 ], "commands": [ - 2, - 2, - 2, - 2, - 2, 2, 1, 2, @@ -201,14 +196,14 @@ 2, 1, 1, - 1 + 1, + 2, + 0, + 1, + 0, + 2 ], "values": [ - 296, - 4, - 231, - 23, - 362, 92, 319, 100, @@ -303,6 +298,11 @@ 373, 162, 245, - 140 + 140, + 149, + 240, + 206, + 75, + 57 ] } From 9e6eeddbf4ffc2634d8ec24cb2f15e8cc339cdb4 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:23:41 -0500 Subject: [PATCH 097/189] PIFO Trees: Telemetry (#1736) --- calyx-py/calyx/builder.py | 2 + calyx-py/calyx/queue_call.py | 125 +- calyx-py/test/correctness/piezo_pifotree.data | 329 +++++ .../test/correctness/piezo_pifotree.expect | 308 +++++ calyx-py/test/correctness/piezo_pifotree.py | 161 +++ calyx-py/test/correctness/piezo_pifotree.yx | 1197 ----------------- calyx-py/test/correctness/pifo.py | 33 +- 7 files changed, 943 insertions(+), 1212 deletions(-) create mode 100644 calyx-py/test/correctness/piezo_pifotree.data create mode 100644 calyx-py/test/correctness/piezo_pifotree.expect create mode 100644 calyx-py/test/correctness/piezo_pifotree.py delete mode 100644 calyx-py/test/correctness/piezo_pifotree.yx diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 249d5e2c4..c206c3b59 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -422,9 +422,11 @@ def unary_use(self, input, cell, groupname=None): """Accepts a cell that performs some computation on value `input`. Creates a combinational group that wires up the cell with this port. Returns the cell and the combintational group. + comb group `groupname` { `cell.name`.in = `input`; } + Returns handles to the cell and the combinational group. """ groupname = groupname or f"{cell.name}_group" diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index 8b85bf395..e10d6539a 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -6,6 +6,8 @@ def insert_main(prog, queue): """Inserts the component `main` into the program. This will be used to `invoke` the component `queue` and feed it a list of commands. + This component will directly interface with external memories and will + finally populate an external memory with the answers. """ main: cb.ComponentBuilder = prog.component("main") @@ -20,7 +22,7 @@ def insert_main(prog, queue): # the value at `i` is pushed if the command at `i` is `2`. # - output: a list of answers, reflecting any pops or peeks from the queue. # - # The user-facing interface of the `queue` component is: + # The user-facing interface of the `queue` component is assumed to be: # - input `cmd` # where each command is a 2-bit unsigned integer, with the following format: # `0`: pop @@ -35,12 +37,9 @@ def insert_main(prog, queue): values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) - # The two components we'll use: + # We'll invoke the queue component, which takes two inputs by reference + # and one input directly. queue = main.cell("myqueue", queue) - - # We will use the `invoke` method to call the `queue` component. - # The queue component takes two inputs by reference and one input directly. - # The two `ref` inputs: err = main.reg("err", 1) # A flag to indicate an error ans = main.reg("ans", 32) # A memory to hold the answer of a pop or peek @@ -103,3 +102,117 @@ def insert_main(prog, queue): ], ), ] + + return main + + +def insert_runner(prog, queue, name, stats_component): + """Inserts the component `name` into the program. + This will be used to `invoke` the component `queue` and feed it one command. + This component is designed to be invoked by some other component, and does not + directly interface with external memories. + """ + assert ( + name != "main" + ), "This method is not designed for the creation of `main`-style components." + + runner: cb.ComponentBuilder = prog.component(name) + + # We take a stats component by reference, + # but all we'll really do with it is pass it to the queue component. + stats = runner.cell("stats_runner", stats_component, is_ref=True) + + # We'll invoke the queue component. + queue = runner.cell("myqueue", queue) + + # The user-facing interface of this component is captured by a number + # of items that are passed to this component by reference. + # + # - 1: `commands`, a list of commands. + # Where each command is a 2-bit unsigned integer with the following format: + # `0`: pop + # `1`: peek + # `2`: push + # - 2: `values`, a list of values. + # Where each value is a 32-bit unsigned integer. + # The value at `i` is pushed if the command at `i` is `2`. + # - 3: `has_ans`, a 1-bit unsigned integer. + # We raise/lower this to indicate whether the queue had a reply to the command. + # - 4: `component_ans`, a 32-bit unsigned integer. + # We put in this register the answer to the command, if any. + # - 5: `component_err`, a 1-bit unsigned integer. + # We raise/lower it to indicates whether an error occurred + # and the queue should no longer be invoked. + # + # The user-facing interface of the `queue` component is assumed to be: + # - input `cmd` + # where each command is a 2-bit unsigned integer, with the following format: + # `0`: pop + # `1`: peek + # `2`: push + # - input `value` + # which is a 32-bit unsigned integer. If `cmd` is `2`, push this value. + # - ref register `ans`, into which the result of a pop or peek is written. + # - ref register `err`, which is raised if an error occurs. + + # Our memories and registers, all of which are passed to us by reference. + commands = runner.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_ref=True) + values = runner.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_ref=True) + has_ans = runner.reg("has_ans", 1, is_ref=True) + ans = runner.reg("component_ans", 32, is_ref=True) + err = runner.reg("component_err", 1, is_ref=True) + + i = runner.reg("i", 32) # The index of the command we're currently processing + cmd = runner.reg("command", 2) # The command we're currently processing + value = runner.reg("value", 32) # The value we're currently processing + + incr_i = runner.incr(i) # i++ + cmd_le_1 = runner.le_use(cmd.out, 1) # cmd <= 1, meaning cmd is pop or peek + + # Wiring to perform `cmd := commands[i]` and `value := values[i]`. + read_cmd = runner.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") + write_cmd_to_reg = runner.mem_write_seq_d1_to_reg(commands, cmd, "write_cmd_phase2") + read_value = runner.mem_read_seq_d1(values, i.out, "read_value") + write_value_to_reg = runner.mem_write_seq_d1_to_reg( + values, value, "write_value_to_reg" + ) + + # Wiring to raise/lower flags and compute a negation. + raise_has_ans = runner.reg_store(has_ans, 1, "raise_has_ans") + lower_has_ans = runner.reg_store(has_ans, 0, "lower_has_ans") + not_err = runner.not_use(err.out) + + # Wiring that raises `err` iff `i = MAX_CMDS`. + check_if_out_of_cmds, _ = runner.eq_store_in_reg( + i.out, cb.const(32, queue_util.MAX_CMDS), "i_eq_MAX_CMDS", 32, err + ) + + runner.control += [ + read_cmd, + write_cmd_to_reg, # `cmd := commands[i]` + read_value, + write_value_to_reg, # `value := values[i]` + cb.invoke( # Invoke the queue. + queue, + in_cmd=cmd.out, + in_value=value.out, + ref_ans=ans, + ref_err=err, + ref_stats=stats, + ), + # We're back from the invoke, and it's time for some post-mortem analysis. + cb.if_with( + not_err, # If there was no error + [ + cb.if_with( + cmd_le_1, # If the command was a pop or peek + [raise_has_ans], # then raise the `has_ans` flag + [lower_has_ans], # else lower the `has_ans` flag + ), + ], + ), + incr_i, # Increment the command index + check_if_out_of_cmds, # If we're out of commands, raise `err` + ] + + return runner diff --git a/calyx-py/test/correctness/piezo_pifotree.data b/calyx-py/test/correctness/piezo_pifotree.data new file mode 100644 index 000000000..485b42724 --- /dev/null +++ b/calyx-py/test/correctness/piezo_pifotree.data @@ -0,0 +1,329 @@ +{ + "commands": { + "data": [ + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { + "data": [ + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, + 374, + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140, + 149, + 240, + 206, + 75, + 57 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 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, + 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 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} diff --git a/calyx-py/test/correctness/piezo_pifotree.expect b/calyx-py/test/correctness/piezo_pifotree.expect new file mode 100644 index 000000000..876500088 --- /dev/null +++ b/calyx-py/test/correctness/piezo_pifotree.expect @@ -0,0 +1,308 @@ +{ + "ans_mem": [ + 92, + 92, + 92, + 386, + 386, + 125, + 236, + 100, + 176, + 176, + 176, + 128, + 128, + 221, + 151, + 174, + 47, + 47, + 159, + 368, + 24, + 207, + 41, + 41, + 41, + 252, + 106, + 106, + 374, + 374, + 374, + 374, + 374, + 374, + 16, + 16, + 16, + 222, + 150, + 150, + 267, + 267, + 267, + 66, + 66, + 66, + 66, + 373, + 373, + 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 + ], + "commands": [ + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2 + ], + "values": [ + 92, + 319, + 100, + 60, + 386, + 125, + 236, + 176, + 262, + 181, + 268, + 128, + 397, + 236, + 55, + 301, + 383, + 399, + 188, + 151, + 18, + 221, + 46, + 106, + 174, + 262, + 312, + 185, + 75, + 174, + 141, + 359, + 279, + 47, + 159, + 351, + 162, + 156, + 90, + 40, + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, + 374, + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140, + 149, + 240, + 206, + 75, + 57 + ] +} diff --git a/calyx-py/test/correctness/piezo_pifotree.py b/calyx-py/test/correctness/piezo_pifotree.py new file mode 100644 index 000000000..45204cdde --- /dev/null +++ b/calyx-py/test/correctness/piezo_pifotree.py @@ -0,0 +1,161 @@ +# pylint: disable=import-error +import fifo +import pifo +import calyx.builder as cb +from calyx import queue_call +from calyx import queue_util + + +def insert_stats(prog, name): + """Inserts a stats component called `name` into the program `prog`. + + It maintains: + - One input port, the index of a flow (0 or 1). + - Two output ports, `count_0` and `count_1`. + + It also maintains two internal registers, `count_0_sto` and `count_1_sto`. + + The component continously outputs the values of the two registers into the + two output ports. + + When invoked, the component reads the flow index and increments + `count_0_sto` or `count_1_sto` as appropriate. + """ + + stats: cb.ComponentBuilder = prog.component(name) + flow = stats.input("flow", 1) + stats.output("count_0", 32) + stats.output("count_1", 32) + + # Two registers to count the number of times we've been invoked with each flow. + count_0_sto = stats.reg("count_0_sto", 32) + count_1_sto = stats.reg("count_1_sto", 32) + + # Wiring to increment the appropriate register. + count_0_incr = stats.incr(count_0_sto) + count_1_incr = stats.incr(count_1_sto) + + # Equality checks. + flow_eq_0 = stats.eq_use(flow, 0) + flow_eq_1 = stats.eq_use(flow, 1) + + with stats.continuous: + stats.this().count_0 = count_0_sto.out + stats.this().count_1 = count_1_sto.out + + # The main logic. + stats.control += [ + cb.par( + cb.if_with(flow_eq_0, [count_0_incr]), + cb.if_with(flow_eq_1, [count_1_incr]), + ), + ] + + return stats + + +def insert_controller(prog, name, stats_component): + """Inserts a controller component called `name` into the program `prog`. + + This component receives, by reference, a `stats` component. + It invokes the `stats` component to retrieve its latest stats. + """ + + controller = prog.component(name) + stats = controller.cell("stats_controller", stats_component, is_ref=True) + + count_0 = controller.reg("count_0", 32) + count_1 = controller.reg("count_1", 32) + + with controller.group("get_data_locally") as get_data_locally: + count_0.in_ = stats.count_0 + count_0.write_en = 1 + count_1.in_ = stats.count_1 + count_1.write_en = 1 + get_data_locally.done = (count_0.done & count_1.done) @ 1 + + # The main logic. + controller.control += [ + get_data_locally, + # Great, now I have the data around locally. + ] + + return controller + + +def insert_main(prog, dataplane, controller, stats_component): + """Inserts the component `main` into the program. + It triggers the dataplane and controller components. + """ + + main: cb.ComponentBuilder = prog.component("main") + + stats = main.cell("stats_main", stats_component) + dataplane = main.cell("dataplane", dataplane) + controller = main.cell("controller", controller) + + has_ans = main.reg("has_ans", 1) + dataplane_ans = main.reg("dataplane_ans", 32) + dataplane_err = main.reg("dataplane_err", 1) + + commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True) + values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) + + j = main.reg("j", 32) # The index on the answer-list we'll write to + incr_j = main.incr(j) # j++ + write_ans = main.mem_store_seq_d1(ans_mem, j.out, dataplane_ans.out, "write_ans") + # ans_mem[j] = dataplane_ans + lower_has_ans = main.reg_store(has_ans, 0, "lower_has_ans") # has_ans := 0 + + not_err = main.not_use(dataplane_err.out) + + main.control += [ + # We will run the dataplane and controller components in parallel, + # in a while loop. The loop will terminate when the dataplane component + # raises `dataplane_err`. + cb.while_with( + not_err, # While the dataplane component has not errored out. + [ + lower_has_ans, # Lower the has-ans flag. + cb.invoke( # Invoke the dataplane component. + dataplane, + ref_commands=commands, + ref_values=values, + ref_has_ans=has_ans, + ref_component_ans=dataplane_ans, + ref_component_err=dataplane_err, + ref_stats_runner=stats, + ), + # If the dataplane component has an answer, + # write it to the answer-list and increment the index `j`. + cb.if_(has_ans.out, [write_ans, incr_j]), + cb.invoke( # Invoke the controller component. + controller, + ref_stats_controller=stats, + ), + ], + ) + ] + + +def build(): + """Top-level function to build the program.""" + prog = cb.Builder() + stats_component = insert_stats(prog, "stats") + fifo_purple = fifo.insert_fifo(prog, "fifo_purple") + fifo_tangerine = fifo.insert_fifo(prog, "fifo_tangerine") + pifo_red = pifo.insert_pifo(prog, "pifo_red", fifo_purple, fifo_tangerine, 100) + fifo_blue = fifo.insert_fifo(prog, "fifo_blue") + pifo_root = pifo.insert_pifo( + prog, "pifo_root", pifo_red, fifo_blue, 200, stats_component + ) + # The root PIFO will take a stats component by reference. + dataplane = queue_call.insert_runner(prog, pifo_root, "dataplane", stats_component) + controller = insert_controller(prog, "controller", stats_component) + insert_main(prog, dataplane, controller, stats_component) + return prog.program + + +if __name__ == "__main__": + build().emit() diff --git a/calyx-py/test/correctness/piezo_pifotree.yx b/calyx-py/test/correctness/piezo_pifotree.yx deleted file mode 100644 index c0357fc52..000000000 --- a/calyx-py/test/correctness/piezo_pifotree.yx +++ /dev/null @@ -1,1197 +0,0 @@ -import "primitives/core.futil"; -import "primitives/binary_operators.futil"; -import "primitives/memories.futil"; -component stats(flow: 1) -> (count_0: 32, count_1: 32) { - cells { - count_0_sto = std_reg(32); - count_1_sto = std_reg(32); - count_0_sto_incr = std_add(32); - count_1_sto_incr = std_add(32); - eq_1 = std_eq(1); - eq_2 = std_eq(1); - } - wires { - group count_0_sto_incr_group { - count_0_sto_incr.left = count_0_sto.out; - count_0_sto_incr.right = 32'd1; - count_0_sto.write_en = 1'd1; - count_0_sto.in = count_0_sto_incr.out; - count_0_sto_incr_group[done] = count_0_sto.done; - } - group count_1_sto_incr_group { - count_1_sto_incr.left = count_1_sto.out; - count_1_sto_incr.right = 32'd1; - count_1_sto.write_en = 1'd1; - count_1_sto.in = count_1_sto_incr.out; - count_1_sto_incr_group[done] = count_1_sto.done; - } - comb group eq_1_group { - eq_1.left = flow; - eq_1.right = 1'd0; - } - comb group eq_2_group { - eq_2.left = flow; - eq_2.right = 1'd1; - } - count_0 = count_0_sto.out; - count_1 = count_1_sto.out; - } - control { - seq { - par { - if eq_1.out with eq_1_group { - seq { - count_0_sto_incr_group; - } - } - if eq_2.out with eq_2_group { - seq { - count_1_sto_incr_group; - } - } - } - } - } -} -component fifo_purple(cmd: 2, value: 32) -> () { - cells { - mem = seq_mem_d1(32, 10, 32); - next_write = std_reg(32); - next_read = std_reg(32); - ref ans = std_reg(32); - ref err = std_reg(1); - len = std_reg(32); - eq_1 = std_eq(2); - eq_2 = std_eq(2); - eq_3 = std_eq(2); - eq_4 = std_eq(32); - eq_5 = std_eq(32); - eq_6 = std_eq(32); - eq_7 = std_eq(32); - next_write_incr = std_add(32); - next_read_incr = std_add(32); - len_incr = std_add(32); - len_decr = std_sub(32); - } - wires { - comb group eq_1_group { - eq_1.left = cmd; - eq_1.right = 2'd0; - } - comb group eq_2_group { - eq_2.left = cmd; - eq_2.right = 2'd1; - } - comb group eq_3_group { - eq_3.left = cmd; - eq_3.right = 2'd2; - } - comb group eq_4_group { - eq_4.left = next_write.out; - eq_4.right = 32'd10; - } - comb group eq_5_group { - eq_5.left = next_read.out; - eq_5.right = 32'd10; - } - comb group eq_6_group { - eq_6.left = len.out; - eq_6.right = 32'd0; - } - comb group eq_7_group { - eq_7.left = len.out; - eq_7.right = 32'd10; - } - group next_write_incr_group { - next_write_incr.left = next_write.out; - next_write_incr.right = 32'd1; - next_write.write_en = 1'd1; - next_write.in = next_write_incr.out; - next_write_incr_group[done] = next_write.done; - } - group next_read_incr_group { - next_read_incr.left = next_read.out; - next_read_incr.right = 32'd1; - next_read.write_en = 1'd1; - next_read.in = next_read_incr.out; - next_read_incr_group[done] = next_read.done; - } - group len_incr_group { - len_incr.left = len.out; - len_incr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_incr.out; - len_incr_group[done] = len.done; - } - group len_decr_group { - len_decr.left = len.out; - len_decr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_decr.out; - len_decr_group[done] = len.done; - } - group flash_write { - next_write.in = 32'd0; - next_write.write_en = 1'd1; - flash_write[done] = next_write.done; - } - group flash_read { - next_read.in = 32'd0; - next_read.write_en = 1'd1; - flash_read[done] = next_read.done; - } - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - group flash_ans { - ans.in = 32'd0; - ans.write_en = 1'd1; - flash_ans[done] = ans.done; - } - group write_payload_to_mem { - mem.addr0 = next_write.out; - mem.write_en = 1'd1; - mem.write_data = value; - write_payload_to_mem[done] = mem.write_done; - } - group read_payload_from_mem_phase1 { - mem.addr0 = next_read.out; - mem.read_en = 1'd1; - read_payload_from_mem_phase1[done] = mem.read_done; - } - group read_payload_from_mem_phase2 { - ans.write_en = 1'd1; - ans.in = mem.read_data; - read_payload_from_mem_phase2[done] = ans.done; - } - } - control { - seq { - par { - if eq_1.out with eq_1_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - next_read_incr_group; - if eq_5.out with eq_5_group { - flash_read; - } - len_decr_group; - } - } - } - if eq_2.out with eq_2_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - } - } - } - if eq_3.out with eq_3_group { - if eq_7.out with eq_7_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - write_payload_to_mem; - next_write_incr_group; - if eq_4.out with eq_4_group { - flash_write; - } - len_incr_group; - } - } - } - } - } - } -} -component fifo_tangerine(cmd: 2, value: 32) -> () { - cells { - mem = seq_mem_d1(32, 10, 32); - next_write = std_reg(32); - next_read = std_reg(32); - ref ans = std_reg(32); - ref err = std_reg(1); - len = std_reg(32); - eq_1 = std_eq(2); - eq_2 = std_eq(2); - eq_3 = std_eq(2); - eq_4 = std_eq(32); - eq_5 = std_eq(32); - eq_6 = std_eq(32); - eq_7 = std_eq(32); - next_write_incr = std_add(32); - next_read_incr = std_add(32); - len_incr = std_add(32); - len_decr = std_sub(32); - } - wires { - comb group eq_1_group { - eq_1.left = cmd; - eq_1.right = 2'd0; - } - comb group eq_2_group { - eq_2.left = cmd; - eq_2.right = 2'd1; - } - comb group eq_3_group { - eq_3.left = cmd; - eq_3.right = 2'd2; - } - comb group eq_4_group { - eq_4.left = next_write.out; - eq_4.right = 32'd10; - } - comb group eq_5_group { - eq_5.left = next_read.out; - eq_5.right = 32'd10; - } - comb group eq_6_group { - eq_6.left = len.out; - eq_6.right = 32'd0; - } - comb group eq_7_group { - eq_7.left = len.out; - eq_7.right = 32'd10; - } - group next_write_incr_group { - next_write_incr.left = next_write.out; - next_write_incr.right = 32'd1; - next_write.write_en = 1'd1; - next_write.in = next_write_incr.out; - next_write_incr_group[done] = next_write.done; - } - group next_read_incr_group { - next_read_incr.left = next_read.out; - next_read_incr.right = 32'd1; - next_read.write_en = 1'd1; - next_read.in = next_read_incr.out; - next_read_incr_group[done] = next_read.done; - } - group len_incr_group { - len_incr.left = len.out; - len_incr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_incr.out; - len_incr_group[done] = len.done; - } - group len_decr_group { - len_decr.left = len.out; - len_decr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_decr.out; - len_decr_group[done] = len.done; - } - group flash_write { - next_write.in = 32'd0; - next_write.write_en = 1'd1; - flash_write[done] = next_write.done; - } - group flash_read { - next_read.in = 32'd0; - next_read.write_en = 1'd1; - flash_read[done] = next_read.done; - } - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - group flash_ans { - ans.in = 32'd0; - ans.write_en = 1'd1; - flash_ans[done] = ans.done; - } - group write_payload_to_mem { - mem.addr0 = next_write.out; - mem.write_en = 1'd1; - mem.write_data = value; - write_payload_to_mem[done] = mem.write_done; - } - group read_payload_from_mem_phase1 { - mem.addr0 = next_read.out; - mem.read_en = 1'd1; - read_payload_from_mem_phase1[done] = mem.read_done; - } - group read_payload_from_mem_phase2 { - ans.write_en = 1'd1; - ans.in = mem.read_data; - read_payload_from_mem_phase2[done] = ans.done; - } - } - control { - seq { - par { - if eq_1.out with eq_1_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - next_read_incr_group; - if eq_5.out with eq_5_group { - flash_read; - } - len_decr_group; - } - } - } - if eq_2.out with eq_2_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - } - } - } - if eq_3.out with eq_3_group { - if eq_7.out with eq_7_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - write_payload_to_mem; - next_write_incr_group; - if eq_4.out with eq_4_group { - flash_write; - } - len_incr_group; - } - } - } - } - } - } -} -component pifo_red(cmd: 2, value: 32) -> () { - cells { - queue_l = fifo_purple(); - queue_r = fifo_tangerine(); - flow = std_reg(1); - lt_1 = std_lt(32); - ref ans = std_reg(32); - ref err = std_reg(1); - len = std_reg(32); - hot = std_reg(1); - eq_2 = std_eq(1); - eq_3 = std_eq(1); - eq_4 = std_eq(1); - eq_5 = std_eq(1); - eq_6 = std_eq(32); - eq_7 = std_eq(32); - eq_8 = std_eq(2); - eq_9 = std_eq(2); - eq_10 = std_eq(2); - eq_11 = std_eq(1); - neq_12 = std_neq(1); - hot_not = std_not(1); - len_incr = std_add(32); - len_decr = std_sub(32); - } - wires { - group infer_flow { - lt_1.left = 32'd100; - lt_1.right = value; - flow.write_en = 1'd1; - flow.in = lt_1.out; - infer_flow[done] = flow.done; - } - comb group eq_2_group { - eq_2.left = hot.out; - eq_2.right = 1'd0; - } - comb group eq_3_group { - eq_3.left = hot.out; - eq_3.right = 1'd1; - } - comb group eq_4_group { - eq_4.left = flow.out; - eq_4.right = 1'd0; - } - comb group eq_5_group { - eq_5.left = flow.out; - eq_5.right = 1'd1; - } - comb group eq_6_group { - eq_6.left = len.out; - eq_6.right = 32'd0; - } - comb group eq_7_group { - eq_7.left = len.out; - eq_7.right = 32'd10; - } - comb group eq_8_group { - eq_8.left = cmd; - eq_8.right = 2'd0; - } - comb group eq_9_group { - eq_9.left = cmd; - eq_9.right = 2'd1; - } - comb group eq_10_group { - eq_10.left = cmd; - eq_10.right = 2'd2; - } - comb group eq_11_group { - eq_11.left = err.out; - eq_11.right = 1'd0; - } - comb group neq_12_group { - neq_12.left = err.out; - neq_12.right = 1'd0; - } - group hot_not_group { - hot_not.in = hot.out; - hot.write_en = 1'd1; - hot.in = hot_not.out; - hot_not_group[done] = hot.done; - } - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - group lower_err { - err.in = 1'd0; - err.write_en = 1'd1; - lower_err[done] = err.done; - } - group flash_ans { - ans.in = 32'd0; - ans.write_en = 1'd1; - flash_ans[done] = ans.done; - } - group len_incr_group { - len_incr.left = len.out; - len_incr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_incr.out; - len_incr_group[done] = len.done; - } - group len_decr_group { - len_decr.left = len.out; - len_decr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_decr.out; - len_decr_group[done] = len.done; - } - } - control { - seq { - par { - if eq_8.out with eq_8_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - par { - if eq_2.out with eq_2_group { - seq { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - par { - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - hot_not_group; - } - } - } - } - } - if eq_3.out with eq_3_group { - seq { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - par { - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - hot_not_group; - } - } - } - } - } - } - len_decr_group; - } - } - } - if eq_9.out with eq_9_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - par { - if eq_2.out with eq_2_group { - seq { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - } - } - if eq_3.out with eq_3_group { - seq { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - } - } - } - } - } - } - if eq_10.out with eq_10_group { - if eq_7.out with eq_7_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - infer_flow; - par { - if eq_4.out with eq_4_group { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - if eq_5.out with eq_5_group { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - len_incr_group; - } - } - } - } - } - } - } - } -} -component fifo_blue(cmd: 2, value: 32) -> () { - cells { - mem = seq_mem_d1(32, 10, 32); - next_write = std_reg(32); - next_read = std_reg(32); - ref ans = std_reg(32); - ref err = std_reg(1); - len = std_reg(32); - eq_1 = std_eq(2); - eq_2 = std_eq(2); - eq_3 = std_eq(2); - eq_4 = std_eq(32); - eq_5 = std_eq(32); - eq_6 = std_eq(32); - eq_7 = std_eq(32); - next_write_incr = std_add(32); - next_read_incr = std_add(32); - len_incr = std_add(32); - len_decr = std_sub(32); - } - wires { - comb group eq_1_group { - eq_1.left = cmd; - eq_1.right = 2'd0; - } - comb group eq_2_group { - eq_2.left = cmd; - eq_2.right = 2'd1; - } - comb group eq_3_group { - eq_3.left = cmd; - eq_3.right = 2'd2; - } - comb group eq_4_group { - eq_4.left = next_write.out; - eq_4.right = 32'd10; - } - comb group eq_5_group { - eq_5.left = next_read.out; - eq_5.right = 32'd10; - } - comb group eq_6_group { - eq_6.left = len.out; - eq_6.right = 32'd0; - } - comb group eq_7_group { - eq_7.left = len.out; - eq_7.right = 32'd10; - } - group next_write_incr_group { - next_write_incr.left = next_write.out; - next_write_incr.right = 32'd1; - next_write.write_en = 1'd1; - next_write.in = next_write_incr.out; - next_write_incr_group[done] = next_write.done; - } - group next_read_incr_group { - next_read_incr.left = next_read.out; - next_read_incr.right = 32'd1; - next_read.write_en = 1'd1; - next_read.in = next_read_incr.out; - next_read_incr_group[done] = next_read.done; - } - group len_incr_group { - len_incr.left = len.out; - len_incr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_incr.out; - len_incr_group[done] = len.done; - } - group len_decr_group { - len_decr.left = len.out; - len_decr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_decr.out; - len_decr_group[done] = len.done; - } - group flash_write { - next_write.in = 32'd0; - next_write.write_en = 1'd1; - flash_write[done] = next_write.done; - } - group flash_read { - next_read.in = 32'd0; - next_read.write_en = 1'd1; - flash_read[done] = next_read.done; - } - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - group flash_ans { - ans.in = 32'd0; - ans.write_en = 1'd1; - flash_ans[done] = ans.done; - } - group write_payload_to_mem { - mem.addr0 = next_write.out; - mem.write_en = 1'd1; - mem.write_data = value; - write_payload_to_mem[done] = mem.write_done; - } - group read_payload_from_mem_phase1 { - mem.addr0 = next_read.out; - mem.read_en = 1'd1; - read_payload_from_mem_phase1[done] = mem.read_done; - } - group read_payload_from_mem_phase2 { - ans.write_en = 1'd1; - ans.in = mem.read_data; - read_payload_from_mem_phase2[done] = ans.done; - } - } - control { - seq { - par { - if eq_1.out with eq_1_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - next_read_incr_group; - if eq_5.out with eq_5_group { - flash_read; - } - len_decr_group; - } - } - } - if eq_2.out with eq_2_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - read_payload_from_mem_phase1; - read_payload_from_mem_phase2; - } - } - } - if eq_3.out with eq_3_group { - if eq_7.out with eq_7_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - write_payload_to_mem; - next_write_incr_group; - if eq_4.out with eq_4_group { - flash_write; - } - len_incr_group; - } - } - } - } - } - } -} -component pifo_root(cmd: 2, value: 32) -> () { - cells { - queue_l = pifo_red(); - queue_r = fifo_blue(); - ref stats = stats(); - flow = std_reg(1); - lt_1 = std_lt(32); - ref ans = std_reg(32); - ref err = std_reg(1); - len = std_reg(32); - hot = std_reg(1); - eq_2 = std_eq(1); - eq_3 = std_eq(1); - eq_4 = std_eq(1); - eq_5 = std_eq(1); - eq_6 = std_eq(32); - eq_7 = std_eq(32); - eq_8 = std_eq(2); - eq_9 = std_eq(2); - eq_10 = std_eq(2); - eq_11 = std_eq(1); - neq_12 = std_neq(1); - hot_not = std_not(1); - len_incr = std_add(32); - len_decr = std_sub(32); - } - wires { - group infer_flow { - lt_1.left = 32'd200; - lt_1.right = value; - flow.write_en = 1'd1; - flow.in = lt_1.out; - infer_flow[done] = flow.done; - } - comb group eq_2_group { - eq_2.left = hot.out; - eq_2.right = 1'd0; - } - comb group eq_3_group { - eq_3.left = hot.out; - eq_3.right = 1'd1; - } - comb group eq_4_group { - eq_4.left = flow.out; - eq_4.right = 1'd0; - } - comb group eq_5_group { - eq_5.left = flow.out; - eq_5.right = 1'd1; - } - comb group eq_6_group { - eq_6.left = len.out; - eq_6.right = 32'd0; - } - comb group eq_7_group { - eq_7.left = len.out; - eq_7.right = 32'd10; - } - comb group eq_8_group { - eq_8.left = cmd; - eq_8.right = 2'd0; - } - comb group eq_9_group { - eq_9.left = cmd; - eq_9.right = 2'd1; - } - comb group eq_10_group { - eq_10.left = cmd; - eq_10.right = 2'd2; - } - comb group eq_11_group { - eq_11.left = err.out; - eq_11.right = 1'd0; - } - comb group neq_12_group { - neq_12.left = err.out; - neq_12.right = 1'd0; - } - group hot_not_group { - hot_not.in = hot.out; - hot.write_en = 1'd1; - hot.in = hot_not.out; - hot_not_group[done] = hot.done; - } - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - group lower_err { - err.in = 1'd0; - err.write_en = 1'd1; - lower_err[done] = err.done; - } - group flash_ans { - ans.in = 32'd0; - ans.write_en = 1'd1; - flash_ans[done] = ans.done; - } - group len_incr_group { - len_incr.left = len.out; - len_incr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_incr.out; - len_incr_group[done] = len.done; - } - group len_decr_group { - len_decr.left = len.out; - len_decr.right = 32'd1; - len.write_en = 1'd1; - len.in = len_decr.out; - len_decr_group[done] = len.done; - } - } - control { - seq { - par { - if eq_8.out with eq_8_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - par { - if eq_2.out with eq_2_group { - seq { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - par { - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - hot_not_group; - } - } - } - } - } - if eq_3.out with eq_3_group { - seq { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - par { - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - hot_not_group; - } - } - } - } - } - } - len_decr_group; - } - } - } - if eq_9.out with eq_9_group { - if eq_6.out with eq_6_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - par { - if eq_2.out with eq_2_group { - seq { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - } - } - if eq_3.out with eq_3_group { - seq { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - if neq_12.out with neq_12_group { - seq { - lower_err; - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - } - } - } - } - } - } - if eq_10.out with eq_10_group { - if eq_7.out with eq_7_group { - seq { - raise_err; - flash_ans; - } - } else { - seq { - lower_err; - infer_flow; - par { - if eq_4.out with eq_4_group { - invoke queue_l[ans=ans, err=err](cmd=cmd, value=value)(); - } - if eq_5.out with eq_5_group { - invoke queue_r[ans=ans, err=err](cmd=cmd, value=value)(); - } - } - if eq_11.out with eq_11_group { - seq { - len_incr_group; - invoke stats(flow=flow.out)(); - } - } - } - } - } - } - } - } -} -component dataplane() -> () { - cells { - ref stats_runner = stats(); - myqueue = pifo_root(); - ref commands = seq_mem_d1(2, 15, 32); - ref values = seq_mem_d1(32, 15, 32); - ref has_ans = std_reg(1); - ref component_ans = std_reg(32); - ref component_err = std_reg(1); - i = std_reg(32); - command = std_reg(2); - value = std_reg(32); - i_incr = std_add(32); - le_1 = std_le(2); - not_2 = std_not(1); - i_eq_MAX_CMDS = std_eq(32); - } - wires { - group i_incr_group { - i_incr.left = i.out; - i_incr.right = 32'd1; - i.write_en = 1'd1; - i.in = i_incr.out; - i_incr_group[done] = i.done; - } - comb group le_1_group { - le_1.left = command.out; - le_1.right = 2'd1; - } - group read_cmd_phase1 { - commands.addr0 = i.out; - commands.read_en = 1'd1; - read_cmd_phase1[done] = commands.read_done; - } - group write_cmd_phase2 { - command.write_en = 1'd1; - command.in = commands.read_data; - write_cmd_phase2[done] = command.done; - } - group read_value { - values.addr0 = i.out; - values.read_en = 1'd1; - read_value[done] = values.read_done; - } - group write_value_to_reg { - value.write_en = 1'd1; - value.in = values.read_data; - write_value_to_reg[done] = value.done; - } - group raise_has_ans { - has_ans.in = 1'd1; - has_ans.write_en = 1'd1; - raise_has_ans[done] = has_ans.done; - } - group lower_has_ans { - has_ans.in = 1'd0; - has_ans.write_en = 1'd1; - lower_has_ans[done] = has_ans.done; - } - comb group not_2_group { - not_2.in = component_err.out; - } - group i_eq_MAX_CMDS_group { - i_eq_MAX_CMDS.left = i.out; - i_eq_MAX_CMDS.right = 32'd15; - component_err.write_en = 1'd1; - component_err.in = i_eq_MAX_CMDS.out; - i_eq_MAX_CMDS_group[done] = component_err.done; - } - } - control { - seq { - read_cmd_phase1; - write_cmd_phase2; - read_value; - write_value_to_reg; - invoke myqueue[ans=component_ans, err=component_err, stats=stats_runner](cmd=command.out, value=value.out)(); - if not_2.out with not_2_group { - seq { - if le_1.out with le_1_group { - seq { - raise_has_ans; - } - } else { - seq { - lower_has_ans; - } - } - i_incr_group; - i_eq_MAX_CMDS_group; - } - } - } - } -} -component controller() -> () { - cells { - ref stats_controller = stats(); - count_0 = std_reg(32); - count_1 = std_reg(32); - } - wires { - group get_data_locally { - count_0.in = stats_controller.count_0; - count_0.write_en = 1'd1; - count_1.in = stats_controller.count_1; - count_1.write_en = 1'd1; - get_data_locally[done] = count_0.done & count_1.done ? 1'd1; - } - } - control { - seq { - get_data_locally; - } - } -} -component main() -> () { - cells { - stats_main = stats(); - dataplane = dataplane(); - controller = controller(); - has_ans = std_reg(1); - dataplane_ans = std_reg(32); - dataplane_err = std_reg(1); - @external commands = seq_mem_d1(2, 15, 32); - @external values = seq_mem_d1(32, 15, 32); - @external ans_mem = seq_mem_d1(32, 10, 32); - j = std_reg(32); - j_incr = std_add(32); - eq_1 = std_eq(1); - } - wires { - group j_incr_group { - j_incr.left = j.out; - j_incr.right = 32'd1; - j.write_en = 1'd1; - j.in = j_incr.out; - j_incr_group[done] = j.done; - } - group write_ans { - ans_mem.addr0 = j.out; - ans_mem.write_en = 1'd1; - ans_mem.write_data = dataplane_ans.out; - write_ans[done] = ans_mem.write_done; - } - comb group eq_1_group { - eq_1.left = dataplane_err.out; - eq_1.right = 1'd0; - } - } - control { - seq { - while eq_1.out with eq_1_group { - seq { - invoke dataplane[commands=commands, values=values, has_ans=has_ans, component_ans=dataplane_ans, component_err=dataplane_err, stats_runner=stats_main]()(); - if has_ans.out { - seq { - write_ans; - j_incr_group; - } - } - invoke controller[stats_controller=stats_main]()(); - } - } - } - } -} diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index 3997e1a79..42c1699df 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -44,7 +44,7 @@ def invoke_subqueue(queue_cell, cmd, value, ans, err) -> cb.invoke: ) -def insert_pifo(prog, name, queue_l, queue_r, boundary): +def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None): """Inserts the component `pifo` into the program. The PIFO achieves a 50/50 split between two "flows" or "kinds". @@ -66,11 +66,13 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): - `push(v, PIFO)`: + If len(PIFO) = MAX_QUEUE_LEN, raise an "overflow" err and exit. + Otherwise, the charge is to enqueue value `v`. - Find out which flow `f` the value `v` should go to; + * Find out which flow `f` the value `v` should go to; `f` better be either `0` or `1`. - Enqueue `v` into `queue_l` if `f` = `0`, and into `queue_r` if `f` = `1`. - Note that the sub-queue's enqueue method is itself partial: it may raise + * Enqueue `v` into `queue_l` if `f` = `0`, and into `queue_r` if `f` = `1`. + * Note that the sub-queue's enqueue method is itself partial: it may raise "overflow", in which case we propagate the overflow flag. + * If the enqueue succeeds, _and_ if a stats component is provided, + invoke the stats component and tell it that a value of flow `f` was enqueued. - `pop(PIFO)`: + If `len(PIFO)` = 0, raise an "underflow" flag and exit. + Try `pop(queue_{hot})`, where we use the value of `hot` to determine @@ -93,6 +95,10 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): queue_l = pifo.cell("queue_l", queue_l) queue_r = pifo.cell("queue_r", queue_r) + # If a stats component was provided, declare it as a cell of this component. + if stats: + stats = pifo.cell("stats", stats, is_ref=True) + flow = pifo.reg("flow", 1) # The flow to push to: 0 or 1. # We will infer this using a separate component; # it is a function of the value being pushed. @@ -284,11 +290,20 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary): invoke_subqueue(queue_r, cmd, value, ans, err), ), ), - len_incr, # Increment the length. - # It is possible that an irrecoverable error was raised above, - # in which case the length should _not_ in fact be incremented. - # However, in that case the PIFO's `err` flag would also - # have been raised, and no one will check this length anyway. + cb.if_with( + err_eq_0, + # If no stats component is provided, + # just increment the length. + [len_incr] + if not stats + else [ + # If a stats component is provided, + # Increment the length and also + # tell the stats component what flow we pushed. + len_incr, + cb.invoke(stats, in_flow=flow.out), + ], + ), ], ), ), From 8135e8fab55eec83757b882584b02d78d6e88086 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:46:46 -0500 Subject: [PATCH 098/189] No peeks (#1781) --- calyx-py/calyx/queue_data_gen.py | 15 +- calyx-py/test/correctness/piezo_pifotree.data | 160 +++++------ .../test/correctness/piezo_pifotree.expect | 250 +++++++++--------- 3 files changed, 217 insertions(+), 208 deletions(-) diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index d6fa9227c..3dbdc9f63 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -1,5 +1,6 @@ import random import json +import sys from typing import Dict, Union from calyx import queue_util @@ -11,11 +12,12 @@ def format_gen(width: int) -> FormatType: return {"is_signed": False, "numeric_type": "bitnum", "width": width} -def dump_json(): +def dump_json(no_peeks: bool): """Prints a JSON representation of the data to stdout. The data itself is populated randomly, following certain rules: - It has three "memories": `commands`, `values`, and `ans_mem`. - The `commands` memory has queue_util.MAX_CMDS items, which are 0, 1, or 2. + If the `no_peeks` flag is set, then items are chosen randomly from 0 and 2. - The `values` memory has queue_util.MAX_CMDS items: random values between 0 and 400. - The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes. @@ -23,7 +25,10 @@ def dump_json(): """ commands = { "commands": { - "data": [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS)], + "data": [ + random.choice([0, 2]) if no_peeks else random.randint(0, 2) + for _ in range(queue_util.MAX_CMDS) + ], "format": format_gen(2), } } @@ -47,5 +52,9 @@ def dump_json(): if __name__ == "__main__": + # Accept a flag that we pass to dump_json. + # This says whether we should have any 1s in the `commands` memory. + + no_peeks = len(sys.argv) > 1 and sys.argv[1] == "--no-peeks" random.seed(5) - dump_json() + dump_json(no_peeks) diff --git a/calyx-py/test/correctness/piezo_pifotree.data b/calyx-py/test/correctness/piezo_pifotree.data index 485b42724..a2f8b6cab 100644 --- a/calyx-py/test/correctness/piezo_pifotree.data +++ b/calyx-py/test/correctness/piezo_pifotree.data @@ -2,105 +2,105 @@ "commands": { "data": [ 2, - 1, - 2, - 1, 2, + 0, 2, + 0, + 0, + 0, + 0, 2, 2, 0, - 1, - 0, 2, 0, 0, 0, - 1, - 1, 0, - 1, + 2, 2, 0, 2, 0, 0, + 0, 2, 0, - 1, - 1, 0, - 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, 0, 0, 0, 2, 2, - 1, 0, + 2, + 2, 0, 0, + 2, 0, + 2, + 2, 0, + 2, 0, + 2, + 2, + 2, + 2, + 2, 0, + 2, + 2, 0, - 1, - 1, 0, 2, + 0, 2, 2, 0, + 2, + 2, + 2, 0, 2, 0, - 1, - 1, 0, - 1, - 1, 0, 0, - 1, 0, - 1, - 1, 2, 2, - 0, 2, 2, 2, - 1, 0, - 1, - 1, - 1, - 1, 2, - 1, - 0, - 1, - 1, 2, 0, + 2, 0, - 1, 0, 2, - 1, - 1, + 2, 0, 2, - 1, - 1, - 1, 2, 0, - 1, + 2, + 2, + 2, 0, - 2 + 0 ], "format": { "is_signed": false, @@ -110,46 +110,6 @@ }, "values": { "data": [ - 92, - 319, - 100, - 60, - 386, - 125, - 236, - 176, - 262, - 181, - 268, - 128, - 397, - 236, - 55, - 301, - 383, - 399, - 188, - 151, - 18, - 221, - 46, - 106, - 174, - 262, - 312, - 185, - 75, - 174, - 141, - 359, - 279, - 47, - 159, - 351, - 162, - 156, - 90, - 40, 320, 76, 369, @@ -209,7 +169,47 @@ 240, 206, 75, - 57 + 57, + 193, + 272, + 91, + 321, + 255, + 173, + 92, + 45, + 251, + 139, + 263, + 400, + 280, + 257, + 184, + 32, + 396, + 182, + 355, + 300, + 339, + 17, + 388, + 156, + 186, + 286, + 360, + 342, + 143, + 248, + 135, + 394, + 353, + 366, + 150, + 174, + 332, + 91, + 297, + 5 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/piezo_pifotree.expect b/calyx-py/test/correctness/piezo_pifotree.expect index 876500088..3cbecc4ce 100644 --- a/calyx-py/test/correctness/piezo_pifotree.expect +++ b/calyx-py/test/correctness/piezo_pifotree.expect @@ -1,54 +1,54 @@ { "ans_mem": [ - 92, - 92, - 92, - 386, - 386, - 125, - 236, - 100, - 176, - 176, - 176, - 128, - 128, - 221, - 151, - 174, - 47, - 47, - 159, - 368, + 76, + 320, + 352, 24, - 207, - 41, - 41, + 273, 41, - 252, - 106, - 106, - 374, - 374, - 374, - 374, - 374, - 374, - 16, - 16, - 16, - 222, - 150, + 304, + 176, + 233, + 28, + 322, + 67, + 190, + 215, + 76, + 317, 150, 267, - 267, - 267, - 66, - 66, - 66, - 66, - 373, - 373, + 162, + 232, + 75, + 352, + 140, + 245, + 57, + 240, + 149, + 255, + 91, + 251, + 173, + 400, + 45, + 355, + 139, + 300, + 17, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, @@ -103,147 +103,107 @@ ], "commands": [ 2, - 1, - 2, - 1, 2, + 0, 2, + 0, + 0, + 0, + 0, 2, 2, 0, - 1, - 0, 2, 0, 0, 0, - 1, - 1, 0, - 1, + 2, 2, 0, 2, 0, 0, + 0, 2, 0, - 1, - 1, 0, - 1, + 0, + 0, + 0, 0, 0, 0, 2, 2, - 1, 0, 0, 0, 0, + 2, + 2, + 0, + 2, + 2, 0, 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, 0, + 2, + 2, 0, - 1, - 1, 0, 2, + 0, 2, 2, 0, + 2, + 2, + 2, 0, 2, 0, - 1, - 1, 0, - 1, - 1, 0, 0, - 1, 0, - 1, - 1, 2, 2, - 0, 2, 2, 2, - 1, 0, - 1, - 1, - 1, - 1, 2, - 1, - 0, - 1, - 1, 2, 0, + 2, 0, - 1, 0, 2, - 1, - 1, + 2, 0, 2, - 1, - 1, - 1, 2, 0, - 1, + 2, + 2, + 2, 0, - 2 + 0 ], "values": [ - 92, - 319, - 100, - 60, - 386, - 125, - 236, - 176, - 262, - 181, - 268, - 128, - 397, - 236, - 55, - 301, - 383, - 399, - 188, - 151, - 18, - 221, - 46, - 106, - 174, - 262, - 312, - 185, - 75, - 174, - 141, - 359, - 279, - 47, - 159, - 351, - 162, - 156, - 90, - 40, 320, 76, 369, @@ -303,6 +263,46 @@ 240, 206, 75, - 57 + 57, + 193, + 272, + 91, + 321, + 255, + 173, + 92, + 45, + 251, + 139, + 263, + 400, + 280, + 257, + 184, + 32, + 396, + 182, + 355, + 300, + 339, + 17, + 388, + 156, + 186, + 286, + 360, + 342, + 143, + 248, + 135, + 394, + 353, + 366, + 150, + 174, + 332, + 91, + 297, + 5 ] } From cad5d5d69af5601a1285a26e7e2a622a42e3e187 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 17 Nov 2023 00:31:45 -0500 Subject: [PATCH 099/189] Add Priya, Anshuman to list of contributors (#1782) --- docs/contributors.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributors.md b/docs/contributors.md index 0b46c3bd2..c0db387eb 100644 --- a/docs/contributors.md +++ b/docs/contributors.md @@ -13,6 +13,7 @@ Here is a list of all the people who have worked on Calyx: - Nathaniel Navarro - Caleb Kim - Andrew Butt +- [Anshuman Mohan](https://www.cs.cornell.edu/~amohan/) **Previous Contributors** @@ -28,5 +29,6 @@ Here is a list of all the people who have worked on Calyx: - YoungSeok Na - [Jan-Paul Ramos](https://jpramos.me) - Jiaxuan (Crystal) Hu +- [Priya Srikumar](https://priyasrikumar.com/) If you're missing from this list, please [add yourself](https://github.com/cucapra/calyx/edit/master/docs/contributors.md)! From accb594cbeef9884d24e7c3190c95fe23f965679 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Sun, 19 Nov 2023 15:22:07 -0500 Subject: [PATCH 100/189] fix (#1784) --- calyx-opt/src/analysis/domination_analysis/dominator_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx-opt/src/analysis/domination_analysis/dominator_map.rs b/calyx-opt/src/analysis/domination_analysis/dominator_map.rs index b8ef1c87a..89d2354fe 100644 --- a/calyx-opt/src/analysis/domination_analysis/dominator_map.rs +++ b/calyx-opt/src/analysis/domination_analysis/dominator_map.rs @@ -156,7 +156,7 @@ fn get_id_static(c: &ir::StaticControl) -> u64 { #[inline] fn get_id(c: &ir::Control) -> u64 { let v = match c { - ir::Control::If(_) => { + ir::Control::If(_) | ir::Control::Static(ir::StaticControl::If(_)) => { if BEGIN { c.get_attribute(BEGIN_ID) } else { From 1cc5c43fa80ca6ad7b4cdf063b3acae498b79bb8 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:59:13 -0500 Subject: [PATCH 101/189] Piezo, PIFOTree: static option! (#1783) --- calyx-py/calyx/builder.py | 59 +++- calyx-py/test/correctness/pifo.py | 8 +- .../{piezo_pifotree.data => sdn.data} | 0 .../{piezo_pifotree.expect => sdn.expect} | 0 .../correctness/{piezo_pifotree.py => sdn.py} | 60 ++-- .../test/correctness/static/sdn_static.data | 329 ++++++++++++++++++ .../test/correctness/static/sdn_static.expect | 308 ++++++++++++++++ .../test/correctness/static/sdn_static.py | 9 + runt.toml | 15 + 9 files changed, 762 insertions(+), 26 deletions(-) rename calyx-py/test/correctness/{piezo_pifotree.data => sdn.data} (100%) rename calyx-py/test/correctness/{piezo_pifotree.expect => sdn.expect} (100%) rename calyx-py/test/correctness/{piezo_pifotree.py => sdn.py} (77%) create mode 100644 calyx-py/test/correctness/static/sdn_static.data create mode 100644 calyx-py/test/correctness/static/sdn_static.expect create mode 100644 calyx-py/test/correctness/static/sdn_static.py diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index c206c3b59..7a6ce0c0f 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -523,17 +523,23 @@ def bitwise_flip_reg(self, reg, cellname=None): not_group.done = reg.done return not_group - def incr(self, reg, val=1, signed=False, cellname=None): + def incr(self, reg, val=1, signed=False, cellname=None, static=False): """Inserts wiring into `self` to perform `reg := reg + val`.""" cellname = cellname or f"{reg.name}_incr" width = reg.infer_width_reg() add_cell = self.add(width, cellname, signed) - with self.group(f"{cellname}_group") as incr_group: + group = ( + self.static_group(f"{cellname}_group", 1) + if static + else self.group(f"{cellname}_group") + ) + with group as incr_group: add_cell.left = reg.out add_cell.right = const(width, val) reg.write_en = 1 reg.in_ = add_cell.out - incr_group.done = reg.done + if not static: + incr_group.done = reg.done return incr_group def decr(self, reg, val=1, signed=False, cellname=None): @@ -847,6 +853,32 @@ def invoke(cell: CellBuilder, **kwargs) -> ast.Invoke: ) +def static_invoke(cell: CellBuilder, **kwargs) -> ast.Invoke: + """Build a `static invoke` control statement. + + The keyword arguments should have the form `in_*`, `out_*`, or `ref_*`, where + `*` is the name of an input port, output port, or ref cell on the invoked cell. + """ + return ast.StaticInvoke( + cell._cell.id, + [ + (k[3:], ExprBuilder.unwrap(v)) + for (k, v) in kwargs.items() + if k.startswith("in_") + ], + [ + (k[4:], ExprBuilder.unwrap(v)) + for (k, v) in kwargs.items() + if k.startswith("out_") + ], + [ + (k[4:], CellBuilder.unwrap_id(v)) + for (k, v) in kwargs.items() + if k.startswith("ref_") + ], + ) + + class ControlBuilder: """Wraps control statements for convenient construction.""" @@ -1256,6 +1288,15 @@ def par(*args) -> ast.ParComp: return ast.ParComp([as_control(x) for x in args]) +def static_par(*args) -> ast.StaticParComp: + """Build a static parallel composition of control expressions. + + Each argument will become its own parallel arm in the resulting composition. + So `par([a,b])` becomes `par {seq {a; b;}}` while `par(a, b)` becomes `par {a; b;}`. + """ + return ast.StaticParComp([as_control(x) for x in args]) + + def seq(*args) -> ast.SeqComp: """Build a sequential composition of control expressions. @@ -1268,6 +1309,18 @@ def seq(*args) -> ast.SeqComp: return ast.SeqComp([as_control(x) for x in args]) +def static_seq(*args) -> ast.StaticSeqComp: + """Build a static sequential composition of control expressions. + + Prefer use of python list syntax over this function. Use only when not directly + modifying the control program with the `+=` operator. + Each argument will become its own sequential arm in the resulting composition. + So `seq([a,b], c)` becomes `seq { seq {a; b;} c }` while `seq(a, b, c)` becomes `seq + {a; b; c;}`. + """ + return ast.StaticSeqComp([as_control(x) for x in args]) + + def add_comp_params(comp: ComponentBuilder, input_ports: List, output_ports: List): """ Adds `input_ports`/`output_ports` as inputs/outputs to comp. diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index 42c1699df..ae868d1ac 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -44,7 +44,7 @@ def invoke_subqueue(queue_cell, cmd, value, ans, err) -> cb.invoke: ) -def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None): +def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None, static=False): """Inserts the component `pifo` into the program. The PIFO achieves a 50/50 split between two "flows" or "kinds". @@ -301,7 +301,11 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None): # Increment the length and also # tell the stats component what flow we pushed. len_incr, - cb.invoke(stats, in_flow=flow.out), + ( + cb.static_invoke(stats, in_flow=flow.out) + if static + else cb.invoke(stats, in_flow=flow.out) + ), ], ), ], diff --git a/calyx-py/test/correctness/piezo_pifotree.data b/calyx-py/test/correctness/sdn.data similarity index 100% rename from calyx-py/test/correctness/piezo_pifotree.data rename to calyx-py/test/correctness/sdn.data diff --git a/calyx-py/test/correctness/piezo_pifotree.expect b/calyx-py/test/correctness/sdn.expect similarity index 100% rename from calyx-py/test/correctness/piezo_pifotree.expect rename to calyx-py/test/correctness/sdn.expect diff --git a/calyx-py/test/correctness/piezo_pifotree.py b/calyx-py/test/correctness/sdn.py similarity index 77% rename from calyx-py/test/correctness/piezo_pifotree.py rename to calyx-py/test/correctness/sdn.py index 45204cdde..43650f0cf 100644 --- a/calyx-py/test/correctness/piezo_pifotree.py +++ b/calyx-py/test/correctness/sdn.py @@ -6,7 +6,7 @@ from calyx import queue_util -def insert_stats(prog, name): +def insert_stats(prog, name, static=False): """Inserts a stats component called `name` into the program `prog`. It maintains: @@ -20,9 +20,13 @@ def insert_stats(prog, name): When invoked, the component reads the flow index and increments `count_0_sto` or `count_1_sto` as appropriate. + + If `static` is False, this is a dynamic component. + Otherwise, it is a static component with delay 1. """ - stats: cb.ComponentBuilder = prog.component(name) + stats: cb.ComponentBuilder = prog.component(name, latency=1 if static else None) + flow = stats.input("flow", 1) stats.output("count_0", 32) stats.output("count_1", 32) @@ -32,24 +36,36 @@ def insert_stats(prog, name): count_1_sto = stats.reg("count_1_sto", 32) # Wiring to increment the appropriate register. - count_0_incr = stats.incr(count_0_sto) - count_1_incr = stats.incr(count_1_sto) + count_0_incr = stats.incr(count_0_sto, static=static) + count_1_incr = stats.incr(count_1_sto, static=static) - # Equality checks. - flow_eq_0 = stats.eq_use(flow, 0) - flow_eq_1 = stats.eq_use(flow, 1) + # The rest of the logic varies depending on whether the component is static. - with stats.continuous: - stats.this().count_0 = count_0_sto.out - stats.this().count_1 = count_1_sto.out + # If not static, we can use comb groups. + if not static: + flow_eq_0 = stats.eq_use(flow, 0) - # The main logic. - stats.control += [ - cb.par( - cb.if_with(flow_eq_0, [count_0_incr]), - cb.if_with(flow_eq_1, [count_1_incr]), - ), - ] + with stats.continuous: + stats.this().count_0 = count_0_sto.out + stats.this().count_1 = count_1_sto.out + + stats.control += cb.par( + cb.if_with(flow_eq_0, count_0_incr, count_1_incr), + ) + + # If static, we need to use continuous assignments and not comb groups. + else: + eq_cell = stats.eq(1, "eq_cell") + + with stats.continuous: + stats.this().count_0 = count_0_sto.out + stats.this().count_1 = count_1_sto.out + eq_cell.left = flow + eq_cell.right = 0 + + stats.control += cb.static_par( + cb.static_if(eq_cell.out, count_0_incr, count_1_incr), + ) return stats @@ -139,16 +155,18 @@ def insert_main(prog, dataplane, controller, stats_component): ] -def build(): - """Top-level function to build the program.""" +def build(static=False): + """Top-level function to build the program. + The `static` flag determines whether the program is static or dynamic. + """ prog = cb.Builder() - stats_component = insert_stats(prog, "stats") + stats_component = insert_stats(prog, "stats", static) fifo_purple = fifo.insert_fifo(prog, "fifo_purple") fifo_tangerine = fifo.insert_fifo(prog, "fifo_tangerine") pifo_red = pifo.insert_pifo(prog, "pifo_red", fifo_purple, fifo_tangerine, 100) fifo_blue = fifo.insert_fifo(prog, "fifo_blue") pifo_root = pifo.insert_pifo( - prog, "pifo_root", pifo_red, fifo_blue, 200, stats_component + prog, "pifo_root", pifo_red, fifo_blue, 200, stats_component, static ) # The root PIFO will take a stats component by reference. dataplane = queue_call.insert_runner(prog, pifo_root, "dataplane", stats_component) diff --git a/calyx-py/test/correctness/static/sdn_static.data b/calyx-py/test/correctness/static/sdn_static.data new file mode 100644 index 000000000..a2f8b6cab --- /dev/null +++ b/calyx-py/test/correctness/static/sdn_static.data @@ -0,0 +1,329 @@ +{ + "commands": { + "data": [ + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { + "data": [ + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, + 374, + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140, + 149, + 240, + 206, + 75, + 57, + 193, + 272, + 91, + 321, + 255, + 173, + 92, + 45, + 251, + 139, + 263, + 400, + 280, + 257, + 184, + 32, + 396, + 182, + 355, + 300, + 339, + 17, + 388, + 156, + 186, + 286, + 360, + 342, + 143, + 248, + 135, + 394, + 353, + 366, + 150, + 174, + 332, + 91, + 297, + 5 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 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, + 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 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + } +} diff --git a/calyx-py/test/correctness/static/sdn_static.expect b/calyx-py/test/correctness/static/sdn_static.expect new file mode 100644 index 000000000..3cbecc4ce --- /dev/null +++ b/calyx-py/test/correctness/static/sdn_static.expect @@ -0,0 +1,308 @@ +{ + "ans_mem": [ + 76, + 320, + 352, + 24, + 273, + 41, + 304, + 176, + 233, + 28, + 322, + 67, + 190, + 215, + 76, + 317, + 150, + 267, + 162, + 232, + 75, + 352, + 140, + 245, + 57, + 240, + 149, + 255, + 91, + 251, + 173, + 400, + 45, + 355, + 139, + 300, + 17, + 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 + ], + "commands": [ + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0 + ], + "values": [ + 320, + 76, + 369, + 352, + 158, + 247, + 82, + 368, + 24, + 41, + 307, + 273, + 207, + 16, + 121, + 379, + 304, + 176, + 128, + 233, + 333, + 215, + 74, + 28, + 326, + 16, + 252, + 171, + 106, + 66, + 374, + 288, + 67, + 322, + 211, + 54, + 86, + 222, + 190, + 76, + 30, + 215, + 150, + 72, + 232, + 317, + 86, + 267, + 232, + 249, + 352, + 373, + 162, + 245, + 140, + 149, + 240, + 206, + 75, + 57, + 193, + 272, + 91, + 321, + 255, + 173, + 92, + 45, + 251, + 139, + 263, + 400, + 280, + 257, + 184, + 32, + 396, + 182, + 355, + 300, + 339, + 17, + 388, + 156, + 186, + 286, + 360, + 342, + 143, + 248, + 135, + 394, + 353, + 366, + 150, + 174, + 332, + 91, + 297, + 5 + ] +} diff --git a/calyx-py/test/correctness/static/sdn_static.py b/calyx-py/test/correctness/static/sdn_static.py new file mode 100644 index 000000000..c011ef3e4 --- /dev/null +++ b/calyx-py/test/correctness/static/sdn_static.py @@ -0,0 +1,9 @@ +# Import the sdn module, which is one level up. +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import sdn + +if __name__ == "__main__": + sdn.build(static=True).emit() diff --git a/runt.toml b/runt.toml index fc4b140d3..8d9d77acb 100644 --- a/runt.toml +++ b/runt.toml @@ -114,6 +114,21 @@ python3 {} |\ -q """ +[[tests]] +name = "[calyx-py] static correctness" +paths = ["calyx-py/test/correctness/static/*.py"] +cmd = """ +name=$(basename {} .py) && +dir=$(dirname {}) && +python3 {} |\ + fud e --from calyx --to jq \ + --through verilog \ + --through dat \ + -s verilog.data "$dir/$name.data" \ + -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + -q +""" ##### Correctness Tests ##### ## Tests that ensure that individual control From 73d88a64ae91d4d120fd3af3a47cf96e1e3befce Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:02:22 -0500 Subject: [PATCH 102/189] Remove unnecessary par in SDN (#1786) --- calyx-py/test/correctness/sdn.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/calyx-py/test/correctness/sdn.py b/calyx-py/test/correctness/sdn.py index 43650f0cf..c22952306 100644 --- a/calyx-py/test/correctness/sdn.py +++ b/calyx-py/test/correctness/sdn.py @@ -49,9 +49,7 @@ def insert_stats(prog, name, static=False): stats.this().count_0 = count_0_sto.out stats.this().count_1 = count_1_sto.out - stats.control += cb.par( - cb.if_with(flow_eq_0, count_0_incr, count_1_incr), - ) + stats.control += cb.if_with(flow_eq_0, count_0_incr, count_1_incr) # If static, we need to use continuous assignments and not comb groups. else: @@ -63,9 +61,7 @@ def insert_stats(prog, name, static=False): eq_cell.left = flow eq_cell.right = 0 - stats.control += cb.static_par( - cb.static_if(eq_cell.out, count_0_incr, count_1_incr), - ) + stats.control += cb.static_if(eq_cell.out, count_0_incr, count_1_incr) return stats From ebc1198b1d102f6e7103896bf79df4964bce8b1e Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:12:20 -0500 Subject: [PATCH 103/189] More thoughtful data gen for Piezo (#1787) --- calyx-py/calyx/queue_data_gen.py | 61 +++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index 3dbdc9f63..87e34b63a 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -12,12 +12,56 @@ def format_gen(width: int) -> FormatType: return {"is_signed": False, "numeric_type": "bitnum", "width": width} -def dump_json(no_peeks: bool): +def piezo_special(): + """A special data-gen helper that creates a commands list while + ensuring that there are: + - No overflows. + - No underflows. + - (queue_util.MAX_CMDS/2) pushes. + - As many pops as there are pushes. + A combination of the above means that no packet is left unpopped. + """ + running_count = 0 # The current size of the queue. + push_goal = int(queue_util.MAX_CMDS / 2) # How many pushes we want overall. + total_push_count = 0 + total_pop_count = 0 + commands = [] + while True: + command = random.choice(["push", "pop"]) + if command == "pop" and running_count == 0: + # This would make us underflow, + # so we'll change the command to `push` instead + command = "push" + if command == "push" and running_count == queue_util.QUEUE_SIZE: + # This would make us overflow, + # so we'll change the command to `pop` instead + command = "pop" + if command == "push": + running_count += 1 + total_push_count += 1 + if command == "pop": + running_count -= 1 + total_pop_count += 1 + # Put the command into `commands`. + commands.append(0 if command == "pop" else 2) + + if total_push_count == push_goal: + # Pad the `commands` list with (push_goal - total_pop_count) `pop`s, + # and then break. + commands += (push_goal - total_pop_count) * [0] + break + + assert len(commands) == queue_util.MAX_CMDS + return commands + + +def dump_json(piezo: bool): """Prints a JSON representation of the data to stdout. The data itself is populated randomly, following certain rules: - It has three "memories": `commands`, `values`, and `ans_mem`. - The `commands` memory has queue_util.MAX_CMDS items, which are 0, 1, or 2. - If the `no_peeks` flag is set, then items are chosen randomly from 0 and 2. + 0: pop, 1: peek, 2: push + If the `piezo` flag is set, then items are chosen from 0 and 2 using a helper. - The `values` memory has queue_util.MAX_CMDS items: random values between 0 and 400. - The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes. @@ -25,10 +69,11 @@ def dump_json(no_peeks: bool): """ commands = { "commands": { - "data": [ - random.choice([0, 2]) if no_peeks else random.randint(0, 2) - for _ in range(queue_util.MAX_CMDS) - ], + "data": ( + piezo_special() + if piezo + else [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS)] + ), "format": format_gen(2), } } @@ -55,6 +100,6 @@ def dump_json(no_peeks: bool): # Accept a flag that we pass to dump_json. # This says whether we should have any 1s in the `commands` memory. - no_peeks = len(sys.argv) > 1 and sys.argv[1] == "--no-peeks" + piezo = len(sys.argv) > 1 and sys.argv[1] == "--piezo" random.seed(5) - dump_json(no_peeks) + dump_json(piezo) From 991f382ee8fc0dee9a56ae096a9f856b50a48f4c Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:36:58 -0500 Subject: [PATCH 104/189] Piezo, PIFO tree: new `.data` and `.expect` files (#1788) * Actually put new files in * Usage directions in comments --- calyx-py/calyx/pifotree_oracle.py | 8 +- calyx-py/calyx/queue_data_gen.py | 7 ++ calyx-py/test/correctness/sdn.data | 50 ++++++------ calyx-py/test/correctness/sdn.expect | 118 +++++++++++++-------------- 4 files changed, 98 insertions(+), 85 deletions(-) diff --git a/calyx-py/calyx/pifotree_oracle.py b/calyx-py/calyx/pifotree_oracle.py index 6969f1be5..6e97727da 100644 --- a/calyx-py/calyx/pifotree_oracle.py +++ b/calyx-py/calyx/pifotree_oracle.py @@ -1,3 +1,10 @@ +# Usage: +# To make a .data file: +# python calyx-py/calyx/queue_data_gen.py --piezo > calyx-py/test/correctness/sdn.data +# To then make a .expect file: +# cat calyx-py/test/correctness/sdn.data | +# python calyx-py/calyx/pifotree_oracle.py > calyx-py/test/correctness/sdn.expect + import calyx.queues as queues from calyx import queue_util @@ -21,4 +28,3 @@ ans = queues.operate_queue(commands, values, pifo) queue_util.dump_json(commands, values, ans) - diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index 87e34b63a..966a2e06c 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -1,3 +1,10 @@ +# Usage: +# To make a .data file: +# python calyx-py/calyx/queue_data_gen.py --piezo > calyx-py/test/correctness/sdn.data +# To then make a .expect file: +# cat calyx-py/test/correctness/sdn.data | +# python calyx-py/calyx/pifotree_oracle.py > calyx-py/test/correctness/sdn.expect + import random import json import sys diff --git a/calyx-py/test/correctness/sdn.data b/calyx-py/test/correctness/sdn.data index a2f8b6cab..b4aca847b 100644 --- a/calyx-py/test/correctness/sdn.data +++ b/calyx-py/test/correctness/sdn.data @@ -1,77 +1,82 @@ { "commands": { "data": [ - 2, 2, 0, 2, 0, + 2, + 2, + 2, + 2, 0, 0, + 2, 0, 2, 2, - 0, + 2, 2, 0, 0, + 2, 0, + 2, + 2, + 2, 0, 2, 2, + 2, + 2, 0, 2, 0, + 2, 0, 0, 2, + 2, 0, + 2, 0, 0, + 2, 0, 0, + 2, + 2, 0, + 2, 0, 0, 2, + 0, 2, 0, 0, 0, 0, - 2, - 2, 0, 2, - 2, - 0, 0, - 2, 0, 2, 2, 0, 2, 0, - 2, - 2, - 2, - 2, - 2, 0, 2, - 2, 0, 0, - 2, 0, 2, - 2, 0, 2, 2, 2, - 0, + 2, 2, 0, 0, @@ -79,27 +84,22 @@ 0, 0, 2, - 2, - 2, + 0, 2, 2, 0, 2, 2, 0, + 0, 2, 0, 0, 2, - 2, 0, 2, - 2, 0, 2, - 2, - 2, - 0, 0 ], "format": { @@ -110,6 +110,7 @@ }, "values": { "data": [ + 40, 320, 76, 369, @@ -208,8 +209,7 @@ 174, 332, 91, - 297, - 5 + 297 ], "format": { "is_signed": false, diff --git a/calyx-py/test/correctness/sdn.expect b/calyx-py/test/correctness/sdn.expect index 3cbecc4ce..390add283 100644 --- a/calyx-py/test/correctness/sdn.expect +++ b/calyx-py/test/correctness/sdn.expect @@ -1,55 +1,55 @@ { "ans_mem": [ + 40, 76, - 320, 352, - 24, + 158, + 247, + 82, 273, + 121, + 207, 41, - 304, - 176, 233, + 176, + 333, + 16, + 215, + 106, + 326, 28, + 252, + 150, + 374, + 16, 322, - 67, - 190, - 215, + 86, + 211, 76, 317, - 150, - 267, - 162, + 72, 232, - 75, + 193, 352, - 140, - 245, 57, 240, - 149, - 255, - 91, - 251, 173, - 400, - 45, - 355, + 91, 139, - 300, + 400, + 32, + 280, + 184, + 257, 17, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 156, + 360, + 186, + 342, + 135, + 366, + 174, + 91, 0, 0, 0, @@ -102,77 +102,82 @@ 0 ], "commands": [ - 2, 2, 0, 2, 0, + 2, + 2, + 2, + 2, 0, 0, + 2, 0, 2, 2, - 0, + 2, 2, 0, 0, + 2, 0, + 2, + 2, + 2, 0, 2, 2, + 2, + 2, 0, 2, 0, + 2, 0, 0, 2, + 2, 0, + 2, 0, 0, + 2, 0, 0, + 2, + 2, 0, + 2, 0, 0, 2, + 0, 2, 0, 0, 0, 0, - 2, - 2, 0, 2, - 2, 0, 0, 2, - 0, - 2, 2, 0, 2, 0, - 2, - 2, - 2, - 2, - 2, 0, 2, - 2, 0, 0, - 2, 0, 2, - 2, 0, 2, 2, 2, - 0, + 2, 2, 0, 0, @@ -180,30 +185,26 @@ 0, 0, 2, - 2, - 2, + 0, 2, 2, 0, 2, 2, 0, + 0, 2, 0, 0, 2, - 2, 0, 2, - 2, 0, 2, - 2, - 2, - 0, 0 ], "values": [ + 40, 320, 76, 369, @@ -302,7 +303,6 @@ 174, 332, 91, - 297, - 5 + 297 ] } From 8216bd46a919b6e23cb44959298b0954ca2fa5ac Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Fri, 24 Nov 2023 20:52:26 -0800 Subject: [PATCH 105/189] Fix some typos and rephrase some `axi-gen.md` documentation (#1789) * fix some typos and rephrase some axi-gen documentation * more rephrasing * Hyphenation fix --------- Co-authored-by: Adrian Sampson --- docs/fud/axi-gen.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/fud/axi-gen.md b/docs/fud/axi-gen.md index 855dadda1..c6500bd1a 100644 --- a/docs/fud/axi-gen.md +++ b/docs/fud/axi-gen.md @@ -1,22 +1,27 @@ # AXI Interface Generation -Calyx currently generates a fairly complex AXI interface that can be daunting + +In order to run programs on FPGAs, fud is capable of utilizing +Calyx to generate a fairly complex AXI interface that can be daunting to deal with if confronting for the first time. The following is an overview of how the generation occurs -and how the output AXI interface behaves as of 2022-9-11. +and how the fud-generated AXI interface behaves as of 2022-9-11. In general, when `fud` is asked to create an [`.xclbin` file][xclbin] a `kernel.xml`, -`main.sv`, and `toplevel.v` are created as intermediate steps for [xilinx tools][xilinx_tools] -to properly work. +`main.sv`, and `toplevel.v` are created as intermediate files required for our +[Xilinx tools][xilinx_tools] to properly work. -`main.sv` contains the SystemVerilog needed for our computations to perform -correctly. It is implemented as an FSM that derives from the original Calyx program. -[`kernel.xml`][kernel_xml] defines register maps and ports of our -toplevel xilinx tools needs. `toplevel.v` wraps our computation kernel and contains -the AXI interface for each memory defined in a Calyx program and corresponds to the standard Calux lowering process. +`main.sv` contains the SystemVerilog implementation of the Calyx program +we are interested in executing on an FPGA. +`toplevel.v` wraps our SystemVerilog implementation and contains +the AXI interface for each memory marked [`@external`][external] in a Calyx program. +Our `toplevel.v` and [`kernel.xml`][kernel_xml] is what our Xilinx tools interface with. +Our toplevel adheres to the Xilinx [kernel interface requirements][kernel_requirements]. +`kernel.xml` defines register maps and ports of our +toplevel module used by our Xilinx tools. -For more info on file generation see [how the Xilinx Toolchain works][xilinx_how] +For more information on the generation of the files mentioned above see [how the Xilinx Toolchain works][xilinx_how] ## Toplevel @@ -31,16 +36,16 @@ To note, separate AXI interfaces are created for each memory the memory. Eventually the BRAMs are read and fed into the computation kernel of `main.sv`, which outputs results directly into the relevant memories as defined in the original Calyx program. -Address and data widths and sizes are determined from cell declerations. +Addresses, data widths, and sizes are determined from cell declarations. > There is always the possiblity that something is hardcoded as a remnant -> from previous versions of our AXI generation. If something is hardcoded where it shouldn't +> of previous versions of our AXI generation. If something is hardcoded where it shouldn't > be please open an [issue][issues]. AXI memory controllers are constructed as (full) [AXI4 managers][signals] that lack a small amount of functionality. For example, [xPROT signals][access_protection] are not currently supported. Additionally, things like [bursting][bursting] are not currently supported, but should be -easy to implement due to the existing infrastructure and generation. +easy to implement due to the existing infrastructure and generation tools. A list of current signals that are hardcoded follows: @@ -56,10 +61,11 @@ A list of current signals that are hardcoded follows: * No [low power signals](https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification/Signal-Descriptions/Low-power-interface-signals?lang=en) are generated. ### Subordinate AXI control controller -In addition to our manager memory controllers, a subordinate controller for -our control module is also generated. This module is responsible for signaling +In addition to our manager memory-controllers, a subordinate interface, +connected to our control module is also generated. +This module is responsible for signaling our computational kernel to start working, as well as calculating the correct -base addresses to use for our memory controllers. Things like address and +base addresses to use for our memory controllers. Things like addresses and data widths are hard coded at the moment. It is suspected that this hardcoding is okay for the types of programs we generate. But more work needs to be done to see if our control structure works for arbitrary programs or needs to be changed to @@ -77,3 +83,4 @@ allow this. [access_protection]: https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification/Transaction-Attributes/Access-permissions?lang=en [toplevel]: https://docs.calyxir.org/lang/attributes.html?highlight=toplevel#toplevel [xilinx_how]: https://docs.calyxir.org/fud/xilinx.html?highlight=synthesis#how-it-works +[kernel_requirements]: https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements From 145039b419b32d657179025e45b013104ca99e21 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Sun, 26 Nov 2023 07:43:35 -0500 Subject: [PATCH 106/189] Piezo, PIFO tree: 10000 pushes and pops (#1790) * 10000 pushes and pops * 10000 * Don't write zeroes to ans --- calyx-py/calyx/queue_data_gen.py | 2 +- calyx-py/calyx/queue_util.py | 2 +- calyx-py/test/correctness/fifo.data | 59848 ++++++++++++++- calyx-py/test/correctness/fifo.expect | 60188 ++++++++++++++- calyx-py/test/correctness/pifo.data | 59848 ++++++++++++++- calyx-py/test/correctness/pifo.expect | 60178 ++++++++++++++- calyx-py/test/correctness/pifo_tree.data | 59848 ++++++++++++++- calyx-py/test/correctness/pifo_tree.expect | 60168 ++++++++++++++- calyx-py/test/correctness/sdn.data | 59848 ++++++++++++++- calyx-py/test/correctness/sdn.expect | 60222 +++++++++++++++- calyx-py/test/correctness/sdn.py | 9 +- .../test/correctness/static/sdn_static.data | 59938 ++++++++++++++- .../test/correctness/static/sdn_static.expect | 60222 +++++++++++++++- 13 files changed, 598663 insertions(+), 1658 deletions(-) diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index 966a2e06c..ea7d9c37c 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -86,7 +86,7 @@ def dump_json(piezo: bool): } values = { "values": { - "data": [random.randint(0, 400) for _ in range(queue_util.MAX_CMDS)], + "data": [random.randint(1, 400) for _ in range(queue_util.MAX_CMDS)], # The `values` memory has queue_util.MAX_CMDS items: random values # between 0 and 400. "format": format_gen(32), diff --git a/calyx-py/calyx/queue_util.py b/calyx-py/calyx/queue_util.py index e04380a0b..4fa751dd7 100644 --- a/calyx-py/calyx/queue_util.py +++ b/calyx-py/calyx/queue_util.py @@ -1,7 +1,7 @@ import json import sys -MAX_CMDS = 100 +MAX_CMDS = 20000 QUEUE_SIZE = 10 diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/fifo.data index 485b42724..bf04ab461 100644 --- a/calyx-py/test/correctness/fifo.data +++ b/calyx-py/test/correctness/fifo.data @@ -100,7 +100,19907 @@ 0, 1, 0, - 2 + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 ], "format": { "is_signed": false, @@ -110,106 +20010,20006 @@ }, "values": { "data": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, 319, - 100, - 60, - 386, - 125, - 236, - 176, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, 262, - 181, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, 268, - 128, - 397, - 236, - 55, - 301, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, 383, - 399, - 188, - 151, - 18, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, 221, - 46, - 106, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, 174, - 262, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, 312, - 185, - 75, - 174, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, 141, - 359, - 279, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, 47, + 149, + 193, 159, - 351, - 162, - 156, - 90, - 40, - 320, - 76, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, 369, - 352, + 336, + 260, + 355, + 103, 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, 82, - 368, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, 24, + 31, 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, 16, - 121, - 379, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, 304, - 176, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, 128, - 233, - 333, - 215, - 74, - 28, - 326, - 16, - 252, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, 171, - 106, - 66, - 374, - 288, - 67, - 322, - 211, + 397, + 78, + 205, + 216, 54, - 86, - 222, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, 190, - 76, - 30, - 215, - 150, - 72, - 232, - 317, - 86, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ], "format": { "is_signed": false, @@ -219,6 +40019,19906 @@ }, "ans_mem": { "data": [ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/fifo.expect index b3523a34e..729314efa 100644 --- a/calyx-py/test/correctness/fifo.expect +++ b/calyx-py/test/correctness/fifo.expect @@ -1,308 +1,60008 @@ { "ans_mem": [ - 92, - 92, - 92, - 100, - 100, - 386, - 125, - 236, - 176, - 176, - 176, - 128, - 128, + 276, + 276, + 276, + 244, + 244, + 122, + 331, + 330, + 204, + 204, + 204, + 311, + 311, + 292, + 257, + 269, + 355, + 355, + 381, + 308, + 263, + 131, + 81, + 81, + 81, + 364, + 389, + 389, + 41, + 41, + 41, + 41, + 41, + 41, + 107, + 107, + 107, + 243, + 300, + 300, + 326, + 326, + 326, + 244, + 244, + 244, + 244, + 288, + 288, + 177, + 322, + 62, + 126, + 126, + 126, + 126, + 96, + 96, + 96, + 307, + 307, + 297, + 146, + 146, + 206, + 206, + 206, + 310, + 310, + 310, + 310, + 172, + 84, + 80, + 80, + 80, + 126, + 342, + 213, + 213, + 134, + 216, + 216, + 216, + 216, + 216, + 239, + 319, + 222, + 222, + 222, + 217, + 307, + 81, + 81, + 222, + 362, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 6, + 232, + 232, + 12, + 12, + 12, + 242, + 182, + 182, + 313, + 313, + 99, + 99, + 99, + 99, + 99, + 99, + 99, + 99, + 13, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 353, + 353, + 353, + 353, + 255, + 217, + 234, + 234, + 234, + 234, + 239, + 239, + 292, + 292, + 292, + 292, + 239, + 117, + 218, + 218, + 327, + 102, + 379, + 143, + 143, + 372, + 241, 151, + 189, + 127, + 127, + 392, + 392, + 293, + 339, + 339, + 339, + 339, + 339, + 374, + 342, + 251, + 251, + 69, + 69, + 69, + 69, + 69, + 173, + 173, + 10, + 10, + 262, + 262, + 262, + 262, + 262, + 216, + 216, + 216, + 216, + 216, + 238, + 304, + 304, + 304, + 204, + 213, + 22, + 22, + 313, + 313, + 85, + 85, + 1, + 1, + 1, + 1, + 1, + 184, + 184, + 184, + 184, + 184, + 184, + 339, + 339, + 339, + 339, + 339, + 339, + 367, + 367, + 367, + 367, + 367, + 357, + 357, + 97, + 117, + 117, + 214, + 214, + 194, + 27, + 27, + 21, + 21, + 21, + 354, + 354, + 64, + 162, + 162, + 162, + 169, + 169, + 169, + 169, + 169, + 136, + 270, + 375, + 375, + 375, + 375, + 375, + 311, + 311, + 311, + 311, + 19, + 100, + 291, + 291, + 291, + 282, + 184, + 110, + 110, + 110, + 110, + 110, + 110, + 110, + 347, + 347, + 347, + 279, + 279, + 220, + 220, + 220, + 220, + 220, + 192, + 389, + 389, + 389, + 389, + 9, + 9, + 31, + 87, + 130, + 130, + 399, + 197, + 392, + 392, + 392, + 258, + 258, + 258, + 194, + 87, + 220, + 49, + 121, + 18, + 18, + 18, + 224, + 204, + 127, + 127, + 126, + 224, + 223, + 19, + 38, + 38, + 46, + 46, 221, - 174, - 47, - 47, - 159, - 368, - 24, - 41, - 207, - 207, - 207, - 16, + 50, + 50, + 387, + 282, + 282, + 181, + 181, + 181, + 181, + 181, + 399, + 79, + 79, + 122, + 122, + 55, + 55, + 42, + 398, + 398, + 398, + 75, + 50, + 50, + 50, + 50, + 253, + 333, + 99, + 99, + 297, + 149, + 88, + 250, + 250, + 8, + 8, + 8, + 8, + 8, + 196, + 233, + 233, + 141, + 369, + 369, + 381, + 102, 252, 252, - 106, - 106, - 106, - 106, - 106, - 106, - 66, - 66, + 389, + 221, + 221, + 221, + 368, + 368, + 368, + 368, + 368, + 368, + 199, + 199, + 199, + 199, + 199, + 29, + 202, + 41, + 41, + 150, + 68, + 54, + 287, + 43, + 389, + 348, + 348, + 6, + 6, + 6, + 6, + 6, + 155, + 221, + 221, + 167, + 245, + 11, + 11, + 11, + 345, + 345, + 345, + 345, + 179, + 122, + 375, + 377, + 391, + 175, + 175, + 175, + 175, + 103, + 103, + 103, + 103, + 363, + 363, + 64, + 264, + 258, + 52, + 52, + 52, + 37, + 37, + 384, + 384, + 384, + 383, + 192, + 192, + 14, + 343, + 143, + 143, + 88, + 38, + 322, + 156, + 156, + 381, + 157, + 33, + 33, + 226, + 44, + 211, + 349, + 388, + 388, + 388, + 388, + 388, + 242, + 115, + 115, + 115, + 246, + 334, + 67, + 67, + 67, + 283, + 283, + 283, + 283, + 26, + 305, + 223, + 56, + 56, + 236, + 83, 66, + 208, + 9, + 96, + 47, + 339, + 339, + 339, + 117, + 117, + 308, + 308, + 14, + 14, + 14, + 240, + 301, + 67, + 40, + 160, + 160, + 106, + 120, + 52, + 52, + 39, + 93, + 93, + 93, + 93, + 360, + 360, + 360, + 360, + 230, + 230, + 230, + 186, + 186, + 65, + 178, + 178, + 178, + 173, + 258, + 10, + 250, + 250, + 250, + 250, + 278, + 278, + 274, + 274, + 274, + 39, + 330, + 330, + 330, + 330, + 3, + 3, + 210, + 210, + 263, + 241, + 241, + 298, + 349, + 224, + 224, + 294, + 294, + 75, + 75, + 75, + 75, + 75, + 75, + 210, + 361, + 361, + 361, + 265, + 190, + 190, + 190, + 261, + 349, + 348, + 348, + 348, + 348, 374, - 222, - 222, - 150, - 150, - 150, - 267, - 267, + 374, + 216, + 110, + 232, + 362, + 362, + 362, + 86, + 86, + 303, + 191, + 381, + 381, + 381, + 381, + 399, + 399, + 399, + 60, + 317, + 317, + 317, + 317, + 369, + 369, + 99, + 63, + 238, + 238, + 238, + 238, + 189, + 77, + 332, + 332, + 321, + 394, + 300, + 300, + 300, + 58, + 58, + 58, + 65, + 65, + 65, + 65, + 169, + 169, + 298, + 298, + 47, + 93, + 19, + 19, + 310, + 310, + 159, + 159, + 185, + 185, + 285, + 228, + 228, + 102, + 211, + 211, + 133, + 133, + 133, + 327, + 327, 267, + 25, + 306, + 6, + 176, + 173, + 173, + 33, + 33, + 314, + 314, + 314, + 202, + 261, + 261, + 396, + 289, + 189, + 144, + 144, + 144, + 99, + 99, + 108, + 97, + 97, + 97, + 97, + 236, + 362, + 362, + 257, + 159, + 317, + 317, + 388, + 56, + 260, + 23, + 229, + 229, + 229, + 229, + 109, + 109, + 200, + 8, + 365, + 365, + 365, + 76, + 76, + 283, + 283, + 283, + 78, + 75, + 248, + 248, + 122, + 273, + 227, + 227, + 332, + 242, + 123, + 123, + 123, + 123, + 123, + 18, + 29, + 29, + 47, + 47, + 46, + 46, + 338, + 246, + 321, + 321, + 43, + 36, + 36, + 36, + 36, + 154, + 154, + 124, + 78, + 78, + 78, + 86, + 45, + 45, + 43, + 48, + 48, + 48, + 48, + 48, + 48, + 48, + 239, + 312, + 312, + 274, + 365, + 365, + 64, + 180, + 88, + 353, + 223, + 223, + 148, + 89, + 12, + 12, + 12, + 191, + 191, + 191, + 191, + 201, + 22, + 22, + 22, + 22, + 22, + 132, + 176, + 176, + 351, + 17, + 17, + 235, + 235, + 235, + 235, + 220, + 220, + 220, + 306, + 306, + 395, + 333, + 333, + 228, + 221, + 189, + 145, + 145, + 213, + 213, + 213, + 213, + 213, + 213, + 70, + 5, + 5, + 5, + 286, + 286, + 286, + 145, + 170, + 170, + 170, + 204, + 76, + 162, + 162, + 56, + 332, + 332, + 198, + 198, + 204, + 223, + 223, + 223, + 223, + 223, 267, + 174, + 93, + 30, + 1, + 182, + 182, + 182, + 114, + 114, + 167, + 167, + 167, + 167, + 167, + 167, + 167, + 136, + 136, + 136, + 136, + 136, + 275, + 196, + 196, + 196, + 155, + 155, + 151, + 170, + 170, + 196, + 196, + 196, + 196, + 12, + 87, + 282, + 282, + 245, + 245, + 245, 373, - 373, - 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 - ], - "commands": [ - 2, - 1, - 2, - 1, - 2, - 2, - 2, - 2, - 0, - 1, - 0, - 2, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 1, + 20, + 20, + 20, + 20, + 326, + 268, + 128, + 128, + 128, + 128, + 128, + 302, 1, - 0, 1, - 0, - 0, - 0, - 2, - 2, 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 1, 1, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, 1, + 325, + 358, + 366, + 366, + 389, + 228, + 228, + 221, + 153, + 153, + 363, + 363, + 363, + 25, + 25, + 25, + 148, + 148, + 221, + 221, + 221, + 221, + 221, + 175, + 28, + 28, + 77, + 238, + 101, + 349, + 349, + 125, + 125, + 125, + 171, + 171, + 225, + 225, + 225, + 370, + 370, + 370, + 91, + 338, + 277, + 123, + 187, + 187, + 187, + 361, + 361, + 361, + 361, + 361, + 59, + 166, + 180, + 180, + 282, + 158, + 158, + 214, + 332, + 332, + 22, + 22, + 22, + 22, + 22, + 22, + 30, + 30, + 30, + 30, + 30, + 387, + 143, + 80, + 80, + 385, + 385, + 327, + 133, + 276, + 70, + 321, + 321, + 321, + 321, + 326, + 326, + 184, + 184, + 184, + 184, + 158, + 70, + 187, + 71, + 71, + 71, + 71, + 71, + 71, + 118, + 118, + 114, + 114, + 114, + 114, + 114, + 266, + 266, + 110, + 352, + 168, + 168, + 359, + 359, + 359, + 359, + 359, + 359, + 359, + 359, + 121, + 217, + 217, + 175, + 175, + 175, + 175, + 33, + 398, + 11, + 11, + 382, + 243, + 48, + 271, + 185, + 185, + 176, + 176, + 176, + 276, + 276, + 187, + 161, + 300, + 46, + 46, + 46, + 46, + 47, + 340, + 340, + 340, + 227, + 227, + 86, + 345, + 345, + 256, + 256, + 355, + 209, + 281, + 152, + 360, + 360, + 360, + 360, + 360, + 360, + 151, + 156, + 156, + 377, + 385, + 385, + 305, + 331, + 331, + 176, + 268, + 268, + 232, + 243, + 281, + 281, + 248, + 86, + 86, + 369, + 369, + 362, + 362, + 362, + 264, + 162, + 168, + 168, + 340, + 299, + 299, + 299, + 299, + 263, + 72, + 72, + 72, + 198, + 286, + 215, + 215, + 227, + 227, + 227, + 75, + 75, + 328, + 196, + 190, + 190, + 281, + 319, + 319, + 319, + 7, + 7, + 76, + 76, + 311, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 137, + 137, + 137, + 137, + 229, + 394, + 394, + 394, + 73, + 27, + 27, + 383, + 311, + 311, + 164, + 358, + 358, + 358, + 352, + 352, + 352, + 28, + 28, + 24, + 326, + 233, + 229, + 229, + 229, + 289, + 289, + 289, + 349, + 349, + 349, + 349, + 105, + 3, + 3, + 313, + 313, + 112, + 112, + 112, + 112, + 266, + 147, + 147, + 147, + 121, + 121, + 249, + 249, + 55, + 55, + 55, + 115, + 115, + 115, + 10, + 10, + 22, + 318, + 318, + 318, + 318, + 318, + 318, + 199, + 199, + 199, + 373, + 373, + 373, + 246, + 224, + 50, + 50, + 50, + 351, + 351, + 351, + 351, + 35, + 269, + 54, + 54, + 394, + 394, + 51, + 293, + 120, + 258, + 179, + 179, + 179, + 179, + 179, + 19, + 240, + 240, + 240, + 240, + 196, + 196, + 196, + 196, + 196, + 125, + 400, + 400, + 400, + 400, + 148, + 385, + 385, + 385, + 385, + 385, + 83, + 83, + 83, + 83, + 83, + 262, + 239, + 239, + 239, + 239, + 268, + 9, + 9, + 281, + 281, + 281, + 281, + 301, + 297, + 297, + 297, + 58, + 58, + 58, + 153, + 149, + 169, + 169, + 6, + 6, + 110, + 177, + 177, + 103, + 103, + 103, + 103, + 185, + 342, + 20, + 66, + 122, + 308, + 308, + 195, + 222, + 222, + 222, + 222, + 222, + 379, + 379, + 379, + 362, + 362, + 53, + 301, + 301, + 167, + 167, + 167, + 238, + 238, + 289, + 289, + 208, + 353, + 100, + 29, + 29, + 325, + 325, + 325, + 325, + 325, + 325, + 325, + 391, + 391, + 391, + 159, + 123, + 90, + 257, + 283, + 283, + 109, + 255, + 363, + 299, + 299, + 103, + 11, + 246, + 246, + 104, + 104, + 104, + 104, + 399, + 388, + 388, + 275, + 275, + 275, + 268, + 268, + 191, + 230, + 115, + 115, + 115, + 115, + 115, + 115, + 144, + 345, + 345, + 297, + 173, + 214, + 214, + 75, + 75, + 21, + 399, + 399, + 15, + 15, + 15, + 15, + 10, + 10, + 10, + 237, + 288, + 379, + 270, + 270, + 270, + 270, + 270, + 272, + 272, + 272, + 272, + 358, + 358, + 358, + 39, + 39, + 298, + 253, + 253, + 253, + 400, + 400, + 400, + 156, + 156, + 56, + 279, + 279, + 37, + 37, + 37, + 37, + 150, + 150, + 150, + 150, + 150, + 203, + 49, + 49, + 73, + 141, + 12, + 195, + 195, + 195, + 51, + 18, + 224, + 224, + 375, + 210, + 351, + 380, + 380, + 380, + 361, + 352, + 207, + 207, + 207, + 207, + 83, + 388, + 388, + 388, + 388, + 17, + 17, + 5, + 5, + 337, + 161, + 280, + 280, + 280, + 280, + 338, + 119, + 119, + 38, + 38, + 38, + 292, + 292, + 292, + 292, + 247, + 247, + 247, + 11, + 11, + 188, + 85, + 154, + 154, + 154, + 108, + 108, + 326, + 209, + 335, + 104, + 104, + 104, + 42, + 109, + 109, + 109, + 85, + 85, + 276, + 161, + 206, + 206, + 397, + 133, + 133, + 133, + 133, + 197, + 197, + 197, + 224, + 224, + 224, + 224, + 224, + 77, + 77, + 83, + 99, + 16, + 16, + 167, + 167, + 167, + 149, + 186, + 239, + 142, + 93, + 93, + 93, + 227, + 227, + 227, + 264, + 264, + 264, + 264, + 102, + 111, + 111, + 111, + 111, + 77, + 77, + 57, + 57, + 57, + 152, + 152, + 181, + 139, + 265, + 128, + 128, + 369, + 94, + 94, + 52, + 27, + 27, + 78, + 83, + 83, + 166, + 166, + 195, + 195, + 318, + 5, + 5, + 5, + 5, + 84, + 84, + 84, + 84, + 27, + 132, + 132, + 132, + 132, + 132, + 132, + 132, + 347, + 312, + 179, + 179, + 139, + 218, + 376, + 376, + 376, + 124, + 124, + 376, + 376, + 215, + 215, + 202, + 313, + 313, + 313, + 55, + 55, + 392, + 392, + 392, + 392, + 392, + 392, + 392, + 204, + 204, + 204, + 204, + 355, + 355, + 355, + 136, + 136, + 131, + 131, + 131, + 131, + 144, + 68, + 31, + 31, + 38, + 90, + 90, + 90, + 218, + 291, + 291, + 291, + 328, + 126, + 377, + 377, + 377, + 175, + 175, + 346, + 316, + 316, + 316, + 316, + 316, + 316, + 316, + 316, + 316, + 112, + 112, + 112, + 112, + 293, + 293, + 64, + 51, + 173, + 290, + 290, + 102, + 102, + 230, + 230, + 230, + 59, + 59, + 59, + 59, + 59, + 177, + 8, + 21, + 21, + 273, + 5, + 5, + 5, + 227, + 17, + 302, + 302, + 159, + 28, + 28, + 247, + 376, + 376, + 298, + 298, + 361, + 3, + 139, + 166, + 166, + 166, + 166, + 368, + 232, + 397, + 397, + 397, + 397, + 281, + 136, + 136, + 136, + 150, + 95, + 95, + 345, + 345, + 379, + 379, + 379, + 379, + 379, + 379, + 10, + 10, + 10, + 10, + 10, + 226, 1, - 0, + 126, + 154, + 154, + 342, + 342, + 342, + 342, + 200, + 200, + 200, + 200, + 302, + 68, + 98, + 125, + 350, + 102, + 285, + 209, + 209, + 209, + 209, + 209, + 368, + 368, + 37, + 160, + 254, + 254, + 254, + 368, + 368, + 368, + 166, + 166, + 76, + 28, + 58, + 66, + 66, + 160, + 355, + 31, + 31, + 31, + 31, + 31, + 31, + 361, + 237, + 237, + 56, + 246, + 312, + 363, + 363, + 262, + 367, + 376, + 376, + 108, + 3, + 234, + 234, + 226, + 288, + 288, + 288, + 35, + 35, + 35, + 272, + 293, + 8, + 35, + 35, + 92, + 11, + 305, + 305, + 305, + 319, + 319, + 193, + 193, + 53, + 53, + 112, + 112, + 372, + 83, + 83, + 83, + 131, + 197, + 197, + 336, + 302, + 302, + 302, + 273, + 273, + 297, + 294, + 294, + 80, + 80, + 121, + 397, + 397, + 397, + 397, + 254, + 199, + 199, + 199, + 264, + 264, + 264, + 264, + 264, + 333, + 333, + 333, + 186, + 186, + 186, + 118, + 19, + 19, + 19, + 19, + 19, + 19, + 46, + 396, + 396, + 133, + 133, + 142, + 306, + 327, + 220, + 32, + 32, + 125, + 168, + 168, + 168, + 168, + 63, + 63, + 63, + 63, + 63, + 63, + 56, + 10, + 200, + 236, + 236, + 1, + 129, + 129, + 129, + 145, + 145, + 145, + 145, + 145, + 9, + 9, + 9, + 247, + 247, + 156, + 156, + 310, + 310, + 150, + 150, + 354, + 19, + 19, + 124, + 261, + 261, + 261, + 328, + 328, + 328, + 27, + 376, + 376, + 199, + 199, + 273, + 273, + 6, + 6, + 6, + 6, + 97, + 97, + 308, + 256, + 163, + 233, + 277, + 277, + 277, + 277, + 277, + 305, + 218, + 218, + 141, + 389, + 208, + 208, + 266, + 178, + 178, + 92, + 92, + 397, + 232, + 232, + 232, + 306, + 392, + 392, + 392, + 227, + 52, + 176, + 176, + 120, + 120, + 120, + 120, + 398, + 188, + 188, + 219, + 125, + 81, + 305, + 25, + 25, + 25, + 25, + 14, + 306, + 306, + 306, + 306, + 161, + 161, + 161, + 161, + 161, + 316, + 316, + 383, + 46, + 219, + 219, + 219, + 97, + 97, + 97, + 11, + 11, + 336, + 336, + 61, + 61, + 61, + 61, + 103, + 380, + 380, + 380, + 368, + 80, + 80, + 278, + 278, + 278, + 278, + 371, + 371, + 371, + 371, + 371, + 371, + 272, + 232, + 232, + 147, + 147, + 147, + 131, + 174, + 174, + 174, + 27, + 368, + 368, + 368, + 113, + 113, + 113, + 161, + 346, + 346, + 346, + 241, + 132, + 132, + 223, + 275, + 275, + 275, + 10, + 366, + 366, + 366, + 70, + 70, + 135, + 160, + 160, + 160, + 370, + 370, + 370, + 226, + 255, + 255, + 255, + 255, + 15, + 394, + 304, + 373, + 240, + 240, + 240, + 240, + 240, + 240, + 240, + 221, + 221, + 136, + 240, + 114, + 114, + 114, + 159, + 362, + 160, + 98, + 108, + 108, + 263, + 263, + 263, + 263, + 147, + 147, + 367, + 384, + 372, + 372, + 296, + 341, + 341, + 341, + 305, + 261, + 17, + 125, + 125, + 384, + 384, + 384, + 251, + 153, + 89, + 89, + 89, + 89, + 320, + 320, + 320, + 320, + 320, + 92, + 323, + 371, + 190, + 128, + 52, + 52, + 52, + 94, + 16, + 168, + 35, + 35, + 155, + 155, + 155, + 74, + 149, + 149, + 149, + 217, + 217, + 239, + 170, + 170, + 170, + 222, + 222, + 250, + 188, + 345, + 183, + 215, + 215, + 155, + 155, + 155, + 155, + 25, + 254, + 254, + 254, + 333, + 333, + 333, + 333, + 333, + 198, + 231, + 231, + 231, + 231, + 395, + 387, + 58, + 58, + 58, + 58, + 292, + 215, + 215, + 215, + 177, + 149, + 166, + 166, + 22, + 398, + 399, + 366, + 366, + 51, + 55, + 142, + 142, + 142, + 28, + 28, + 28, + 28, + 28, + 251, + 140, + 140, + 366, + 366, + 274, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 39, + 39, + 301, + 301, + 172, + 172, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 167, + 167, + 167, + 167, + 159, + 382, + 6, + 6, + 6, + 6, + 392, + 392, + 56, + 153, + 126, + 180, + 180, + 374, + 374, + 374, + 244, + 244, + 244, + 265, + 384, + 384, + 247, + 224, + 224, + 224, + 224, + 16, + 16, + 344, + 358, + 358, + 54, + 54, + 54, + 352, + 125, + 125, + 342, + 361, + 361, + 91, + 91, + 344, + 344, + 43, + 327, + 11, + 399, + 147, + 147, + 301, + 301, + 301, + 154, + 154, + 201, + 78, + 78, + 195, + 92, + 180, + 180, + 343, + 343, + 343, + 37, + 392, + 392, + 275, + 275, + 275, + 378, + 363, + 363, + 363, + 363, + 363, + 363, + 363, + 363, + 24, + 293, + 63, + 63, + 155, + 99, + 166, + 167, + 34, + 34, + 273, + 273, + 67, + 67, + 67, + 33, + 33, + 33, + 33, + 33, + 33, + 192, + 123, + 123, + 123, + 123, + 123, + 157, + 345, + 345, + 351, + 351, + 245, + 245, + 245, + 245, + 245, + 363, + 363, + 149, + 149, + 360, + 360, + 252, + 114, + 114, + 114, + 349, + 349, + 349, + 91, + 242, + 71, + 71, + 71, + 71, + 71, + 60, + 277, + 92, + 92, + 92, + 329, + 10, + 10, + 239, + 195, + 195, + 195, + 36, + 182, + 182, + 50, + 50, + 50, + 308, + 308, + 174, + 393, + 33, + 150, + 216, + 21, + 21, + 21, + 119, + 119, + 196, + 182, + 182, + 182, + 182, + 316, + 247, + 56, + 213, + 38, + 38, + 399, + 91, + 91, + 289, + 189, + 374, + 374, + 220, + 220, + 143, + 93, + 320, + 320, + 53, + 287, + 287, + 38, + 38, + 124, + 218, + 13, + 13, + 29, + 29, + 29, + 29, + 29, + 29, + 3, + 3, + 286, + 286, + 344, + 336, + 336, + 177, + 27, + 27, + 117, + 37, + 37, + 37, + 37, + 221, + 221, + 172, + 172, + 172, + 391, + 328, + 328, + 288, + 288, + 369, + 50, + 50, + 50, + 50, + 50, + 50, + 26, + 26, + 254, + 168, + 116, + 350, + 350, + 350, + 339, + 339, + 158, + 342, + 181, + 290, + 326, + 326, + 326, + 82, + 130, + 185, + 185, + 185, + 201, + 201, + 201, + 177, + 177, + 177, + 392, + 392, + 4, + 91, + 240, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 55, + 55, + 315, + 39, + 39, + 190, + 190, + 190, + 349, + 366, + 119, + 119, + 266, + 266, + 317, + 317, + 317, + 38, + 123, + 225, + 225, + 225, + 225, + 226, + 199, + 199, + 26, + 26, + 344, + 169, + 375, + 238, + 238, + 238, + 238, + 152, + 250, + 250, + 250, + 13, + 116, + 116, + 122, + 122, + 122, + 122, + 122, + 122, + 122, + 43, + 43, + 43, + 13, + 13, + 104, + 52, + 52, + 372, + 372, + 9, + 114, + 83, + 83, + 83, + 296, + 296, + 95, + 113, + 57, + 57, + 395, + 395, + 395, + 395, + 374, + 374, + 290, + 260, + 260, + 120, + 120, + 261, + 283, + 283, + 108, + 108, + 108, + 323, + 280, + 69, + 75, + 75, + 91, + 356, + 141, + 266, + 266, + 180, + 180, + 19, + 8, + 315, + 381, + 218, + 218, + 241, + 341, + 355, + 355, + 355, + 59, + 59, + 59, + 59, + 275, + 305, + 305, + 119, + 354, + 354, + 275, + 275, + 217, + 168, + 168, + 301, + 7, + 7, + 7, + 104, + 104, + 255, + 138, + 138, + 138, + 138, + 138, + 138, + 138, + 336, + 197, + 197, + 94, + 94, + 94, + 278, + 278, + 278, + 293, + 293, + 293, + 293, + 365, + 365, + 286, + 147, + 147, + 147, + 147, + 147, + 147, + 133, + 38, + 38, + 38, + 38, + 80, + 257, + 320, + 320, + 320, + 80, + 164, + 164, + 164, + 167, + 167, + 102, + 102, + 21, + 21, + 46, + 46, + 13, + 13, + 47, + 136, + 303, + 303, + 121, + 204, + 204, + 383, + 383, + 383, + 383, + 326, + 62, + 233, + 70, + 331, + 331, + 272, + 272, + 272, + 177, + 177, + 21, + 101, + 101, + 138, + 234, + 234, + 251, + 251, + 283, + 187, + 33, + 33, + 214, + 214, + 125, + 125, + 125, + 18, + 18, + 274, + 274, + 274, + 120, + 242, + 242, + 192, + 68, + 68, + 68, + 378, + 378, + 148, + 134, + 49, + 49, + 49, + 49, + 111, + 111, + 350, + 350, + 204, + 348, + 163, + 383, + 383, + 42, + 42, + 42, + 260, + 260, + 317, + 250, + 148, + 148, + 273, + 273, + 95, + 282, + 313, + 58, + 58, + 217, + 217, + 217, + 235, + 199, + 199, + 199, + 334, + 334, + 334, + 334, + 334, + 100, + 100, + 312, + 312, + 284, + 284, + 22, + 152, + 204, + 204, + 204, + 225, + 225, + 225, + 199, + 199, + 199, + 199, + 199, + 345, + 317, + 317, + 5, + 392, + 392, + 342, + 295, + 295, + 295, + 295, + 135, + 135, + 376, + 227, + 227, + 227, + 227, + 352, + 352, + 352, + 155, + 155, + 263, + 263, + 263, + 263, + 154, + 176, + 176, + 193, + 249, + 117, + 117, + 27, + 27, + 27, + 333, + 333, + 333, + 241, + 241, + 241, + 298, + 298, + 113, + 45, + 45, + 45, + 28, + 280, + 25, + 25, + 272, + 250, + 282, + 282, + 282, + 282, + 215, + 215, + 358, + 269, + 271, + 271, + 271, + 108, + 197, + 197, + 117, + 270, + 270, + 78, + 236, + 225, + 14, + 250, + 82, + 82, + 82, + 131, + 131, + 131, + 27, + 27, + 27, + 27, + 286, + 53, + 53, + 53, + 375, + 375, + 47, + 47, + 47, + 47, + 47, + 294, + 248, + 248, + 248, + 127, + 143, + 144, + 144, + 15, + 185, + 123, + 162, + 69, + 329, + 343, + 343, + 10, + 329, + 329, + 173, + 173, + 173, + 353, + 141, + 141, + 159, + 159, + 159, + 159, + 159, + 178, + 181, + 55, + 119, + 296, + 59, + 184, + 184, + 119, + 275, + 275, + 296, + 296, + 296, + 296, + 129, + 129, + 328, + 396, + 396, + 396, + 41, + 41, + 50, + 50, + 50, + 14, + 14, + 14, + 370, + 254, + 19, + 19, + 19, + 19, + 165, + 362, + 265, + 253, + 253, + 25, + 230, + 162, + 220, + 124, + 124, + 135, + 176, + 63, + 339, + 179, + 87, + 343, + 195, + 195, + 195, + 195, + 225, + 269, + 269, + 102, + 239, + 239, + 212, + 146, + 146, + 146, + 250, + 308, + 132, + 305, + 110, + 299, + 299, + 299, + 299, + 299, + 299, + 72, + 72, + 79, + 79, + 79, + 38, + 244, + 244, + 248, + 248, + 101, + 282, + 282, + 81, + 81, + 81, + 199, + 326, + 169, + 387, + 387, + 186, + 186, + 186, + 196, + 318, + 267, + 273, + 22, + 248, + 61, + 157, + 157, + 157, + 157, + 164, + 164, + 211, + 364, + 364, + 248, + 248, + 393, + 393, + 49, + 210, + 100, + 100, + 100, + 100, + 215, + 183, + 225, + 144, + 165, + 165, + 165, + 70, + 339, + 339, + 239, + 269, + 300, + 148, + 94, + 5, + 5, + 223, + 226, + 226, + 237, + 105, + 186, + 186, + 186, + 262, + 262, + 91, + 91, + 84, + 84, + 241, + 241, + 241, + 77, + 215, + 215, + 215, + 275, + 275, + 275, + 275, + 275, + 117, + 72, + 72, + 72, + 284, + 150, + 9, + 9, + 9, + 9, + 230, + 230, + 230, + 222, + 222, + 222, + 226, + 226, + 226, + 226, + 372, + 372, + 81, + 81, + 302, + 398, + 398, + 156, + 125, + 125, + 261, + 337, + 337, + 198, + 256, + 6, + 90, + 90, + 90, + 246, + 246, + 389, + 64, + 250, + 22, + 379, + 379, + 379, + 379, + 379, + 379, + 379, + 70, + 268, + 277, + 168, + 116, + 235, + 223, + 223, + 271, + 185, + 275, + 50, + 50, + 324, + 324, + 324, + 324, + 324, + 60, + 60, + 90, + 54, + 271, + 383, + 383, + 383, + 383, + 161, + 253, + 253, + 253, + 395, + 395, + 77, + 121, + 124, + 177, + 177, + 262, + 3, + 264, + 343, + 343, + 343, + 242, + 46, + 44, + 116, + 93, + 93, + 93, + 5, + 203, + 11, + 11, + 11, + 11, + 11, + 84, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 277, + 277, + 277, + 7, + 7, + 142, + 142, + 142, + 386, + 250, + 250, + 174, + 174, + 174, + 174, + 349, + 246, + 246, + 259, + 259, + 259, + 259, + 303, + 138, + 138, + 130, + 130, + 130, + 130, + 130, + 198, + 39, + 39, + 18, + 90, + 90, + 297, + 307, + 182, + 137, + 137, + 137, + 136, + 16, + 351, + 184, + 132, + 130, + 130, + 24, + 24, + 24, + 24, + 231, + 343, + 343, + 343, + 343, + 343, + 150, + 45, + 45, + 45, + 45, + 333, + 3, + 3, + 3, + 3, + 188, + 188, + 188, + 188, + 273, + 104, + 104, + 104, + 296, + 177, + 298, + 75, + 75, + 75, + 75, + 75, + 75, + 75, + 244, + 113, + 113, + 113, + 266, + 7, + 17, + 297, + 297, + 125, + 125, + 125, + 183, + 277, + 124, + 271, + 233, + 233, + 233, + 217, + 217, + 217, + 217, + 129, + 8, + 8, + 210, + 162, + 162, + 274, + 274, + 24, + 239, + 237, + 265, + 34, + 34, + 378, + 378, + 378, + 268, + 268, + 268, + 29, + 389, + 144, + 144, + 308, + 176, + 176, + 197, + 197, + 82, + 82, + 190, + 355, + 278, + 278, + 278, + 398, + 398, + 398, + 398, + 115, + 115, + 115, + 115, + 150, + 33, + 33, + 33, + 189, + 189, + 350, + 311, + 311, + 291, + 224, + 224, + 59, + 98, + 98, + 98, + 98, + 98, + 98, + 379, + 380, + 241, + 391, + 391, + 391, + 96, + 96, + 96, + 54, + 323, + 323, + 323, + 391, + 305, + 305, + 75, + 358, + 358, + 358, + 358, + 146, + 42, + 187, + 184, + 271, + 271, + 271, + 113, + 113, + 246, + 195, + 195, + 195, + 379, + 379, + 379, + 379, + 379, + 245, + 130, + 113, + 113, + 113, + 210, + 210, + 327, + 38, + 207, + 207, + 207, + 207, + 207, + 207, + 207, + 207, + 207, + 207, + 172, + 377, + 377, + 377, + 374, + 26, + 26, + 8, + 342, + 258, + 193, + 198, + 198, + 26, + 26, + 26, + 345, + 196, + 196, + 196, + 196, + 196, + 391, + 391, + 354, + 378, + 378, + 378, + 378, + 172, + 172, + 172, + 172, + 172, + 172, + 172, + 172, + 136, + 136, + 136, + 377, + 4, + 4, + 385, + 277, + 149, + 31, + 31, + 99, + 99, + 99, + 43, + 14, + 14, + 226, + 2, + 2, + 148, + 83, + 374, + 184, + 184, + 184, + 274, + 274, + 274, + 6, + 6, + 6, + 6, + 346, + 346, + 346, + 204, + 204, + 88, + 88, + 88, + 56, + 56, + 163, + 277, + 277, + 277, + 277, + 202, + 202, + 202, + 202, + 78, + 22, + 383, + 383, + 260, + 389, + 389, + 389, + 389, + 167, + 30, + 30, + 3, + 1, + 1, + 1, + 246, + 56, + 56, + 56, + 322, + 322, + 322, + 322, + 322, + 322, + 362, + 362, + 362, + 128, + 395, + 377, + 218, + 54, + 54, + 39, + 39, + 213, + 199, + 199, + 199, + 199, + 199, + 199, + 205, + 205, + 186, + 206, + 341, + 341, + 341, + 341, + 282, + 282, + 282, + 326, + 222, + 222, + 222, + 222, + 222, + 180, + 355, + 355, + 355, + 150, + 266, + 119, + 389, + 389, + 383, + 196, + 324, + 7, + 48, + 270, + 58, + 58, + 31, + 211, + 66, + 66, + 66, + 330, + 159, + 159, + 60, + 60, + 370, + 370, + 370, + 370, + 370, + 370, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 187, + 176, + 215, + 50, + 186, + 258, + 258, + 203, + 151, + 5, + 5, + 5, + 75, + 380, + 316, + 371, + 161, + 161, + 399, + 139, + 64, + 232, + 232, + 265, + 110, + 155, + 155, + 56, + 367, + 300, + 300, + 175, + 123, + 257, + 257, + 257, + 369, + 380, + 102, + 68, + 112, + 112, + 312, + 145, + 277, + 212, + 68, + 243, + 151, + 151, + 157, + 157, + 157, + 163, + 339, + 256, + 256, + 256, + 16, + 253, + 332, + 332, + 349, + 349, + 178, + 178, + 311, + 24, + 24, + 24, + 24, + 252, + 252, + 10, + 10, + 281, + 281, + 281, + 281, + 232, + 340, + 397, + 397, + 397, + 397, + 397, + 397, + 397, + 5, + 5, + 5, + 167, + 167, + 98, + 170, + 170, + 225, + 225, + 208, + 70, + 328, + 177, + 129, + 129, + 24, + 24, + 24, + 24, + 155, + 155, + 214, + 386, + 394, + 33, + 33, + 254, + 254, + 254, + 214, + 146, + 96, + 96, + 96, + 96, + 228, + 228, + 178, + 109, + 109, + 261, + 261, + 261, + 261, + 133, + 90, + 90, + 90, + 41, + 41, + 214, + 392, + 392, + 36, + 36, + 230, + 380, + 380, + 380, + 380, + 380, + 380, + 380, + 356, + 356, + 174, + 27, + 239, + 260, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 191, + 191, + 208, + 208, + 208, + 208, + 363, + 283, + 283, + 57, + 57, + 373, + 276, + 276, + 276, + 276, + 276, + 286, + 245, + 245, + 245, + 245, + 230, + 55, + 151, + 151, + 151, + 151, + 327, + 357, + 357, + 357, + 357, + 357, + 206, + 206, + 45, + 228, + 331, + 85, + 85, + 85, + 248, + 248, + 248, + 269, + 46, + 214, + 164, + 299, + 299, + 251, + 251, + 251, + 146, + 146, + 146, + 140, + 140, + 301, + 301, + 301, + 188, + 47, + 47, + 47, + 47, + 47, + 53, + 336, + 336, + 296, + 189, + 189, + 189, + 189, + 157, + 157, + 18, + 18, + 18, + 121, + 386, + 386, + 386, + 192, + 116, + 138, + 302, + 86, + 92, + 295, + 385, + 385, + 182, + 63, + 353, + 353, + 60, + 60, + 60, + 207, + 287, + 215, + 215, + 275, + 275, + 275, + 275, + 275, + 275, + 234, + 234, + 256, + 256, + 280, + 280, + 337, + 337, + 104, + 104, + 195, + 195, + 195, + 195, + 195, + 195, + 64, + 337, + 337, + 253, + 253, + 253, + 253, + 253, + 253, + 253, + 346, + 346, + 346, + 346, + 346, + 207, + 78, + 204, + 253, + 253, + 371, + 371, + 371, + 352, + 203, + 203, + 142, + 142, + 142, + 142, + 142, + 70, + 70, + 70, + 280, + 214, + 261, + 229, + 76, + 181, + 181, + 194, + 335, + 158, + 158, + 233, + 233, + 233, + 233, + 299, + 299, + 299, + 299, + 249, + 249, + 77, + 262, + 267, + 4, + 4, + 4, + 165, + 165, + 101, + 101, + 246, + 57, + 57, + 245, + 71, + 71, + 231, + 231, + 231, + 108, + 108, + 108, + 108, + 108, + 162, + 111, + 262, + 262, + 262, + 43, + 43, + 314, + 314, + 314, + 210, + 366, + 366, + 366, + 366, + 366, + 366, + 57, + 57, + 268, + 119, + 268, + 287, + 287, + 287, + 151, + 151, + 151, + 151, + 266, + 217, + 285, + 285, + 247, + 247, + 247, + 247, + 387, + 63, + 212, + 285, + 285, + 85, + 85, + 85, + 205, + 205, + 365, + 365, + 122, + 291, + 184, + 176, + 226, + 37, + 37, + 180, + 180, + 47, + 47, + 164, + 95, + 95, + 95, + 95, + 95, + 95, + 379, + 379, + 379, + 341, + 341, + 341, + 47, + 47, + 105, + 105, + 105, + 192, + 192, + 396, + 316, + 316, + 316, + 95, + 95, + 302, + 302, + 302, + 156, + 156, + 264, + 225, + 225, + 243, + 243, + 243, + 243, + 243, + 29, + 284, + 309, + 309, + 309, + 135, + 79, + 79, + 262, + 262, + 186, + 186, + 186, + 121, + 121, + 121, + 121, + 101, + 68, + 174, + 174, + 174, + 174, + 394, + 204, + 249, + 249, + 295, + 116, + 116, + 116, + 116, + 184, + 282, + 115, + 115, + 115, + 115, + 115, + 230, + 230, + 230, + 230, + 230, + 336, + 122, + 241, + 53, + 309, + 309, + 309, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 16, + 344, + 344, + 344, + 145, + 254, + 62, + 176, + 176, + 176, + 176, + 103, + 103, + 231, + 16, + 16, + 381, + 381, + 381, + 381, + 86, + 204, + 25, + 341, + 341, + 341, + 341, + 184, + 184, + 284, + 84, + 84, + 98, + 28, + 377, + 373, + 373, + 373, + 373, + 288, + 288, + 353, + 186, + 186, + 228, + 228, + 228, + 69, + 69, + 398, + 156, + 156, + 156, + 262, + 262, + 26, + 26, + 43, + 326, + 398, + 398, + 284, + 284, + 281, + 281, + 31, + 31, + 217, + 332, + 332, + 332, + 332, + 70, + 302, + 60, + 60, + 60, + 60, + 276, + 313, + 313, + 32, + 173, + 173, + 211, + 315, + 315, + 188, + 118, + 118, + 118, + 94, + 94, + 386, + 386, + 386, + 386, + 114, + 114, + 114, + 114, + 114, + 231, + 31, + 335, + 335, + 335, + 344, + 38, + 368, + 368, + 368, + 368, + 368, + 368, + 61, + 278, + 225, + 36, + 36, + 36, + 36, + 148, + 342, + 20, + 20, + 294, + 294, + 180, + 180, + 180, + 180, + 153, + 153, + 278, + 278, + 278, + 386, + 225, + 225, + 310, + 323, + 156, + 34, + 182, + 339, + 40, + 57, + 57, + 218, + 209, + 209, + 180, + 180, + 230, + 142, + 142, + 142, + 142, + 6, + 276, + 276, + 18, + 336, + 137, + 137, + 344, + 344, + 217, + 364, + 389, + 20, + 20, + 289, + 289, + 218, + 218, + 218, + 392, + 392, + 392, + 392, + 392, + 239, + 239, + 239, + 239, + 239, + 206, + 206, + 206, + 271, + 271, + 346, + 346, + 346, + 375, + 375, + 375, + 375, + 375, + 375, + 386, + 243, + 276, + 370, + 33, + 33, + 12, + 12, + 165, + 209, + 130, + 146, + 283, + 57, + 57, + 255, + 308, + 13, + 13, + 64, + 64, + 64, + 64, + 293, + 293, + 114, + 242, + 383, + 243, + 124, + 377, + 278, + 278, + 187, + 154, + 320, + 320, + 274, + 181, + 181, + 114, + 114, + 303, + 119, + 119, + 119, + 214, + 322, + 256, + 336, + 109, + 280, + 280, + 280, + 280, + 280, + 124, + 124, + 353, + 381, + 101, + 101, + 362, + 5, + 5, + 5, + 5, + 315, + 50, + 280, + 217, + 217, + 33, + 34, + 34, + 34, + 34, + 34, + 329, + 283, + 283, + 283, + 283, + 16, + 16, + 16, + 238, + 238, + 238, + 332, + 57, + 221, + 342, + 79, + 155, + 155, + 388, + 76, + 197, + 197, + 66, + 66, + 66, + 66, + 223, + 223, + 303, + 303, + 303, + 303, + 303, + 211, + 211, + 78, + 78, + 78, + 180, + 180, + 166, + 130, + 311, + 311, + 311, + 311, + 311, + 311, + 311, + 137, + 302, + 302, + 302, + 138, + 56, + 90, + 90, + 90, + 90, + 90, + 90, + 299, + 340, + 229, + 55, + 288, + 320, + 268, + 262, + 262, + 262, + 262, + 262, + 262, + 232, + 112, + 246, + 246, + 246, + 121, + 121, + 224, + 224, + 224, + 224, + 224, + 224, + 399, + 399, + 399, + 214, + 214, + 270, + 270, + 316, + 316, + 49, + 49, + 107, + 107, + 107, + 314, + 314, + 222, + 299, + 299, + 312, + 312, + 213, + 289, + 289, + 289, + 253, + 203, + 203, + 312, + 312, + 312, + 312, + 312, + 160, + 97, + 8, + 8, + 8, + 160, + 400, + 189, + 189, + 189, + 21, + 300, + 300, + 300, + 308, + 155, + 328, + 328, + 328, + 33, + 253, + 381, + 381, + 262, + 242, + 242, + 329, + 329, + 329, + 340, + 182, + 182, + 164, + 164, + 240, + 384, + 8, + 83, + 83, + 236, + 231, + 199, + 199, + 199, + 199, + 116, + 123, + 299, + 299, + 18, + 18, + 80, + 290, + 290, + 177, + 177, + 177, + 309, + 309, + 309, + 218, + 218, + 321, + 321, + 321, + 163, + 301, + 301, + 301, + 301, + 204, + 77, + 23, + 361, + 216, + 216, + 216, + 199, + 199, + 199, + 199, + 238, + 128, + 128, + 132, + 207, + 396, + 189, + 285, + 285, + 285, + 376, + 304, + 304, + 72, + 72, + 72, + 72, + 106, + 106, + 201, + 87, + 87, + 87, + 87, + 87, + 87, + 282, + 265, + 121, + 316, + 316, + 316, + 104, + 38, + 38, + 38, + 38, + 168, + 168, + 168, + 4, + 4, + 4, + 37, + 285, + 285, + 121, + 121, + 121, + 278, + 278, + 278, + 278, + 188, + 259, + 316, + 364, + 150, + 53, + 53, + 284, + 284, + 167, + 167, + 120, + 120, + 330, + 330, + 330, + 330, + 129, + 379, + 149, + 149, + 131, + 131, + 131, + 32, + 246, + 348, + 348, + 371, + 371, + 255, + 267, + 163, + 111, + 195, + 377, + 377, + 109, + 109, + 400, + 400, + 400, + 400, + 400, + 359, + 359, + 201, + 201, + 201, + 201, + 201, + 201, + 312, + 66, + 66, + 77, + 33, + 130, + 231, + 231, + 231, + 162, + 221, + 221, + 52, + 52, + 326, + 80, + 63, + 63, + 63, + 267, + 287, + 287, + 287, + 287, + 287, + 287, + 190, + 50, + 50, + 50, + 50, + 360, + 277, + 277, + 277, + 255, + 292, + 292, + 222, + 222, + 222, + 222, + 222, + 182, + 182, + 182, + 182, + 223, + 32, + 30, + 30, + 136, + 111, + 111, + 111, + 111, + 297, + 130, + 255, + 118, + 118, + 118, + 182, + 182, + 182, + 182, + 158, + 158, + 323, + 144, + 144, + 103, + 254, + 303, + 303, + 303, + 303, + 167, + 29, + 29, + 29, + 29, + 29, + 168, + 139, + 139, + 139, + 139, + 58, + 369, + 369, + 147, + 132, + 26, + 286, + 286, + 286, + 286, + 202, + 352, + 196, + 196, + 39, + 39, + 153, + 153, + 241, + 143, + 143, + 143, + 117, + 117, + 117, + 117, + 117, + 397, + 288, + 290, + 370, + 370, + 370, + 19, + 131, + 269, + 269, + 77, + 77, + 86, + 228, + 241, + 241, + 241, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 166, + 166, + 166, + 166, + 166, + 166, + 339, + 78, + 72, + 140, + 116, + 134, + 134, + 134, + 148, + 148, + 148, + 148, + 148, + 148, + 335, + 127, + 127, + 127, + 127, + 321, + 321, + 321, + 364, + 168, + 168, + 168, + 168, + 168, + 168, + 295, + 295, + 246, + 205, + 205, + 363, + 260, + 260, + 260, + 1, + 1, + 1, + 1, + 1, + 1, + 21, + 257, + 257, + 257, + 48, + 48, + 174, + 367, + 68, + 71, + 71, + 71, + 71, + 17, + 363, + 50, + 271, + 185, + 353, + 353, + 353, + 134, + 267, + 372, + 372, + 372, + 370, + 134, + 354, + 354, + 373, + 347, + 347, + 347, + 347, + 347, + 347, + 347, + 347, + 347, + 217, + 217, + 217, + 217, + 217, + 9, + 352, + 102, + 102, + 97, + 97, + 97, + 369, + 70, + 400, + 320, + 13, + 13, + 13, + 143, + 217, + 359, + 359, + 359, + 359, + 359, + 359, + 257, + 243, + 243, + 243, + 243, + 73, + 73, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 271, + 331, + 331, + 331, + 367, + 367, + 367, + 58, + 58, + 238, + 163, + 33, + 171, + 171, + 171, + 171, + 171, + 171, + 171, + 103, + 360, + 183, + 183, + 183, + 183, + 235, + 235, + 232, + 232, + 12, + 12, + 12, + 12, + 302, + 302, + 302, + 302, + 110, + 110, + 237, + 121, + 242, + 157, + 371, + 371, + 371, + 371, + 371, + 322, + 30, + 77, + 123, + 380, + 80, + 80, + 80, + 80, + 72, + 72, + 72, + 235, + 235, + 398, + 199, + 274, + 274, + 339, + 89, + 228, + 312, + 312, + 312, + 312, + 69, + 69, + 59, + 59, + 59, + 59, + 59, + 148, + 364, + 234, + 234, + 302, + 375, + 102, + 312, + 172, + 55, + 55, + 55, + 55, + 247, + 122, + 122, + 357, + 38, + 38, + 119, + 119, + 195, + 35, + 35, + 35, + 243, + 243, + 243, + 261, + 261, + 86, + 246, + 275, + 275, + 335, + 202, + 202, + 173, + 292, + 292, + 292, + 292, + 292, + 135, + 381, + 278, + 278, + 278, + 256, + 364, + 364, + 109, + 184, + 276, + 276, + 39, + 76, + 76, + 76, + 76, + 76, + 76, + 192, + 25, + 25, + 25, + 3, + 137, + 208, + 164, + 164, + 53, + 53, + 394, + 130, + 258, + 258, + 327, + 327, + 327, + 213, + 49, + 247, + 223, + 223, + 171, + 43, + 43, + 174, + 174, + 174, + 174, + 159, + 20, + 354, + 354, + 329, + 329, + 195, + 270, + 175, + 78, + 129, + 387, + 252, + 76, + 76, + 259, + 172, + 172, + 172, + 37, + 364, + 364, + 364, + 364, + 172, + 172, + 172, + 240, + 161, + 234, + 234, + 118, + 118, + 118, + 118, + 118, + 118, + 36, + 36, + 25, + 25, + 171, + 171, + 121, + 267, + 267, + 300, + 274, + 20, + 20, + 113, + 113, + 174, + 174, + 174, + 174, + 174, + 174, + 300, + 216, + 216, + 201, + 201, + 390, + 390, + 291, + 149, + 351, + 297, + 297, + 297, + 182, + 182, + 182, + 182, + 182, + 182, + 182, + 182, + 182, + 153, + 266, + 154, + 154, + 117, + 117, + 117, + 258, + 258, + 339, + 339, + 339, + 339, + 339, + 339, + 30, + 392, + 392, + 392, + 294, + 84, + 84, + 84, + 227, + 227, + 362, + 362, + 308, + 99, + 278, + 27, + 154, + 154, + 81, + 81, + 76, + 76, + 76, + 272, + 272, + 172, + 161, + 161, + 234, + 103, + 108, + 66, + 66, + 66, + 349, + 349, + 349, + 349, + 196, + 291, + 137, + 137, + 137, + 93, + 29, + 29, + 141, + 278, + 266, + 266, + 92, + 92, + 92, + 62, + 62, + 162, + 106, + 106, + 254, + 254, + 351, + 360, + 160, + 243, + 243, + 225, + 351, + 373, + 373, + 89, + 160, + 160, + 271, + 296, + 296, + 347, + 347, + 318, + 234, + 234, + 234, + 358, + 262, + 179, + 179, + 239, + 239, + 239, + 239, + 239, + 44, + 152, + 211, + 329, + 131, + 131, + 131, + 364, + 364, + 364, + 364, + 237, + 145, + 152, + 152, + 152, + 214, + 191, + 191, + 191, + 124, + 41, + 161, + 161, + 161, + 161, + 93, + 93, + 93, + 398, + 398, + 313, + 366, + 366, + 73, + 222, + 17, + 17, + 17, + 293, + 348, + 304, + 304, + 322, + 153, + 153, + 65, + 65, + 178, + 387, + 387, + 387, + 387, + 254, + 339, + 339, + 339, + 230, + 230, + 230, + 230, + 137, + 137, + 137, + 154, + 154, + 286, + 286, + 177, + 177, + 83, + 83, + 318, + 149, + 149, + 149, + 73, + 73, + 278, + 362, + 362, + 399, + 385, + 177, + 320, + 320, + 320, + 320, + 194, + 144, + 210, + 210, + 32, + 228, + 321, + 386, + 386, + 386, + 386, + 157, + 360, + 360, + 360, + 360, + 360, + 200, + 200, + 200, + 200, + 155, + 210, + 210, + 210, + 23, + 23, + 23, + 117, + 117, + 319, + 319, + 153, + 153, + 66, + 295, + 295, + 295, + 165, + 165, + 231, + 231, + 231, + 231, + 198, + 396, + 26, + 26, + 223, + 330, + 123, + 123, + 123, + 272, + 272, + 272, + 38, + 38, + 316, + 1, + 1, + 100, + 100, + 100, + 100, + 264, + 264, + 398, + 398, + 398, + 19, + 19, + 19, + 19, + 19, + 304, + 70, + 23, + 23, + 311, + 348, + 348, + 349, + 349, + 349, + 349, + 349, + 349, + 349, + 237, + 237, + 237, + 237, + 237, + 337, + 229, + 229, + 229, + 229, + 236, + 160, + 160, + 49, + 280, + 280, + 42, + 42, + 42, + 256, + 127, + 126, + 126, + 126, + 219, + 214, + 341, + 341, + 341, + 285, + 285, + 285, + 285, + 112, + 112, + 112, + 112, + 26, + 280, + 22, + 240, + 240, + 278, + 278, + 278, + 299, + 299, + 223, + 223, + 223, + 102, + 266, + 277, + 277, + 277, + 250, + 250, + 250, + 250, + 100, + 374, + 109, + 109, + 109, + 109, + 109, + 109, + 202, + 332, + 332, + 332, + 332, + 323, + 186, + 186, + 109, + 70, + 197, + 272, + 272, + 329, + 329, + 337, + 337, + 198, + 198, + 198, + 208, + 56, + 193, + 342, + 342, + 342, + 342, + 75, + 75, + 167, + 80, + 98, + 382, + 382, + 382, + 382, + 382, + 349, + 362, + 238, + 221, + 221, + 216, + 216, + 92, + 92, + 227, + 227, + 351, + 351, + 351, + 351, + 343, + 222, + 230, + 214, + 214, + 214, + 214, + 214, + 214, + 383, + 383, + 179, + 179, + 62, + 62, + 62, + 62, + 1, + 1, + 303, + 303, + 165, + 165, + 165, + 16, + 16, + 318, + 318, + 318, + 310, + 350, + 350, + 350, + 350, + 350, + 350, + 350, + 313, + 313, + 26, + 26, + 34, + 34, + 180, + 180, + 180, + 175, + 315, + 315, + 33, + 33, + 151, + 171, + 6, + 101, + 165, + 394, + 206, + 260, + 260, + 260, + 260, + 260, + 260, + 252, + 36, + 36, + 36, + 36, + 36, + 118, + 118, + 118, + 391, + 391, + 17, + 177, + 177, + 177, + 334, + 334, + 334, + 396, + 396, + 269, + 355, + 301, + 394, + 394, + 394, + 348, + 348, + 246, + 364, + 364, + 374, + 109, + 109, + 109, + 329, + 329, + 15, + 362, + 362, + 110, + 207, + 251, + 126, + 170, + 170, + 365, + 233, + 397, + 255, + 197, + 197, + 197, + 379, + 379, + 379, + 379, + 225, + 45, + 45, + 217, + 217, + 217, + 217, + 86, + 147, + 358, + 167, + 167, + 167, + 37, + 37, + 37, + 37, + 37, + 386, + 386, + 113, + 113, + 113, + 358, + 358, + 103, + 353, + 123, + 123, + 123, + 123, + 123, + 144, + 145, + 145, + 70, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 105, + 105, + 105, + 105, + 169, + 169, + 169, + 107, + 107, + 107, + 107, + 107, + 398, + 212, + 212, + 212, + 185, + 185, + 194, + 194, + 194, + 194, + 194, + 148, + 174, + 334, + 334, + 18, + 18, + 18, + 247, + 247, + 26, + 314, + 141, + 173, + 173, + 173, + 341, + 23, + 23, + 36, + 36, + 367, + 367, + 367, + 308, + 308, + 308, + 308, + 308, + 308, + 228, + 360, + 87, + 332, + 332, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 191, + 191, + 154, + 154, + 154, + 66, + 57, + 4, + 123, + 123, + 163, + 163, + 357, + 226, + 108, + 108, + 151, + 151, + 151, + 151, + 380, + 384, + 346, + 186, + 186, + 161, + 275, + 182, + 182, + 182, + 9, + 9, + 357, + 357, + 357, + 323, + 5, + 5, + 208, + 235, + 235, + 131, + 307, + 247, + 13, + 13, + 13, + 13, + 13, + 287, + 287, + 140, + 140, + 140, + 86, + 112, + 86, + 86, + 28, + 28, + 28, + 256, + 256, + 256, + 256, + 111, + 111, + 287, + 287, + 287, + 287, + 323, + 323, + 323, + 142, + 142, + 142, + 4, + 67, + 236, + 236, + 324, + 21, + 21, + 276, + 280, + 280, + 280, + 298, + 295, + 194, + 194, + 194, + 173, + 286, + 41, + 223, + 223, + 343, + 69, + 193, + 193, + 204, + 136, + 54, + 54, + 337, + 337, + 337, + 165, + 8, + 8, + 8, + 8, + 8, + 349, + 349, + 349, + 349, + 349, + 349, + 58, + 58, + 58, + 6, + 104, + 169, + 169, + 105, + 105, + 365, + 365, + 375, + 375, + 29, + 29, + 29, + 29, + 319, + 354, + 122, + 122, + 15, + 15, + 15, + 212, + 212, + 186, + 295, + 132, + 90, + 90, + 90, + 53, + 84, + 252, + 252, + 252, + 250, + 250, + 380, + 380, + 380, + 384, + 384, + 335, + 256, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 320, + 395, + 256, + 30, + 162, + 162, + 247, + 247, + 309, + 309, + 301, + 301, + 119, + 399, + 305, + 50, + 50, + 50, + 50, + 50, + 46, + 46, + 46, + 190, + 97, + 97, + 44, + 399, + 193, + 156, + 331, + 178, + 178, + 178, + 178, + 178, + 178, + 178, + 141, + 141, + 11, + 48, + 24, + 44, + 44, + 44, + 75, + 75, + 22, + 119, + 86, + 86, + 86, + 126, + 207, + 142, + 67, + 67, + 67, + 67, + 67, + 67, + 225, + 225, + 360, + 20, + 88, + 195, + 195, + 257, + 58, + 217, + 217, + 217, + 217, + 251, + 183, + 377, + 377, + 377, + 321, + 321, + 73, + 125, + 391, + 391, + 300, + 300, + 300, + 300, + 2, + 2, + 2, + 338, + 298, + 298, + 360, + 12, + 57, + 57, + 57, + 57, + 57, + 171, + 171, + 92, + 92, + 92, + 92, + 210, + 210, + 215, + 139, + 149, + 130, + 130, + 342, + 342, + 99, + 378, + 378, + 378, + 378, + 378, + 378, + 167, + 84, + 84, + 155, + 155, + 139, + 389, + 190, + 190, + 14, + 14, + 289, + 289, + 289, + 325, + 325, + 235, + 235, + 235, + 235, + 235, + 235, + 235, + 235, + 42, + 42, + 265, + 394, + 394, + 64, + 64, + 325, + 325, + 325, + 28, + 28, + 28, + 28, + 2, + 120, + 120, + 145, + 389, + 389, + 389, + 389, + 389, + 41, + 41, + 41, + 41, + 70, + 70, + 396, + 216, + 280, + 280, + 280, + 280, + 161, + 161, + 161, + 51, + 259, + 292, + 359, + 359, + 359, + 359, + 359, + 28, + 28, + 361, + 70, + 224, + 350, + 216, + 95, + 113, + 113, + 157, + 157, + 116, + 116, + 342, + 342, + 342, + 365, + 365, + 321, + 307, + 279, + 279, + 279, + 73, + 177, + 177, + 172, + 128, + 128, + 236, + 109, + 84, + 349, + 116, + 114, + 114, + 114, + 114, + 114, + 182, + 182, + 294, + 112, + 112, + 218, + 261, + 115, + 111, + 111, + 375, + 67, + 25, + 25, + 188, + 336, + 336, + 255, + 255, + 340, + 340, + 18, + 238, + 238, + 238, + 351, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 361, + 344, + 344, + 400, + 177, + 177, + 357, + 146, + 57, + 57, + 351, + 351, + 351, + 351, + 351, + 351, + 351, + 351, + 364, + 364, + 102, + 308, + 138, + 321, + 321, + 207, + 207, + 208, + 208, + 252, + 397, + 397, + 139, + 139, + 139, + 207, + 181, + 181, + 181, + 181, + 181, + 217, + 217, + 217, + 217, + 217, + 296, + 296, + 296, + 296, + 296, + 26, + 26, + 52, + 382, + 382, + 203, + 203, + 349, + 349, + 279, + 279, + 145, + 145, + 145, + 355, + 355, + 218, + 49, + 49, + 49, + 310, + 254, + 140, + 140, + 140, + 140, + 137, + 137, + 137, + 325, + 163, + 163, + 279, + 126, + 126, + 126, + 267, + 213, + 220, + 164, + 164, + 62, + 254, + 130, + 323, + 60, + 125, + 125, + 207, + 207, + 284, + 109, + 241, + 241, + 241, + 241, + 346, + 346, + 346, + 306, + 306, + 140, + 156, + 147, + 198, + 339, + 108, + 108, + 108, + 366, + 366, + 366, + 366, + 309, + 400, + 238, + 238, + 72, + 349, + 349, + 394, + 394, + 394, + 120, + 120, + 120, + 94, + 237, + 375, + 375, + 102, + 198, + 13, + 129, + 109, + 109, + 196, + 190, + 190, + 114, + 114, + 114, + 121, + 121, + 361, + 308, + 136, + 222, + 222, + 222, + 222, + 222, + 55, + 68, + 68, + 68, + 386, + 385, + 172, + 172, + 156, + 156, + 361, + 26, + 26, + 26, + 26, + 26, + 114, + 114, + 158, + 219, + 341, + 341, + 89, + 266, + 321, + 321, + 321, + 321, + 383, + 383, + 383, + 383, + 383, + 383, + 162, + 162, + 398, + 6, + 42, + 37, + 37, + 37, + 256, + 256, + 384, + 69, + 69, + 69, + 69, + 69, + 69, + 69, + 216, + 46, + 46, + 91, + 151, + 221, + 221, + 141, + 141, + 141, + 141, + 141, + 141, + 18, + 306, + 306, + 306, + 306, + 306, + 336, + 311, + 142, + 269, + 213, + 302, + 302, + 190, + 190, + 191, + 184, + 370, + 370, + 351, + 319, + 319, + 319, + 319, + 165, + 279, + 390, + 128, + 307, + 222, + 252, + 252, + 252, + 252, + 252, + 21, + 21, + 241, + 355, + 355, + 355, + 60, + 203, + 124, + 11, + 149, + 149, + 149, + 149, + 357, + 357, + 357, + 126, + 149, + 149, + 149, + 149, + 149, + 360, + 343, + 206, + 361, + 361, + 361, + 178, + 104, + 104, + 104, + 104, + 104, + 104, + 125, + 125, + 268, + 268, + 69, + 232, + 176, + 176, + 176, + 176, + 176, + 192, + 192, + 192, + 321, + 334, + 290, + 165, + 2, + 2, + 31, + 31, + 179, + 179, + 179, + 179, + 179, + 179, + 179, + 179, + 115, + 341, + 341, + 163, + 163, + 163, + 95, + 95, + 45, + 23, + 29, + 238, + 243, + 243, + 146, + 291, + 142, + 317, + 383, + 119, + 119, + 46, + 360, + 55, + 30, + 30, + 30, + 30, + 30, + 71, + 71, + 204, + 204, + 204, + 113, + 113, + 113, + 113, + 50, + 50, + 385, + 338, + 338, + 202, + 316, + 309, + 309, + 295, + 220, + 57, + 63, + 63, + 388, + 255, + 348, + 306, + 306, + 306, + 150, + 119, + 400, + 397, + 391, + 391, + 391, + 322, + 322, + 198, + 56, + 56, + 272, + 272, + 272, + 272, + 192, + 389, + 389, + 204, + 67, + 46, + 46, + 46, + 213, + 213, + 213, + 134, + 11, + 11, + 183, + 183, + 183, + 183, + 235, + 235, + 235, + 389, + 389, + 389, + 357, + 357, + 357, + 357, + 67, + 143, + 350, + 350, + 350, + 394, + 354, + 354, + 180, + 180, + 180, + 180, + 180, + 180, + 116, + 116, + 116, + 41, + 192, + 192, + 192, + 192, + 83, + 83, + 93, + 314, + 314, + 257, + 38, + 284, + 238, + 4, + 4, + 4, + 4, + 4, + 383, + 383, + 383, + 383, + 22, + 22, + 37, + 57, + 57, + 357, + 153, + 195, + 255, + 19, + 19, + 19, + 13, + 13, + 21, + 192, + 211, + 211, + 54, + 54, + 256, + 169, + 169, + 169, + 169, + 395, + 395, + 163, + 163, + 163, + 163, + 28, + 28, + 4, + 346, + 346, + 341, + 297, + 212, + 212, + 46, + 46, + 207, + 271, + 271, + 271, + 100, + 100, + 100, + 100, + 100, + 230, + 292, + 134, + 134, + 238, + 238, + 233, + 233, + 204, + 204, + 204, + 112, + 129, + 271, + 103, + 375, + 375, + 18, + 18, + 26, + 26, + 8, + 90, + 273, + 169, + 169, + 308, + 246, + 246, + 246, + 246, + 246, + 342, + 342, + 204, + 148, + 123, + 39, + 39, + 39, + 39, + 270, + 104, + 104, + 110, + 110, + 97, + 97, + 400, + 400, + 400, + 400, + 351, + 351, + 301, + 301, + 301, + 301, + 301, + 226, + 226, + 226, + 87, + 170, + 376, + 376, + 376, + 383, + 196, + 241, + 107, + 371, + 371, + 371, + 328, + 328, + 328, + 5, + 5, + 322, + 375, + 375, + 274, + 274, + 152, + 303, + 37, + 37, + 129, + 129, + 129, + 64, + 18, + 18, + 18, + 290, + 290, + 290, + 290, + 290, + 64, + 64, + 64, + 64, + 131, + 155, + 155, + 1, + 348, + 348, + 348, + 233, + 147, + 215, + 211, + 211, + 211, + 211, + 211, + 211, + 222, + 222, + 222, + 222, + 222, + 222, + 351, + 351, + 351, + 351, + 351, + 351, + 367, + 385, + 385, + 27, + 27, + 349, + 349, + 349, + 166, + 375, + 253, + 71, + 78, + 78, + 78, + 78, + 78, + 26, + 26, + 26, + 259, + 259, + 259, + 313, + 104, + 176, + 309, + 309, + 309, + 150, + 323, + 291, + 373, + 123, + 123, + 123, + 123, + 123, + 123, + 123, + 171, + 73, + 236, + 236, + 382, + 305, + 305, + 305, + 166, + 386, + 386, + 206, + 206, + 14, + 14, + 353, + 242, + 150, + 150, + 191, + 191, + 84, + 263, + 105, + 158, + 158, + 73, + 73, + 73, + 357, + 159, + 159, + 335, + 335, + 353, + 16, + 150, + 301, + 143, + 145, + 145, + 145, + 145, + 172, + 172, + 172, + 146, + 146, + 7, + 7, + 7, + 373, + 360, + 360, + 351, + 351, + 351, + 111, + 111, + 111, + 111, + 111, + 197, + 29, + 29, + 29, + 29, + 343, + 263, + 134, + 134, + 227, + 232, + 232, + 260, + 260, + 270, + 270, + 268, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 121, + 84, + 41, + 43, + 91, + 91, + 11, + 206, + 10, + 10, + 87, + 87, + 143, + 143, + 143, + 143, + 342, + 342, + 342, + 107, + 351, + 400, + 118, + 322, + 322, + 322, + 395, + 106, + 106, + 334, + 334, + 392, + 103, + 323, + 282, + 169, + 169, + 203, + 377, + 377, + 377, + 380, + 243, + 243, + 4, + 4, + 392, + 24, + 300, + 273, + 230, + 27, + 60, + 80, + 80, + 80, + 119, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 58, + 133, + 133, + 133, + 219, + 58, + 220, + 220, + 256, + 256, + 256, + 324, + 264, + 93, + 346, + 205, + 205, + 205, + 398, + 33, + 33, + 33, + 33, + 334, + 334, + 225, + 225, + 339, + 339, + 283, + 281, + 281, + 281, + 281, + 281, + 281, + 53, + 364, + 364, + 226, + 217, + 380, + 380, + 200, + 200, + 56, + 56, + 328, + 328, + 328, + 328, + 1, + 268, + 268, + 137, + 137, + 137, + 137, + 137, + 137, + 280, + 224, + 140, + 140, + 140, + 140, + 287, + 169, + 120, + 120, + 155, + 155, + 146, + 146, + 146, + 37, + 40, + 187, + 88, + 334, + 70, + 70, + 70, + 70, + 97, + 233, + 233, + 70, + 70, + 38, + 237, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 45, + 45, + 45, + 209, + 209, + 209, + 64, + 9, + 164, + 164, + 164, + 198, + 261, + 261, + 255, + 255, + 37, + 59, + 246, + 142, + 190, + 190, + 190, + 27, + 27, + 27, + 301, + 138, + 138, + 138, + 138, + 365, + 62, + 150, + 165, + 7, + 7, + 7, + 388, + 388, + 119, + 119, + 119, + 34, + 276, + 374, + 374, + 374, + 374, + 374, + 374, + 21, + 239, + 239, + 239, + 231, + 231, + 231, + 231, + 35, + 229, + 229, + 143, + 143, + 232, + 232, + 232, + 232, + 188, + 188, + 188, + 195, + 168, + 168, + 168, + 168, + 168, + 174, + 71, + 71, + 102, + 338, + 6, + 6, + 6, + 6, + 272, + 91, + 238, + 238, + 238, + 317, + 89, + 137, + 383, + 383, + 181, + 181, + 217, + 92, + 42, + 178, + 178, + 248, + 352, + 280, + 353, + 399, + 399, + 399, + 353, + 353, + 353, + 353, + 353, + 96, + 96, + 325, + 325, + 325, + 325, + 89, + 143, + 143, + 143, + 143, + 180, + 163, + 163, + 163, + 163, + 395, + 395, + 395, + 282, + 282, + 282, + 282, + 282, + 183, + 183, + 45, + 65, + 18, + 18, + 18, + 271, + 378, + 331, + 242, + 39, + 191, + 191, + 191, + 93, + 93, + 270, + 270, + 22, + 104, + 104, + 104, + 287, + 103, + 272, + 53, + 44, + 378, + 306, + 156, + 156, + 31, + 31, + 72, + 236, + 388, + 388, + 388, + 14, + 14, + 172, + 57, + 133, + 262, + 262, + 87, + 201, + 59, + 59, + 224, + 224, + 29, + 155, + 155, + 155, + 155, + 22, + 149, + 23, + 305, + 95, + 127, + 127, + 350, + 375, + 375, + 375, + 330, + 331, + 331, + 331, + 331, + 46, + 390, + 390, + 147, + 347, + 347, + 319, + 319, + 201, + 201, + 105, + 391, + 241, + 204, + 204, + 60, + 60, + 64, + 253, + 195, + 195, + 321, + 61, + 108, + 44, + 44, + 312, + 312, + 312, + 312, + 312, + 136, + 123, + 221, + 221, + 65, + 166, + 166, + 166, + 166, + 166, + 166, + 166, + 115, + 115, + 259, + 259, + 40, + 68, + 254, + 254, + 254, + 254, + 348, + 4, + 2, + 356, + 356, + 356, + 356, + 174, + 257, + 257, + 394, + 394, + 299, + 299, + 26, + 100, + 100, + 100, + 100, + 83, + 83, + 83, + 83, + 83, + 106, + 106, + 106, + 106, + 106, + 198, + 198, + 108, + 108, + 108, + 108, + 284, + 251, + 251, + 251, + 355, + 61, + 61, + 385, + 385, + 385, + 385, + 350, + 350, + 350, + 350, + 350, + 7, + 7, + 17, + 17, + 91, + 91, + 181, + 181, + 142, + 136, + 136, + 130, + 5, + 367, + 367, + 306, + 387, + 387, + 331, + 331, + 331, + 237, + 237, + 237, + 237, + 237, + 190, + 146, + 361, + 334, + 334, + 334, + 334, + 334, + 338, + 223, + 59, + 233, + 233, + 233, + 233, + 339, + 339, + 371, + 371, + 371, + 68, + 68, + 230, + 230, + 230, + 230, + 60, + 49, + 285, + 71, + 276, + 276, + 276, + 69, + 190, + 147, + 147, + 147, + 230, + 253, + 253, + 380, + 195, + 195, + 195, + 195, + 398, + 398, + 69, + 69, + 207, + 207, + 207, + 16, + 351, + 351, + 351, + 149, + 149, + 149, + 149, + 80, + 224, + 238, + 238, + 238, + 238, + 238, + 100, + 100, + 68, + 68, + 271, + 116, + 116, + 68, + 296, + 288, + 288, + 123, + 342, + 68, + 163, + 163, + 163, + 138, + 149, + 149, + 163, + 163, + 163, + 163, + 163, + 170, + 274, + 263, + 75, + 75, + 75, + 75, + 75, + 358, + 347, + 60, + 163, + 163, + 49, + 2, + 2, + 2, + 307, + 307, + 307, + 307, + 204, + 120, + 120, + 120, + 120, + 120, + 185, + 362, + 35, + 120, + 120, + 276, + 276, + 262, + 262, + 262, + 165, + 165, + 151, + 257, + 53, + 320, + 320, + 320, + 320, + 106, + 57, + 394, + 394, + 335, + 252, + 252, + 135, + 135, + 135, + 135, + 135, + 135, + 103, + 103, + 389, + 389, + 316, + 316, + 262, + 254, + 178, + 328, + 328, + 105, + 166, + 166, + 166, + 62, + 203, + 203, + 387, + 387, + 154, + 137, + 282, + 43, + 260, + 260, + 91, + 91, + 91, + 91, + 91, + 91, + 289, + 289, + 98, + 98, + 100, + 100, + 100, + 100, + 100, + 24, + 117, + 117, + 169, + 169, + 169, + 92, + 92, + 110, + 110, + 322, + 312, + 247, + 247, + 247, + 69, + 69, + 153, + 153, + 153, + 153, + 153, + 150, + 169, + 169, + 220, + 33, + 33, + 284, + 284, + 392, + 181, + 181, + 181, + 48, + 48, + 62, + 141, + 141, + 141, + 217, + 188, + 314, + 117, + 200, + 200, + 230, + 230, + 230, + 230, + 230, + 285, + 285, + 364, + 364, + 364, + 364, + 62, + 331, + 331, + 254, + 254, + 310, + 310, + 310, + 228, + 228, + 288, + 333, + 69, + 110, + 110, + 110, + 201, + 201, + 201, + 201, + 201, + 201, + 201, + 201, + 143, + 143, + 143, + 22, + 22, + 360, + 360, + 98, + 298, + 298, + 22, + 22, + 67, + 190, + 190, + 324, + 324, + 324, + 324, + 324, + 324, + 299, + 150, + 150, + 247, + 103, + 14, + 307, + 307, + 307, + 307, + 161, + 161, + 46, + 38, + 38, + 38, + 38, + 299, + 159, + 159, + 322, + 236, + 236, + 4, + 4, + 112, + 112, + 112, + 357, + 46, + 46, + 46, + 22, + 22, + 111, + 17, + 385, + 148, + 148, + 148, + 302, + 336, + 272, + 319, + 339, + 339, + 83, + 83, + 395, + 395, + 33, + 33, + 332, + 332, + 332, + 332, + 12, + 45, + 146, + 146, + 177, + 214, + 347, + 347, + 347, + 278, + 248, + 264, + 107, + 107, + 107, + 107, + 219, + 179, + 179, + 137, + 137, + 137, + 164, + 363, + 363, + 363, + 363, + 131, + 174, + 384, + 201, + 201, + 303, + 303, + 370, + 370, + 212, + 274, + 315, + 189, + 189, + 314, + 141, + 141, + 220, + 96, + 96, + 178, + 178, + 364, + 97, + 97, + 97, + 35, + 187, + 189, + 26, + 26, + 26, + 26, + 26, + 26, + 83, + 83, + 162, + 162, + 108, + 286, + 286, + 286, + 286, + 199, + 199, + 64, + 171, + 171, + 171, + 171, + 284, + 284, + 324, + 324, + 324, + 8, + 8, + 19, + 325, + 325, + 325, + 325, + 58, + 58, + 58, + 58, + 58, + 58, + 58, + 58, + 335, + 328, + 20, + 134, + 355, + 73, + 120, + 390, + 336, + 336, + 336, + 336, + 276, + 240, + 93, + 93, + 53, + 34, + 34, + 277, + 183, + 170, + 181, + 181, + 181, + 4, + 4, + 4, + 40, + 227, + 96, + 107, + 107, + 107, + 160, + 295, + 295, + 295, + 18, + 16, + 16, + 16, + 16, + 57, + 57, + 134, + 368, + 134, + 134, + 134, + 134, + 134, + 128, + 88, + 88, + 268, + 268, + 56, + 42, + 42, + 42, + 205, + 51, + 302, + 16, + 16, + 16, + 7, + 150, + 382, + 382, + 329, + 329, + 334, + 22, + 22, + 177, + 140, + 186, + 21, + 21, + 235, + 235, + 351, + 351, + 347, + 347, + 347, + 322, + 58, + 58, + 252, + 252, + 252, + 142, + 215, + 215, + 215, + 124, + 124, + 371, + 371, + 261, + 261, + 261, + 62, + 62, + 62, + 32, + 32, + 210, + 210, + 210, + 284, + 139, + 58, + 244, + 142, + 208, + 25, + 25, + 25, + 303, + 289, + 394, + 394, + 292, + 292, + 272, + 272, + 272, + 272, + 272, + 206, + 305, + 347, + 133, + 133, + 133, + 133, + 133, + 93, + 189, + 213, + 213, + 46, + 255, + 341, + 168, + 208, + 208, + 208, + 61, + 107, + 107, + 150, + 395, + 395, + 333, + 358, + 351, + 355, + 355, + 244, + 244, + 300, + 300, + 300, + 300, + 300, + 300, + 138, + 29, + 29, + 29, + 301, + 13, + 13, + 100, + 100, + 100, + 100, + 51, + 181, + 181, + 181, + 181, + 141, + 141, + 233, + 86, + 266, + 266, + 322, + 397, + 397, + 41, + 41, + 41, + 41, + 41, + 41, + 41, + 41, + 159, + 274, + 274, + 274, + 274, + 274, + 43, + 43, + 65, + 65, + 65, + 138, + 138, + 138, + 138, + 49, + 49, + 23, + 184, + 184, + 77, + 77, + 77, + 144, + 144, + 77, + 77, + 218, + 218, + 367, + 380, + 380, + 380, + 1, + 218, + 141, + 343, + 251, + 251, + 211, + 113, + 113, + 102, + 6, + 364, + 364, + 176, + 372, + 356, + 374, + 374, + 252, + 252, + 252, + 101, + 10, + 10, + 10, + 361, + 289, + 311, + 206, + 206, + 98, + 48, + 256, + 256, + 240, + 240, + 240, + 340, + 266, + 266, + 266, + 266, + 35, + 35, + 183, + 183, + 183, + 389, + 389, + 389, + 32, + 32, + 319, + 2, + 2, + 2, + 362, + 283, + 183, + 183, + 157, + 157, + 317, + 317, + 91, + 381, + 347, + 347, + 246, + 246, + 246, + 246, + 318, + 188, + 133, + 201, + 201, + 201, + 201, + 201, + 282, + 282, + 282, + 282, + 193, + 124, + 77, + 77, + 77, + 77, + 215, + 215, + 127, + 127, + 328, + 328, + 251, + 76, + 76, + 76, + 76, + 44, + 44, + 280, + 334, + 334, + 334, + 158, + 152, + 373, + 373, + 373, + 359, + 59, + 324, + 324, + 334, + 334, + 92, + 392, + 323, + 323, + 236, + 323, + 323, + 372, + 25, + 25, + 87, + 87, + 87, + 102, + 260, + 288, + 20, + 256, + 256, + 256, + 264, + 131, + 311, + 311, + 311, + 283, + 283, + 40, + 393, + 393, + 57, + 345, + 35, + 35, + 66, + 362, + 42, + 42, + 42, + 42, + 42, + 42, + 325, + 72, + 360, + 399, + 399, + 399, + 399, + 267, + 117, + 117, + 366, + 74, + 74, + 74, + 74, + 253, + 253, + 253, + 166, + 389, + 355, + 273, + 194, + 194, + 57, + 126, + 345, + 345, + 250, + 346, + 70, + 240, + 41, + 32, + 32, + 351, + 351, + 252, + 252, + 252, + 252, + 252, + 120, + 32, + 32, + 16, + 16, + 16, + 76, + 396, + 396, + 389, + 389, + 389, + 307, + 307, + 284, + 89, + 58, + 374, + 342, + 342, + 342, + 342, + 342, + 342, + 3, + 51, + 339, + 131, + 131, + 198, + 212, + 212, + 41, + 84, + 84, + 359, + 359, + 359, + 9, + 9, + 9, + 132, + 132, + 310, + 310, + 310, + 348, + 348, + 348, + 348, + 245, + 245, + 245, + 117, + 218, + 218, + 389, + 255, + 289, + 233, + 66, + 66, + 66, + 66, + 66, + 72, + 198, + 198, + 316, + 316, + 316, + 370, + 323, + 218, + 32, + 32, + 32, + 254, + 254, + 254, + 254, + 254, + 254, + 171, + 23, + 23, + 314, + 396, + 396, + 396, + 396, + 396, + 396, + 90, + 322, + 322, + 206, + 206, + 300, + 300, + 287, + 287, + 287, + 91, + 331, + 250, + 250, + 80, + 343, + 343, + 343, + 343, + 343, + 18, + 18, + 18, + 18, + 370, + 132, + 132, + 222, + 275, + 218, + 250, + 387, + 387, + 387, + 387, + 274, + 274, + 274, + 274, + 274, + 274, + 274, + 34, + 34, + 34, + 340, + 340, + 340, + 340, + 340, + 220, + 286, + 326, + 326, + 136, + 136, + 136, + 38, + 38, + 38, + 38, + 368, + 400, + 50, + 50, + 25, + 25, + 73, + 73, + 73, + 141, + 141, + 184, + 169, + 169, + 169, + 246, + 246, + 246, + 101, + 101, + 101, + 92, + 92, + 181, + 360, + 360, + 360, + 317, + 317, + 198, + 198, + 130, + 130, + 130, + 130, + 172, + 172, + 260, + 189, + 80, + 282, + 282, + 327, + 327, + 226, + 85, + 252, + 252, + 252, + 252, + 251, + 251, + 314, + 314, + 249, + 320, + 193, + 193, + 270, + 270, + 270, + 241, + 366, + 366, + 139, + 347, + 347, + 347, + 302, + 185, + 304, + 158, + 158, + 325, + 325, + 186, + 360, + 56, + 56, + 317, + 346, + 175, + 175, + 80, + 27, + 395, + 180, + 341, + 341, + 364, + 364, + 178, + 178, + 261, + 261, + 261, + 248, + 248, + 55, + 55, + 87, + 17, + 17, + 17, + 17, + 321, + 362, + 362, + 362, + 153, + 277, + 63, + 63, + 135, + 135, + 135, + 135, + 135, + 284, + 149, + 340, + 340, + 264, + 264, + 264, + 264, + 17, + 203, + 55, + 61, + 61, + 385, + 385, + 385, + 359, + 54, + 54, + 54, + 257, + 257, + 398, + 111, + 111, + 111, + 111, + 201, + 386, + 386, + 386, + 321, + 321, + 145, + 310, + 310, + 228, + 35, + 79, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 121, + 189, + 77, + 77, + 77, + 77, + 258, + 58, + 58, + 58, + 58, + 143, + 143, + 143, + 143, + 143, + 374, + 60, + 157, + 344, + 344, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 10, + 119, + 119, + 251, + 251, + 251, + 251, + 78, + 150, + 185, + 185, + 360, + 39, + 39, + 39, + 39, + 260, + 246, + 246, + 246, + 386, + 386, + 386, + 386, + 386, + 82, + 82, + 82, + 45, + 45, + 45, + 238, + 238, + 238, + 238, + 238, + 238, + 133, + 120, + 120, + 126, + 126, + 61, + 61, + 386, + 386, + 386, + 386, + 124, + 210, + 210, + 354, + 19, + 19, + 19, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 267, + 74, + 288, + 288, + 288, + 288, + 288, + 288, + 288, + 324, + 324, + 103, + 103, + 103, + 103, + 170, + 170, + 170, + 170, + 341, + 341, + 341, + 341, + 341, + 348, + 315, + 267, + 267, + 311, + 138, + 138, + 32, + 200, + 34, + 34, + 386, + 386, + 386, + 386, + 386, + 386, + 386, + 168, + 99, + 99, + 99, + 365, + 59, + 59, + 59, + 59, + 59, + 381, + 381, + 312, + 312, + 23, + 357, + 31, + 31, + 359, + 359, + 359, + 359, + 359, + 54, + 54, + 54, + 322, + 287, + 368, + 368, + 368, + 165, + 165, + 71, + 71, + 71, + 347, + 262, + 324, + 324, + 324, + 336, + 336, + 114, + 99, + 255, + 257, + 222, + 222, + 387, + 156, + 156, + 191, + 191, + 261, + 261, + 178, + 142, + 142, + 142, + 109, + 57, + 57, + 57, + 138, + 115, + 115, + 115, + 115, + 115, + 308, + 308, + 313, + 313, + 252, + 252, + 252, + 252, + 45, + 45, + 37, + 37, + 179, + 97, + 97, + 97, + 97, + 97, + 97, + 262, + 262, + 332, + 332, + 332, + 374, + 194, + 194, + 194, + 317, + 17, + 319, + 319, + 365, + 228, + 228, + 76, + 76, + 273, + 273, + 356, + 356, + 93, + 93, + 215, + 267, + 267, + 373, + 337, + 337, + 337, + 337, + 61, + 390, + 360, + 77, + 77, + 77, + 121, + 32, + 32, + 32, + 126, + 126, + 156, + 52, + 385, + 385, + 385, + 105, + 267, + 111, + 161, + 161, + 161, + 161, + 302, + 302, + 191, + 191, + 191, + 350, + 139, + 380, + 380, + 380, + 380, + 380, + 32, + 143, + 143, + 41, + 313, + 313, + 73, + 216, + 216, + 305, + 312, + 312, + 312, + 137, + 117, + 7, + 154, + 154, + 154, + 154, + 377, + 297, + 29, + 29, + 29, + 29, + 29, + 29, + 29, + 50, + 50, + 50, + 90, + 329, + 329, + 248, + 59, + 59, + 59, + 59, + 107, + 107, + 107, + 107, + 107, + 272, + 287, + 297, + 354, + 354, + 194, + 194, + 194, + 194, + 194, + 194, + 194, + 373, + 373, + 348, + 193, + 193, + 193, + 193, + 193, + 193, + 193, + 193, + 193, + 193, + 193, + 39, + 39, + 244, + 244, + 244, + 244, + 385, + 385, + 385, + 60, + 60, + 60, + 85, + 373, + 43, + 43, + 43, + 263, + 47, + 47, + 47, + 272, + 272, + 142, + 142, + 142, + 142, + 237, + 373, + 373, + 373, + 373, + 373, + 187, + 22, + 22, + 22, + 83, + 93, + 359, + 260, + 260, + 260, + 260, + 220, + 178, + 178, + 384, + 384, + 384, + 12, + 49, + 49, + 49, + 185, + 2, + 91, + 266, + 266, + 218, + 218, + 167, + 284, + 175, + 175, + 336, + 336, + 336, + 343, + 343, + 343, + 343, + 379, + 316, + 213, + 213, + 222, + 222, + 357, + 345, + 67, + 310, + 242, + 136, + 202, + 202, + 202, + 202, + 202, + 330, + 330, + 141, + 141, + 163, + 163, + 23, + 283, + 20, + 20, + 375, + 375, + 216, + 216, + 223, + 179, + 179, + 322, + 385, + 305, + 143, + 143, + 143, + 239, + 239, + 17, + 44, + 44, + 66, + 66, + 66, + 178, + 373, + 373, + 373, + 373, + 142, + 47, + 99, + 99, + 99, + 99, + 189, + 77, + 261, + 39, + 39, + 39, + 39, + 39, + 39, + 39, + 132, + 132, + 132, + 102, + 102, + 102, + 186, + 186, + 282, + 125, + 125, + 273, + 273, + 43, + 43, + 49, + 222, + 222, + 222, + 222, + 250, + 250, + 29, + 29, + 2, + 2, + 2, + 2, + 158, + 158, + 321, + 93, + 41, + 41, + 41, + 345, + 182, + 29, + 224, + 335, + 176, + 360, + 360, + 300, + 317, + 317, + 317, + 317, + 237, + 237, + 237, + 237, + 107, + 341, + 341, + 341, + 341, + 101, + 101, + 45, + 45, + 45, + 371, + 371, + 371, + 16, + 16, + 182, + 34, + 34, + 372, + 216, + 114, + 114, + 121, + 121, + 121, + 243, + 3, + 28, + 28, + 28, + 28, + 28, + 206, + 206, + 206, + 206, + 176, + 283, + 283, + 283, + 399, + 399, + 154, + 96, + 82, + 82, + 322, + 18, + 18, + 123, + 25, + 83, + 253, + 253, + 253, + 168, + 168, + 168, + 5, + 294, + 341, + 299, + 299, + 299, + 299, + 10, + 10, + 235, + 56, + 56, + 364, + 364, + 72, + 369, + 185, + 261, + 261, + 37, + 37, + 37, + 211, + 211, + 310, + 151, + 151, + 16, + 380, + 380, + 380, + 380, + 205, + 218, + 146, + 146, + 146, + 268, + 268, + 220, + 220, + 96, + 288, + 295, + 250, + 250, + 6, + 6, + 6, + 6, + 6, + 279, + 204, + 204, + 204, + 204, + 155, + 221, + 221, + 8, + 8, + 170, + 170, + 363, + 363, + 363, + 363, + 23, + 23, + 195, + 195, + 195, + 320, + 320, + 320, + 320, + 320, + 320, + 320, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 287, + 287, + 144, + 144, + 144, + 58, + 95, + 379, + 379, + 238, + 152, + 152, + 81, + 81, + 81, + 77, + 81, + 237, + 36, + 36, + 36, + 207, + 207, + 112, + 146, + 146, + 297, + 297, + 297, + 228, + 228, + 228, + 228, + 74, + 151, + 112, + 112, + 56, + 87, + 87, + 138, + 255, + 255, + 255, + 193, + 193, + 314, + 314, + 240, + 60, + 163, + 163, + 208, + 208, + 366, + 366, + 395, + 275, + 275, + 155, + 155, + 190, + 190, + 52, + 52, + 52, + 52, + 176, + 361, + 337, + 32, + 32, + 32, + 137, + 72, + 72, + 72, + 149, + 113, + 113, + 139, + 139, + 351, + 44, + 44, + 44, + 44, + 377, + 377, + 377, + 382, + 168, + 385, + 287, + 287, + 237, + 190, + 119, + 119, + 119, + 119, + 41, + 41, + 41, + 258, + 258, + 258, + 272, + 272, + 242, + 353, + 353, + 9, + 368, + 254, + 320, + 320, + 347, + 136, + 285, + 280, + 96, + 96, + 125, + 125, + 393, + 225, + 225, + 225, + 305, + 305, + 244, + 271, + 373, + 75, + 75, + 75, + 62, + 81, + 172, + 172, + 172, + 172, + 172, + 172, + 219, + 219, + 75, + 75, + 258, + 258, + 69, + 69, + 69, + 203, + 86, + 86, + 86, + 86, + 86, + 86, + 70, + 70, + 70, + 254, + 358, + 358, + 358, + 358, + 36, + 182, + 190, + 190, + 190, + 190, + 190, + 190, + 332, + 332, + 126, + 271, + 386, + 334, + 166, + 234, + 234, + 113, + 168, + 121, + 121, + 121, + 121, + 39, + 39, + 39, + 121, + 357, + 177, + 189, + 294, + 294, + 294, + 37, + 37, + 37, + 129, + 374, + 84, + 84, + 84, + 84, + 280, + 297, + 297, + 297, + 240, + 240, + 240, + 240, + 117, + 178, + 22, + 356, + 101, + 38, + 175, + 175, + 239, + 167, + 167, + 167, + 167, + 167, + 157, + 81, + 91, + 91, + 91, + 377, + 377, + 377, + 77, + 353, + 353, + 233, + 342, + 342, + 10, + 10, + 10, + 10, + 10, + 122, + 377, + 377, + 352, + 173, + 78, + 78, + 191, + 62, + 62, + 62, + 62, + 62, + 62, + 62, + 62, + 366, + 366, + 366, + 326, + 326, + 326, + 190, + 6, + 6, + 6, + 6, + 6, + 326, + 8, + 173, + 128, + 128, + 213, + 213, + 213, + 290, + 222, + 222, + 222, + 222, + 138, + 61, + 194, + 137, + 137, + 371, + 371, + 371, + 371, + 371, + 289, + 289, + 112, + 5, + 5, + 5, + 309, + 37, + 199, + 199, + 199, + 241, + 318, + 318, + 275, + 275, + 275, + 275, + 275, + 109, + 109, + 109, + 109, + 109, + 109, + 187, + 34, + 53, + 133, + 229, + 265, + 265, + 265, + 265, + 293, + 334, + 240, + 390, + 390, + 390, + 239, + 32, + 32, + 32, + 59, + 388, + 388, + 388, + 337, + 337, + 252, + 259, + 259, + 248, + 248, + 35, + 35, + 35, + 23, + 23, + 23, + 23, + 23, + 371, + 371, + 371, + 388, + 77, + 77, + 381, + 262, + 262, + 117, + 218, + 397, + 360, + 360, + 177, + 177, + 177, + 73, + 163, + 163, + 163, + 201, + 201, + 201, + 68, + 68, + 68, + 68, + 68, + 331, + 331, + 298, + 227, + 227, + 227, + 227, + 43, + 43, + 43, + 43, + 43, + 297, + 64, + 64, + 64, + 64, + 272, + 187, + 187, + 187, + 187, + 336, + 217, + 217, + 82, + 106, + 377, + 377, + 212, + 212, + 212, + 320, + 316, + 208, + 208, + 250, + 164, + 164, + 103, + 103, + 155, + 155, + 155, + 155, + 155, + 155, + 348, + 165, + 165, + 165, + 320, + 320, + 320, + 320, + 156, + 334, + 286, + 301, + 289, + 208, + 338, + 109, + 109, + 25, + 25, + 25, + 25, + 25, + 25, + 181, + 353, + 36, + 96, + 96, + 96, + 72, + 354, + 354, + 354, + 354, + 281, + 304, + 395, + 337, + 337, + 337, + 337, + 341, + 341, + 392, + 392, + 392, + 392, + 392, + 392, + 193, + 193, + 193, + 193, + 131, + 72, + 145, + 290, + 348, + 63, + 302, + 85, + 91, + 91, + 91, + 91, + 55, + 52, + 221, + 137, + 47, + 47, + 291, + 229, + 229, + 384, + 384, + 384, + 234, + 364, + 196, + 122, + 122, + 122, + 272, + 243, + 243, + 36, + 49, + 49, + 49, + 22, + 22, + 89, + 89, + 160, + 192, + 192, + 192, + 148, + 180, + 172, + 101, + 101, + 101, + 101, + 304, + 304, + 349, + 56, + 123, + 225, + 225, + 47, + 126, + 51, + 199, + 45, + 153, + 387, + 387, + 387, + 387, + 347, + 55, + 55, + 196, + 196, + 223, + 223, + 266, + 84, + 126, + 283, + 396, + 396, + 396, + 261, + 39, + 39, + 220, + 220, + 220, + 300, + 300, + 380, + 380, + 29, + 29, + 29, + 109, + 109, + 109, + 109, + 86, + 5, + 5, + 189, + 391, + 391, + 391, + 123, + 123, + 305, + 305, + 305, + 251, + 156, + 156, + 156, + 322, + 322, + 72, + 43, + 292, + 328, + 393, + 130, + 130, + 319, + 47, + 31, + 300, + 300, + 363, + 363, + 306, + 225, + 225, + 219, + 267, + 267, + 284, + 46, + 226, + 265, + 235, + 235, + 398, + 133, + 238, + 238, + 238, + 238, + 238, + 214, + 214, + 214, + 181, + 124, + 310, + 310, + 99, + 99, + 99, + 99, + 99, + 99, + 99, + 201, + 339, + 339, + 134, + 107, + 82, + 377, + 377, + 139, + 63, + 63, + 63, + 228, + 228, + 152, + 246, + 304, + 304, + 304, + 304, + 304, + 304, + 304, + 304, + 304, + 304, + 304, + 33, + 33, + 31, + 319, + 186, + 186, + 78, + 181, + 120, + 241, + 241, + 241, + 241, + 376, + 376, + 376, + 374, + 374, + 374, + 115, + 62, + 62, + 183, + 183, + 368, + 299, + 299, + 178, + 178, + 178, + 178, + 178, + 92, + 92, + 370, + 399, + 399, + 399, + 166, + 166, + 34, + 244, + 244, + 244, + 244, + 240, + 71, + 104, + 74, + 242, + 166, + 166, + 166, + 184, + 184, + 184, + 166, + 317, + 347, + 79, + 274, + 274, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 281, + 166, + 253, + 235, + 139, + 139, + 286, + 286, + 242, + 242, + 242, + 242, + 242, + 242, + 190, + 190, + 100, + 100, + 160, + 114, + 55, + 55, + 55, + 55, + 55, + 153, + 153, + 285, + 291, + 139, + 210, + 210, + 210, + 97, + 97, + 278, + 80, + 318, + 318, + 318, + 318, + 318, + 318, + 268, + 268, + 268, + 156, + 156, + 36, + 36, + 327, + 327, + 387, + 387, + 263, + 231, + 294, + 270, + 270, + 270, + 160, + 160, + 160, + 141, + 204, + 21, + 61, + 267, + 346, + 346, + 253, + 253, + 122, + 307, + 221, + 221, + 221, + 221, + 367, + 367, + 367, + 290, + 290, + 329, + 369, + 169, + 169, + 392, + 45, + 45, + 103, + 103, + 125, + 147, + 48, + 96, + 96, + 98, + 98, + 98, + 98, + 98, + 276, + 353, + 369, + 369, + 301, + 252, + 252, + 252, + 252, + 252, + 202, + 202, + 202, + 388, + 388, + 184, + 23, + 23, + 23, + 23, + 23, + 229, + 229, + 229, + 229, + 229, + 229, + 229, + 169, + 78, + 279, + 279, + 279, + 279, + 391, + 391, + 17, + 17, + 327, + 327, + 307, + 307, + 400, + 141, + 141, + 141, + 141, + 141, + 141, + 141, + 141, + 257, + 244, + 312, + 312, + 229, + 85, + 165, + 234, + 23, + 189, + 189, + 36, + 36, + 36, + 36, + 119, + 149, + 149, + 149, + 149, + 149, + 149, + 149, + 149, + 143, + 50, + 55, + 76, + 226, + 226, + 226, + 165, + 165, + 315, + 327, + 327, + 251, + 160, + 377, + 377, + 377, + 197, + 197, + 197, + 197, + 339, + 44, + 180, + 166, + 233, + 233, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 188, + 98, + 98, + 98, + 98, + 98, + 98, + 30, + 100, + 100, + 167, + 167, + 195, + 195, + 99, + 99, + 315, + 315, + 315, + 173, + 128, + 327, + 327, + 327, + 52, + 52, + 52, + 52, + 52, + 52, + 322, + 322, + 284, + 8, + 8, + 293, + 293, + 293, + 242, + 242, + 50, + 322, + 322, + 225, + 225, + 169, + 163, + 163, + 194, + 227, + 332, + 46, + 46, + 337, + 21, + 21, + 21, + 21, + 170, + 170, + 170, + 365, + 365, + 365, + 259, + 285, + 11, + 75, + 140, + 390, + 256, + 256, + 233, + 233, + 77, + 77, + 241, + 241, + 241, + 241, + 241, + 46, + 23, + 23, + 23, + 252, + 318, + 83, + 108, + 108, + 108, + 377, + 86, + 86, + 86, + 345, + 328, + 50, + 185, + 185, + 166, + 166, + 63, + 229, + 229, + 229, + 229, + 79, + 26, + 26, + 303, + 222, + 297, + 354, + 370, + 224, + 224, + 317, + 225, + 225, + 225, + 225, + 242, + 241, + 271, + 42, + 367, + 107, + 107, + 107, + 258, + 258, + 258, + 258, + 221, + 221, + 221, + 97, + 97, + 97, + 170, + 196, + 136, + 57, + 57, + 57, + 224, + 224, + 323, + 323, + 323, + 310, + 292, + 309, + 146, + 146, + 146, + 146, + 146, + 87, + 87, + 202, + 202, + 355, + 355, + 301, + 208, + 208, + 233, + 233, + 279, + 279, + 353, + 392, + 63, + 63, + 63, + 131, + 131, + 236, + 236, + 236, + 236, + 236, + 236, + 307, + 131, + 131, + 131, + 131, + 244, + 244, + 244, + 244, + 58, + 331, + 331, + 331, + 162, + 258, + 258, + 237, + 237, + 108, + 105, + 371, + 254, + 254, + 254, + 251, + 62, + 62, + 212, + 367, + 367, + 249, + 256, + 256, + 256, + 340, + 340, + 91, + 89, + 67, + 398, + 398, + 398, + 91, + 91, + 91, + 91, + 393, + 153, + 153, + 255, + 98, + 98, + 98, + 128, + 128, + 128, + 128, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 56, + 398, + 398, + 231, + 39, + 366, + 366, + 366, + 366, + 241, + 241, + 241, + 276, + 380, + 153, + 153, + 256, + 256, + 63, + 63, + 63, + 162, + 7, + 7, + 7, + 7, + 117, + 117, + 168, + 168, + 168, + 181, + 90, + 244, + 244, + 244, + 244, + 78, + 78, + 78, + 328, + 328, + 328, + 195, + 195, + 195, + 195, + 195, + 66, + 327, + 327, + 40, + 40, + 213, + 213, + 108, + 255, + 255, + 255, + 255, + 255, + 296, + 296, + 212, + 212, + 223, + 223, + 200, + 370, + 90, + 90, + 226, + 226, + 226, + 22, + 323, + 323, + 323, + 24, + 11, + 11, + 349, + 89, + 142, + 41, + 41, + 41, + 41, + 41, + 41, + 260, + 146, + 193, + 154, + 156, + 35, + 35, + 235, + 392, + 392, + 392, + 115, + 115, + 355, + 355, + 131, + 73, + 73, + 357, + 357, + 357, + 299, + 299, + 299, + 268, + 268, + 268, + 64, + 64, + 64, + 64, + 64, + 70, + 175, + 17, + 17, + 296, + 296, + 296, + 138, + 144, + 13, + 274, + 187, + 187, + 187, + 187, + 391, + 127, + 7, + 145, + 145, + 145, + 116, + 126, + 126, + 126, + 285, + 285, + 285, + 285, + 285, + 176, + 176, + 176, + 176, + 176, + 163, + 163, + 69, + 217, + 217, + 217, + 217, + 217, + 217, + 217, + 217, + 256, + 256, + 256, + 385, + 385, + 258, + 43, + 43, + 43, + 110, + 219, + 192, + 329, + 329, + 50, + 50, + 50, + 50, + 361, + 337, + 178, + 178, + 178, + 178, + 204, + 260, + 288, + 288, + 288, + 125, + 81, + 74, + 74, + 74, + 74, + 28, + 182, + 132, + 132, + 315, + 315, + 315, + 315, + 334, + 391, + 391, + 391, + 139, + 139, + 139, + 275, + 275, + 246, + 169, + 70, + 153, + 393, + 393, + 393, + 393, + 393, + 246, + 246, + 250, + 367, + 367, + 42, + 98, + 112, + 112, + 112, + 112, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 44, + 44, + 44, + 44, + 44, + 44, + 44, + 244, + 244, + 394, + 106, + 106, + 48, + 48, + 21, + 21, + 203, + 187, + 400, + 400, + 301, + 301, + 134, + 134, + 25, + 25, + 25, + 25, + 361, + 210, + 239, + 311, + 311, + 37, + 37, + 37, + 37, + 255, + 311, + 212, + 33, + 9, + 355, + 355, + 17, + 290, + 196, + 2, + 2, + 2, + 2, + 174, + 106, + 3, + 247, + 59, + 59, + 78, + 78, + 357, + 357, + 303, + 197, + 106, + 257, + 257, + 330, + 103, + 83, + 83, + 299, + 360, + 360, + 112, + 112, + 112, + 112, + 112, + 112, + 231, + 18, + 18, + 334, + 223, + 223, + 224, + 198, + 198, + 198, + 198, + 198, + 114, + 114, + 23, + 23, + 23, + 240, + 240, + 240, + 240, + 240, + 284, + 284, + 105, + 186, + 186, + 396, + 288, + 129, + 162, + 298, + 298, + 298, + 226, + 226, + 226, + 226, + 226, + 226, + 3, + 3, + 3, + 3, + 12, + 131, + 131, + 131, + 131, + 10, + 17, + 21, + 21, + 21, + 21, + 83, + 98, + 236, + 200, + 200, + 200, + 138, + 138, + 314, + 14, + 138, + 58, + 58, + 58, + 58, + 58, + 142, + 186, + 209, + 209, + 209, + 209, + 209, + 169, + 162, + 162, + 239, + 48, + 48, + 396, + 114, + 114, + 114, + 376, + 377, + 377, + 181, + 181, + 156, + 284, + 284, + 284, + 284, + 264, + 380, + 30, + 30, + 133, + 133, + 133, + 133, + 166, + 319, + 328, + 393, + 393, + 144, + 144, + 144, + 194, + 194, + 17, + 275, + 273, + 110, + 110, + 110, + 110, + 110, + 110, + 114, + 41, + 41, + 349, + 60, + 60, + 228, + 228, + 228, + 164, + 164, + 142, + 142, + 142, + 142, + 142, + 59, + 59, + 59, + 59, + 59, + 290, + 290, + 290, + 290, + 311, + 311, + 191, + 186, + 253, + 254, + 253, + 253, + 92, + 374, + 374, + 165, + 165, + 153, + 153, + 397, + 397, + 29, + 60, + 293, + 155, + 155, + 155, + 228, + 228, + 187, + 331, + 88, + 387, + 387, + 376, + 394, + 253, + 253, + 79, + 195, + 195, + 195, + 195, + 367, + 124, + 217, + 217, + 217, + 217, + 217, + 217, + 22, + 202, + 202, + 202, + 202, + 230, + 230, + 230, + 230, + 156, + 156, + 156, + 235, + 184, + 330, + 47, + 297, + 283, + 283, + 174, + 174, + 174, + 174, + 82, + 82, + 4, + 4, + 337, + 337, + 337, + 10, + 10, + 10, + 10, + 209, + 209, + 150, + 150, + 162, + 162, + 162, + 262, + 153, + 153, + 390, + 390, + 132, + 13, + 395, + 122, + 357, + 7, + 7, + 64, + 64, + 180, + 178, + 178, + 390, + 383, + 383, + 383, + 70, + 360, + 360, + 34, + 34, + 34, + 61, + 189, + 376, + 290, + 9, + 383, + 17, + 175, + 371, + 31, + 76, + 259, + 259, + 353, + 353, + 353, + 353, + 353, + 138, + 138, + 138, + 361, + 204, + 297, + 297, + 297, + 297, + 294, + 294, + 180, + 180, + 48, + 48, + 80, + 80, + 80, + 267, + 78, + 78, + 307, + 307, + 221, + 221, + 4, + 4, + 4, + 15, + 15, + 15, + 274, + 237, + 237, + 237, + 237, + 120, + 129, + 396, + 396, + 396, + 296, + 296, + 241, + 382, + 382, + 382, + 22, + 174, + 174, + 83, + 83, + 298, + 274, + 274, + 351, + 378, + 84, + 87, + 87, + 12, + 123, + 325, + 90, + 90, + 90, + 201, + 201, + 201, + 201, + 71, + 199, + 199, + 107, + 107, + 136, + 312, + 312, + 312, + 312, + 312, + 280, + 169, + 169, + 23, + 252, + 252, + 315, + 315, + 315, + 315, + 235, + 235, + 141, + 141, + 141, + 141, + 141, + 88, + 284, + 288, + 288, + 116, + 116, + 75, + 248, + 35, + 35, + 287, + 263, + 263, + 263, + 263, + 48, + 48, + 23, + 273, + 273, + 144, + 72, + 72, + 305, + 91, + 54, + 54, + 235, + 104, + 145, + 145, + 145, + 145, + 209, + 209, + 193, + 193, + 193, + 193, + 181, + 205, + 205, + 49, + 49, + 115, + 164, + 345, + 338, + 178, + 227, + 233, + 233, + 272, + 272, + 173, + 173, + 173, + 173, + 334, + 280, + 280, + 167, + 167, + 167, + 167, + 167, + 22, + 22, + 274, + 277, + 277, + 277, + 277, + 277, + 264, + 369, + 163, + 163, + 61, + 199, + 199, + 188, + 188, + 324, + 324, + 146, + 146, + 146, + 172, + 172, + 37, + 37, + 37, + 37, + 61, + 50, + 50, + 180, + 92, + 92, + 187, + 187, + 219, + 219, + 219, + 326, + 326, + 321, + 31, + 31, + 117, + 388, + 215, + 327, + 327, + 327, + 327, + 327, + 8, + 8, + 8, + 8, + 245, + 369, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 289, + 289, + 241, + 283, + 283, + 243, + 155, + 155, + 389, + 64, + 337, + 337, + 204, + 365, + 198, + 198, + 198, + 198, + 147, + 58, + 58, + 385, + 385, + 385, + 385, + 385, + 319, + 5, + 149, + 149, + 149, + 273, + 194, + 161, + 161, + 268, + 268, + 268, + 268, + 228, + 228, + 228, + 117, + 199, + 253, + 358, + 340, + 340, + 340, + 340, + 340, + 340, + 275, + 262, + 58, + 58, + 58, + 263, + 263, + 87, + 38, + 38, + 38, + 217, + 135, + 135, + 135, + 357, + 357, + 357, + 357, + 303, + 8, + 8, + 242, + 242, + 247, + 247, + 247, + 25, + 25, + 337, + 206, + 373, + 357, + 357, + 357, + 329, + 293, + 148, + 31, + 210, + 392, + 255, + 255, + 394, + 394, + 394, + 394, + 394, + 394, + 290, + 161, + 161, + 161, + 105, + 105, + 248, + 248, + 125, + 125, + 315, + 332, + 332, + 332, + 143, + 258, + 258, + 258, + 4, + 4, + 81, + 81, + 81, + 152, + 252, + 252, + 252, + 252, + 252, + 252, + 61, + 61, + 342, + 342, + 126, + 126, + 126, + 318, + 394, + 91, + 91, + 91, + 126, + 126, + 126, + 126, + 3, + 3, + 3, + 3, + 14, + 14, + 163, + 304, + 304, + 97, + 97, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 29, + 79, + 79, + 143, + 143, + 199, + 175, + 10, + 10, + 47, + 148, + 148, + 148, + 17, + 130, + 381, + 381, + 150, + 150, + 229, + 137, + 298, + 298, + 298, + 298, + 298, + 298, + 286, + 155, + 44, + 203, + 293, + 293, + 276, + 196, + 196, + 196, + 196, + 27, + 27, + 27, + 27, + 396, + 396, + 396, + 330, + 330, + 352, + 274, + 270, + 59, + 316, + 13, + 13, + 63, + 329, + 36, + 36, + 254, + 88, + 88, + 88, + 88, + 88, + 88, + 88, + 154, + 2, + 2, + 296, + 29, + 29, + 266, + 91, + 219, + 385, + 385, + 225, + 225, + 225, + 225, + 87, + 87, + 87, + 168, + 168, + 294, + 25, + 25, + 345, + 345, + 345, + 383, + 263, + 331, + 369, + 109, + 109, + 29, + 37, + 168, + 168, + 228, + 278, + 278, + 278, + 278, + 90, + 273, + 273, + 273, + 273, + 273, + 259, + 259, + 7, + 7, + 358, + 372, + 372, + 55, + 115, + 316, + 170, + 387, + 387, + 387, + 387, + 25, + 25, + 25, + 25, + 350, + 350, + 319, + 112, + 112, + 139, + 344, + 344, + 344, + 344, + 344, + 344, + 344, + 217, + 217, + 163, + 163, + 163, + 292, + 292, + 292, + 67, + 226, + 226, + 294, + 148, + 148, + 148, + 148, + 198, + 198, + 198, + 198, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 195, + 195, + 195, + 248, + 200, + 328, + 85, + 81, + 331, + 331, + 331, + 331, + 331, + 87, + 87, + 87, + 87, + 396, + 396, + 54, + 54, + 54, + 54, + 299, + 299, + 299, + 256, + 353, + 353, + 44, + 44, + 163, + 118, + 118, + 118, + 118, + 59, + 38, + 38, + 38, + 38, + 103, + 43, + 43, + 43, + 260, + 260, + 229, + 229, + 2, + 2, + 328, + 328, + 328, + 328, + 328, + 328, + 385, + 46, + 149, + 149, + 149, + 149, + 149, + 5, + 344, + 2, + 205, + 205, + 47, + 193, + 135, + 331, + 265, + 265, + 265, + 45, + 45, + 78, + 78, + 78, + 260, + 179, + 9, + 9, + 9, + 9, + 9, + 231, + 231, + 243, + 243, + 243, + 243, + 243, + 359, + 359, + 359, + 172, + 166, + 192, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 + ], + "commands": [ + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 + ], + "values": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, 1, - 0, - 0, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, 1, - 0, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, 2, - 0, - 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, 1, - 0, - 1, - 1, - 1, - 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, 1, - 0, - 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, 1, - 2, - 0, - 0, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, 1, - 0, - 2, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, 1, - 0, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, 1, - 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, 2, - 0, - 1, - 0, - 2 - ], - "values": [ + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, 319, - 100, - 60, - 386, - 125, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, 236, - 176, - 262, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, 181, - 268, - 128, - 397, - 236, - 55, - 301, - 383, - 399, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, 188, - 151, - 18, - 221, - 46, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, 106, - 174, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, 312, - 185, - 75, - 174, - 141, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, 279, - 47, - 159, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, 162, - 156, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, 90, - 40, - 320, - 76, - 369, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, 352, - 158, - 247, - 82, - 368, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, 24, - 41, - 307, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, - 16, - 121, - 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, + 87, 326, - 16, - 252, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, 171, - 106, - 66, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, 374, - 288, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, 67, - 322, - 211, - 54, - 86, - 222, - 190, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, 30, - 215, - 150, - 72, - 232, - 317, - 86, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ] } diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/pifo.data index 485b42724..bf04ab461 100644 --- a/calyx-py/test/correctness/pifo.data +++ b/calyx-py/test/correctness/pifo.data @@ -100,7 +100,19907 @@ 0, 1, 0, - 2 + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 ], "format": { "is_signed": false, @@ -110,106 +20010,20006 @@ }, "values": { "data": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, 319, - 100, - 60, - 386, - 125, - 236, - 176, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, 262, - 181, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, 268, - 128, - 397, - 236, - 55, - 301, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, 383, - 399, - 188, - 151, - 18, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, 221, - 46, - 106, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, 174, - 262, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, 312, - 185, - 75, - 174, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, 141, - 359, - 279, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, 47, + 149, + 193, 159, - 351, - 162, - 156, - 90, - 40, - 320, - 76, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, 369, - 352, + 336, + 260, + 355, + 103, 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, 82, - 368, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, 24, + 31, 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, 16, - 121, - 379, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, 304, - 176, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, 128, - 233, - 333, - 215, - 74, - 28, - 326, - 16, - 252, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, 171, - 106, - 66, - 374, - 288, - 67, - 322, - 211, + 397, + 78, + 205, + 216, 54, - 86, - 222, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, 190, - 76, - 30, - 215, - 150, - 72, - 232, - 317, - 86, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ], "format": { "is_signed": false, @@ -219,6 +40019,19906 @@ }, "ans_mem": { "data": [ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/pifo.expect index e13d98057..585016985 100644 --- a/calyx-py/test/correctness/pifo.expect +++ b/calyx-py/test/correctness/pifo.expect @@ -1,308 +1,60008 @@ { "ans_mem": [ - 92, - 92, - 92, - 386, - 386, + 276, + 276, + 122, + 276, + 276, + 244, + 331, + 330, + 204, + 204, + 204, + 311, + 311, + 292, + 257, + 269, + 355, + 355, + 381, + 131, + 308, + 81, + 263, + 263, + 263, + 364, + 41, + 41, + 389, + 389, + 389, + 389, + 389, + 389, + 107, + 107, + 107, + 243, + 300, + 300, + 326, + 326, + 326, + 244, + 244, + 244, + 177, + 244, + 244, + 288, + 62, + 322, + 126, + 126, + 126, + 126, + 307, + 307, + 307, + 96, + 96, + 297, + 146, + 146, + 206, + 206, + 206, + 172, + 172, + 172, + 172, + 310, + 84, + 342, + 342, + 342, + 80, + 213, + 126, + 126, + 216, + 134, + 134, + 134, + 134, + 134, + 239, + 319, + 222, + 222, + 222, + 217, + 81, + 307, + 307, + 222, + 362, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 232, + 6, + 6, + 242, + 242, + 242, + 12, + 313, + 313, + 182, + 182, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 99, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 13, + 13, + 13, + 13, + 255, + 117, + 217, + 217, + 217, + 217, + 102, + 102, + 234, + 234, + 234, + 234, + 143, + 239, + 151, + 151, + 292, + 189, + 239, + 127, + 127, + 218, + 327, + 379, + 372, + 241, + 241, + 392, + 392, + 293, + 339, + 339, + 339, + 339, + 339, + 69, + 374, + 173, + 173, + 342, + 342, + 342, + 342, + 342, + 10, + 10, + 251, + 251, + 262, + 262, + 262, + 262, + 262, + 216, + 216, + 22, + 22, + 22, + 216, + 85, + 85, + 85, + 238, + 1, + 304, + 304, + 184, + 184, + 204, + 204, + 97, + 97, + 97, + 97, + 97, + 213, + 213, + 213, + 213, + 213, + 213, + 117, + 117, + 117, + 117, + 117, + 117, + 313, + 313, + 313, + 313, + 313, + 194, + 194, + 339, + 27, + 27, + 367, + 367, + 21, + 357, + 357, + 64, + 64, + 64, + 214, + 214, + 162, + 354, + 354, + 354, + 169, + 169, + 169, + 169, + 169, + 270, + 136, + 375, + 375, + 375, + 375, + 375, + 19, + 19, + 19, + 19, + 311, 100, - 236, - 125, - 176, - 176, - 176, - 128, - 128, + 291, + 291, + 291, + 184, + 282, + 110, + 110, + 110, + 110, + 110, + 110, + 110, + 347, + 347, + 347, + 192, + 192, + 279, + 279, + 279, + 279, + 279, + 9, + 220, + 220, + 220, + 220, + 31, + 31, + 389, + 87, + 399, + 399, + 130, + 392, + 197, + 197, + 197, + 258, + 258, + 258, + 194, + 220, + 87, + 224, + 49, + 204, + 204, + 204, + 121, + 224, + 18, + 18, + 127, + 223, + 126, + 19, + 38, + 38, + 46, + 46, 221, - 151, - 174, - 47, - 47, - 159, + 50, + 50, + 387, + 282, + 282, + 181, + 181, + 181, + 181, + 181, + 399, + 79, + 79, + 398, + 398, + 122, + 122, + 253, + 55, + 55, + 55, + 333, + 42, + 42, + 42, + 42, + 297, + 75, + 250, + 250, + 50, + 99, + 149, + 233, + 233, + 88, + 88, + 88, + 88, + 88, + 369, + 8, + 8, + 381, + 196, + 196, + 252, + 141, + 389, + 389, + 102, + 221, + 221, + 221, + 199, + 199, + 199, + 199, + 199, + 199, 368, - 24, - 207, - 41, + 368, + 368, + 368, + 368, + 29, + 202, 41, 41, - 252, - 16, - 16, - 374, - 374, - 374, - 374, - 374, - 374, - 106, - 106, - 106, - 222, - 66, + 287, + 150, + 389, + 68, + 54, + 43, + 348, + 348, + 6, + 6, + 6, + 6, + 6, + 155, + 221, + 221, + 167, + 245, + 11, + 11, + 11, + 345, + 345, + 345, + 345, + 179, + 122, + 375, + 377, + 391, + 175, + 175, + 175, + 175, + 363, + 363, + 363, + 363, + 103, + 103, + 264, + 64, + 258, + 52, + 52, + 52, + 384, + 384, + 37, + 37, + 37, + 383, + 192, + 192, + 343, + 14, + 143, + 143, + 88, + 38, + 322, + 156, + 156, + 381, + 157, + 33, + 33, + 226, + 44, + 211, + 349, + 388, + 388, + 388, + 388, + 115, + 388, + 242, + 67, + 67, + 242, + 246, + 334, + 334, + 334, + 283, + 283, + 283, + 283, + 26, + 305, + 56, + 223, + 223, + 236, + 83, 66, + 208, + 9, + 96, + 339, + 47, + 47, + 47, + 117, + 308, + 117, + 117, + 14, + 14, + 14, + 240, + 67, + 301, + 40, + 160, + 160, + 106, + 120, + 52, + 52, + 360, + 39, + 39, + 39, + 39, + 230, + 230, + 230, + 230, + 93, + 93, + 93, + 186, + 186, + 65, + 178, + 178, + 178, + 173, + 258, + 10, + 250, + 250, + 250, + 250, + 278, + 278, + 274, + 274, + 274, + 39, + 330, + 330, + 330, + 330, + 3, + 3, + 210, + 210, + 263, + 241, + 241, + 298, + 75, + 349, + 349, + 224, + 224, + 294, + 294, + 190, + 190, + 190, + 190, + 294, + 110, + 110, + 110, + 210, + 361, + 361, + 361, + 265, + 261, + 349, + 86, + 86, + 86, + 349, + 349, + 191, + 348, + 374, + 216, + 216, + 60, + 216, + 216, + 99, + 232, + 63, + 63, + 63, + 63, + 362, + 362, + 362, + 189, + 303, + 303, + 303, + 303, + 77, + 77, + 381, + 399, + 317, + 317, + 317, + 58, + 317, + 369, + 65, + 65, + 238, + 169, + 332, + 332, + 332, + 47, + 47, + 47, + 321, + 321, + 321, + 321, + 93, + 93, + 394, + 394, + 19, + 300, + 159, + 159, + 298, + 298, + 185, + 185, + 310, + 310, + 102, + 285, + 285, + 133, + 228, + 228, + 25, + 25, + 25, + 211, + 211, + 6, + 327, + 176, 267, + 173, + 306, + 306, + 33, + 33, + 314, + 314, + 314, + 189, + 202, + 202, + 144, + 261, + 99, + 396, + 396, + 396, + 289, + 108, + 289, + 97, + 97, + 97, + 97, + 236, + 362, + 362, + 257, + 159, + 317, + 317, + 388, + 56, + 260, + 23, + 229, + 229, + 229, + 229, + 109, + 109, + 200, + 8, + 365, + 365, + 365, + 76, + 76, + 283, + 283, + 283, + 78, + 75, + 248, + 248, + 122, + 273, + 227, + 123, + 227, + 18, + 332, + 332, + 332, + 332, + 332, + 29, + 242, + 242, + 47, + 47, + 46, + 46, + 338, + 246, + 321, + 321, + 43, + 36, + 36, + 36, + 36, + 154, + 154, + 124, + 78, + 78, + 78, + 86, + 45, + 45, + 43, + 48, + 48, + 48, + 48, + 48, + 239, + 239, + 48, + 312, + 312, + 274, + 64, + 64, + 365, + 180, + 88, + 353, + 148, + 148, + 223, + 89, + 12, + 12, + 12, + 191, + 191, + 191, + 191, + 201, + 22, + 22, + 22, + 22, + 22, + 351, + 132, + 132, + 235, + 176, + 176, + 220, + 220, + 220, + 220, + 17, + 17, + 17, + 306, + 306, + 189, + 395, + 395, + 145, + 333, + 70, + 228, + 228, + 5, + 5, + 5, + 5, + 5, + 5, + 221, + 213, + 213, + 213, + 145, + 145, + 145, + 286, + 170, + 170, + 170, + 204, + 76, + 332, + 332, + 162, + 56, + 56, + 204, + 204, + 198, + 223, + 223, + 174, + 174, + 174, + 223, + 93, 267, - 267, - 150, - 150, - 150, - 150, - 373, - 373, - 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 - ], - "commands": [ - 2, + 30, + 275, 1, - 2, 1, - 2, - 2, - 2, - 2, - 0, 1, - 0, - 2, - 0, - 0, - 0, - 1, - 1, - 0, - 1, - 2, - 0, - 2, - 0, - 0, - 2, - 0, + 182, + 182, + 114, + 114, + 114, + 114, + 114, + 114, + 114, + 167, + 282, + 282, + 282, + 282, + 167, + 245, + 245, + 245, + 136, + 136, + 373, + 196, + 196, + 155, + 155, + 326, + 326, + 155, + 268, + 151, + 151, + 302, + 302, + 302, + 170, + 325, + 325, + 325, + 325, + 196, + 358, + 12, + 12, + 12, + 12, + 12, + 366, + 87, + 87, + 87, + 87, + 87, + 87, + 389, + 20, + 228, + 228, + 128, + 221, + 221, 1, + 363, + 363, + 153, + 153, + 153, + 221, + 221, + 221, + 25, + 25, + 238, + 238, + 238, + 238, + 238, + 148, + 175, + 175, + 28, + 77, + 101, + 349, + 349, + 125, + 125, + 125, + 225, + 225, + 171, + 171, + 171, + 370, + 370, + 370, + 91, + 338, + 123, + 277, + 187, + 187, + 187, + 361, + 361, + 361, + 361, + 361, + 59, + 166, + 180, + 282, + 180, + 158, + 214, + 158, + 332, + 332, + 22, + 22, + 22, + 22, + 22, + 22, + 387, + 387, + 387, + 387, + 387, + 30, + 385, + 143, + 143, + 327, + 327, + 80, + 276, + 133, + 321, + 70, + 70, + 70, + 70, + 326, + 326, + 184, + 184, + 184, + 184, + 266, + 158, + 352, + 70, + 70, + 70, + 70, + 70, + 70, + 359, + 359, + 187, + 187, + 187, + 187, + 187, + 217, + 217, + 71, + 398, + 118, + 118, + 114, + 114, + 114, + 114, + 382, + 382, + 382, + 382, + 114, + 243, + 243, + 110, + 110, + 110, + 110, + 271, + 168, + 276, + 276, + 121, + 175, + 33, + 11, + 300, + 300, + 48, + 48, + 48, + 340, + 340, + 185, + 227, + 176, + 345, + 345, + 345, + 345, + 187, + 256, + 256, + 256, + 161, + 161, + 355, + 46, + 46, + 209, + 209, + 47, + 281, + 86, + 360, + 152, + 152, + 152, + 152, + 152, + 152, + 151, + 377, + 377, + 156, + 385, + 385, + 176, + 305, + 305, + 86, + 331, + 331, + 268, + 232, + 243, + 243, + 281, + 248, + 248, + 369, + 369, + 362, + 362, + 362, + 264, + 162, + 340, + 340, + 168, + 299, + 299, + 299, + 299, + 72, + 263, + 263, + 263, + 198, + 286, + 75, + 75, + 215, + 215, + 215, + 196, + 196, + 227, + 190, + 328, + 328, + 7, + 281, + 281, + 281, + 76, + 76, + 319, + 319, + 33, + 311, + 311, + 311, + 311, + 311, + 311, + 311, + 137, + 137, + 137, + 137, + 229, + 73, + 73, + 73, + 394, + 27, + 27, + 383, + 164, + 164, + 311, + 28, + 28, + 28, + 358, + 358, + 358, + 24, + 24, + 352, + 105, + 326, + 3, + 3, + 3, + 233, + 233, + 233, + 112, + 112, + 112, + 112, + 229, + 147, + 147, + 289, + 289, + 121, + 121, + 121, + 121, + 349, + 55, + 55, + 55, + 313, + 313, + 115, + 115, + 266, + 266, + 266, + 10, + 10, + 10, + 249, + 249, + 22, + 318, + 318, + 318, + 318, + 318, + 318, + 199, + 199, + 199, + 373, + 373, + 373, + 50, + 246, + 35, + 35, + 35, + 224, + 224, + 224, + 224, + 54, + 351, + 51, + 51, + 269, + 269, + 120, + 394, + 179, + 293, + 19, + 19, + 19, + 19, + 19, + 258, + 196, + 196, + 196, + 196, + 240, + 240, + 240, + 240, + 240, + 125, + 400, + 400, + 400, + 400, + 148, + 385, + 385, + 385, + 385, + 385, + 83, + 83, + 83, + 83, + 83, + 262, + 9, + 9, + 9, + 9, + 239, + 268, + 268, + 58, + 58, + 58, + 58, + 281, + 153, + 153, + 153, + 301, + 301, + 301, + 149, + 297, + 169, + 169, + 6, + 6, + 110, + 342, + 342, + 177, + 177, + 177, + 177, + 103, + 185, + 20, + 66, + 122, + 308, + 308, + 195, + 222, + 222, + 222, + 222, + 222, + 379, + 379, + 379, + 362, + 362, + 53, + 301, + 301, + 167, + 167, + 167, + 238, + 238, + 289, + 289, + 208, + 100, + 353, + 29, + 29, + 325, + 325, + 159, + 159, + 159, + 159, + 159, + 325, + 325, + 325, + 123, + 391, + 90, + 257, + 109, + 109, + 283, + 255, + 103, + 363, + 363, + 11, + 299, + 104, + 104, + 246, + 246, + 246, + 246, + 191, + 399, + 399, + 115, + 115, + 115, + 388, + 388, + 144, + 275, + 173, + 173, + 173, + 173, + 173, + 173, + 268, + 75, + 75, + 230, + 21, + 345, + 345, + 15, + 15, + 297, + 10, + 10, + 214, + 214, + 214, + 214, + 399, + 399, + 39, + 399, + 237, + 288, + 379, + 379, + 379, + 379, + 379, + 270, + 270, + 270, + 270, + 272, + 156, + 156, + 272, + 272, + 56, + 358, + 358, + 358, + 37, + 37, + 37, + 298, + 298, + 150, + 253, + 253, + 49, + 49, + 49, + 49, + 400, + 400, + 400, + 400, + 400, + 73, + 279, + 279, + 141, + 203, + 12, + 224, + 224, + 224, + 195, + 375, + 51, + 51, + 210, + 18, + 351, + 83, + 83, + 83, + 380, + 361, + 352, + 352, + 17, + 17, + 352, + 5, + 5, + 5, + 5, + 207, + 207, + 161, + 161, + 388, + 119, + 337, + 337, + 337, + 337, + 38, + 280, + 280, + 11, + 11, + 11, + 338, + 338, + 338, + 338, + 188, + 188, + 188, + 292, + 292, + 85, + 247, + 154, + 154, + 154, + 326, + 326, + 108, + 209, + 104, + 335, + 335, + 335, + 42, + 109, + 109, + 109, + 276, + 276, + 85, + 161, + 206, + 206, + 133, + 397, + 397, + 397, + 397, + 197, + 197, + 197, + 224, + 224, + 224, + 224, + 224, + 77, + 77, + 83, + 99, + 16, + 16, + 239, + 239, + 239, + 167, + 227, + 149, + 264, + 186, + 186, + 186, + 142, + 142, + 142, + 93, + 93, + 93, + 93, + 102, + 111, + 111, + 111, + 111, + 77, + 77, + 57, + 265, + 265, + 57, + 57, + 369, + 152, + 181, + 139, + 139, + 128, + 94, + 94, + 52, + 27, + 27, + 78, + 83, + 83, + 166, + 166, + 195, + 318, + 195, + 5, + 5, + 5, + 347, + 5, + 5, + 5, + 5, + 312, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 218, + 27, + 376, + 376, + 132, + 179, + 376, + 376, + 376, + 139, + 139, + 215, + 215, + 124, + 124, + 202, + 55, + 55, + 55, + 313, + 313, + 392, + 392, + 392, + 392, + 392, + 392, + 392, + 204, + 204, + 204, + 204, + 355, + 136, + 136, + 355, + 355, + 131, + 131, + 131, + 131, + 218, + 144, + 68, + 68, + 291, + 31, + 31, + 31, + 328, + 38, + 38, + 38, + 377, + 90, + 346, + 346, + 346, + 126, + 126, + 316, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 293, + 293, + 293, + 293, + 112, + 112, + 290, + 64, + 230, + 51, + 51, + 273, + 273, + 173, + 173, + 173, + 102, + 227, + 227, + 227, + 227, + 102, + 302, + 59, + 59, + 247, + 177, + 177, + 177, + 376, + 8, + 298, + 298, + 21, + 361, + 361, + 5, + 17, + 17, + 159, + 368, + 159, + 232, + 28, + 397, + 397, + 397, + 397, + 3, + 281, + 139, + 139, + 139, + 139, + 345, + 166, + 166, + 166, + 379, + 136, + 136, + 226, + 226, + 150, + 150, + 150, + 150, + 150, + 150, + 342, + 342, + 342, + 342, + 342, + 95, + 302, + 10, + 350, + 350, 1, - 0, 1, - 0, - 0, - 0, - 2, - 2, 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 1, + 285, + 285, + 285, + 285, + 126, + 209, + 154, + 368, + 200, + 68, + 98, + 125, + 125, + 125, + 125, + 125, + 254, + 254, + 102, + 37, + 368, + 368, + 368, + 160, + 160, + 160, + 166, + 166, + 76, + 28, + 58, + 66, + 355, + 66, + 160, + 31, + 31, + 31, + 31, + 31, + 31, + 361, + 237, + 237, + 56, + 246, + 312, + 363, + 363, + 262, + 367, + 376, + 376, + 108, + 3, + 234, + 234, + 226, + 35, + 35, + 35, + 288, + 288, + 288, + 8, + 272, + 293, + 35, + 35, + 92, + 11, + 305, + 305, + 305, + 193, + 193, + 319, + 319, + 53, + 53, + 372, + 372, + 112, + 83, + 83, + 83, + 131, + 197, + 197, + 336, + 302, + 302, + 302, + 273, + 273, + 297, + 294, + 80, + 294, + 294, + 121, + 397, + 397, + 397, + 397, + 254, + 199, + 199, + 199, + 264, + 264, + 264, + 264, + 264, + 186, + 186, + 186, + 333, + 333, + 333, + 118, + 396, + 396, + 396, + 396, + 396, + 396, + 19, + 306, + 306, + 46, + 46, + 327, + 133, + 220, + 142, + 32, + 32, + 125, + 168, + 236, + 236, + 236, + 168, + 168, + 168, + 168, + 168, + 168, + 63, + 56, + 10, + 200, + 200, 1, + 129, + 129, + 129, + 145, + 145, + 145, + 145, + 247, + 145, + 145, + 145, + 310, + 310, + 9, + 9, + 354, + 354, + 156, + 156, + 261, + 150, + 150, + 328, + 19, + 19, + 19, + 376, + 376, + 376, + 124, + 273, + 273, + 27, + 27, + 308, + 308, + 199, + 199, + 199, + 199, + 256, + 256, + 6, + 233, + 97, + 277, + 163, + 163, + 163, + 163, + 163, + 305, + 141, + 141, + 218, + 178, + 389, + 389, + 92, + 208, + 208, + 266, + 52, + 266, + 176, + 176, + 176, + 397, + 120, + 120, + 120, + 232, + 188, + 306, + 306, + 125, + 125, + 125, + 125, + 392, + 81, + 81, + 227, + 25, + 398, + 14, + 219, + 219, + 219, + 219, + 161, + 305, + 305, + 305, + 305, + 46, + 46, + 46, + 46, + 46, + 306, + 306, + 316, + 383, + 97, + 97, + 97, + 219, + 219, + 219, + 11, + 11, + 336, + 336, + 61, + 61, + 61, + 61, + 380, + 103, + 103, + 103, + 368, + 80, + 80, + 278, + 278, + 278, + 278, + 147, + 147, + 147, + 147, + 147, + 147, + 371, + 131, + 131, + 272, + 272, + 272, + 174, + 232, + 232, + 232, + 27, + 368, + 368, + 368, + 113, + 113, + 113, + 346, + 161, + 161, + 161, + 241, + 132, + 132, + 223, + 10, + 10, + 10, + 275, + 70, + 70, + 70, + 366, + 366, + 135, + 370, + 370, + 370, + 160, + 160, + 160, + 226, + 15, + 15, + 15, + 15, + 255, + 394, + 304, + 373, + 240, + 240, + 136, + 136, + 136, + 136, + 136, + 240, + 240, + 114, + 221, + 159, + 159, + 159, + 240, + 160, + 362, + 98, + 108, + 108, + 263, + 263, + 263, + 263, + 147, + 147, + 367, + 384, + 372, + 372, + 296, + 17, + 17, + 17, + 341, + 125, + 305, + 153, + 153, + 261, + 261, + 261, + 89, + 384, + 92, + 92, + 92, + 92, + 251, + 251, + 251, + 251, + 251, + 190, + 320, + 128, + 323, + 52, + 371, + 371, + 371, + 94, + 16, + 168, + 35, + 35, + 155, + 155, + 155, + 74, + 217, + 217, + 217, + 149, + 149, + 239, + 170, + 170, + 170, + 222, + 222, + 188, + 250, + 183, + 345, + 155, + 155, + 215, + 215, + 215, + 215, + 25, + 254, + 254, + 254, + 198, + 198, + 198, + 198, + 198, + 333, + 58, + 58, + 58, + 58, + 231, + 177, + 395, + 395, + 395, + 395, + 149, + 387, + 166, + 166, + 292, + 22, + 215, + 215, + 215, + 398, + 399, + 51, + 51, + 366, + 55, + 142, + 142, + 251, + 142, + 142, + 142, + 142, + 142, + 366, + 28, + 28, + 274, + 274, + 140, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 39, + 39, + 301, + 301, + 172, + 172, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 112, + 112, + 112, + 112, + 392, + 167, + 374, + 374, + 374, + 374, + 159, + 159, + 244, + 6, + 265, + 56, + 56, + 384, + 384, + 384, + 153, + 153, + 153, + 247, + 126, + 126, + 224, + 180, + 180, + 180, + 180, + 344, + 344, + 16, + 358, + 358, + 54, + 54, + 54, + 352, + 125, + 125, + 342, + 91, + 91, + 361, + 361, + 43, + 43, + 344, + 11, + 327, + 147, + 399, + 399, + 154, + 154, + 154, + 301, + 301, + 78, + 201, + 201, + 195, + 92, + 343, + 343, + 180, + 180, + 180, + 392, + 37, + 37, + 275, + 275, + 275, + 24, + 378, + 378, + 378, + 378, + 378, + 378, + 378, + 378, + 63, + 363, + 155, + 155, + 293, + 99, + 273, + 166, + 345, + 345, + 167, + 167, + 351, + 351, + 351, + 34, + 34, + 34, + 34, + 34, + 34, + 245, + 67, + 67, + 67, + 67, + 67, + 363, + 33, + 33, + 360, + 360, + 192, + 192, + 192, + 192, + 192, + 252, + 252, + 123, + 123, + 349, + 349, + 157, + 242, + 242, + 242, + 149, + 149, + 149, + 277, + 114, + 329, + 329, + 329, + 329, + 329, + 91, + 239, + 71, + 71, + 71, + 60, + 92, + 92, + 10, + 195, + 195, + 195, + 36, + 182, + 182, + 50, + 50, + 50, + 308, + 308, + 174, + 393, + 33, + 216, + 150, + 21, + 21, + 21, + 119, + 119, + 196, + 182, + 316, + 316, + 316, + 182, + 247, + 56, + 213, + 38, + 38, + 399, + 91, + 91, + 289, + 189, + 374, + 374, + 143, + 143, + 220, + 93, + 320, + 320, + 53, + 287, + 287, + 38, + 38, + 218, + 124, + 286, + 286, + 13, + 13, + 13, + 13, + 13, + 13, + 344, + 344, + 29, + 29, + 336, + 3, + 3, + 221, + 177, + 177, + 391, + 27, + 27, + 27, + 27, + 328, + 328, + 117, + 117, + 117, + 288, + 37, + 37, + 369, + 369, + 172, + 254, + 254, + 254, + 254, + 254, + 254, + 50, + 50, + 26, + 168, + 116, + 350, + 350, + 350, + 339, + 339, + 158, + 342, + 181, + 290, + 326, + 326, + 326, + 82, + 130, + 185, + 185, + 185, + 201, + 201, + 201, + 177, + 177, + 177, + 392, + 392, + 4, + 240, + 91, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 55, + 55, + 315, + 39, + 39, + 349, + 349, + 349, + 190, + 366, + 119, + 119, + 266, + 266, + 38, + 38, + 38, + 317, + 123, + 225, + 225, + 225, + 225, + 199, + 226, + 226, + 26, + 26, + 344, + 169, + 375, + 152, + 152, + 152, + 152, + 238, + 13, + 13, + 13, + 250, + 116, + 116, + 372, + 372, + 372, + 372, + 372, + 372, + 372, + 122, + 122, + 122, + 296, + 296, + 43, + 395, + 395, + 13, + 13, + 104, + 52, + 9, + 9, + 374, + 9, + 9, + 290, + 114, + 260, + 260, + 83, + 83, + 83, + 83, + 261, + 261, + 95, + 283, + 283, + 113, + 113, + 323, + 57, + 57, + 280, + 280, + 280, + 120, + 356, + 108, + 266, + 266, + 69, + 75, + 91, + 141, + 141, + 180, + 180, + 19, + 315, + 8, + 381, + 218, + 218, + 241, + 341, + 59, + 59, + 59, + 355, + 355, + 355, + 355, + 119, + 275, + 275, + 168, + 305, + 305, + 7, + 7, + 354, + 104, + 104, + 275, + 138, + 138, + 138, + 217, + 217, + 197, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 94, + 255, + 255, + 147, + 147, + 147, + 336, + 336, + 336, + 133, + 133, + 133, + 133, + 278, + 278, + 38, + 293, + 293, + 293, + 293, + 293, + 293, + 80, + 365, + 365, + 365, + 365, + 80, + 286, + 164, + 164, + 164, + 257, + 167, + 167, + 167, + 320, + 320, + 102, + 102, + 303, + 303, + 21, + 21, + 204, + 204, + 46, + 383, + 13, + 13, + 326, + 47, + 47, + 233, + 233, + 233, + 233, + 136, + 331, + 121, + 272, + 62, + 62, + 234, + 234, + 234, + 70, + 70, + 251, + 177, + 177, + 283, + 21, + 21, + 214, + 214, + 101, + 138, + 187, + 274, + 187, + 187, + 33, + 33, + 242, + 33, + 33, + 125, + 125, + 378, + 125, + 18, + 18, + 120, + 192, + 192, + 192, + 68, + 68, + 350, + 148, + 204, + 204, + 204, + 204, + 134, + 134, + 348, + 348, + 49, + 383, + 111, + 260, + 260, + 163, + 163, + 163, + 317, + 317, + 42, + 250, + 148, + 148, + 273, + 273, + 95, + 282, + 58, + 313, + 313, + 199, + 199, + 199, + 217, + 100, + 100, + 100, + 235, + 235, + 235, + 235, + 235, + 22, + 22, + 334, + 334, + 152, + 152, + 312, + 199, + 284, + 284, + 284, + 5, + 5, + 5, + 204, + 204, + 204, + 204, + 204, + 135, + 225, + 225, + 345, + 317, + 317, + 392, + 342, + 342, + 342, + 342, + 295, + 295, + 376, + 227, + 155, + 155, + 155, + 227, + 227, + 227, + 154, + 154, + 352, + 352, + 352, + 352, + 176, + 263, + 263, + 193, + 249, + 117, + 117, + 333, + 333, + 333, + 27, + 27, + 27, + 241, + 241, + 241, + 113, + 113, + 298, + 45, + 45, + 45, + 280, + 28, + 272, + 272, + 25, + 250, + 108, + 108, + 108, + 108, + 282, + 282, + 197, + 215, + 117, + 117, + 117, + 358, + 78, + 78, + 269, + 14, + 14, + 271, + 82, + 270, + 131, + 236, + 27, + 27, + 27, + 225, + 225, + 225, + 27, + 27, + 27, + 250, + 53, + 286, + 286, + 286, + 47, + 47, + 375, + 375, + 375, + 375, + 375, + 127, + 294, + 294, + 294, + 143, + 248, + 144, + 144, + 329, + 15, + 343, + 185, + 123, + 162, + 69, + 69, + 329, + 10, + 10, + 353, + 353, + 353, + 173, + 141, + 141, + 159, + 159, + 159, + 159, + 159, + 178, + 296, + 181, + 55, + 119, + 59, + 184, + 184, + 275, + 119, + 119, + 296, + 296, + 296, + 296, + 129, + 129, + 328, + 396, + 41, + 41, + 396, + 396, + 50, + 50, + 50, + 370, + 370, + 370, + 14, + 254, + 19, + 19, + 19, + 19, + 362, + 165, + 265, + 25, + 25, + 253, + 162, + 230, + 124, + 220, + 220, + 135, + 339, + 176, + 343, + 63, + 225, + 179, + 269, + 269, + 269, + 269, + 87, + 239, + 239, + 195, + 212, + 212, + 102, + 250, + 250, + 250, + 146, + 308, + 132, + 305, + 110, + 299, + 299, + 299, + 299, + 299, + 299, + 72, + 72, + 244, + 244, + 244, + 79, + 248, + 248, + 38, + 38, + 282, + 101, + 101, + 326, + 326, + 326, + 81, + 387, + 199, + 318, + 318, + 169, + 169, + 169, + 267, + 186, + 273, + 196, + 248, + 22, + 61, + 157, + 157, + 157, + 157, + 164, + 211, + 164, + 364, + 364, + 248, + 248, + 393, + 393, + 49, + 210, + 100, + 100, + 100, + 100, + 215, + 183, + 225, + 144, + 339, + 339, + 339, + 165, + 70, + 70, + 239, + 148, + 269, + 94, + 300, + 5, + 5, + 223, + 105, + 105, + 226, + 237, + 186, + 186, + 186, + 262, + 262, + 91, + 91, + 241, + 241, + 84, + 84, + 84, + 215, + 77, + 77, + 77, + 275, + 275, + 275, + 275, + 275, + 117, + 284, + 284, + 284, + 72, + 230, + 150, + 150, + 150, + 150, + 222, + 222, + 222, + 9, + 9, + 9, + 226, + 226, + 226, + 226, + 81, + 81, + 372, + 372, + 156, + 302, + 302, + 125, + 398, + 398, + 198, + 261, + 261, + 6, + 337, + 90, + 256, + 256, + 256, + 64, + 64, + 246, + 22, + 389, + 250, + 379, + 70, + 70, + 70, + 70, + 70, + 70, + 379, + 168, + 268, + 116, + 277, + 235, + 223, + 223, + 185, + 271, + 275, + 50, + 50, + 324, + 324, + 324, + 324, + 324, + 60, + 60, + 271, + 90, + 383, + 54, + 54, + 54, + 54, + 253, + 161, + 161, + 161, + 395, + 395, + 77, + 262, + 121, + 264, + 264, + 124, + 343, + 177, + 242, + 242, + 242, + 3, + 46, + 44, + 116, + 93, + 93, + 93, + 5, + 203, + 11, + 11, + 11, + 11, + 11, + 237, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 277, + 277, + 277, + 7, + 7, + 386, + 386, + 386, + 142, + 250, + 250, + 174, + 174, + 174, + 174, + 349, + 138, + 138, + 246, + 246, + 246, + 246, + 130, + 259, + 259, + 198, + 198, + 198, + 198, + 198, + 303, + 39, + 39, + 297, + 18, + 18, + 307, + 90, + 351, + 182, + 182, + 182, + 137, + 136, + 16, + 184, + 132, + 130, + 231, + 130, + 130, + 130, + 130, + 24, + 343, + 343, + 343, + 343, + 343, + 150, + 45, + 333, + 333, + 333, + 45, + 273, + 273, + 273, + 273, + 3, + 3, + 3, + 3, + 296, + 188, + 188, + 188, + 298, + 104, + 244, + 177, + 177, + 177, + 177, + 177, + 177, + 177, + 266, + 75, + 75, + 75, + 297, + 113, + 7, + 17, + 17, + 125, + 125, + 125, + 183, + 277, + 124, + 271, + 233, + 129, + 129, + 233, + 233, + 233, + 233, + 8, + 217, + 217, + 162, + 210, + 210, + 24, + 24, + 274, + 34, + 239, + 29, + 237, + 237, + 144, + 144, + 144, + 265, + 265, + 265, + 176, + 378, + 197, + 197, + 268, + 82, + 82, + 389, + 389, + 190, + 190, + 308, + 115, + 355, + 355, + 355, + 150, + 150, + 150, + 150, + 278, + 278, + 278, + 278, + 33, + 398, + 398, + 398, + 189, + 189, + 350, + 59, + 59, + 311, + 98, + 98, + 291, + 224, + 224, + 96, + 96, + 96, + 96, + 224, + 54, + 379, + 75, + 75, + 75, + 380, + 380, + 380, + 146, + 241, + 241, + 241, + 42, + 391, + 391, + 187, + 323, + 323, + 323, + 323, + 184, + 391, + 113, + 305, + 195, + 195, + 195, + 358, + 358, + 130, + 271, + 271, + 271, + 113, + 113, + 113, + 113, + 113, + 246, + 38, + 379, + 379, + 379, + 172, + 172, + 245, + 26, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 8, + 327, + 327, + 327, + 193, + 207, + 207, + 198, + 377, + 26, + 374, + 196, + 196, + 342, + 342, + 342, + 196, + 258, + 172, + 172, + 172, + 172, + 345, + 345, + 136, + 391, + 391, + 391, + 391, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 354, + 354, + 354, + 149, + 378, + 378, + 31, + 377, + 99, + 385, + 385, + 43, + 43, + 43, + 277, + 14, + 14, + 226, + 2, + 2, + 374, + 148, + 274, + 83, + 83, + 83, + 346, + 346, + 346, + 184, + 184, + 184, + 184, + 204, + 204, + 204, + 6, + 6, + 277, + 277, + 277, + 88, + 88, + 202, + 56, + 56, + 56, + 56, + 383, + 383, + 383, + 383, + 163, + 260, + 78, + 78, + 389, + 22, + 22, + 22, + 22, + 246, + 167, + 167, + 30, + 3, + 322, + 322, + 3, + 362, + 362, + 362, + 1, + 1, + 1, + 1, + 1, + 1, + 395, + 395, + 395, + 56, + 377, + 128, + 218, + 54, + 54, + 213, + 213, + 39, + 205, + 205, + 205, + 205, + 205, + 205, + 199, + 199, + 206, + 186, + 341, + 341, + 341, + 341, + 180, + 180, + 180, + 282, + 326, + 150, + 150, + 150, + 150, + 326, + 119, + 119, + 119, + 222, + 355, + 266, + 389, + 389, + 196, + 383, + 7, + 324, + 48, + 270, + 58, + 58, + 31, + 211, + 66, + 66, + 66, + 330, + 159, + 159, + 370, + 370, + 60, + 60, + 60, + 60, + 60, + 60, + 215, + 215, + 215, + 215, + 215, + 215, + 215, + 102, + 258, + 187, + 203, + 176, + 50, + 50, + 186, + 380, + 151, + 151, + 151, + 316, + 5, + 371, + 75, + 399, + 399, + 161, + 139, + 64, + 232, + 232, + 110, + 265, + 155, + 155, + 367, + 56, + 300, + 300, + 175, + 123, + 257, + 257, + 257, + 369, + 380, + 102, + 312, + 68, + 68, + 277, + 112, + 145, + 212, + 68, + 243, + 151, + 151, + 157, + 157, + 157, + 163, + 339, + 16, + 16, + 16, + 256, + 253, + 332, + 178, + 332, + 332, + 349, + 349, + 311, + 24, + 24, + 24, + 24, + 252, + 252, + 10, + 10, + 281, + 281, + 281, + 281, + 232, + 340, + 397, + 397, + 397, + 397, + 397, + 397, + 397, + 5, + 5, + 5, + 167, + 167, + 225, + 98, + 98, + 208, + 208, + 170, + 328, + 70, + 214, + 177, + 177, + 386, + 386, + 386, + 386, + 129, + 129, + 394, + 24, + 155, + 33, + 33, + 254, + 254, + 254, + 146, + 214, + 96, + 96, + 96, + 96, + 228, + 228, + 178, + 261, + 261, + 109, + 109, + 109, + 109, + 214, + 133, + 133, + 133, + 392, + 392, + 90, + 230, + 230, + 41, + 41, + 380, + 36, + 36, + 36, + 36, + 36, + 36, + 36, + 356, + 356, + 174, + 239, + 27, + 260, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 208, + 208, + 191, + 191, + 191, + 191, + 363, + 57, + 57, + 283, + 283, + 55, + 373, + 373, + 373, + 373, + 373, + 151, + 276, + 276, + 276, + 276, + 45, + 286, + 245, + 245, + 245, + 245, + 85, + 230, + 230, + 230, + 230, + 230, + 46, + 46, + 327, + 357, + 206, + 228, + 228, + 228, + 331, + 331, + 331, + 248, + 269, + 164, + 214, + 146, + 146, + 299, + 299, + 299, + 140, + 140, + 140, + 251, + 251, + 188, + 188, + 188, + 301, + 47, + 47, + 47, + 47, + 47, + 336, + 53, + 53, + 296, + 189, + 189, + 189, + 189, + 386, + 386, + 157, + 157, + 157, + 302, + 18, + 18, + 18, + 295, + 121, + 385, + 192, + 116, + 138, + 353, + 86, + 86, + 207, + 92, + 287, + 287, + 182, + 182, + 182, + 215, + 63, + 275, + 275, + 60, + 60, + 60, + 60, + 60, + 60, + 234, + 234, + 104, + 104, + 256, + 256, + 195, + 195, + 280, + 280, + 64, + 64, + 64, + 64, + 64, + 64, + 337, + 78, + 78, + 337, + 337, + 337, + 337, + 337, + 337, + 337, + 142, + 142, + 142, + 142, + 142, + 253, + 70, + 346, + 207, + 207, + 204, + 204, + 204, + 253, + 371, + 76, + 371, + 371, + 371, + 371, + 371, + 181, + 181, + 181, + 352, + 194, + 203, + 158, + 280, + 214, + 77, + 214, + 261, + 4, + 4, + 229, + 229, + 229, + 229, + 165, + 165, + 165, + 165, + 335, + 335, + 101, + 233, + 57, + 299, + 299, + 299, + 71, + 71, + 249, + 249, + 108, + 262, + 262, + 162, + 267, + 267, + 111, + 111, + 111, + 246, + 246, + 246, + 246, + 246, + 43, + 245, + 57, + 57, + 57, + 231, + 231, + 119, + 119, + 119, + 262, + 151, + 151, + 151, + 151, + 151, + 151, + 314, + 314, + 210, + 366, + 268, + 63, + 63, + 63, + 268, + 268, + 268, + 268, + 287, + 266, + 85, + 85, + 217, + 217, + 217, + 217, + 122, + 285, + 184, + 247, + 247, + 176, + 176, + 176, + 387, + 387, + 37, + 37, + 212, + 180, + 285, + 47, + 205, + 164, + 164, + 365, + 365, + 95, + 95, + 291, + 226, + 226, + 47, + 47, + 47, + 47, + 226, + 226, + 226, + 105, + 105, + 105, + 379, + 379, + 192, + 192, + 192, + 341, + 341, + 95, + 396, + 396, + 396, + 156, + 156, + 316, + 316, + 316, + 29, + 29, + 302, + 135, + 135, + 264, + 264, + 264, + 264, + 264, + 79, + 225, + 243, + 243, + 243, + 284, + 309, + 309, + 262, + 186, + 262, + 262, + 262, + 121, + 121, + 121, + 121, + 101, + 68, + 174, + 394, + 394, + 394, + 174, + 204, + 249, + 249, + 295, + 116, + 116, + 116, + 116, + 184, + 282, + 115, + 115, + 115, + 115, + 115, + 230, + 230, + 230, + 230, + 230, + 122, + 336, + 53, + 241, + 148, + 148, + 148, + 309, + 309, + 309, + 309, + 309, + 309, + 309, + 16, + 344, + 344, + 344, + 145, + 254, + 62, + 176, + 176, + 176, + 231, + 176, + 176, + 381, + 103, + 103, + 204, + 204, + 204, + 204, + 16, + 341, + 86, + 25, + 25, + 25, + 25, + 184, + 284, + 184, + 84, + 84, + 98, + 377, + 28, + 373, + 373, + 373, + 373, + 288, + 186, + 288, + 353, + 353, + 228, + 228, + 228, + 69, + 69, + 398, + 156, + 156, + 156, + 262, + 262, + 26, + 26, + 326, + 43, + 398, + 398, + 284, + 31, + 284, + 284, + 70, + 70, + 281, + 217, + 217, + 217, + 217, + 332, + 302, + 60, + 60, + 60, + 60, + 276, + 32, + 32, + 313, + 173, + 173, + 211, + 188, + 188, + 315, + 118, + 118, + 118, + 386, + 386, + 94, + 94, + 94, + 94, + 231, + 231, + 231, + 231, + 231, + 114, + 335, + 31, + 31, + 31, + 344, + 38, + 368, + 368, + 368, + 368, + 368, + 368, + 61, + 278, + 36, + 225, + 225, + 225, + 225, + 148, + 342, + 20, + 20, + 294, + 294, + 180, + 180, + 180, + 180, + 278, + 278, + 153, + 153, + 153, + 386, + 156, + 156, + 225, + 34, + 310, + 182, + 323, + 40, + 339, + 57, + 57, + 218, + 180, + 180, + 209, + 209, + 142, + 230, + 230, + 230, + 230, + 6, + 276, + 276, + 18, + 336, + 137, + 137, + 344, + 344, + 20, + 217, + 364, + 389, + 389, + 289, + 289, + 218, + 218, + 218, + 392, + 392, + 392, + 392, + 392, + 239, + 239, + 239, + 239, + 239, + 206, + 206, + 206, + 271, + 271, + 346, + 33, + 33, + 346, + 346, + 346, + 346, + 346, + 346, + 12, + 375, + 165, + 386, + 130, + 130, + 243, + 243, + 146, + 276, + 57, + 370, + 13, + 209, + 209, + 64, + 283, + 114, + 114, + 255, + 255, + 255, + 255, + 124, + 124, + 308, + 187, + 293, + 154, + 242, + 383, + 243, + 243, + 181, + 377, + 114, + 114, + 278, + 119, + 119, + 320, + 320, + 274, + 303, + 303, + 109, + 303, + 124, + 214, + 322, + 256, + 336, + 336, + 336, + 101, + 101, + 336, + 336, + 280, + 5, + 353, + 353, + 381, + 362, + 362, + 362, + 362, + 50, + 315, + 280, + 217, + 217, + 33, + 34, + 34, + 34, + 329, + 329, + 34, + 283, + 283, + 283, + 283, + 16, + 16, + 16, + 238, + 238, + 238, + 57, + 332, + 79, + 221, + 155, + 342, + 342, + 76, + 388, + 197, + 197, + 66, + 223, + 223, + 223, + 66, + 66, + 303, + 303, + 303, + 303, + 303, + 78, + 78, + 211, + 211, + 211, + 180, + 180, + 311, + 166, + 302, + 302, + 302, + 302, + 302, + 302, + 302, + 130, + 299, + 299, + 299, + 137, + 340, + 138, + 138, + 138, + 138, + 138, + 138, + 229, + 56, + 288, + 90, + 320, + 55, + 268, + 262, + 262, + 262, + 262, + 112, + 112, + 262, + 121, + 232, + 232, + 232, + 49, + 49, + 246, + 246, + 246, + 246, + 246, + 246, + 107, + 107, + 107, + 224, + 224, + 399, + 399, + 214, + 214, + 270, + 270, + 316, + 316, + 316, + 314, + 314, + 222, + 160, + 160, + 299, + 299, + 97, + 312, + 312, + 312, + 8, + 213, + 213, + 160, + 160, + 160, + 160, + 160, + 289, + 189, + 253, + 253, + 253, + 21, + 203, + 155, + 155, + 155, + 312, + 33, + 33, + 33, + 400, + 300, + 308, + 308, + 308, + 328, + 253, + 381, + 381, + 262, + 242, + 182, + 242, + 242, + 242, + 164, + 329, + 329, + 8, + 8, + 340, + 83, + 240, + 199, + 199, + 384, + 116, + 236, + 236, + 236, + 236, + 123, + 231, + 299, + 18, + 299, + 299, + 80, + 290, + 290, + 177, + 177, + 177, + 309, + 309, + 309, + 218, + 218, + 321, + 321, + 163, + 321, + 301, + 77, + 77, + 77, + 301, + 23, + 204, + 361, + 216, + 216, + 216, + 199, + 199, + 199, + 199, + 238, + 128, + 128, + 207, + 132, + 396, + 189, + 285, + 285, + 285, + 72, + 376, + 376, + 106, + 106, + 106, + 106, + 304, + 304, + 87, + 201, + 201, + 201, + 201, + 201, + 201, + 121, + 282, + 104, + 265, + 265, + 265, + 38, + 316, + 316, + 316, + 316, + 168, + 168, + 168, + 285, + 285, + 285, + 4, + 278, + 278, + 37, + 37, + 37, + 259, + 259, + 259, + 259, + 121, + 316, + 188, + 364, + 150, + 284, + 284, + 53, + 53, + 330, + 330, + 167, + 167, + 379, + 379, + 379, + 379, + 120, + 246, + 129, + 129, + 348, + 348, + 348, + 149, + 371, + 131, + 131, + 255, + 255, + 32, + 267, + 163, + 377, + 111, + 400, + 400, + 195, + 195, + 359, + 359, + 359, + 359, + 359, + 109, + 109, + 201, + 201, + 201, + 201, + 201, + 201, + 66, + 312, + 312, + 77, + 231, + 33, + 221, + 221, + 221, + 130, + 326, + 326, + 162, + 162, + 267, + 52, + 287, + 287, + 287, + 80, + 360, + 360, + 360, + 360, + 360, + 360, + 63, + 277, + 277, + 190, + 190, + 255, + 50, + 50, + 50, + 292, + 50, + 50, + 222, + 222, + 222, + 222, + 222, + 182, + 182, + 182, + 182, + 223, + 32, + 297, + 297, + 30, + 255, + 255, + 255, + 255, + 136, + 111, + 323, + 130, + 130, + 130, + 118, + 254, + 254, + 254, + 118, + 118, + 303, + 182, + 182, + 158, + 144, + 103, + 103, + 103, + 103, + 167, + 29, + 29, + 369, + 369, + 369, + 29, + 168, + 168, + 168, + 168, + 139, + 58, + 58, + 147, + 132, + 26, + 286, + 286, + 286, + 286, + 196, + 202, + 39, + 39, + 352, + 352, + 153, + 153, + 241, + 143, + 143, + 143, + 397, + 397, + 397, + 397, + 397, + 117, + 288, + 19, + 290, + 290, + 290, + 131, + 370, + 77, + 77, + 269, + 269, + 86, + 228, + 6, + 6, + 6, + 241, + 241, + 241, + 241, + 241, + 241, + 241, + 166, + 166, + 166, + 166, + 166, + 166, + 339, + 78, + 335, + 72, + 321, + 140, + 140, + 140, + 364, + 364, + 364, + 364, + 364, + 364, + 116, + 295, + 295, + 295, + 295, + 134, + 134, + 134, + 246, + 148, + 148, + 148, + 148, + 148, + 148, + 205, + 205, + 127, + 363, + 363, + 168, + 260, + 260, + 260, + 1, + 1, + 1, + 1, + 1, + 1, + 257, + 21, + 21, + 21, + 367, + 367, + 48, + 363, + 174, + 271, + 271, + 271, + 271, + 68, + 353, + 71, + 267, + 17, + 50, + 50, + 50, + 185, + 372, + 134, + 134, + 134, + 370, + 134, + 354, + 354, + 373, + 347, + 347, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 347, + 347, + 347, + 347, + 347, + 102, + 217, + 97, + 97, + 352, + 352, + 352, + 70, + 369, + 13, + 400, + 143, + 143, + 143, + 320, + 73, + 217, + 217, + 217, + 217, + 217, + 217, + 58, + 359, + 359, + 359, + 359, + 163, + 163, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 33, + 243, + 243, + 243, + 171, + 171, + 171, + 266, + 266, + 103, + 271, + 183, + 331, + 331, + 331, + 331, + 331, + 331, + 331, + 12, + 367, + 12, + 12, + 12, + 12, + 238, + 238, + 110, + 110, + 360, + 360, + 360, + 121, + 235, + 235, + 235, + 235, + 157, + 157, + 232, + 30, + 302, + 77, + 237, + 237, + 237, + 237, + 237, + 123, + 242, + 80, + 371, + 72, + 322, + 322, + 322, + 322, + 199, + 199, + 199, + 380, + 380, + 89, + 235, + 69, + 69, + 398, + 59, + 274, + 148, + 148, + 148, + 148, + 339, + 339, + 102, + 102, + 102, + 102, + 102, + 228, + 172, + 312, + 312, + 364, + 234, + 55, + 302, + 122, + 375, + 375, + 375, + 375, + 38, + 312, + 312, + 119, + 247, + 247, + 195, + 195, + 357, + 35, + 35, + 35, + 243, + 243, + 243, + 86, + 86, + 261, + 173, + 246, + 246, + 135, + 275, + 275, + 109, + 335, + 335, + 335, + 335, + 335, + 184, + 202, + 39, + 39, + 39, + 292, + 76, + 76, + 381, + 192, + 278, + 278, + 25, + 256, + 256, + 256, + 256, + 256, + 256, + 3, + 364, + 364, + 364, + 137, + 276, + 164, + 208, + 208, + 53, + 53, + 394, + 130, + 258, + 258, + 49, + 49, + 49, + 327, + 171, + 213, + 43, + 43, + 247, + 174, + 174, + 223, + 223, + 223, + 223, + 159, + 354, + 20, + 20, + 329, + 329, + 195, + 270, + 175, + 387, + 78, + 252, + 129, + 259, + 259, + 76, + 364, + 364, + 364, + 172, + 240, + 240, + 240, + 240, + 37, + 37, + 37, + 234, + 172, + 267, + 267, + 161, + 161, + 161, + 161, + 161, + 161, + 300, + 300, + 118, + 118, + 274, + 274, + 36, + 300, + 300, + 25, + 216, + 171, + 171, + 201, + 201, + 121, + 121, + 121, + 121, + 121, + 121, + 390, + 20, + 20, + 291, + 291, + 113, + 113, + 351, + 174, + 297, + 149, + 149, + 149, + 182, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 182, + 153, + 258, + 258, + 154, + 154, + 154, + 339, + 339, + 117, + 117, + 117, + 117, + 117, + 117, + 392, + 30, + 30, + 30, + 294, + 84, + 84, + 84, + 227, + 227, + 99, + 99, + 362, + 27, + 308, + 154, + 278, + 278, + 81, + 81, + 272, + 272, + 272, + 76, + 76, + 234, + 172, + 172, + 349, + 161, + 291, + 103, + 103, + 103, + 278, + 278, + 278, + 278, + 108, + 266, + 66, + 66, + 66, + 196, + 137, + 137, + 93, + 29, + 141, + 141, + 92, + 92, + 92, + 62, + 62, + 162, + 106, + 254, + 106, + 106, + 351, + 360, + 160, + 243, + 243, + 225, + 351, + 373, + 373, + 89, + 271, + 271, + 160, + 296, + 296, + 347, + 347, + 318, + 234, + 234, + 234, + 358, + 262, + 179, + 179, + 239, + 239, + 239, + 239, + 239, + 44, + 211, + 152, + 329, + 131, + 131, + 131, + 364, + 364, + 364, + 364, + 145, + 237, + 152, + 152, + 152, + 214, + 191, + 191, + 191, + 124, + 41, + 161, + 161, + 398, + 398, + 161, + 161, + 161, + 313, + 313, + 93, + 366, + 366, + 73, + 222, + 17, + 17, + 17, + 293, + 348, + 304, + 304, + 153, + 322, + 322, + 65, + 65, + 387, + 178, + 178, + 178, + 178, + 254, + 137, + 137, + 137, + 339, + 339, + 339, + 339, + 154, + 154, + 154, + 230, + 230, + 177, + 177, + 286, + 286, + 83, + 83, + 318, + 149, + 149, + 149, + 278, + 278, + 73, + 362, + 362, + 177, + 399, + 194, + 385, + 385, + 385, + 385, + 144, + 320, + 32, + 32, + 210, + 228, + 321, + 386, + 157, + 157, + 157, + 386, + 200, + 200, + 200, + 200, + 200, + 360, + 360, + 360, + 360, + 155, + 210, + 210, + 210, + 23, + 23, + 23, + 319, + 319, + 117, + 117, + 295, + 295, + 153, + 231, + 231, + 231, + 66, + 66, + 396, + 396, + 396, + 396, + 165, + 223, + 198, + 198, + 330, + 26, + 272, + 272, + 272, + 123, + 123, + 123, + 316, + 316, + 38, + 264, + 264, + 1, + 1, + 1, + 1, + 398, + 398, + 100, + 100, + 100, + 19, + 304, + 304, + 304, + 304, + 19, + 311, + 70, + 70, + 348, + 23, + 23, + 349, + 349, + 349, + 349, + 349, + 349, + 349, + 160, + 160, + 160, + 160, + 160, + 237, + 49, + 49, + 49, + 49, + 337, + 42, + 42, + 229, + 127, + 127, + 236, + 236, + 236, + 126, + 280, + 112, + 112, + 112, + 256, + 26, + 219, + 219, + 219, + 22, + 22, + 22, + 22, + 214, + 214, + 214, + 214, + 102, + 341, + 100, + 285, + 285, + 280, + 280, + 280, + 240, + 240, + 278, + 278, + 278, + 299, + 109, + 223, + 223, + 223, + 266, + 266, + 266, + 266, + 186, + 277, + 109, + 109, + 109, + 109, + 109, + 109, + 250, + 70, + 70, + 70, + 70, + 374, + 197, + 197, + 202, + 198, + 332, + 56, + 56, + 323, + 323, + 193, + 193, + 272, + 272, + 272, + 75, + 329, + 167, + 337, + 337, + 337, + 337, + 80, + 80, + 208, + 98, + 342, + 92, + 92, + 92, + 92, + 92, + 382, + 349, + 362, + 238, + 238, + 221, + 221, + 216, + 216, + 227, + 227, + 179, + 179, + 179, + 179, + 351, + 62, + 343, + 1, + 1, + 1, + 1, + 1, + 1, + 222, + 222, + 165, + 165, + 230, + 230, + 230, + 230, + 16, + 16, + 214, + 214, + 26, + 26, + 26, + 383, + 383, + 34, + 34, + 34, + 303, + 180, + 180, + 180, + 180, + 180, + 180, + 180, + 318, + 318, + 175, + 175, + 310, + 310, + 33, + 33, + 33, + 350, + 151, + 151, + 313, + 313, + 171, + 315, + 6, + 394, + 101, + 206, + 165, + 260, + 260, + 260, + 260, + 260, + 260, + 36, + 252, + 252, + 252, + 252, + 252, + 118, + 118, + 118, + 391, + 391, + 17, + 334, + 334, + 334, + 177, + 177, + 177, + 396, + 396, + 269, + 355, + 301, + 394, + 394, + 394, + 348, + 348, + 246, + 364, + 364, + 374, + 109, + 109, + 109, + 329, + 329, + 15, + 362, + 362, + 110, + 207, + 251, + 126, + 170, + 170, + 365, + 233, + 397, + 255, + 197, + 197, + 197, + 379, + 379, + 379, + 379, + 45, + 225, + 225, + 86, + 86, + 86, + 86, + 217, + 147, + 358, + 167, + 167, + 167, + 386, + 386, + 386, + 386, + 386, + 37, + 37, + 358, + 358, + 358, + 113, + 113, + 353, + 103, + 123, + 123, + 255, + 255, + 255, + 123, + 144, + 144, + 145, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 70, + 70, + 70, + 70, + 212, + 212, + 212, + 105, + 105, + 105, + 105, + 105, + 334, + 169, + 169, + 169, + 247, + 247, + 107, + 107, + 107, + 107, + 107, + 314, + 185, + 341, + 341, + 194, + 194, + 194, + 148, + 148, + 174, + 18, + 367, + 26, + 26, + 26, + 308, + 141, + 141, + 228, + 228, + 173, + 173, + 173, + 360, + 360, + 360, + 360, + 360, + 360, + 23, + 332, + 36, + 87, + 87, + 175, + 357, + 357, + 357, + 357, + 357, + 357, + 175, + 175, + 226, + 226, + 226, + 191, + 154, + 66, + 57, + 57, + 4, + 4, + 380, + 123, + 384, + 384, + 163, + 163, + 163, + 163, + 346, + 108, + 275, + 151, + 151, + 357, + 186, + 323, + 323, + 323, + 161, + 161, + 208, + 208, + 208, + 182, + 9, + 235, + 9, + 307, + 307, + 5, + 131, + 247, + 13, + 13, + 13, + 13, + 13, + 287, + 287, + 140, + 140, + 140, + 86, + 112, + 86, + 86, + 256, + 256, + 256, + 28, + 28, + 28, + 28, + 287, + 287, + 111, + 111, + 111, + 111, + 323, + 323, + 323, + 142, + 142, + 142, + 236, + 4, + 324, + 324, + 67, + 276, + 276, + 21, + 280, + 280, + 280, + 194, + 298, + 173, + 173, + 173, + 295, + 41, + 286, + 223, + 223, + 343, + 69, + 204, + 204, + 193, + 136, + 337, + 337, + 54, + 54, + 54, + 349, + 165, + 165, + 165, + 165, + 165, + 8, + 365, + 365, + 365, + 365, + 365, + 8, + 8, + 8, + 375, + 58, + 6, + 6, + 104, + 104, + 169, + 319, + 169, + 169, + 354, + 354, + 354, + 354, + 105, + 212, + 29, + 29, + 295, + 295, + 295, + 122, + 122, + 15, + 186, + 252, + 132, + 132, + 132, + 250, + 90, + 380, + 380, + 380, + 53, + 53, + 384, + 384, + 384, + 84, + 84, + 335, + 112, + 256, + 256, + 256, + 256, + 256, + 256, + 256, + 256, + 30, + 320, + 162, + 395, + 119, + 119, + 256, + 256, + 50, + 50, + 247, + 247, + 46, + 309, + 190, + 301, + 301, + 301, + 301, + 301, + 97, + 97, + 97, + 399, + 44, + 44, + 305, + 193, + 399, + 156, + 331, + 178, + 178, + 178, + 178, + 178, + 178, + 178, + 141, + 141, + 11, + 48, + 24, + 44, + 44, + 207, + 44, + 44, + 75, + 22, + 119, + 119, + 225, + 119, + 86, + 360, + 126, + 126, + 126, + 126, + 126, + 126, + 142, + 142, + 67, + 20, + 88, + 257, + 257, + 195, + 58, + 217, + 217, + 217, + 217, + 251, + 183, + 377, + 377, + 377, + 73, + 73, + 321, + 125, + 391, + 391, + 300, + 2, + 2, + 2, + 300, + 300, + 300, + 12, + 338, + 338, + 57, + 298, + 171, + 171, + 171, + 171, + 171, + 360, + 360, + 92, + 92, + 92, + 92, + 210, + 210, + 139, + 215, + 149, + 342, + 342, + 130, + 130, + 378, + 99, + 99, + 99, + 99, + 99, + 99, + 389, + 167, + 167, + 289, + 289, + 84, + 325, + 155, + 155, + 235, + 235, + 139, + 139, + 139, + 265, + 265, + 190, + 190, + 190, + 190, + 190, + 190, + 190, + 190, + 394, + 394, + 14, + 325, + 325, + 42, + 42, + 64, + 64, + 64, + 28, + 28, + 28, + 28, + 2, + 120, + 120, + 389, + 145, + 145, + 145, + 145, + 145, + 396, + 396, + 396, + 396, + 41, + 41, + 216, + 70, + 280, + 280, + 280, + 280, + 161, + 161, + 161, + 259, + 51, + 292, + 28, + 28, + 28, + 28, + 28, + 359, + 359, + 70, + 361, + 95, + 224, + 113, + 350, + 157, + 157, + 216, + 216, + 116, + 116, + 342, + 342, + 342, + 73, + 73, + 365, + 177, + 321, + 321, + 321, + 172, + 307, + 307, + 128, + 279, + 279, + 109, + 236, + 84, + 349, + 116, + 114, + 294, + 294, + 294, + 294, + 114, + 114, + 218, + 182, + 182, + 261, + 112, + 375, + 115, + 115, + 111, + 67, + 25, + 336, + 25, + 255, + 255, + 188, + 188, + 340, + 340, + 18, + 238, + 238, + 238, + 351, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 361, + 177, + 177, + 344, + 146, + 146, + 400, + 57, + 357, + 357, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 351, + 351, + 138, + 364, + 308, + 321, + 321, + 207, + 207, + 139, + 139, + 208, + 252, + 252, + 397, + 397, + 181, + 397, + 26, + 26, + 26, + 26, + 26, + 207, + 207, + 207, + 207, + 207, + 52, + 52, + 52, + 52, + 52, + 217, + 217, + 145, + 296, + 296, + 49, + 49, + 382, + 382, + 203, + 203, + 349, + 349, + 140, + 349, + 349, + 137, + 279, + 279, + 279, + 163, + 355, + 126, + 126, + 126, + 126, + 218, + 218, + 218, + 310, + 254, + 254, + 164, + 325, + 325, + 325, + 62, + 279, + 267, + 213, + 130, + 213, + 220, + 254, + 60, + 323, + 125, + 125, + 207, + 207, + 109, + 284, + 140, + 140, + 140, + 140, + 241, + 241, + 241, + 156, + 156, + 346, + 147, + 306, + 198, + 339, + 108, + 108, + 108, + 366, + 366, + 366, + 366, + 309, + 400, + 72, + 72, + 238, + 120, + 120, + 349, + 349, + 349, + 94, + 94, + 94, + 394, + 102, + 237, + 237, + 198, + 375, + 13, + 129, + 109, + 109, + 196, + 190, + 361, + 190, + 190, + 190, + 308, + 308, + 114, + 222, + 121, + 136, + 136, + 136, + 386, + 386, + 136, + 385, + 385, + 385, + 55, + 361, + 68, + 68, + 172, + 172, + 219, + 156, + 156, + 156, + 156, + 156, + 341, + 341, + 26, + 266, + 114, + 114, + 321, + 158, + 383, + 383, + 383, + 383, + 89, + 89, + 89, + 89, + 89, + 89, + 398, + 398, + 162, + 256, + 6, + 384, + 384, + 384, + 42, + 42, + 216, + 37, + 37, + 37, + 37, + 37, + 37, + 37, + 221, + 69, + 69, + 306, + 46, + 336, + 336, + 91, + 91, + 311, + 311, + 311, + 311, + 151, + 269, + 269, + 269, + 269, + 269, + 141, + 213, + 141, + 302, + 18, + 370, + 370, + 142, + 142, + 351, + 190, + 191, + 319, + 191, + 184, + 184, + 184, + 279, + 184, + 390, + 165, + 307, + 128, + 222, + 21, + 21, + 21, + 21, + 21, + 252, + 252, + 60, + 241, + 241, + 241, + 124, + 355, + 11, + 203, + 149, + 149, + 149, + 149, + 357, + 357, + 357, + 126, + 360, + 360, + 360, + 360, + 360, + 149, + 343, + 178, + 206, + 206, + 206, + 104, + 361, + 361, + 361, + 361, + 361, + 361, + 125, + 125, + 268, + 268, + 69, + 232, + 176, + 176, + 176, + 176, + 176, + 321, + 321, + 321, + 192, + 334, + 165, + 290, + 2, + 2, + 341, + 341, + 31, + 31, + 31, + 31, + 31, + 31, + 31, + 31, + 238, + 179, + 179, + 115, + 115, + 243, + 115, + 115, + 163, + 291, + 95, + 45, + 23, + 23, + 29, + 317, + 146, + 383, + 142, + 119, + 119, + 46, + 360, + 55, + 30, + 30, + 30, + 30, + 30, + 71, + 71, + 204, + 204, + 204, + 113, + 113, + 113, + 113, + 385, + 385, + 50, + 338, + 338, + 202, + 57, + 316, + 316, + 63, + 309, + 295, + 220, + 220, + 388, + 255, + 348, + 306, + 150, + 150, + 306, + 119, + 400, + 397, + 391, + 391, + 391, + 322, + 322, + 198, + 56, + 56, + 272, + 272, + 272, + 272, + 192, + 389, + 389, + 67, + 204, + 46, + 46, + 46, + 213, + 213, + 213, + 134, + 235, + 235, + 11, + 11, + 11, + 11, + 389, + 389, + 389, + 183, + 183, + 183, + 357, + 357, + 357, + 357, + 67, + 350, + 143, + 143, + 143, + 394, + 180, + 180, + 354, + 354, + 354, + 354, + 354, + 354, + 116, + 116, + 116, + 314, + 41, + 41, + 41, + 41, + 257, + 257, + 192, + 284, + 284, + 83, + 238, + 93, + 383, + 38, + 38, + 38, + 38, + 38, + 357, + 357, + 357, + 357, + 4, + 4, + 255, + 22, + 22, + 37, + 57, + 153, + 195, + 19, + 19, + 19, + 13, + 211, + 13, + 21, + 256, + 256, + 192, + 192, + 395, + 54, + 54, + 54, + 54, + 169, + 169, + 163, + 163, + 163, + 346, + 163, + 163, + 341, + 28, + 28, + 4, + 297, + 46, + 46, + 212, + 212, + 100, + 207, + 207, + 207, + 271, + 271, + 271, + 271, + 271, + 134, + 230, + 292, + 292, + 238, + 238, + 233, + 233, + 112, + 112, + 112, + 204, + 129, + 271, + 103, + 375, + 375, + 18, + 18, + 26, + 26, + 8, + 273, + 90, + 169, + 169, + 308, + 246, + 246, + 148, + 148, + 148, + 246, + 246, + 123, + 342, + 39, + 204, + 204, + 204, + 204, + 104, + 270, + 270, + 110, + 110, + 400, + 400, + 97, + 97, + 97, + 97, + 351, + 351, + 87, + 87, + 87, + 87, + 87, + 301, + 301, + 301, + 170, + 226, + 196, + 196, + 196, + 376, + 107, + 383, + 5, + 241, + 241, + 241, + 152, + 152, + 152, + 371, + 371, + 37, + 328, + 328, + 129, + 129, + 322, + 64, + 375, + 375, + 18, + 18, + 18, + 274, + 64, + 64, + 64, + 303, + 303, + 303, + 303, + 303, + 131, + 131, + 131, + 131, + 290, + 155, + 155, + 348, + 1, + 1, + 1, + 233, + 147, + 215, + 27, + 27, + 27, + 27, + 27, + 27, + 211, + 211, + 211, + 166, + 166, + 166, + 222, + 222, + 222, + 222, + 222, + 222, + 71, + 222, + 222, + 78, + 78, + 351, + 351, + 351, + 26, + 367, + 385, + 349, + 375, + 375, + 375, + 104, + 104, + 375, + 375, + 375, + 176, + 176, + 176, + 253, + 150, + 259, + 123, + 123, + 123, + 313, + 171, + 309, + 323, + 291, + 291, + 291, + 73, + 73, + 73, + 73, + 291, + 373, + 236, + 236, + 382, + 166, + 166, + 166, + 305, + 386, + 386, + 14, + 14, + 206, + 206, + 353, + 150, + 242, + 242, + 191, + 191, + 263, + 84, + 105, + 158, + 158, + 73, + 73, + 73, + 357, + 159, + 159, + 335, + 335, + 353, + 16, + 150, + 301, + 143, + 145, + 145, + 145, + 145, + 172, + 172, + 172, + 146, + 146, + 373, + 373, + 373, + 7, + 360, + 360, + 351, + 351, + 351, + 111, + 111, + 111, + 111, + 111, + 343, + 197, + 197, + 197, + 197, + 29, + 263, + 134, + 134, + 227, + 232, + 232, + 260, + 260, + 270, + 270, + 268, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 206, + 121, + 84, + 41, + 43, + 43, + 91, + 11, + 10, + 10, + 87, + 87, + 143, + 143, + 143, + 342, + 143, + 143, + 143, + 351, + 107, + 400, + 118, + 322, + 322, + 322, + 395, + 106, + 106, + 334, + 334, + 103, + 392, + 323, + 282, + 169, + 169, + 203, + 377, + 377, + 377, + 380, + 4, + 4, + 243, + 243, + 392, + 24, + 300, + 27, + 273, + 60, + 230, + 80, + 80, + 80, + 119, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 58, + 219, + 219, + 219, + 133, + 58, + 220, + 220, + 256, + 256, + 256, + 324, + 264, + 93, + 346, + 205, + 205, + 205, + 33, + 398, + 398, + 398, + 398, + 334, + 334, + 225, + 225, + 339, + 339, + 283, + 281, + 281, + 281, + 281, + 281, + 281, + 53, + 364, + 364, + 226, + 217, + 380, + 380, + 200, + 200, + 328, + 328, + 56, + 56, + 56, + 56, + 268, + 1, + 1, + 280, + 280, + 280, + 280, + 280, + 280, + 137, + 224, + 140, + 140, + 140, + 140, + 287, + 169, + 120, + 120, + 155, + 155, + 146, + 146, + 146, + 37, + 40, + 334, + 187, + 88, + 70, + 70, + 233, + 233, + 70, + 237, + 237, + 97, + 97, + 70, + 209, + 38, + 38, + 38, + 38, + 38, + 38, + 38, + 38, + 261, + 261, + 261, + 33, + 33, + 33, + 255, + 45, + 246, + 246, + 246, + 64, + 301, + 301, + 9, + 9, + 164, + 198, + 365, + 37, + 59, + 59, + 388, + 59, + 59, + 59, + 142, + 276, + 276, + 276, + 276, + 190, + 374, + 27, + 138, + 62, + 62, + 239, + 62, + 62, + 150, + 231, + 231, + 150, + 165, + 7, + 7, + 7, + 7, + 7, + 7, + 119, + 229, + 229, + 229, + 34, + 34, + 34, + 34, + 21, + 35, + 35, + 143, + 232, + 143, + 143, + 143, + 143, + 188, + 188, + 188, + 195, + 168, + 168, + 168, + 168, + 338, + 168, + 174, + 174, + 71, + 102, + 6, + 6, + 6, + 272, + 6, + 238, + 91, + 91, + 91, + 317, + 89, + 383, + 137, + 137, + 217, + 217, + 181, + 92, + 248, + 42, + 42, + 352, + 178, + 280, + 353, + 399, + 96, + 96, + 399, + 399, + 399, + 399, + 399, + 89, + 89, + 353, + 353, + 353, + 353, + 143, + 325, + 325, + 325, + 325, + 180, + 395, + 395, + 395, + 395, + 163, + 163, + 163, + 282, + 282, + 282, + 282, + 282, + 183, + 183, + 271, + 45, + 378, + 378, + 378, + 65, + 331, + 18, + 242, + 39, + 270, + 270, + 270, + 191, + 191, + 93, + 93, + 22, + 104, + 104, + 104, + 287, + 103, + 272, + 53, + 44, + 378, + 156, + 306, + 306, + 31, + 31, + 72, + 236, + 388, + 388, + 388, + 14, + 14, + 172, + 57, + 133, + 262, + 262, + 87, + 201, + 59, + 59, + 224, + 224, + 29, + 155, + 155, + 305, + 305, + 155, + 22, + 149, + 23, + 95, + 127, + 127, + 350, + 375, + 46, + 46, + 375, + 147, + 147, + 147, + 147, + 330, + 105, + 105, + 331, + 390, + 390, + 347, + 347, + 319, + 60, + 319, + 64, + 201, + 391, + 391, + 241, + 241, + 204, + 195, + 253, + 253, + 61, + 321, + 108, + 312, + 312, + 44, + 44, + 44, + 44, + 44, + 136, + 221, + 123, + 123, + 65, + 166, + 166, + 166, + 166, + 166, + 259, + 259, + 166, + 166, + 115, + 115, + 254, + 40, + 348, + 348, + 348, + 348, + 68, + 4, + 2, + 356, + 356, + 356, + 356, + 174, + 257, + 257, + 26, + 26, + 394, + 394, + 100, + 299, + 299, + 299, + 299, + 83, + 83, + 83, + 83, + 83, + 284, + 284, + 284, + 284, + 284, + 106, + 106, + 251, + 251, + 251, + 251, + 198, + 355, + 355, + 355, + 108, + 385, + 385, + 61, + 61, + 61, + 61, + 350, + 350, + 350, + 350, + 350, + 7, + 7, + 17, + 17, + 91, + 91, + 367, + 367, + 181, + 306, + 306, + 142, + 387, + 136, + 136, + 331, + 130, + 130, + 237, + 237, + 237, + 5, + 5, + 5, + 5, + 5, + 361, + 190, + 334, + 146, + 146, + 146, + 146, + 146, + 338, + 59, + 223, + 233, + 68, + 68, + 68, + 233, + 233, + 60, + 60, + 60, + 339, + 339, + 49, + 49, + 49, + 49, + 371, + 71, + 230, + 69, + 285, + 285, + 285, + 190, + 276, + 147, + 147, + 147, + 230, + 195, + 195, + 253, + 69, + 69, + 69, + 69, + 380, + 380, + 16, + 16, + 398, + 398, + 398, + 149, + 207, + 207, + 207, + 80, + 80, + 80, + 80, + 351, + 100, + 224, + 224, + 224, + 224, + 224, + 68, + 68, + 238, + 238, + 116, + 271, + 271, + 68, + 296, + 123, + 123, + 288, + 68, + 342, + 163, + 163, + 163, + 274, + 138, + 138, + 263, + 263, + 263, + 263, + 263, + 149, + 358, + 163, + 170, + 170, + 170, + 170, + 347, + 170, + 75, + 307, + 60, + 60, + 204, + 163, + 163, + 163, + 362, + 362, + 362, + 362, + 49, + 276, + 276, + 276, + 276, + 276, + 2, + 262, + 120, + 257, + 257, + 185, + 185, + 35, + 35, + 35, + 320, + 320, + 120, + 165, + 151, + 394, + 394, + 394, + 394, + 53, + 335, + 106, + 106, + 252, + 57, + 57, + 389, + 389, + 389, + 389, + 389, + 389, + 135, + 135, + 316, + 316, + 103, + 103, + 262, + 178, + 254, + 105, + 105, + 328, + 166, + 166, + 166, + 203, + 62, + 62, + 387, + 387, + 154, + 282, + 137, + 260, + 43, + 43, + 289, + 289, + 289, + 289, + 289, + 289, + 91, + 91, + 98, + 98, + 100, + 100, + 100, + 100, + 100, + 24, + 117, + 117, + 169, + 169, + 322, + 169, + 169, + 312, + 312, + 92, + 247, + 110, + 110, + 110, + 69, + 220, + 69, + 69, + 69, + 69, + 69, + 284, + 153, + 153, + 392, + 150, + 150, + 169, + 169, + 33, + 181, + 181, + 217, + 181, + 181, + 48, + 314, + 314, + 314, + 62, + 230, + 141, + 285, + 188, + 188, + 364, + 364, + 364, + 364, + 364, + 117, + 117, + 331, + 331, + 331, + 331, + 200, + 254, + 254, + 62, + 62, + 310, + 310, + 310, + 69, + 69, + 228, + 110, + 288, + 143, + 143, + 143, + 333, + 333, + 333, + 333, + 333, + 333, + 333, + 333, + 22, + 22, + 22, + 201, + 201, + 98, + 98, + 360, + 22, + 22, + 298, + 298, + 67, + 324, + 324, + 190, + 190, + 190, + 190, + 190, + 190, + 299, + 150, + 150, + 247, + 103, + 307, + 14, + 14, + 14, + 14, + 299, + 299, + 161, + 322, + 322, + 322, + 322, + 46, + 236, + 236, + 38, + 357, + 357, + 159, + 159, + 385, + 385, + 385, + 4, + 302, + 302, + 302, + 112, + 112, + 336, + 46, + 272, + 22, + 22, + 22, + 319, + 111, + 339, + 17, + 395, + 395, + 148, + 148, + 332, + 332, + 83, + 83, + 33, + 214, + 214, + 214, + 33, + 347, + 12, + 12, + 278, + 45, + 248, + 248, + 248, + 146, + 264, + 177, + 219, + 219, + 219, + 219, + 107, + 363, + 363, + 179, + 179, + 179, + 384, + 137, + 137, + 137, + 137, + 201, + 164, + 303, + 131, + 131, + 370, + 370, + 174, + 174, + 212, + 189, + 274, + 141, + 141, + 315, + 96, + 96, + 314, + 178, + 178, + 220, + 220, + 97, + 364, + 364, + 364, + 35, + 286, + 187, + 189, + 189, + 189, + 189, + 284, + 284, + 189, + 189, + 26, + 26, + 83, + 162, + 324, + 324, + 324, + 162, + 162, + 108, + 199, + 199, + 199, + 199, + 64, + 64, + 171, + 171, + 171, + 325, + 325, + 8, + 335, + 335, + 335, + 335, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 19, + 328, + 58, + 355, + 20, + 390, + 134, + 336, + 73, + 120, + 120, + 276, + 276, + 120, + 240, + 93, + 93, + 277, + 53, + 53, + 34, + 183, + 170, + 181, + 181, + 181, + 4, + 4, + 227, + 4, + 40, + 96, + 107, + 295, + 295, + 107, + 160, + 160, + 160, + 18, + 16, + 16, + 16, + 368, + 16, + 16, + 268, + 57, + 205, + 205, + 205, + 205, + 205, + 134, + 302, + 302, + 134, + 134, + 128, + 88, + 88, + 88, + 56, + 382, + 42, + 329, + 329, + 329, + 51, + 334, + 16, + 16, + 7, + 7, + 150, + 22, + 22, + 177, + 140, + 186, + 21, + 235, + 21, + 21, + 351, + 351, + 347, + 347, + 58, + 347, + 322, + 322, + 252, + 252, + 252, + 142, + 215, + 215, + 215, + 124, + 124, + 371, + 371, + 62, + 62, + 62, + 261, + 261, + 261, + 32, + 32, + 210, + 210, + 210, + 139, + 284, + 58, + 244, + 142, + 208, + 25, + 25, + 25, + 303, + 289, + 394, + 394, + 133, + 133, + 292, + 292, + 292, + 292, + 292, + 93, + 272, + 189, + 206, + 206, + 206, + 206, + 206, + 46, + 305, + 168, + 168, + 347, + 213, + 61, + 255, + 107, + 107, + 107, + 341, + 150, + 150, + 208, + 395, + 395, + 333, + 358, + 351, + 355, + 355, + 244, + 244, + 138, + 138, + 138, + 138, + 138, + 138, + 300, + 29, + 29, + 29, + 301, + 13, + 13, + 233, + 233, + 233, + 233, + 100, + 266, + 266, + 266, + 266, + 51, + 51, + 322, + 181, + 397, + 397, + 141, + 274, + 274, + 86, + 86, + 86, + 86, + 86, + 86, + 86, + 86, + 41, + 159, + 159, + 159, + 159, + 159, + 43, + 43, + 65, + 65, + 218, + 65, + 65, + 65, + 65, + 367, + 367, + 138, + 380, + 380, + 49, + 49, + 49, + 218, + 218, + 23, + 23, + 343, + 343, + 184, + 251, + 251, + 251, + 77, + 211, + 144, + 77, + 1, + 1, + 141, + 113, + 113, + 102, + 364, + 6, + 6, + 372, + 176, + 356, + 374, + 374, + 252, + 252, + 101, + 252, + 10, + 10, + 10, + 361, + 98, + 289, + 48, + 48, + 311, + 206, + 256, + 35, + 256, + 256, + 256, + 183, + 240, + 240, + 240, + 240, + 32, + 32, + 340, + 340, + 340, + 2, + 2, + 2, + 266, + 266, + 389, + 319, + 319, + 319, + 362, + 283, + 183, + 183, + 157, + 317, + 157, + 157, + 381, + 91, + 347, + 347, + 246, + 246, + 246, + 188, + 246, + 133, + 318, + 201, + 201, + 201, + 193, + 193, + 201, + 201, + 201, + 201, + 124, + 282, + 77, + 77, + 77, + 77, + 215, + 215, + 127, + 127, + 328, + 328, + 76, + 251, + 251, + 251, + 251, + 44, + 44, + 280, + 158, + 158, + 158, + 334, + 152, + 373, + 373, + 373, + 59, + 359, + 92, + 92, + 324, + 324, + 25, + 334, + 87, + 87, + 392, + 102, + 102, + 323, + 236, + 20, + 236, + 236, + 236, + 131, + 323, + 372, + 260, + 288, + 288, + 288, + 256, + 264, + 311, + 311, + 40, + 311, + 311, + 283, + 393, + 57, + 393, + 345, + 35, + 35, + 362, + 66, + 42, + 42, + 42, + 325, + 325, + 325, + 42, + 72, + 360, + 399, + 399, + 399, + 399, + 117, + 267, + 267, + 74, + 366, + 366, + 366, + 366, + 166, + 166, + 166, + 253, + 389, + 355, + 273, + 194, + 194, + 57, + 126, + 345, + 345, + 250, + 346, + 70, + 240, + 41, + 32, + 32, + 351, + 351, + 252, + 252, + 252, + 120, + 120, + 252, + 32, + 32, + 16, + 16, + 16, + 76, + 396, + 396, + 389, + 389, + 389, + 307, + 307, + 284, + 89, + 374, + 58, + 342, + 342, + 342, + 342, + 342, + 342, + 3, + 339, + 51, + 131, + 131, + 198, + 212, + 212, + 41, + 84, + 84, + 359, + 359, + 359, + 9, + 9, + 9, + 310, + 310, + 132, + 132, + 132, + 348, + 348, + 348, + 348, + 117, + 117, + 117, + 245, + 66, + 66, + 218, + 72, + 389, + 198, + 255, + 255, + 255, + 255, + 255, + 32, + 289, + 289, + 171, + 171, + 171, + 233, + 23, + 316, + 370, + 90, + 90, + 370, + 370, + 370, + 370, + 370, + 370, + 323, + 91, + 91, + 218, + 254, + 254, + 254, + 254, + 80, + 80, + 314, + 396, + 396, + 396, + 396, + 322, + 322, + 206, + 206, + 206, + 300, + 287, + 331, + 331, + 250, + 343, + 343, + 18, + 18, + 18, + 343, + 343, + 343, + 343, + 132, + 370, + 370, + 222, + 275, + 218, + 250, + 387, + 387, + 387, + 387, + 274, + 34, + 34, + 34, + 34, + 34, + 34, + 274, + 274, + 274, + 340, + 340, + 340, + 340, + 340, + 220, + 286, + 326, + 136, + 326, + 326, + 326, + 38, + 38, + 38, + 38, + 368, + 50, + 400, + 400, + 25, + 25, + 246, + 246, + 246, + 73, + 73, + 360, + 141, + 141, + 141, + 317, + 317, + 317, + 184, + 184, + 184, + 260, + 260, + 169, + 282, + 282, + 282, + 101, + 101, + 92, + 327, + 92, + 92, + 92, + 92, + 226, + 226, + 181, + 252, + 198, + 251, + 251, + 130, + 130, + 314, + 172, + 249, + 249, + 249, + 249, + 189, + 189, + 320, + 320, + 80, + 270, + 85, + 85, + 241, + 241, + 241, + 193, + 366, + 366, + 139, + 347, + 347, + 347, + 185, + 302, + 158, + 304, + 304, + 186, + 186, + 325, + 56, + 360, + 360, + 175, + 317, + 80, + 80, + 346, + 27, + 395, + 180, + 341, + 341, + 178, + 178, + 364, + 364, + 55, + 55, + 55, + 261, + 261, + 87, + 87, + 248, + 17, + 17, + 17, + 17, + 321, + 153, + 153, + 153, + 362, + 63, + 277, + 277, + 135, + 135, + 135, + 135, + 135, + 284, + 149, + 340, + 340, + 17, + 17, + 17, + 17, + 264, + 55, + 203, + 61, + 61, + 385, + 385, + 385, + 54, + 359, + 359, + 359, + 111, + 111, + 257, + 145, + 145, + 145, + 145, + 398, + 201, + 201, + 201, + 386, + 386, + 35, + 321, + 321, + 310, + 228, + 79, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 121, + 258, + 189, + 189, + 189, + 189, + 374, + 77, + 77, + 77, + 77, + 344, + 344, + 344, + 344, + 344, + 58, + 251, + 143, + 60, + 60, + 157, + 157, + 157, + 157, + 157, + 360, + 360, + 360, + 360, + 157, + 157, + 260, + 260, + 260, + 260, + 10, + 246, + 119, + 119, + 386, + 78, + 78, + 78, + 78, + 238, + 150, + 150, + 150, + 386, + 386, + 386, + 386, + 386, + 185, + 185, + 185, + 210, + 210, + 210, + 39, + 39, + 39, + 39, + 39, + 39, + 354, + 82, + 82, + 267, + 267, + 45, + 45, + 288, + 288, + 288, + 288, + 133, + 324, + 324, + 120, + 126, + 341, + 341, + 126, + 126, + 126, + 126, + 126, + 126, + 126, + 126, + 126, + 126, + 348, + 61, + 315, + 315, + 315, + 315, + 315, + 315, + 315, + 124, + 124, + 267, + 267, + 267, + 267, + 19, + 19, + 19, + 19, + 311, + 311, + 311, + 311, + 311, + 61, + 386, + 74, + 74, + 365, + 103, + 103, + 381, + 170, + 312, + 312, + 138, + 138, + 138, + 138, + 138, + 138, + 138, + 357, + 32, + 32, + 32, + 359, + 200, + 200, + 200, + 200, + 200, + 322, + 322, + 34, + 34, + 287, + 168, + 368, + 368, + 99, + 99, + 99, + 99, + 99, + 347, + 347, + 347, + 59, + 262, + 23, + 23, + 23, + 324, + 324, + 31, + 31, + 31, + 336, + 54, + 255, + 255, + 255, + 165, + 165, + 71, + 257, + 114, + 222, + 99, + 99, + 387, + 156, + 156, + 261, + 261, + 191, + 191, + 178, + 142, + 142, + 142, + 109, + 308, + 308, + 308, + 57, + 313, + 313, + 313, + 313, + 313, + 138, + 138, + 252, + 252, + 115, + 115, + 115, + 115, + 262, + 262, + 45, + 45, + 332, + 37, + 37, + 37, + 37, + 37, + 37, + 374, + 374, + 179, + 179, + 179, + 317, + 97, + 97, + 97, + 319, + 194, + 365, + 365, + 17, + 228, + 228, + 76, + 76, + 273, + 273, + 93, + 93, + 356, + 356, + 61, + 215, + 215, + 77, + 267, + 267, + 267, + 267, + 121, + 373, + 32, + 337, + 337, + 337, + 126, + 390, + 390, + 390, + 156, + 156, + 360, + 52, + 385, + 385, + 385, + 105, + 267, + 111, + 302, + 302, + 302, + 302, + 161, + 161, + 350, + 350, + 350, + 191, + 380, + 139, + 139, + 139, + 139, + 139, + 313, + 32, + 32, + 216, + 143, + 143, + 305, + 41, + 41, + 312, + 73, + 73, + 73, + 377, + 137, + 297, + 117, + 117, + 117, + 117, + 329, + 7, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 154, + 154, + 154, + 272, + 29, + 29, + 287, + 50, + 50, + 50, + 50, + 297, + 297, + 297, + 297, + 297, + 90, + 354, + 59, + 373, + 373, + 107, + 107, + 107, + 107, + 107, + 107, + 107, + 348, + 348, + 194, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 193, + 193, + 385, + 385, + 385, + 385, + 39, + 39, + 39, + 373, + 373, + 373, + 60, + 263, + 85, + 85, + 85, + 272, + 43, + 43, + 43, + 237, + 237, + 47, + 47, + 47, + 47, + 373, + 142, + 142, + 142, + 142, + 142, + 359, + 187, + 187, + 187, + 260, + 22, + 220, + 83, + 83, + 83, + 83, + 384, + 93, + 93, + 266, + 266, + 266, + 178, + 218, + 218, + 218, + 12, + 284, + 49, + 336, + 336, + 185, + 185, + 343, + 2, + 379, + 379, + 91, + 91, + 91, + 316, + 316, + 316, + 316, + 167, + 213, + 175, + 175, + 222, + 222, + 67, + 357, + 136, + 345, + 310, + 242, + 202, + 141, + 141, + 141, + 141, + 202, + 202, + 163, + 163, + 330, + 330, + 23, + 283, + 20, + 20, + 375, + 375, + 216, + 216, + 223, + 179, + 179, + 322, + 385, + 143, + 305, + 305, + 305, + 17, + 17, + 239, + 44, + 44, + 373, + 373, + 373, + 66, + 261, + 261, + 261, + 261, + 178, + 142, + 47, + 47, + 47, + 47, + 99, + 282, + 189, + 77, + 77, + 77, + 77, + 77, + 273, + 273, + 77, + 77, + 77, + 222, + 222, + 222, + 39, + 39, + 250, + 132, + 132, + 321, + 321, + 102, + 102, + 186, + 345, + 345, + 345, + 345, + 125, + 125, + 224, + 224, + 43, + 43, + 43, + 43, + 49, + 49, + 29, + 335, + 2, + 2, + 2, + 360, + 158, + 300, + 93, + 317, + 41, + 237, + 237, + 182, + 341, + 341, + 341, + 341, + 29, + 29, + 29, + 29, + 371, + 176, + 176, + 176, + 176, + 372, + 372, + 107, + 107, + 107, + 216, + 216, + 216, + 101, + 101, + 243, + 45, + 45, + 16, + 182, + 206, + 206, + 34, + 34, + 34, + 283, + 114, + 399, + 399, + 399, + 399, + 399, + 121, + 121, + 121, + 121, + 3, + 28, + 28, + 322, + 28, + 28, + 176, + 154, + 96, + 96, + 82, + 18, + 18, + 123, + 25, + 253, + 83, + 83, + 83, + 168, + 168, + 168, + 5, + 294, + 10, + 341, + 341, + 341, + 341, + 56, + 56, + 299, + 235, + 235, + 364, + 364, + 72, + 369, + 185, + 261, + 261, + 37, + 37, + 37, + 211, + 211, + 151, + 310, + 310, + 16, + 380, + 380, + 380, + 380, + 146, + 205, + 96, + 96, + 96, + 218, + 218, + 6, + 6, + 268, + 220, + 288, + 295, + 295, + 250, + 250, + 250, + 155, + 155, + 250, + 279, + 8, + 8, + 8, + 279, + 170, + 170, + 204, + 204, + 23, + 23, + 221, + 221, + 221, + 221, + 195, + 195, + 363, + 363, + 363, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 320, + 320, + 320, + 320, + 320, + 320, + 320, + 144, + 144, + 287, + 287, + 287, + 58, + 379, + 95, + 95, + 238, + 152, + 152, + 237, + 237, + 237, + 81, + 207, + 77, + 297, + 297, + 297, + 81, + 81, + 228, + 36, + 36, + 112, + 112, + 112, + 146, + 146, + 146, + 146, + 74, + 151, + 112, + 112, + 255, + 56, + 56, + 87, + 314, + 314, + 314, + 138, + 138, + 240, + 240, + 193, + 208, + 60, + 60, + 366, + 366, + 163, + 163, + 395, + 155, + 155, + 275, + 275, + 190, + 190, + 52, + 52, + 52, + 52, + 176, + 361, + 337, + 32, + 32, + 32, + 137, + 72, + 72, + 72, + 149, + 113, + 113, + 351, + 351, + 139, + 44, + 44, + 377, + 377, + 44, + 44, + 44, + 382, + 168, + 385, + 190, + 190, + 287, + 119, + 237, + 237, + 237, + 237, + 41, + 41, + 41, + 258, + 258, + 258, + 9, + 9, + 272, + 136, + 136, + 242, + 96, + 353, + 125, + 125, + 368, + 254, + 320, + 347, + 285, + 285, + 280, + 280, + 75, + 393, + 393, + 393, + 62, + 62, + 225, + 81, + 305, + 172, + 172, + 172, + 244, + 75, + 271, + 271, + 271, + 271, + 271, + 271, + 69, + 69, + 373, + 373, + 86, + 86, + 219, + 219, + 219, + 70, + 258, + 258, + 258, + 258, + 258, + 258, + 36, + 36, + 36, + 203, + 182, + 182, + 182, + 182, + 254, + 190, + 358, + 358, + 358, + 358, + 358, + 358, + 126, + 126, + 332, + 166, + 271, + 113, + 386, + 168, + 168, + 334, + 121, + 234, + 234, + 234, + 234, + 39, + 39, + 39, + 121, + 357, + 177, + 294, + 189, + 189, + 189, + 37, + 374, + 374, + 37, + 129, + 84, + 280, + 280, + 280, + 84, + 297, + 297, + 297, + 117, + 117, + 117, + 117, + 240, + 178, + 22, + 356, + 101, + 38, + 175, + 175, + 239, + 167, + 167, + 167, + 167, + 167, + 377, + 157, + 81, + 353, + 353, + 81, + 81, + 81, + 233, + 91, + 91, + 342, + 77, + 77, + 377, + 377, + 377, + 377, + 377, + 10, + 352, + 352, + 122, + 366, + 173, + 173, + 326, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 326, + 326, + 326, + 191, + 191, + 191, + 213, + 62, + 62, + 62, + 62, + 62, + 290, + 190, + 222, + 6, + 6, + 8, + 371, + 371, + 8, + 173, + 173, + 289, + 289, + 173, + 128, + 138, + 61, + 309, + 61, + 61, + 61, + 61, + 61, + 241, + 241, + 194, + 318, + 318, + 318, + 137, + 275, + 112, + 112, + 112, + 229, + 5, + 5, + 265, + 265, + 265, + 265, + 265, + 37, + 37, + 37, + 37, + 37, + 37, + 293, + 199, + 334, + 109, + 240, + 187, + 187, + 187, + 187, + 390, + 34, + 239, + 53, + 53, + 53, + 133, + 32, + 388, + 388, + 32, + 337, + 337, + 337, + 59, + 59, + 252, + 35, + 35, + 259, + 23, + 248, + 248, + 248, + 248, + 77, + 77, + 77, + 77, + 248, + 248, + 248, + 117, + 371, + 371, + 177, + 388, + 388, + 381, + 73, + 262, + 163, + 163, + 218, + 218, + 218, + 397, + 360, + 68, + 68, + 360, + 360, + 360, + 43, + 43, + 43, + 43, + 43, + 201, + 201, + 64, + 331, + 331, + 331, + 331, + 187, + 187, + 187, + 187, + 187, + 298, + 82, + 82, + 82, + 82, + 227, + 106, + 106, + 106, + 106, + 297, + 272, + 164, + 272, + 336, + 217, + 217, + 377, + 103, + 103, + 377, + 212, + 320, + 320, + 155, + 316, + 316, + 208, + 208, + 250, + 155, + 155, + 155, + 155, + 155, + 348, + 165, + 165, + 165, + 320, + 320, + 320, + 320, + 156, + 334, + 286, + 301, + 289, + 208, + 338, + 109, + 109, + 25, + 25, + 25, + 25, + 353, + 353, + 25, + 354, + 181, + 281, + 281, + 281, + 36, + 304, + 304, + 304, + 304, + 96, + 395, + 72, + 337, + 337, + 337, + 337, + 193, + 193, + 341, + 341, + 341, + 341, + 341, + 341, + 131, + 131, + 131, + 131, + 392, + 72, + 290, + 145, + 348, + 63, + 302, + 85, + 221, + 221, + 221, + 221, + 91, + 55, + 291, + 52, + 229, + 229, + 137, + 384, + 384, + 47, + 47, + 47, + 234, + 196, + 364, + 122, + 122, + 122, + 272, + 36, + 36, + 243, + 49, + 49, + 49, + 22, + 22, + 89, + 89, + 160, + 192, + 192, + 192, + 148, + 180, + 172, + 101, + 101, + 304, + 304, + 101, + 101, + 349, + 56, + 225, + 123, + 123, + 47, + 126, + 387, + 51, + 199, + 45, + 153, + 153, + 153, + 153, + 347, + 55, + 55, + 223, + 223, + 196, + 196, + 266, + 84, + 126, + 283, + 396, + 396, + 396, + 261, + 39, + 39, + 220, + 220, + 220, + 300, + 300, + 380, + 380, + 29, + 29, + 29, + 109, + 109, + 109, + 109, + 86, + 5, + 5, + 189, + 391, + 391, + 391, + 123, + 123, + 305, + 305, + 305, + 251, + 156, + 156, + 156, + 322, + 322, + 72, + 292, + 43, + 328, + 393, + 130, + 130, + 319, + 47, + 31, + 300, + 300, + 363, + 363, + 306, + 225, + 225, + 219, + 267, + 267, + 284, + 46, + 226, + 265, + 133, + 133, + 235, + 181, + 398, + 398, + 398, + 398, + 398, + 124, + 124, + 124, + 238, + 99, + 214, + 214, + 134, + 134, + 134, + 134, + 134, + 134, + 134, + 310, + 107, + 107, + 201, + 82, + 339, + 139, + 139, + 377, + 63, + 63, + 63, + 228, + 228, + 152, + 246, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 33, + 304, + 304, + 31, + 319, + 186, + 186, + 78, + 241, + 181, + 376, + 376, + 376, + 376, + 120, + 120, + 120, + 374, + 374, + 374, + 115, + 368, + 368, + 62, + 62, + 299, + 183, + 183, + 370, + 370, + 370, + 370, + 370, + 178, + 178, + 399, + 92, + 92, + 92, + 244, + 244, + 166, + 240, + 240, + 240, + 240, + 34, + 242, + 71, + 317, + 104, + 347, + 347, + 347, + 74, + 74, + 74, + 274, + 166, + 248, + 184, + 166, + 166, + 79, + 79, + 79, + 281, + 281, + 281, + 281, + 281, + 79, + 253, + 166, + 235, + 139, + 139, + 286, + 286, + 190, + 190, + 190, + 190, + 190, + 190, + 242, + 242, + 100, + 100, + 285, + 160, + 291, + 291, + 291, + 291, + 291, + 114, + 114, + 55, + 210, + 153, + 139, + 139, + 139, + 97, + 97, + 278, + 80, + 318, + 318, + 318, + 318, + 318, + 318, + 156, + 156, + 156, + 268, + 268, + 36, + 36, + 327, + 327, + 387, + 387, + 263, + 231, + 294, + 270, + 160, + 160, + 270, + 270, + 270, + 141, + 204, + 21, + 61, + 267, + 122, + 122, + 346, + 346, + 253, + 307, + 221, + 221, + 221, + 221, + 367, + 367, + 169, + 367, + 367, + 290, + 45, + 329, + 329, + 103, + 369, + 369, + 125, + 125, + 392, + 147, + 48, + 96, + 96, + 98, + 98, + 98, + 98, + 276, + 98, + 353, + 369, + 369, + 301, + 252, + 252, + 252, + 252, + 184, + 252, + 252, + 252, + 23, + 23, + 202, + 169, + 169, + 169, + 169, + 169, + 388, + 388, + 388, + 388, + 388, + 388, + 388, + 78, + 229, + 17, + 17, + 17, + 17, + 279, + 279, + 141, + 141, + 391, + 391, + 85, + 85, + 327, + 165, + 165, + 165, + 165, + 165, + 165, + 165, + 165, + 307, + 400, + 257, + 257, + 244, + 312, + 229, + 234, + 23, + 189, + 189, + 36, + 36, + 36, + 36, + 119, + 149, + 149, + 149, + 149, + 149, + 149, + 149, + 149, + 226, + 143, + 315, + 50, + 327, + 327, + 327, + 55, + 55, + 251, + 76, + 76, + 165, + 377, + 160, + 160, + 160, + 339, + 339, + 339, + 339, + 197, + 233, + 44, + 237, + 180, + 180, + 166, + 166, + 166, + 166, + 166, + 166, + 166, + 166, + 188, + 98, + 315, + 315, + 315, + 315, + 315, + 98, + 30, + 30, + 100, + 100, + 327, + 327, + 167, + 167, + 322, + 322, + 322, + 195, + 284, + 99, + 99, + 99, + 293, + 293, + 293, + 293, + 293, + 293, + 173, + 173, + 242, + 128, + 128, + 322, + 322, + 322, + 52, + 52, + 225, + 8, + 8, + 227, + 227, + 50, + 332, + 332, + 169, + 337, + 163, + 365, + 365, + 194, + 259, + 259, + 259, + 259, + 46, + 46, + 46, + 285, + 285, + 285, + 21, + 390, + 170, + 256, + 11, + 233, + 75, + 75, + 241, + 241, + 140, + 140, + 252, + 252, + 252, + 252, + 252, + 77, + 318, + 318, + 318, + 46, + 377, + 23, + 345, + 345, + 345, + 83, + 328, + 328, + 328, + 108, + 86, + 50, + 185, + 185, + 166, + 166, + 63, + 229, + 229, + 229, + 229, + 79, + 26, + 26, + 303, + 222, + 297, + 354, + 370, + 224, + 224, + 317, + 225, + 42, + 42, + 42, + 225, + 107, + 242, + 241, + 271, + 367, + 367, + 367, + 258, + 258, + 258, + 258, + 221, + 97, + 97, + 221, + 221, + 221, + 170, + 196, + 224, + 136, + 136, + 136, + 323, + 323, + 57, + 57, + 57, + 310, + 146, + 292, + 87, + 87, + 87, + 87, + 87, + 309, + 309, + 202, + 202, + 355, + 355, + 301, + 208, + 208, + 233, + 63, + 233, + 233, + 131, + 279, + 353, + 353, + 353, + 392, + 392, + 236, + 131, + 131, + 131, + 131, + 131, + 236, + 58, + 58, + 58, + 58, + 307, + 307, + 307, + 307, + 162, + 244, + 244, + 244, + 108, + 331, + 331, + 105, + 105, + 258, + 62, + 237, + 371, + 371, + 371, + 254, + 251, + 251, + 212, + 367, + 367, + 91, + 249, + 249, + 249, + 89, + 89, + 256, + 67, + 340, + 91, + 91, + 91, + 398, + 398, + 398, + 398, + 153, + 393, + 393, + 98, + 255, + 255, + 255, + 128, + 128, + 128, + 128, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 56, + 56, + 231, + 39, + 366, + 366, + 366, + 366, + 241, + 241, + 241, + 153, + 276, + 63, + 63, + 380, + 380, + 256, + 256, + 256, + 162, + 7, + 7, + 7, + 7, + 117, + 117, + 168, + 244, + 244, + 168, + 328, + 181, + 181, + 181, + 181, + 90, + 90, + 327, + 90, + 90, + 90, + 78, + 78, + 78, + 78, + 78, + 195, + 66, + 66, + 40, + 213, + 40, + 40, + 108, + 255, + 255, + 255, + 255, + 255, + 296, + 296, + 212, + 212, + 223, + 200, + 223, + 90, + 370, + 370, + 226, + 22, + 22, + 226, + 323, + 24, + 24, + 323, + 11, + 11, + 349, + 89, + 142, + 41, + 41, + 41, + 41, + 260, + 260, + 41, + 146, + 193, + 154, + 156, + 235, + 235, + 35, + 392, + 392, + 392, + 115, + 115, + 355, + 355, + 131, + 73, + 357, + 73, + 73, + 73, + 299, + 299, + 299, + 268, + 268, + 268, + 64, + 64, + 64, + 64, + 64, + 70, + 175, + 17, + 17, + 296, + 296, + 296, + 138, + 274, + 144, + 391, + 13, + 13, + 13, + 13, + 187, + 127, + 7, + 145, + 285, + 285, + 145, + 116, + 116, + 116, + 126, + 126, + 126, + 217, + 217, + 126, + 126, + 126, + 126, + 126, + 256, + 256, + 176, + 385, + 385, + 385, + 385, + 385, + 385, + 385, + 385, + 163, + 163, + 163, + 258, + 258, + 69, + 219, + 219, + 219, + 43, + 329, + 110, + 361, + 361, + 192, + 192, + 192, + 192, + 337, + 50, + 204, + 204, + 204, + 204, + 178, + 260, + 125, + 125, + 125, + 288, + 81, + 315, + 315, + 315, + 315, + 74, + 334, + 28, + 28, + 391, + 391, + 391, + 391, + 182, + 275, + 275, + 275, + 132, + 132, + 132, + 246, + 246, + 139, + 393, + 169, + 246, + 70, + 70, + 70, + 70, + 70, + 250, + 250, + 153, + 367, + 367, + 42, + 98, + 112, + 112, + 112, + 112, + 24, + 24, + 24, + 24, + 24, + 244, + 244, + 24, + 24, + 24, + 24, + 24, + 24, + 24, + 394, + 394, + 44, + 203, + 203, + 106, + 106, + 400, + 400, + 48, + 301, + 21, + 21, + 187, + 361, + 187, + 187, + 210, + 210, + 210, + 210, + 134, + 239, + 25, + 311, + 311, + 37, + 37, + 37, + 37, + 255, + 311, + 212, + 33, + 355, + 9, + 9, + 290, + 17, + 247, + 196, + 196, + 196, + 196, + 357, + 2, + 303, + 174, + 106, + 257, + 106, + 106, + 330, + 330, + 3, + 59, + 78, + 197, + 197, + 106, + 103, + 83, + 83, + 299, + 112, + 112, + 360, + 360, + 360, + 360, + 360, + 360, + 18, + 231, + 231, + 198, + 334, + 334, + 114, + 223, + 223, + 223, + 223, + 223, + 23, + 23, + 224, + 224, + 224, + 105, + 105, + 105, + 105, + 105, + 240, + 240, + 186, + 284, + 284, + 396, + 288, + 129, + 162, + 298, + 298, + 298, + 3, + 3, + 3, + 3, + 3, + 3, + 226, + 226, + 226, + 226, + 12, + 131, + 131, + 131, + 131, + 10, + 17, + 21, + 21, + 21, + 21, + 236, + 83, + 98, + 200, + 200, + 200, + 314, + 314, + 138, + 14, + 138, + 58, + 209, + 209, + 209, + 209, + 58, + 239, + 142, + 142, + 142, + 142, + 142, + 396, + 186, + 186, + 376, + 169, + 169, + 377, + 162, + 162, + 162, + 284, + 48, + 48, + 264, + 264, + 114, + 380, + 380, + 380, + 380, + 181, + 319, + 156, + 156, + 328, + 328, + 328, + 328, + 30, + 393, + 133, + 275, + 275, + 166, + 166, + 166, + 273, + 273, + 144, + 349, + 194, + 228, + 228, + 228, + 228, + 228, + 228, + 17, + 290, + 290, + 110, + 311, + 311, + 114, + 114, + 114, + 41, + 41, + 253, + 253, + 253, + 253, + 253, + 60, + 60, + 60, + 60, + 60, + 254, + 254, + 254, + 254, + 164, + 164, + 253, + 142, + 374, + 59, + 397, + 397, + 191, + 186, + 186, + 92, + 92, + 165, + 165, + 153, + 153, + 29, + 60, + 293, + 155, + 155, + 155, + 228, + 228, + 187, + 331, + 88, + 387, + 387, + 376, + 394, + 253, + 253, + 79, + 367, + 367, + 367, + 367, + 195, + 217, + 124, + 124, + 124, + 124, + 124, + 124, + 202, + 22, + 22, + 22, + 22, + 230, + 230, + 230, + 230, + 156, + 156, + 156, + 235, + 184, + 330, + 47, + 297, + 174, + 174, + 283, + 283, + 283, + 283, + 82, + 82, + 337, + 337, + 4, + 4, + 4, + 209, + 209, + 209, + 209, + 10, + 10, + 262, + 262, + 150, + 150, + 150, + 390, + 162, + 162, + 153, + 153, + 132, + 13, + 395, + 122, + 357, + 7, + 7, + 64, + 64, + 180, + 390, + 390, + 178, + 383, + 383, + 383, + 70, + 360, + 360, + 34, + 34, + 34, + 376, + 61, + 290, + 189, + 383, + 9, + 17, + 175, + 371, + 31, + 76, + 259, + 259, + 353, + 353, + 138, + 138, + 138, + 353, + 353, + 353, + 361, + 204, + 297, + 297, + 180, + 180, + 297, + 297, + 48, + 48, + 294, + 294, + 80, + 80, + 80, + 267, + 78, + 78, + 307, + 307, + 4, + 4, + 221, + 221, + 221, + 15, + 15, + 15, + 274, + 120, + 120, + 120, + 120, + 237, + 129, + 396, + 396, + 396, + 296, + 296, + 22, + 241, + 241, + 241, + 174, + 382, + 382, + 83, + 83, + 298, + 274, + 274, + 84, + 351, + 87, + 378, + 378, + 12, + 325, + 123, + 201, + 201, + 201, + 90, + 90, + 90, + 90, + 71, + 199, + 199, + 107, + 107, + 136, + 312, + 312, + 312, + 312, + 312, + 280, + 169, + 169, + 23, + 252, + 252, + 315, + 315, + 141, + 141, + 315, + 315, + 235, + 235, + 235, + 235, + 235, + 88, + 284, + 116, + 116, + 288, + 288, + 75, + 248, + 35, + 35, + 287, + 48, + 48, + 48, + 48, + 263, + 263, + 23, + 273, + 273, + 144, + 305, + 305, + 72, + 235, + 91, + 91, + 54, + 104, + 209, + 209, + 209, + 209, + 145, + 145, + 205, + 205, + 205, + 205, + 193, + 345, + 345, + 181, + 181, + 338, + 49, + 227, + 115, + 233, + 164, + 272, + 272, + 178, + 178, + 173, + 173, + 173, + 334, + 173, + 280, + 280, + 167, + 167, + 167, + 167, + 167, + 274, + 274, + 22, + 277, + 277, + 277, + 277, + 277, + 163, + 264, + 61, + 61, + 369, + 199, + 199, + 324, + 324, + 188, + 188, + 146, + 146, + 146, + 172, + 172, + 37, + 37, + 37, + 37, + 219, + 61, + 61, + 50, + 180, + 180, + 92, + 92, + 187, + 326, + 326, + 187, + 187, + 321, + 31, + 31, + 388, + 117, + 215, + 8, + 8, + 8, + 8, + 8, + 327, + 327, + 327, + 327, + 8, + 245, + 155, + 155, + 155, + 155, + 155, + 155, + 155, + 369, + 369, + 64, + 289, + 289, + 198, + 241, + 241, + 147, + 283, + 243, + 243, + 389, + 58, + 337, + 337, + 337, + 337, + 204, + 365, + 365, + 385, + 385, + 385, + 385, + 385, + 5, + 319, + 149, + 149, + 149, + 273, + 194, + 161, + 268, + 161, + 161, + 161, + 161, + 228, + 228, + 228, + 117, + 253, + 199, + 358, + 58, + 58, + 58, + 58, + 58, + 58, + 340, + 87, + 275, + 275, + 275, + 38, + 38, + 262, + 135, + 135, + 135, + 263, + 8, + 8, + 8, + 217, + 217, + 217, + 217, + 357, + 303, + 303, + 242, + 242, + 25, + 25, + 25, + 247, + 247, + 337, + 206, + 373, + 357, + 357, + 148, + 357, + 31, + 329, + 293, + 210, + 392, + 255, + 255, + 394, + 394, + 161, + 161, + 161, + 161, + 394, + 105, + 105, + 105, + 290, + 290, + 125, + 125, + 248, + 248, + 315, + 332, + 332, + 332, + 143, + 258, + 258, + 258, + 4, + 4, + 81, + 81, + 252, + 81, + 152, + 152, + 152, + 152, + 152, + 152, + 342, + 342, + 61, + 61, + 318, + 318, + 318, + 126, + 394, + 91, + 91, + 91, + 304, + 304, + 304, + 304, + 126, + 126, + 126, + 126, + 266, + 266, + 3, + 14, + 14, + 163, + 163, + 97, + 97, + 97, + 97, + 97, + 97, + 97, + 97, + 29, + 79, + 79, + 143, + 143, + 199, + 381, + 175, + 175, + 10, + 47, + 47, + 47, + 148, + 229, + 17, + 17, + 130, + 130, + 150, + 137, + 298, + 298, + 298, + 298, + 298, + 298, + 155, + 286, + 44, + 203, + 293, + 293, + 196, + 276, + 276, + 276, + 276, + 27, + 27, + 27, + 27, + 396, + 396, + 396, + 330, + 330, + 352, + 274, + 270, + 59, + 316, + 13, + 13, + 63, + 329, + 36, + 36, + 254, + 88, + 88, + 88, + 88, + 88, + 88, + 88, + 296, + 154, + 154, + 266, + 2, + 2, + 29, + 91, + 219, + 385, + 87, + 385, + 385, + 385, + 385, + 168, + 168, + 168, + 225, + 225, + 25, + 294, + 294, + 345, + 109, + 109, + 345, + 29, + 383, + 263, + 37, + 37, + 331, + 168, + 369, + 369, + 228, + 278, + 90, + 90, + 90, + 278, + 273, + 7, + 7, + 7, + 7, + 273, + 273, + 259, + 259, + 358, + 372, + 372, + 55, + 115, + 316, + 170, + 387, + 387, + 387, + 387, + 25, + 25, + 25, + 25, + 350, + 350, + 112, + 319, + 319, + 139, + 344, + 344, + 344, + 344, + 344, + 344, + 344, + 163, + 163, + 217, + 217, + 217, + 67, + 67, + 67, + 292, + 148, + 148, + 226, + 198, + 198, + 198, + 198, + 294, + 294, + 294, + 294, + 181, + 181, + 181, + 181, + 181, + 181, + 181, + 248, + 248, + 248, + 195, + 328, + 200, + 331, + 85, + 396, + 396, + 396, + 396, + 396, + 81, + 81, + 81, + 299, + 87, + 87, + 256, + 256, + 256, + 256, + 87, + 87, + 87, + 353, + 54, + 54, + 260, + 260, + 44, + 229, + 229, + 229, + 229, + 163, + 328, + 328, + 328, + 328, + 118, + 385, + 385, + 385, + 59, + 59, + 38, + 38, + 103, + 344, + 103, + 103, + 103, + 103, + 103, + 103, + 43, + 2, + 46, + 205, + 205, + 205, + 205, + 46, + 331, + 149, + 5, + 265, + 5, + 2, + 47, + 193, + 135, + 135, + 260, + 135, + 135, + 231, + 231, + 231, + 45, + 243, + 78, + 78, + 78, + 78, + 78, + 359, + 359, + 179, + 179, + 179, + 179, + 179, + 9, + 9, + 9, + 238, + 172, + 166, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 + ], + "commands": [ + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 + ], + "values": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, 2, - 2, - 2, - 0, - 0, - 2, - 0, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, 1, - 0, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, 1, - 0, - 0, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, 1, - 0, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, 2, - 0, - 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, 1, - 0, - 1, - 1, - 1, - 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, 1, - 0, - 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, 1, - 2, - 0, - 0, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, 1, - 0, - 2, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, 1, - 0, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, 1, - 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, 2, - 0, - 1, - 0, - 2 - ], - "values": [ + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, 319, - 100, - 60, - 386, - 125, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, 236, - 176, - 262, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, 181, - 268, - 128, - 397, - 236, - 55, - 301, - 383, - 399, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, 188, - 151, - 18, - 221, - 46, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, 106, - 174, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, 312, - 185, - 75, - 174, - 141, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, 279, - 47, - 159, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, 162, - 156, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, 90, - 40, - 320, - 76, - 369, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, 352, - 158, - 247, - 82, - 368, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, 24, - 41, - 307, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, - 16, - 121, - 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, + 87, 326, - 16, - 252, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, 171, - 106, - 66, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, 374, - 288, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, 67, - 322, - 211, - 54, - 86, - 222, - 190, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, 30, - 215, - 150, - 72, - 232, - 317, - 86, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ] } diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/pifo_tree.data index 485b42724..bf04ab461 100644 --- a/calyx-py/test/correctness/pifo_tree.data +++ b/calyx-py/test/correctness/pifo_tree.data @@ -100,7 +100,19907 @@ 0, 1, 0, - 2 + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 ], "format": { "is_signed": false, @@ -110,106 +20010,20006 @@ }, "values": { "data": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, 319, - 100, - 60, - 386, - 125, - 236, - 176, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, 262, - 181, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, 268, - 128, - 397, - 236, - 55, - 301, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, 383, - 399, - 188, - 151, - 18, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, 221, - 46, - 106, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, 174, - 262, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, 312, - 185, - 75, - 174, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, 141, - 359, - 279, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, 47, + 149, + 193, 159, - 351, - 162, - 156, - 90, - 40, - 320, - 76, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, 369, - 352, + 336, + 260, + 355, + 103, 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, 82, - 368, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, 24, + 31, 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, 16, - 121, - 379, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, 304, - 176, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, 128, - 233, - 333, - 215, - 74, - 28, - 326, - 16, - 252, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, 171, - 106, - 66, - 374, - 288, - 67, - 322, - 211, + 397, + 78, + 205, + 216, 54, - 86, - 222, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, 190, - 76, - 30, - 215, - 150, - 72, - 232, - 317, - 86, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ], "format": { "is_signed": false, @@ -219,6 +40019,19906 @@ }, "ans_mem": { "data": [ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/pifo_tree.expect index 876500088..113b95700 100644 --- a/calyx-py/test/correctness/pifo_tree.expect +++ b/calyx-py/test/correctness/pifo_tree.expect @@ -1,308 +1,60008 @@ { "ans_mem": [ - 92, - 92, - 92, - 386, - 386, - 125, - 236, - 100, - 176, - 176, - 176, - 128, - 128, - 221, - 151, - 174, - 47, - 47, - 159, - 368, - 24, - 207, + 276, + 276, + 122, + 276, + 276, + 244, + 331, + 330, + 204, + 204, + 204, + 311, + 311, + 292, + 257, + 269, + 355, + 355, + 381, + 131, + 308, + 81, + 263, + 263, + 263, + 364, + 107, + 107, + 389, + 389, + 389, + 389, + 389, + 389, 41, 41, 41, - 252, - 106, - 106, - 374, - 374, - 374, - 374, - 374, - 374, - 16, - 16, - 16, + 243, + 300, + 300, + 326, + 326, + 326, + 244, + 244, + 244, + 177, + 244, + 244, + 288, + 62, + 322, + 126, + 126, + 126, + 126, + 307, + 307, + 307, + 96, + 96, + 297, + 146, + 146, + 206, + 206, + 206, + 172, + 84, + 84, + 84, + 310, + 172, + 342, + 342, + 342, + 80, + 213, + 126, + 126, + 216, + 134, + 134, + 134, + 134, + 134, + 239, + 319, + 222, + 222, 222, + 217, + 81, + 307, + 307, + 222, + 362, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 169, + 232, + 6, + 6, + 242, + 242, + 242, + 12, + 313, + 313, + 182, + 182, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 99, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 353, + 117, + 117, + 117, + 117, + 255, + 13, + 217, + 217, + 217, + 217, + 102, + 102, + 234, + 234, + 234, + 234, + 143, + 239, + 151, + 151, + 292, + 189, + 239, + 127, + 127, + 218, + 327, + 379, + 372, + 241, + 241, + 392, + 392, + 293, + 339, + 339, + 339, + 339, + 339, + 69, + 374, + 173, + 173, + 342, + 342, + 342, + 342, + 342, + 10, + 10, + 251, + 251, + 262, + 262, + 262, + 262, + 262, + 216, + 216, + 22, + 22, + 22, + 216, + 85, + 184, + 184, + 238, + 85, + 304, + 304, + 1, + 1, + 204, + 204, + 117, + 117, + 117, + 117, + 117, + 213, + 213, + 213, + 213, + 213, + 213, + 97, + 97, + 97, + 97, + 97, + 97, + 313, + 313, + 313, + 313, + 313, + 194, + 194, + 339, + 27, + 27, + 367, + 367, + 162, + 357, + 357, + 21, + 21, + 21, + 214, + 214, + 169, + 354, + 354, + 354, + 64, + 64, + 64, + 64, + 64, + 270, + 136, + 375, + 375, + 375, + 375, + 375, + 19, + 19, + 19, + 19, + 311, + 184, + 291, + 291, + 291, + 100, + 282, + 110, + 110, + 110, + 110, + 110, + 110, + 110, + 347, + 347, + 347, + 9, + 9, + 279, + 279, + 279, + 279, + 279, + 192, + 220, + 220, + 220, + 220, + 31, + 31, + 389, + 130, + 399, + 399, + 87, + 392, + 197, + 197, + 197, + 258, + 258, + 258, + 87, + 220, + 194, + 224, + 49, + 204, + 204, + 204, + 121, + 224, + 18, + 18, + 127, + 223, + 126, + 19, + 38, + 38, + 46, + 46, + 221, + 50, + 50, + 387, + 282, + 282, + 181, + 181, + 181, + 181, + 181, + 399, + 79, + 79, + 398, + 398, + 122, + 122, + 253, + 55, + 55, + 55, + 333, + 42, + 42, + 149, + 149, + 297, + 42, + 250, + 250, + 196, + 75, + 50, + 233, + 233, + 141, + 141, + 141, + 141, + 141, + 369, + 99, + 99, + 381, + 102, + 102, + 252, + 88, + 389, + 389, + 8, + 221, + 221, + 221, + 199, + 199, + 199, + 199, + 199, + 199, + 368, + 368, + 368, + 368, + 368, + 29, + 202, 150, 150, + 287, + 41, + 389, + 68, + 54, + 43, + 348, + 348, + 6, + 6, + 6, + 6, + 6, + 155, + 221, + 221, + 167, + 245, + 11, + 11, + 11, + 345, + 345, + 345, + 345, + 179, + 122, + 375, + 377, + 391, + 175, + 175, + 175, + 175, + 363, + 363, + 363, + 363, + 64, + 64, + 264, + 103, + 258, + 52, + 52, + 52, + 384, + 384, + 37, + 37, + 37, + 383, + 192, + 192, + 343, + 14, + 143, + 143, + 88, + 38, + 322, + 156, + 156, + 381, + 33, + 157, + 157, + 226, + 44, + 211, + 349, + 388, + 388, + 388, + 388, + 115, + 388, + 242, + 67, + 67, + 242, + 246, + 334, + 334, + 334, + 283, + 283, + 283, + 283, + 26, + 305, + 56, + 223, + 223, + 236, + 83, + 66, + 208, + 9, + 96, + 339, + 117, + 117, + 117, + 47, + 308, + 47, + 47, + 14, + 14, + 14, + 240, + 67, + 301, + 40, + 160, + 160, + 106, + 52, + 120, + 120, + 360, + 39, + 39, + 39, + 39, + 230, + 230, + 230, + 230, + 93, + 186, + 186, + 93, + 93, + 65, + 178, + 178, + 178, + 173, + 258, + 10, + 250, + 250, + 250, + 250, + 278, + 278, + 274, + 274, + 274, + 39, + 330, + 330, + 330, + 330, + 3, + 3, + 210, + 210, + 263, + 241, + 241, + 298, + 75, + 349, + 349, + 224, + 224, + 294, + 294, + 190, + 190, + 190, + 190, + 294, + 110, + 110, + 110, + 210, + 361, + 361, + 361, + 265, + 261, + 349, + 86, + 86, + 86, + 349, + 349, + 191, + 348, + 374, + 216, + 216, + 60, + 216, + 216, + 99, + 232, + 63, + 63, + 63, + 63, + 362, + 362, + 362, + 189, + 303, + 303, + 303, + 303, + 77, + 77, + 381, + 399, + 317, + 317, + 317, + 58, + 317, + 369, + 65, + 65, + 238, + 169, + 332, + 332, + 332, + 47, + 47, + 47, + 321, + 321, + 321, + 321, + 159, + 159, + 394, + 394, + 93, + 300, + 185, + 185, + 298, + 298, + 19, + 19, + 310, + 310, + 102, + 285, + 285, + 25, + 228, + 228, + 133, + 133, + 133, + 211, + 211, + 6, + 327, + 176, 267, + 33, + 306, + 306, + 173, + 173, + 314, + 314, + 314, + 99, + 202, + 202, + 189, + 261, + 144, + 396, + 396, + 396, + 289, + 97, + 289, + 108, + 108, + 108, + 108, + 236, + 362, + 362, + 257, + 159, + 317, + 317, + 388, + 56, + 260, + 23, + 229, + 229, + 229, + 229, + 109, + 109, + 8, + 200, + 365, + 365, + 365, + 76, + 76, + 283, + 283, + 283, + 78, + 75, + 248, + 248, + 122, + 273, + 227, + 18, + 227, + 123, + 332, + 332, + 332, + 332, + 332, + 29, + 242, + 242, + 47, + 47, + 46, + 46, + 338, + 246, + 321, + 321, + 43, + 36, + 36, + 154, + 154, + 36, + 36, + 124, + 78, + 78, + 78, + 86, + 45, + 45, + 43, + 48, + 48, + 48, + 48, + 48, + 239, + 239, + 48, + 312, + 312, + 274, + 64, + 64, + 365, + 180, + 88, + 353, + 148, + 148, + 223, + 89, + 12, + 12, + 12, + 191, + 191, + 191, + 191, + 201, + 22, + 22, + 22, + 22, + 22, + 351, + 132, + 132, + 235, + 17, + 17, + 220, + 220, + 220, + 220, + 176, + 176, + 176, + 306, + 306, + 189, + 395, + 395, + 70, + 333, + 145, + 228, + 228, + 5, + 5, + 5, + 5, + 5, + 5, + 221, + 213, + 213, + 213, + 145, + 145, + 145, + 286, + 170, + 76, + 76, + 204, + 170, + 332, + 332, + 56, + 162, + 162, + 204, + 204, + 198, + 223, + 223, + 174, + 93, + 93, + 223, + 174, 267, - 267, - 66, - 66, - 66, - 66, - 373, + 30, + 275, + 182, + 182, + 182, + 1, + 1, + 114, + 114, + 114, + 114, + 114, + 114, + 114, + 12, + 282, + 282, + 282, + 282, + 12, + 245, + 245, + 245, + 167, + 167, 373, - 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 - ], - "commands": [ - 2, - 1, - 2, - 1, - 2, - 2, - 2, - 2, - 0, - 1, - 0, - 2, - 0, - 0, - 0, + 87, + 87, + 136, + 136, + 326, + 326, + 136, + 268, + 20, + 20, + 302, + 302, + 302, + 196, + 325, + 325, + 325, + 325, 1, + 358, + 155, + 155, + 155, + 155, + 155, + 366, + 151, + 151, + 151, + 151, + 151, + 25, + 389, + 151, + 228, + 228, + 170, + 221, + 221, + 196, + 363, + 363, + 28, + 28, + 28, + 221, + 221, + 221, + 128, + 128, + 238, + 238, + 238, + 238, + 238, + 77, + 153, + 153, + 148, + 175, + 101, + 349, + 349, + 125, + 125, + 125, + 225, + 225, + 91, + 91, + 91, + 370, + 370, + 370, + 171, + 338, + 123, + 277, + 59, + 59, + 59, + 361, + 361, + 361, + 361, + 361, + 187, + 166, + 180, + 282, + 180, + 158, + 214, + 158, + 332, + 332, + 22, + 22, + 22, + 22, + 22, + 22, + 387, + 387, + 387, + 387, + 387, + 143, + 385, + 30, + 30, + 327, + 327, + 133, + 276, + 80, + 321, + 184, + 184, + 184, + 184, + 326, + 326, + 70, + 70, + 70, + 70, + 266, + 158, + 352, + 70, + 70, + 70, + 70, + 70, + 70, + 359, + 359, + 187, + 187, + 187, + 187, + 187, + 217, + 217, + 71, + 398, + 118, + 118, + 33, + 33, + 33, + 33, + 382, + 382, + 382, + 382, + 33, + 243, + 243, + 114, + 114, + 114, + 114, + 271, + 11, + 276, + 276, + 110, + 48, + 168, + 121, + 300, + 300, + 46, + 46, + 46, + 340, + 340, + 175, + 227, + 47, + 345, + 345, + 345, + 345, + 185, + 256, + 256, + 256, + 86, + 86, + 355, + 176, + 176, + 209, + 209, + 187, + 281, + 161, + 360, + 152, + 152, + 152, + 152, + 152, + 152, + 151, + 377, + 377, + 156, + 385, + 385, + 176, + 305, + 305, + 86, + 331, + 331, + 268, + 232, + 243, + 243, + 281, + 248, + 248, + 369, + 369, + 362, + 362, + 362, + 264, + 162, + 340, + 340, + 168, + 299, + 299, + 299, + 299, + 72, + 263, + 263, + 263, + 198, + 286, + 75, + 75, + 215, + 215, + 215, + 196, + 196, + 227, + 7, + 328, + 328, + 190, + 281, + 281, + 281, + 76, + 76, + 319, + 319, + 137, + 311, + 311, + 311, + 311, + 311, + 311, + 311, + 33, + 33, + 33, + 33, + 229, + 164, + 164, + 164, + 394, + 73, + 73, + 383, + 27, + 27, + 311, + 28, + 28, + 28, + 358, + 358, + 358, + 24, + 105, + 352, + 24, + 326, + 112, + 112, + 112, + 233, + 233, + 233, + 3, + 3, + 3, + 3, + 229, + 147, + 147, + 289, + 289, + 55, + 55, + 55, + 55, + 349, + 121, + 121, + 121, + 313, + 313, + 10, + 10, + 266, + 266, + 266, + 115, + 115, + 115, + 249, + 249, + 22, + 318, + 318, + 318, + 318, + 318, + 318, + 199, + 199, + 199, + 373, + 373, + 373, + 50, + 246, + 35, + 35, + 35, + 224, + 224, + 224, + 224, + 120, + 351, + 54, + 54, + 269, + 269, + 179, + 394, + 51, + 293, + 19, + 196, + 196, + 196, + 196, + 258, + 19, + 19, + 19, + 19, + 240, + 240, + 240, + 240, + 240, + 125, + 400, + 400, + 400, + 400, + 83, + 385, + 385, + 385, + 385, + 385, + 148, + 148, + 148, + 148, + 148, + 262, + 9, + 9, + 9, + 9, + 239, + 268, + 268, + 58, + 58, + 58, + 58, + 281, + 153, + 153, + 153, + 301, + 301, + 301, + 149, + 297, + 6, + 6, + 169, + 169, + 110, + 342, + 342, + 177, + 177, + 20, + 20, + 177, + 103, + 185, + 66, + 122, + 308, + 308, + 195, + 222, + 222, + 222, + 222, + 222, + 379, + 379, + 379, + 362, + 362, + 53, + 301, + 301, + 167, + 167, + 167, + 238, + 238, + 289, + 289, + 208, + 100, + 353, + 29, + 29, + 325, + 325, + 159, + 159, + 159, + 159, + 159, + 325, + 325, + 325, + 90, + 391, + 123, + 257, + 109, + 109, + 283, + 255, + 103, + 363, + 363, + 11, + 299, + 104, + 104, + 246, + 246, + 246, + 246, + 191, + 399, + 399, + 115, + 115, + 115, + 388, + 388, + 75, + 275, + 144, + 144, + 144, + 144, + 144, + 144, + 268, + 21, + 21, + 230, + 173, + 345, + 345, + 15, + 15, + 297, + 10, + 10, + 214, + 214, + 214, + 214, + 399, + 399, + 39, + 399, + 237, + 288, + 379, + 379, + 379, + 379, + 379, + 270, + 270, + 270, + 270, + 272, + 156, + 156, + 272, + 272, + 56, + 358, + 358, + 358, + 150, + 150, + 150, + 298, + 298, + 37, + 253, + 253, + 141, + 141, + 141, + 141, + 400, + 400, + 400, + 400, + 400, + 49, + 279, + 279, + 195, + 203, + 73, + 224, + 224, + 224, + 12, + 375, + 51, + 51, + 210, + 18, + 351, + 83, + 83, + 83, + 380, + 361, + 352, + 352, + 161, + 161, + 352, + 17, + 17, + 17, + 17, + 207, + 207, + 119, + 119, + 388, + 5, + 337, + 337, + 337, + 337, + 38, + 280, + 280, + 188, + 188, + 188, + 338, + 338, + 338, + 338, + 11, + 11, + 11, + 292, + 292, + 85, + 247, + 154, + 154, + 154, + 326, + 326, + 108, + 209, + 104, + 335, + 335, + 335, + 42, + 109, + 109, + 109, + 276, + 276, + 85, + 161, + 206, + 206, + 133, + 397, + 397, + 397, + 397, + 197, + 197, + 197, + 224, + 224, + 224, + 224, + 224, + 77, + 77, + 83, + 99, + 167, + 167, + 239, + 239, + 239, + 16, + 227, + 149, + 264, + 93, + 93, + 93, + 186, + 186, + 186, + 77, + 77, + 77, + 77, + 142, + 57, + 57, + 57, + 57, + 102, + 102, + 111, + 265, + 265, + 111, + 111, + 369, + 152, + 181, + 139, + 94, + 139, + 52, + 52, + 128, + 27, + 27, + 78, + 83, + 166, + 83, + 83, + 195, + 318, + 195, + 5, + 5, + 5, + 347, + 5, + 5, + 5, + 5, + 312, + 132, + 132, + 132, + 132, + 132, + 132, + 132, + 218, + 84, + 376, + 376, + 179, + 27, + 376, + 376, + 376, + 139, + 139, + 215, + 215, + 55, + 55, + 202, + 124, + 124, + 124, + 313, + 313, + 392, + 392, + 392, + 392, + 392, + 392, + 392, + 204, + 204, + 204, + 204, + 355, + 136, + 136, + 355, + 355, + 131, + 131, + 131, + 68, + 218, + 131, + 31, + 31, + 291, + 144, + 144, + 144, + 328, + 38, + 38, + 38, + 377, + 126, + 346, + 346, + 346, + 90, + 90, + 316, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 293, + 293, + 293, + 293, + 64, + 64, + 290, + 112, + 230, + 51, + 51, + 273, + 273, + 173, + 173, + 173, + 59, + 227, + 227, + 227, + 227, + 59, + 302, + 102, + 102, + 247, + 8, + 8, + 8, + 376, + 177, + 298, + 298, + 21, + 361, + 361, + 159, + 5, + 5, + 139, + 368, + 139, + 232, + 17, + 397, + 397, + 397, + 397, + 166, + 281, + 28, + 28, + 28, + 28, + 345, + 136, + 136, + 136, + 379, + 3, + 3, + 226, + 226, + 150, + 150, + 150, + 150, + 150, + 150, + 342, + 342, + 342, + 342, + 342, + 95, + 302, + 126, + 350, + 350, + 10, + 10, + 10, + 10, + 285, + 285, + 285, + 285, + 154, + 209, 1, - 0, + 368, + 200, + 68, + 125, + 98, + 98, + 98, + 98, + 98, + 254, + 254, + 102, + 37, + 368, + 368, + 368, + 160, + 160, + 160, + 76, + 76, + 166, + 28, + 160, + 58, + 355, + 58, + 66, + 31, + 31, + 31, + 31, + 31, + 31, + 361, + 237, + 237, + 56, + 246, + 312, + 363, + 363, + 262, + 367, + 376, + 376, + 108, + 3, + 234, + 234, + 226, + 35, + 35, + 35, + 288, + 288, + 288, + 8, + 272, + 293, + 35, + 35, + 92, + 11, + 305, + 305, + 305, + 193, + 193, + 319, + 319, + 53, + 53, + 372, + 372, + 112, + 83, + 83, + 83, + 131, + 197, + 197, + 336, + 302, + 302, + 302, + 273, + 273, + 297, + 294, + 80, + 294, + 294, + 121, + 397, + 397, + 397, + 397, + 254, + 199, + 199, + 19, + 264, + 264, + 264, + 264, + 264, + 199, + 199, + 199, + 333, + 333, + 333, + 46, + 396, + 396, + 396, + 396, + 396, + 396, + 186, + 306, + 306, + 118, + 118, + 327, + 32, + 220, + 133, + 142, + 142, + 125, + 63, + 236, + 236, + 236, + 63, + 63, + 63, + 63, + 63, + 63, + 168, + 56, + 200, + 10, + 10, + 129, 1, - 2, - 0, - 2, - 0, - 0, - 2, - 0, 1, 1, + 145, + 145, + 145, + 145, + 247, + 145, + 145, + 145, + 310, + 310, + 9, + 9, + 354, + 354, + 156, + 156, + 261, + 19, + 19, + 328, + 150, + 150, + 150, + 376, + 376, + 376, + 27, + 273, + 273, + 124, + 124, + 308, + 308, + 6, + 6, + 6, + 6, + 256, + 256, + 199, + 233, + 97, + 277, + 163, + 163, + 163, + 163, + 163, + 305, + 92, + 92, + 218, + 141, + 389, + 389, + 178, + 208, + 208, + 266, + 52, + 266, + 176, + 176, + 176, + 397, + 120, + 120, + 120, + 232, + 81, + 306, + 306, + 188, + 188, + 188, + 188, + 392, + 25, + 25, + 227, + 125, + 398, + 14, + 219, + 219, + 219, + 219, + 161, + 305, + 305, + 305, + 305, + 46, + 46, + 46, + 46, + 46, + 306, + 306, + 316, + 383, + 97, + 97, + 97, + 219, + 219, + 219, + 103, + 103, + 336, + 336, + 11, + 11, + 11, + 11, + 380, + 61, + 61, + 61, + 368, + 80, + 80, + 278, + 278, + 278, + 278, + 147, + 147, + 147, + 147, + 147, + 147, + 371, + 27, + 27, + 272, + 272, + 272, + 131, + 232, + 232, + 232, + 174, + 368, + 368, + 368, + 113, + 113, + 113, + 346, + 161, + 161, + 161, + 241, + 10, + 10, + 223, + 132, + 132, + 132, + 275, + 70, + 70, + 70, + 366, + 366, + 135, + 370, + 370, + 370, + 15, + 15, + 15, + 226, + 160, + 160, + 160, + 160, + 255, + 394, + 304, + 373, + 240, + 240, + 136, + 136, + 136, + 136, + 136, + 240, + 240, + 114, + 221, + 159, + 159, + 98, + 240, + 159, + 362, + 160, + 108, + 108, + 263, + 263, + 263, + 263, + 147, + 147, + 367, + 384, + 372, + 372, + 296, + 17, + 17, + 17, + 341, + 125, + 305, + 89, + 89, + 261, + 261, + 261, + 153, + 384, + 92, + 92, + 92, + 92, + 251, + 251, + 251, + 251, + 251, + 190, + 320, + 52, + 323, + 128, + 371, + 371, + 371, + 94, + 168, + 16, + 155, + 155, + 35, + 35, + 35, + 74, + 217, + 217, + 217, + 149, + 149, + 239, + 170, + 170, + 170, + 222, + 222, + 188, + 250, + 25, + 345, + 183, + 183, + 215, + 215, + 215, + 215, + 155, + 254, + 254, + 254, + 58, + 58, + 58, + 58, + 58, + 333, + 198, + 198, + 198, + 198, + 231, + 177, + 395, + 395, + 395, + 395, + 22, + 387, + 149, + 149, + 292, + 166, + 215, + 215, + 215, + 398, + 399, + 51, + 51, + 366, + 142, + 55, + 55, + 251, + 55, + 55, + 55, + 55, + 55, + 366, + 140, + 140, + 274, + 274, + 28, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 375, + 172, + 172, + 301, + 301, + 39, + 39, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 382, + 112, + 112, + 112, + 112, + 392, + 6, + 374, + 374, + 374, + 374, + 167, + 167, + 244, + 56, + 265, + 159, + 159, + 384, + 384, + 384, + 153, + 153, + 153, + 247, + 126, + 16, + 224, + 126, + 126, + 126, + 126, + 344, + 344, + 54, + 358, + 358, + 180, + 180, + 180, + 352, + 91, + 91, + 342, + 125, + 125, + 361, + 361, + 43, + 43, + 344, + 147, + 327, + 11, + 399, + 399, + 154, + 154, + 154, + 301, + 301, + 78, + 201, + 201, + 195, + 92, + 343, + 343, + 180, + 180, + 180, + 392, + 37, + 37, + 275, + 275, + 275, + 24, + 378, + 378, + 378, + 378, + 378, + 378, + 378, + 378, + 155, + 363, + 63, + 63, + 293, + 166, + 273, + 99, + 345, + 345, + 167, + 167, + 351, + 351, + 351, + 34, + 34, + 34, + 34, + 34, + 34, + 245, + 192, + 192, + 192, + 192, + 192, + 363, + 67, + 67, + 360, + 360, + 123, + 123, + 123, + 123, + 123, + 252, + 252, + 33, + 33, + 349, + 349, + 157, + 242, + 242, + 242, + 91, + 91, + 91, + 277, + 149, + 329, + 329, + 329, + 329, + 329, + 71, + 239, + 114, + 114, + 114, + 60, + 195, + 195, + 92, + 182, + 182, + 182, + 10, + 36, + 36, + 50, + 50, + 50, + 308, + 308, + 174, + 393, + 33, + 216, + 150, + 21, + 21, + 21, + 119, + 119, + 196, + 182, + 316, + 316, + 316, + 56, + 247, + 182, + 213, + 38, + 38, + 399, + 189, + 189, + 289, + 91, + 374, + 374, + 143, + 143, + 220, + 93, + 320, + 320, + 53, + 287, + 287, + 124, + 124, + 218, + 38, + 286, + 286, + 177, + 177, + 177, + 177, + 177, + 177, + 344, + 344, + 13, + 13, + 336, + 117, + 117, + 221, + 29, + 29, + 391, + 172, + 172, + 172, + 172, + 328, + 328, + 3, + 3, + 3, + 288, + 27, + 27, + 369, + 369, + 37, + 254, + 254, + 254, + 254, + 254, + 254, + 168, + 168, + 50, + 116, + 26, + 350, + 350, + 350, + 339, + 339, + 158, + 342, + 181, + 290, + 326, + 326, + 326, + 82, + 130, + 185, + 185, + 185, + 201, + 201, + 201, + 177, + 4, + 4, + 392, + 392, + 177, + 240, + 91, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 303, + 190, + 190, + 315, + 55, + 55, + 349, + 349, + 349, + 119, + 366, + 39, + 39, + 266, + 266, + 123, + 123, + 123, + 317, + 38, + 225, + 225, + 225, + 225, + 199, + 226, + 226, + 26, + 26, + 344, + 169, + 375, + 13, + 13, + 13, + 13, + 238, + 152, + 152, + 152, + 250, + 43, + 43, + 372, + 372, + 372, + 372, + 372, + 372, + 372, + 116, + 116, + 116, + 296, + 296, + 13, + 395, + 395, + 122, + 122, + 52, + 104, + 9, + 9, + 374, + 9, + 9, + 290, + 114, + 260, + 260, + 83, + 83, + 83, + 83, + 261, + 261, + 113, + 283, + 283, + 95, + 95, + 323, + 120, + 120, + 280, + 280, + 280, + 57, + 356, + 108, + 266, + 266, + 69, + 141, + 75, + 180, + 180, + 91, + 91, + 19, + 315, + 8, + 381, + 218, + 218, + 241, + 341, + 59, + 119, + 119, + 355, + 355, + 355, + 355, + 59, + 275, + 275, + 168, + 305, + 305, + 7, + 7, + 354, + 104, + 104, + 275, + 94, + 94, + 94, + 217, + 217, + 138, + 301, + 301, + 301, + 301, + 301, + 301, + 301, + 197, + 255, + 255, + 38, + 38, + 38, + 336, + 336, + 336, + 147, + 147, + 147, + 147, + 278, + 278, + 80, + 293, + 293, + 293, + 293, + 293, + 293, + 133, + 365, + 365, + 365, + 365, + 80, + 286, + 164, + 164, + 164, + 257, + 21, + 21, + 21, + 320, + 320, + 167, + 167, + 303, + 303, + 46, + 46, + 204, + 204, + 102, + 383, + 13, + 13, + 326, + 136, + 136, + 233, + 233, + 233, + 233, + 47, + 331, + 121, + 272, + 62, + 62, + 234, + 234, + 234, + 177, + 177, + 251, + 70, + 70, + 283, + 101, + 101, + 214, + 214, + 21, + 138, + 33, + 274, + 33, + 33, + 187, + 187, + 242, + 187, + 187, + 18, + 18, + 378, + 18, + 125, + 125, + 68, + 120, + 120, + 120, + 49, + 49, + 350, + 192, + 204, + 204, + 204, + 204, + 42, + 42, + 348, + 348, + 148, + 383, + 95, + 260, + 260, + 134, + 134, + 134, + 317, + 317, + 58, + 250, + 111, + 111, + 273, + 273, + 163, + 282, + 148, + 313, + 313, + 199, + 100, + 100, + 217, + 199, + 199, + 199, + 235, + 235, + 235, + 235, + 235, + 22, + 22, + 334, + 334, + 152, + 152, + 312, + 5, + 284, + 284, + 284, + 199, + 199, + 199, + 204, + 204, + 204, + 204, + 204, + 135, + 225, + 225, + 345, + 317, + 317, + 392, + 342, + 342, + 342, + 342, + 295, + 295, + 376, + 227, + 155, + 155, + 155, + 227, + 227, + 227, + 154, + 154, + 352, + 352, + 352, + 352, + 27, + 263, + 263, + 176, + 249, + 45, + 45, + 333, + 333, + 333, + 193, + 193, + 193, + 241, + 241, + 241, + 28, + 28, + 298, + 117, + 117, + 117, + 280, + 25, + 272, + 272, + 113, + 250, + 108, + 108, + 108, + 78, + 282, + 282, + 108, + 215, + 197, + 197, + 14, + 358, + 197, + 197, + 269, + 82, + 82, + 271, + 117, + 270, + 27, + 236, + 131, + 131, + 131, + 225, + 225, + 225, + 27, + 27, + 27, + 250, + 127, + 286, + 286, + 286, + 53, + 53, + 375, + 375, + 375, + 375, + 375, + 143, + 294, + 294, + 294, + 47, + 248, + 144, + 144, + 329, + 15, + 343, + 185, + 69, + 123, + 10, + 10, + 329, + 162, + 162, + 353, + 353, + 353, + 173, + 141, + 141, + 159, + 159, + 159, + 159, + 159, + 55, + 296, + 178, + 59, + 181, + 119, + 184, + 184, + 275, + 119, + 119, + 296, + 296, + 296, + 296, + 129, + 129, + 328, + 396, + 41, + 41, + 396, + 396, + 50, + 50, + 50, + 370, + 370, + 370, + 14, + 254, + 165, + 165, + 165, + 165, + 362, + 19, + 265, + 162, + 162, + 253, + 25, + 230, + 124, + 220, + 220, + 63, + 339, + 135, + 343, + 87, + 225, + 176, + 269, + 269, + 269, + 269, + 179, + 239, + 239, + 195, + 212, + 212, + 102, + 250, + 250, + 250, + 146, + 308, + 72, + 305, + 132, + 299, + 299, + 299, + 299, + 299, + 299, + 79, + 79, + 244, + 244, + 244, + 110, + 248, + 248, + 38, + 38, + 282, + 101, + 101, + 326, + 326, + 326, + 81, + 387, + 199, + 318, + 318, + 22, + 22, + 22, + 267, + 169, + 273, + 61, + 248, + 186, + 196, + 157, + 157, + 157, + 157, + 164, + 211, + 164, + 364, + 364, + 248, + 248, + 393, + 393, + 49, + 210, + 100, + 100, + 100, + 100, + 215, + 183, + 225, + 144, + 339, + 339, + 339, + 70, + 165, + 165, + 239, + 94, + 269, + 148, + 300, + 5, + 5, + 223, + 105, + 105, + 226, + 237, + 186, + 186, + 186, + 262, + 262, + 91, + 91, + 241, + 241, + 117, + 117, + 117, + 215, + 84, + 84, + 84, + 275, + 275, + 275, + 275, + 275, + 150, + 284, + 284, + 284, + 77, + 230, + 72, + 72, + 156, + 156, + 222, + 222, + 222, + 72, + 72, + 72, + 226, + 226, + 226, + 226, + 125, + 125, + 372, + 372, + 9, + 302, + 302, + 198, + 398, + 398, + 81, + 261, + 261, + 6, + 337, + 90, + 256, + 256, + 256, + 64, + 64, + 246, + 22, + 389, + 250, + 379, + 168, + 168, + 168, + 168, + 168, + 168, + 379, + 70, + 268, + 116, + 277, + 235, + 223, + 223, + 185, + 271, + 275, + 50, + 50, + 324, + 324, + 324, + 324, + 324, + 60, + 161, + 271, + 60, + 383, + 90, + 90, + 90, + 90, + 253, + 121, + 121, + 121, + 395, + 395, + 54, + 262, + 124, + 264, + 264, + 77, + 343, + 177, + 242, + 242, + 242, + 3, + 116, + 46, + 44, + 93, + 93, + 93, + 5, + 203, + 11, + 11, + 11, + 142, + 142, + 237, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 11, + 277, + 277, + 277, + 174, + 174, + 386, + 386, + 386, + 84, + 250, + 250, + 138, + 138, + 138, + 138, + 349, + 7, + 7, + 246, + 246, + 246, + 246, + 130, + 259, + 259, + 39, + 39, + 39, + 39, + 39, + 303, + 198, + 198, + 297, + 18, + 18, + 307, + 182, + 351, + 90, + 90, + 90, + 137, + 16, + 136, + 184, + 24, + 132, + 231, + 132, + 132, + 132, + 132, + 130, + 343, + 343, + 343, + 343, + 343, + 150, + 45, + 333, + 333, + 333, + 45, + 273, + 273, + 273, + 273, + 188, + 188, + 188, + 188, + 296, + 3, + 3, + 3, + 298, + 104, + 244, + 75, + 75, + 75, + 75, + 75, + 75, + 75, + 266, + 177, + 177, + 177, + 297, + 7, + 113, + 17, + 17, + 125, + 125, + 125, + 183, + 277, + 124, + 271, + 233, + 8, + 8, + 233, + 233, + 233, + 233, + 129, + 217, + 217, + 24, + 210, + 210, + 162, + 162, + 274, + 34, + 239, + 29, + 237, + 237, + 144, + 144, + 144, + 265, + 265, + 265, + 82, + 378, + 176, + 176, + 268, + 197, + 197, + 389, + 389, + 33, + 33, + 308, + 190, + 355, + 355, + 355, + 115, + 115, + 115, + 115, + 278, + 278, + 278, + 278, + 150, + 398, + 398, + 398, + 59, + 59, + 350, + 189, + 189, + 311, + 98, + 98, + 291, + 224, + 224, + 96, + 96, + 96, + 96, + 224, + 54, + 379, + 75, + 75, + 75, + 380, + 380, + 380, + 146, + 241, + 241, + 241, + 42, + 391, + 391, + 187, + 323, + 323, + 323, + 323, + 184, + 391, + 113, + 305, + 195, + 195, + 195, + 358, + 358, + 130, + 271, + 271, + 271, + 38, + 38, + 38, + 38, + 38, + 246, + 113, + 379, + 379, + 379, + 26, + 26, + 245, + 172, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 210, + 8, + 327, + 327, + 327, + 193, + 207, + 207, + 26, + 377, + 198, + 374, + 196, + 196, + 342, + 342, + 342, + 196, + 258, + 4, + 4, + 4, + 4, + 345, + 345, + 172, + 391, + 391, + 391, + 391, + 31, + 31, + 31, + 31, + 31, + 31, + 31, + 31, + 354, + 354, + 354, + 136, + 378, + 378, + 99, + 377, + 149, + 385, + 385, + 43, + 43, + 43, + 277, + 148, + 148, + 226, + 14, + 14, + 374, + 184, + 274, + 2, + 2, + 2, + 346, + 346, + 346, + 163, + 163, + 163, + 163, + 204, + 204, + 204, + 83, + 83, + 277, + 277, + 277, + 6, + 6, + 202, + 167, + 167, + 167, + 167, + 383, + 383, + 383, + 383, + 88, + 260, + 56, + 56, + 389, + 78, + 78, + 78, + 78, + 246, + 22, + 22, + 30, + 3, + 322, + 322, + 3, + 362, + 362, + 362, + 1, + 128, + 128, + 128, + 128, + 128, + 395, + 395, + 395, + 1, + 377, + 56, + 218, + 199, + 199, + 213, + 213, + 54, + 205, + 205, + 205, + 205, + 205, + 205, + 186, + 186, + 206, + 39, + 341, + 341, + 341, + 341, + 180, + 180, + 180, + 282, + 326, + 150, + 150, + 150, + 150, + 326, + 119, + 119, + 119, + 222, + 355, + 266, + 389, + 389, + 196, + 383, + 7, + 324, + 48, + 270, + 58, + 58, + 31, + 211, + 159, + 159, + 159, + 330, + 66, + 66, + 370, + 370, + 102, + 102, + 102, + 102, + 102, + 102, + 215, + 215, + 215, + 215, + 215, + 215, + 215, + 60, + 258, + 187, + 203, + 50, + 176, + 176, + 5, + 380, + 186, + 186, + 186, + 316, + 75, + 371, + 151, + 399, + 399, + 161, + 139, + 64, + 232, + 232, + 110, + 265, + 155, + 155, + 367, + 56, + 300, + 300, + 175, + 123, + 257, + 257, + 257, + 369, + 380, + 68, + 312, + 102, + 102, + 277, + 112, + 145, + 212, + 68, + 243, + 151, + 151, + 157, + 157, + 157, + 163, + 339, + 16, + 16, + 16, + 256, + 253, + 332, + 178, + 332, + 332, + 349, + 349, + 311, + 24, + 24, + 24, + 24, + 252, + 252, + 10, + 10, + 281, + 281, + 281, + 281, + 232, + 340, + 397, + 397, + 397, + 397, + 397, + 397, + 397, + 5, + 5, + 5, + 167, + 167, + 225, + 98, + 98, + 208, + 208, + 170, + 328, + 70, + 214, + 177, + 177, + 386, + 386, + 386, + 386, + 24, + 24, + 394, + 129, + 33, + 155, + 155, + 254, + 254, + 254, + 146, + 214, + 96, + 96, + 96, + 96, + 228, + 228, + 178, + 261, + 261, + 90, + 90, + 90, + 90, + 214, + 109, + 109, + 109, + 392, + 392, + 41, + 230, + 230, + 133, + 133, + 380, + 36, + 36, + 36, + 36, + 36, + 36, + 36, + 356, + 356, + 174, + 239, + 27, + 260, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 148, + 208, + 208, + 57, + 57, + 57, + 57, + 363, + 191, + 191, + 283, + 283, + 55, + 373, + 373, + 373, + 373, + 373, + 151, + 276, + 276, + 276, + 276, + 45, + 286, + 245, + 245, + 245, + 245, + 85, + 230, + 230, + 230, + 230, + 230, + 46, + 46, + 327, + 357, + 206, + 228, + 228, + 228, + 331, + 331, + 331, + 248, + 269, + 164, + 214, + 146, + 146, + 299, + 299, + 299, + 47, + 47, + 47, + 251, + 251, + 140, + 140, + 140, + 301, + 53, + 53, + 53, + 53, + 53, + 336, + 188, + 188, + 296, + 18, + 18, + 18, + 18, + 386, + 386, + 189, + 189, + 189, + 302, + 86, + 86, + 86, + 295, + 157, + 385, + 92, + 121, + 63, + 353, + 192, + 192, + 207, + 60, + 287, + 287, + 116, + 116, + 116, + 215, + 138, + 275, + 275, + 64, + 64, + 64, + 64, + 64, + 64, + 234, + 234, + 182, + 182, + 256, + 256, + 78, + 78, + 280, + 280, + 104, + 104, + 104, + 104, + 104, + 104, + 337, + 195, + 195, + 337, + 337, + 337, + 337, + 337, + 337, + 337, + 70, + 70, + 70, + 70, + 70, + 253, + 142, + 346, + 207, + 207, + 204, + 204, + 204, + 253, + 371, + 76, + 371, + 371, + 371, + 371, + 371, + 181, + 181, + 181, + 352, + 194, + 203, + 158, + 280, + 214, + 77, + 214, + 261, + 4, + 4, + 229, + 229, + 229, + 229, + 165, + 165, + 165, + 165, + 335, + 335, + 57, + 233, + 101, + 299, + 299, + 299, + 71, + 71, + 249, + 249, + 108, + 262, + 262, + 162, + 267, + 267, + 43, + 43, + 43, + 246, + 246, + 246, + 246, + 246, + 111, + 245, + 57, + 57, + 57, + 231, + 231, + 119, + 119, + 119, + 262, + 151, + 151, + 151, + 151, + 151, + 151, + 314, + 314, + 210, + 366, + 268, + 63, + 63, + 63, + 268, + 268, + 268, + 268, + 287, + 266, + 85, + 85, + 217, + 217, + 217, + 217, + 122, + 285, + 184, + 247, + 247, + 37, + 37, + 37, + 387, + 387, + 176, + 176, + 212, + 47, + 285, + 180, + 205, + 164, + 164, + 365, + 365, + 95, + 95, + 291, + 226, + 226, + 47, + 105, + 105, + 105, + 226, + 226, + 226, + 47, + 47, + 47, + 379, + 379, + 192, + 192, + 192, + 341, + 341, + 95, + 396, + 396, + 396, + 156, + 156, + 316, + 316, + 316, + 29, + 29, + 302, + 135, + 135, + 264, + 264, + 264, + 264, + 264, + 79, + 225, + 243, + 243, + 243, + 284, + 309, + 309, + 262, + 186, + 262, + 262, + 262, + 121, + 121, + 68, + 68, + 121, + 101, + 174, + 394, + 394, + 394, + 174, + 204, + 249, + 249, + 295, + 116, + 116, + 116, + 116, + 184, + 282, + 115, + 115, + 115, + 115, + 115, + 230, + 230, + 230, + 230, + 230, + 53, + 336, + 122, + 241, + 16, + 16, + 16, + 309, + 309, + 309, + 309, + 309, + 309, + 309, + 148, + 344, + 344, + 344, + 62, + 254, + 145, + 176, + 176, + 176, + 231, + 176, + 176, + 381, + 16, + 16, + 204, + 204, + 204, + 204, + 103, + 341, + 86, + 25, + 25, + 25, + 184, + 25, + 284, + 25, + 84, + 84, + 98, + 377, + 28, + 373, + 373, + 373, + 373, + 288, + 186, + 288, + 353, + 353, + 228, + 228, + 228, + 69, + 69, + 398, + 156, + 156, + 156, + 262, + 262, + 26, + 26, + 326, + 43, + 398, + 398, + 284, + 31, + 284, + 284, + 70, + 70, + 281, + 217, + 217, + 217, + 217, + 332, + 302, + 60, + 60, + 60, + 60, + 276, + 173, + 173, + 313, + 32, + 32, + 211, + 188, + 188, + 315, + 94, + 94, + 94, + 386, + 386, + 118, + 118, + 118, + 118, + 231, + 231, + 231, + 231, + 231, + 31, + 335, + 114, + 114, + 114, + 344, + 38, + 368, + 368, + 368, + 368, + 368, + 368, + 148, + 278, + 61, + 225, + 225, + 225, + 225, + 180, + 342, + 36, + 36, + 294, + 294, + 153, + 153, + 153, + 153, + 278, + 278, + 20, + 20, + 20, + 386, + 156, + 156, + 225, + 34, + 310, + 182, + 323, + 40, + 339, + 180, + 180, + 218, + 57, + 57, + 209, + 209, + 142, + 230, + 230, + 230, + 230, + 6, + 276, + 276, + 137, + 336, + 18, + 18, + 344, + 344, + 20, + 217, + 364, + 389, + 389, + 289, + 289, + 218, + 218, + 218, + 392, + 392, + 392, + 392, + 392, + 239, + 239, + 239, + 239, + 239, + 206, + 206, + 206, + 271, + 271, + 346, + 33, + 33, + 346, + 346, + 346, + 346, + 346, + 346, + 165, + 375, + 12, + 386, + 130, + 130, + 243, + 243, + 57, + 276, + 146, + 370, + 13, + 209, + 209, + 64, + 283, + 114, + 114, + 255, + 255, + 255, + 255, + 124, + 124, + 308, + 187, + 293, + 154, + 242, + 383, + 243, + 243, + 181, + 377, + 114, + 114, + 278, + 119, + 119, + 320, + 320, + 274, + 303, + 303, + 109, + 303, + 124, + 214, + 322, + 256, + 336, + 336, + 336, + 101, + 101, + 336, + 336, + 280, + 5, + 353, + 353, + 381, + 362, + 362, + 362, + 362, + 50, + 315, + 280, + 217, + 217, + 33, + 34, + 34, + 34, + 329, + 329, + 34, + 283, + 283, + 283, + 283, + 16, + 16, + 16, + 238, + 238, + 238, + 155, + 332, + 57, + 221, + 197, + 342, + 342, + 79, + 388, + 76, + 76, + 66, + 223, + 223, + 223, + 66, + 180, + 303, + 303, + 303, + 303, + 303, + 66, + 66, + 211, + 211, + 211, + 166, + 166, + 311, + 78, + 302, + 302, + 302, + 302, + 302, + 302, + 302, + 130, + 299, + 299, + 299, + 56, + 340, + 137, + 137, + 137, + 137, + 137, + 137, + 229, + 90, + 288, + 138, + 320, + 55, + 268, + 262, + 262, + 262, + 262, + 112, + 112, + 262, + 121, + 232, + 232, + 232, + 49, + 49, + 246, + 246, + 246, + 246, + 246, + 246, + 107, + 107, + 107, + 224, + 224, + 399, + 399, + 214, + 214, + 270, + 270, + 316, + 316, + 316, + 314, + 314, + 222, + 160, + 160, + 299, + 299, + 97, + 312, + 312, + 312, + 160, + 213, + 213, + 8, + 8, + 8, + 8, + 8, + 289, + 189, + 253, + 253, + 253, + 21, + 203, + 155, + 155, + 155, + 312, + 33, + 33, + 33, + 400, + 300, + 308, + 308, + 308, + 328, + 253, + 381, + 381, + 262, + 242, + 182, + 242, + 242, + 242, + 164, + 329, + 329, + 8, + 8, + 340, + 199, + 240, + 83, + 83, + 384, + 116, + 236, + 236, + 236, + 236, + 123, + 231, + 299, + 18, + 299, + 299, + 80, + 290, + 290, + 177, + 177, + 177, + 309, + 309, + 309, + 218, + 218, + 321, + 321, + 163, + 321, + 301, + 77, + 77, + 77, + 301, + 23, + 204, + 361, + 216, + 216, + 216, + 199, + 199, + 199, + 199, + 238, + 128, + 128, + 207, + 132, + 396, + 189, + 285, + 285, + 285, + 72, + 376, + 376, + 106, + 106, + 106, + 106, + 304, + 304, + 87, + 201, + 201, + 201, + 201, + 201, + 201, + 121, + 282, + 104, + 265, + 265, + 265, + 38, + 316, + 316, + 316, + 316, + 168, + 168, + 168, + 285, + 285, + 285, + 4, + 278, + 278, + 121, + 121, + 121, + 259, + 259, + 259, + 259, + 37, + 316, + 188, + 364, + 53, + 284, + 284, + 150, + 150, + 330, + 330, + 32, + 32, + 379, + 379, + 379, + 379, + 167, + 246, + 120, + 120, + 348, + 348, + 348, + 129, + 371, + 149, + 149, + 255, + 255, + 131, + 267, + 163, + 377, + 111, + 400, + 400, + 195, + 195, + 359, + 359, + 359, + 359, + 359, + 66, + 66, + 201, + 201, + 201, + 201, + 201, + 201, + 109, + 312, + 312, + 77, + 231, + 130, + 221, + 221, + 221, + 33, + 326, + 326, + 162, + 162, + 267, + 52, + 287, + 287, + 287, + 190, + 360, + 360, + 360, + 360, + 360, + 360, + 80, + 277, + 277, + 182, + 182, + 255, + 63, + 63, + 63, + 292, + 136, + 136, + 222, + 222, + 222, + 222, + 222, + 50, + 50, + 50, + 50, + 223, + 111, + 297, + 297, + 50, + 255, + 255, + 255, + 255, + 130, + 32, + 323, + 118, + 118, + 118, + 30, + 254, + 254, + 254, + 30, + 30, + 303, + 182, + 182, + 158, + 144, + 103, + 29, + 29, + 29, + 103, + 58, + 58, + 369, + 369, + 369, + 58, + 167, + 167, + 167, + 167, + 26, + 168, + 168, + 139, + 147, + 132, + 286, + 286, + 286, + 286, + 39, + 202, + 196, + 196, + 352, + 352, + 153, + 153, + 241, + 143, + 143, + 143, + 397, + 397, + 397, + 397, + 397, + 19, + 288, + 117, + 290, + 290, + 290, + 77, + 370, + 131, + 131, + 269, + 269, + 86, + 228, + 166, + 166, + 166, + 241, + 241, + 241, + 241, + 241, + 241, + 241, + 6, + 6, + 6, + 6, + 6, + 6, + 339, + 140, + 335, + 78, + 321, + 116, + 116, + 116, + 364, + 364, + 364, + 364, + 364, + 364, + 72, + 295, + 295, + 295, + 295, + 134, + 134, + 134, + 246, + 1, + 1, + 1, + 1, + 1, + 1, + 205, + 205, + 148, + 363, + 363, + 21, + 260, + 260, + 260, + 127, + 127, + 127, + 127, + 127, + 127, + 257, + 48, + 48, + 48, + 367, + 367, + 168, + 363, + 68, + 271, + 271, + 271, + 271, + 174, + 353, + 71, + 267, + 185, + 17, + 17, + 17, + 134, + 372, + 50, + 50, + 50, + 370, + 134, + 354, + 354, + 373, + 347, + 347, + 9, + 9, + 9, + 9, + 9, + 9, + 9, + 347, + 347, + 347, + 347, + 347, + 102, + 217, + 97, + 97, + 352, + 352, + 352, + 143, + 369, + 70, + 400, + 13, + 13, + 13, + 320, + 73, + 217, + 217, + 217, + 217, + 217, + 217, + 58, + 359, + 359, + 359, + 359, + 163, + 163, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 257, + 33, + 243, + 243, + 243, + 171, + 171, + 171, + 266, + 266, + 103, + 271, + 12, + 331, + 331, + 331, + 331, + 331, + 331, + 331, + 183, + 367, + 12, + 12, + 12, + 12, + 238, + 238, + 110, + 110, + 360, + 360, + 360, + 30, + 235, + 235, + 235, + 235, + 121, + 121, + 232, + 77, + 302, + 157, + 237, + 237, + 237, + 237, + 237, + 80, + 242, + 123, + 371, + 72, + 322, + 322, + 322, + 322, + 199, + 199, + 199, + 380, + 380, + 89, + 235, + 148, + 148, + 398, + 69, + 274, + 59, + 102, + 102, + 102, + 339, + 339, + 59, + 59, + 59, + 59, + 59, + 228, + 172, + 312, + 312, + 364, + 234, + 55, + 302, + 122, + 375, + 375, + 375, + 375, + 38, + 312, + 312, + 119, + 247, + 247, + 35, + 35, + 357, + 195, + 195, + 195, + 243, + 243, + 243, + 86, + 86, + 261, + 173, + 246, + 246, + 135, + 275, + 275, + 109, + 335, + 335, + 335, + 335, + 335, + 39, + 202, + 184, + 184, + 184, + 292, + 76, + 76, + 381, + 192, + 278, + 278, + 25, + 256, + 256, + 256, + 256, + 256, + 256, + 137, + 364, + 364, + 364, + 3, + 276, + 164, + 208, + 208, + 53, + 53, + 394, + 130, + 258, + 258, + 49, + 49, + 49, + 327, + 171, + 213, + 43, + 43, + 247, + 174, + 174, + 223, + 223, + 223, + 223, + 20, + 354, + 159, + 159, + 329, + 329, + 78, + 270, + 195, + 387, + 76, + 252, + 175, + 259, + 259, + 37, + 364, + 364, + 364, + 129, + 240, + 240, + 240, + 240, + 36, + 36, + 36, + 234, + 172, + 267, + 267, + 25, + 25, + 25, + 25, + 25, + 25, + 300, + 300, + 172, + 172, + 274, + 274, + 20, + 300, + 300, + 161, + 216, + 118, + 118, + 201, + 201, + 171, + 171, + 171, + 171, + 171, + 171, + 390, + 121, + 121, + 291, + 291, + 113, + 113, + 351, + 174, + 297, + 149, + 149, + 149, + 182, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 266, + 182, + 153, + 258, + 258, + 154, + 154, + 154, + 339, + 339, + 30, + 30, + 30, + 30, + 30, + 30, + 392, + 117, + 117, + 117, + 294, + 84, + 84, + 84, + 227, + 227, + 154, + 154, + 362, + 99, + 308, + 172, + 278, + 278, + 27, + 27, + 272, + 272, + 272, + 161, + 161, + 234, + 81, + 81, + 349, + 103, + 291, + 76, + 76, + 76, + 278, + 278, + 278, + 278, + 108, + 266, + 66, + 66, + 66, + 196, + 93, + 93, + 137, + 29, + 141, + 141, + 92, + 92, + 92, + 162, + 162, + 62, + 106, + 254, + 106, + 106, + 351, + 360, + 160, + 243, + 243, + 225, + 351, + 373, + 373, + 89, + 271, + 271, + 160, + 296, + 296, + 347, + 347, + 318, + 234, + 234, + 234, + 358, + 262, + 179, + 44, + 239, + 239, + 239, + 239, + 239, + 179, + 211, + 152, + 329, + 131, + 131, + 131, + 364, + 364, + 364, + 364, + 145, + 237, + 152, + 152, + 152, + 214, + 191, + 41, + 41, + 191, + 124, + 161, + 161, + 398, + 398, + 93, + 93, + 93, + 313, + 313, + 161, + 366, + 366, + 73, + 222, + 17, + 17, + 17, + 293, + 348, + 304, + 304, + 153, + 322, + 322, + 65, + 65, + 387, + 178, + 178, + 178, + 178, + 254, + 83, + 83, + 83, + 339, + 339, + 339, + 339, + 137, + 137, + 137, + 230, + 230, + 73, + 73, + 286, + 286, + 154, + 154, + 318, + 177, + 177, + 177, + 278, + 278, + 149, + 362, + 362, + 177, + 399, + 194, + 385, + 385, + 385, + 385, + 32, + 320, + 144, + 144, + 210, + 228, + 321, + 386, + 157, + 157, + 157, + 386, + 200, + 200, + 23, + 23, + 23, + 360, + 360, + 360, + 360, + 200, + 210, + 210, + 210, + 66, + 66, + 66, + 319, + 319, + 155, + 155, + 295, + 295, + 117, + 231, + 231, + 231, + 153, + 153, + 396, + 396, + 396, + 396, + 26, + 223, + 165, + 165, + 330, + 38, + 272, + 272, + 272, + 198, + 198, + 198, + 316, + 316, + 1, + 264, + 264, + 123, + 123, + 123, + 123, + 398, + 398, + 100, + 100, + 100, + 19, + 304, + 304, + 304, + 304, + 19, + 311, + 70, + 70, + 348, + 23, + 23, + 349, + 349, + 349, + 349, + 349, + 349, + 349, + 160, + 160, + 160, + 160, + 160, + 237, + 49, + 49, + 49, + 49, + 337, + 127, + 127, + 229, + 42, + 42, + 236, + 236, + 236, + 126, + 280, + 26, + 26, + 26, + 256, + 112, + 219, + 219, + 219, + 22, + 22, + 22, + 22, + 214, + 214, + 214, + 214, + 102, + 341, + 100, + 285, + 285, + 280, + 280, + 280, + 240, + 240, + 278, + 278, + 278, + 299, + 109, + 223, + 223, + 223, + 266, + 266, + 266, + 266, + 70, + 277, + 186, + 186, + 186, + 186, + 186, + 186, + 250, + 109, + 109, + 109, + 109, + 374, + 197, + 197, + 202, + 198, + 332, + 56, + 56, + 323, + 323, + 193, + 193, + 272, + 272, + 272, + 75, + 329, + 167, + 337, + 337, + 337, + 337, + 80, + 80, + 208, + 98, + 342, + 92, + 92, + 92, + 92, + 92, + 382, + 349, + 362, + 238, + 238, + 221, + 221, + 216, + 216, + 227, + 227, + 179, + 179, + 179, + 179, + 351, + 62, + 343, + 165, + 165, + 165, + 165, + 165, + 165, + 222, + 222, + 1, + 1, + 230, + 230, + 230, + 230, + 16, + 16, + 214, + 214, + 26, + 26, + 180, + 383, + 383, + 26, + 26, + 26, + 303, + 175, + 175, + 175, + 175, + 175, + 175, + 175, + 318, + 318, + 34, + 34, + 310, + 310, + 151, + 151, + 151, + 350, + 33, + 33, + 313, + 313, + 171, + 315, + 6, + 394, + 101, + 206, + 165, + 260, + 260, + 260, + 260, + 260, + 260, + 36, + 252, + 252, + 252, + 252, + 252, + 118, + 118, + 118, + 391, + 391, + 17, + 334, + 334, + 334, + 177, + 177, + 177, + 396, + 396, + 269, + 355, + 301, + 394, + 394, + 394, + 348, + 348, + 246, + 364, + 364, + 374, + 109, + 109, + 109, + 329, + 329, + 15, + 362, + 362, + 110, + 207, + 251, + 126, + 170, + 170, + 365, + 233, + 397, + 255, + 197, + 197, + 197, + 379, + 379, + 379, + 379, + 45, + 225, + 225, + 86, + 86, + 147, + 147, + 217, + 86, + 358, + 167, + 167, + 167, + 386, + 386, + 386, + 386, + 386, + 37, + 37, + 358, + 358, + 358, + 113, + 113, + 353, + 70, + 103, + 103, + 255, + 255, + 255, + 103, + 123, + 123, + 144, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 145, + 145, + 145, + 145, + 212, + 212, + 212, + 105, + 105, + 105, + 105, + 105, + 334, + 18, + 18, + 18, + 247, + 247, + 169, + 169, + 169, + 169, + 169, + 314, + 26, + 341, + 341, + 107, + 107, + 107, + 23, + 23, + 185, + 194, + 367, + 36, + 36, + 36, + 308, + 148, + 148, + 228, + 228, + 87, + 87, + 87, + 360, + 360, + 360, + 360, + 360, + 360, + 174, + 332, + 66, + 141, + 141, + 57, + 357, + 357, + 357, + 357, + 357, + 357, + 57, + 57, + 226, + 226, + 226, + 173, + 4, + 175, + 191, + 191, + 154, + 154, + 380, + 123, + 384, + 384, + 163, + 9, + 9, + 9, + 346, + 163, + 275, + 108, + 108, + 357, + 5, + 323, + 323, + 323, + 151, + 151, + 208, + 208, + 208, + 186, + 161, + 235, + 161, + 307, + 307, + 182, + 131, + 247, + 13, + 13, + 13, + 13, + 13, + 287, + 287, + 140, + 140, + 140, + 86, + 112, + 86, + 86, + 256, + 256, + 256, + 111, + 111, + 111, + 111, + 287, + 287, + 28, + 28, + 28, + 28, + 323, + 323, + 323, + 142, + 142, + 142, + 236, + 4, + 324, + 324, + 67, + 276, + 276, + 194, + 280, + 280, + 280, + 21, + 298, + 173, + 173, + 173, + 295, + 41, + 286, + 223, + 223, + 343, + 193, + 204, + 204, + 69, + 136, + 337, + 337, + 54, + 54, + 54, + 349, + 165, + 165, + 165, + 165, + 165, + 8, + 365, + 365, + 365, + 365, + 365, + 8, + 8, + 8, + 375, + 104, + 58, + 58, + 169, + 169, + 6, + 319, + 6, + 6, + 354, + 354, + 354, + 354, + 105, + 212, + 29, + 29, + 295, + 295, + 295, + 122, + 122, + 15, + 186, + 252, + 90, + 90, + 90, + 250, + 132, + 380, + 380, + 380, + 53, + 53, + 384, + 384, + 384, + 84, + 112, + 335, + 84, + 256, + 256, + 256, + 256, + 256, + 256, + 256, + 256, + 162, + 320, + 30, + 395, + 119, + 119, + 256, + 256, + 50, + 50, + 247, + 247, + 190, + 309, + 46, + 301, + 301, + 301, + 301, + 301, + 193, + 193, + 193, + 399, + 97, + 97, + 305, + 156, + 399, + 44, + 331, + 178, + 178, + 178, + 178, + 178, + 178, + 178, + 11, + 11, + 141, + 48, + 119, + 24, + 24, + 207, + 24, + 24, + 126, + 44, + 75, + 142, + 225, + 142, + 75, + 360, + 22, + 22, + 22, + 22, + 22, + 22, + 86, + 86, + 67, + 20, + 195, + 257, + 257, + 88, + 58, + 217, + 217, + 217, + 217, + 251, + 183, + 377, + 377, + 377, + 73, + 73, + 321, + 125, + 391, + 391, + 300, + 2, + 2, + 2, + 300, + 300, + 300, + 12, + 338, + 338, + 171, + 298, + 57, + 57, + 57, + 57, + 57, + 360, + 360, + 139, + 139, + 139, + 139, + 210, + 210, + 92, + 215, + 149, + 342, + 342, + 99, + 99, + 378, + 130, + 130, + 130, + 130, + 130, + 130, + 389, + 84, + 84, + 289, + 289, + 167, + 325, + 14, + 14, + 235, + 235, + 155, + 155, + 155, + 265, + 265, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 394, + 394, + 139, + 325, + 325, + 64, + 64, + 190, + 190, + 190, + 28, + 28, + 28, + 28, + 120, + 2, + 2, + 389, + 145, + 145, + 145, + 145, + 145, + 396, + 396, + 396, + 396, + 41, + 41, + 216, + 161, + 280, + 280, + 280, + 280, + 70, + 70, + 70, + 259, + 51, + 292, + 28, + 28, + 113, + 113, + 113, + 359, + 359, + 28, + 361, + 157, + 224, + 70, + 350, + 116, + 116, + 216, + 216, + 95, + 95, + 342, + 342, + 342, + 177, + 177, + 365, + 73, + 321, + 321, + 321, + 172, + 307, + 307, + 84, + 279, + 279, + 128, + 236, + 109, + 349, + 116, + 114, + 294, + 294, + 294, + 294, + 114, + 114, + 218, + 182, + 67, + 261, + 182, + 375, + 25, + 25, + 112, + 115, + 111, + 336, + 111, + 255, + 255, + 18, + 18, + 340, + 340, + 188, + 238, + 238, + 238, + 351, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 108, + 361, + 177, + 177, + 344, + 146, + 57, + 400, + 146, + 357, + 357, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 102, + 351, + 351, + 138, + 364, + 308, + 321, + 321, + 207, + 207, + 139, + 139, + 208, + 252, + 252, + 397, + 397, + 26, + 397, + 181, + 181, + 181, + 181, + 181, + 207, + 207, + 207, + 207, + 207, + 52, + 52, + 52, + 52, + 52, + 217, + 217, + 145, + 296, + 296, + 49, + 49, + 382, + 382, + 203, + 203, + 349, + 349, + 140, + 349, + 349, + 137, + 279, + 279, + 279, + 163, + 355, + 126, + 126, + 126, + 126, + 218, + 218, + 218, + 310, + 254, + 254, + 164, + 325, + 325, + 325, + 62, + 279, + 267, + 213, + 130, + 213, + 220, + 254, + 60, + 323, + 125, + 125, + 207, + 207, + 109, + 284, + 140, + 140, + 140, + 140, + 241, + 241, + 241, + 156, + 156, + 346, + 147, + 306, + 198, + 339, + 108, + 108, + 108, + 366, + 366, + 366, + 366, + 309, + 400, + 72, + 72, + 238, + 120, + 120, + 349, + 349, + 349, + 94, + 94, + 94, + 394, + 102, + 237, + 237, + 13, + 375, + 198, + 129, + 109, + 109, + 196, + 190, + 361, + 190, + 190, + 190, + 308, + 308, + 114, + 222, + 55, + 121, + 121, + 121, + 386, + 386, + 121, + 385, + 385, + 385, + 68, + 361, + 136, + 136, + 26, + 26, + 219, + 172, + 172, + 172, + 172, + 172, + 341, + 341, + 89, + 266, + 156, + 156, + 321, + 6, + 383, + 383, + 383, + 383, + 114, + 114, + 114, + 114, + 114, + 114, + 398, + 398, + 42, + 256, + 158, + 384, + 384, + 384, + 37, + 37, + 216, + 162, + 162, + 162, + 162, + 162, + 162, + 162, + 221, + 69, + 69, + 306, + 151, + 336, + 336, + 46, + 46, + 311, + 311, + 311, + 311, + 141, + 269, + 269, + 269, + 269, + 269, + 91, + 213, + 141, + 302, + 18, + 370, + 370, + 142, + 142, + 351, + 190, + 191, + 319, + 191, + 184, + 184, + 184, + 279, + 184, + 390, + 165, + 307, + 21, + 222, + 128, + 128, + 128, + 128, + 128, + 252, + 252, + 60, + 241, + 241, + 241, + 124, + 355, + 11, + 203, + 149, + 149, + 149, + 149, + 357, + 357, + 357, + 126, + 360, + 360, + 360, + 360, + 360, + 69, + 343, + 149, + 206, + 206, + 206, + 178, + 361, + 361, + 361, + 361, + 361, + 361, + 104, + 104, + 268, + 268, + 2, + 232, + 125, + 125, + 125, + 125, + 125, + 321, + 321, + 321, + 31, + 334, + 176, + 290, + 95, + 95, + 341, + 341, + 192, + 192, + 192, + 192, + 192, + 192, + 192, + 192, + 238, + 45, + 45, + 165, + 165, + 243, + 165, + 165, + 23, + 291, + 179, + 29, + 115, + 115, + 163, + 317, + 146, + 383, + 142, + 119, + 46, + 119, + 360, + 55, + 30, + 30, + 30, + 30, + 30, + 71, + 71, + 204, + 204, + 204, + 113, + 113, + 113, + 113, + 385, + 385, + 50, + 338, + 338, + 202, + 57, + 316, + 316, + 63, + 309, + 295, + 220, + 220, + 388, + 255, + 348, + 306, + 150, + 150, + 306, + 119, + 400, + 397, + 391, + 391, + 391, + 322, + 322, + 198, + 56, + 56, + 272, + 272, + 272, + 272, + 192, + 389, + 389, + 67, + 204, + 134, + 134, + 134, + 213, + 213, + 213, + 46, + 235, + 235, + 183, + 183, + 183, + 183, + 389, + 389, + 389, + 11, + 11, + 11, + 357, + 357, + 357, + 357, + 143, + 350, + 67, + 67, + 67, + 394, + 180, + 180, + 354, + 354, + 354, + 354, + 354, + 354, + 41, + 41, + 41, + 314, + 116, + 116, + 116, + 116, + 257, + 257, + 83, + 284, + 284, + 192, + 238, + 93, + 383, + 38, + 153, + 153, + 153, + 153, + 357, + 357, + 357, + 357, + 38, + 38, + 255, + 195, + 195, + 4, + 22, + 37, + 57, + 19, + 19, + 192, + 19, + 211, + 19, + 13, + 256, + 256, + 169, + 169, + 395, + 21, + 21, + 21, + 21, + 163, + 163, + 54, + 54, + 54, + 346, + 54, + 54, + 341, + 28, + 28, + 4, + 297, + 46, + 46, + 212, + 212, + 100, + 207, + 207, + 207, + 271, + 271, + 271, + 271, + 271, + 134, + 230, + 292, + 292, + 238, + 238, + 233, + 233, + 112, + 112, + 112, + 204, + 129, + 271, + 103, + 375, + 375, + 18, + 18, + 26, + 26, + 8, + 273, + 90, + 169, + 169, + 308, + 246, + 246, + 39, + 39, + 39, + 246, + 246, + 148, + 342, + 97, + 204, + 204, + 204, + 204, + 123, + 270, + 270, + 87, + 87, + 400, + 400, + 104, + 104, + 104, + 104, + 351, + 351, + 110, + 110, + 110, + 110, + 110, + 301, + 301, + 301, + 5, + 226, + 170, + 170, + 170, + 376, + 196, + 383, + 107, + 241, + 241, + 241, + 37, + 37, + 37, + 371, + 371, + 152, + 328, + 328, + 64, + 64, + 322, + 129, + 375, + 375, + 18, + 18, + 18, + 274, + 131, + 131, + 131, + 303, + 303, + 303, + 303, + 303, + 64, + 64, + 64, + 64, + 290, + 155, + 155, + 348, + 1, + 1, + 1, + 233, + 147, + 215, + 27, + 27, + 27, + 27, + 27, + 27, + 211, + 211, + 211, + 166, + 166, + 166, + 222, + 222, + 222, + 222, + 222, + 222, + 71, + 222, + 222, + 78, + 78, + 351, + 351, + 351, + 26, + 367, + 385, + 349, + 375, + 375, + 375, + 104, + 104, + 375, + 375, + 375, + 176, + 176, + 176, + 253, + 150, + 259, + 123, + 123, + 123, + 313, + 171, + 309, + 323, + 291, + 291, + 291, + 73, + 73, + 73, + 73, + 291, + 373, + 236, + 236, + 382, + 166, + 166, + 166, + 305, + 386, + 386, + 14, + 14, + 206, + 206, + 353, + 150, + 242, + 242, + 84, + 84, + 263, + 191, + 105, + 158, + 73, + 158, + 158, + 158, + 357, + 159, + 159, + 335, + 335, + 353, + 16, + 150, + 301, + 143, + 145, + 145, + 145, + 145, + 172, + 172, + 172, + 146, + 146, + 373, + 373, + 373, + 7, + 360, + 360, + 351, + 351, + 351, + 111, + 111, + 111, + 111, + 111, + 343, + 29, + 29, + 29, + 29, + 197, + 263, + 134, + 134, + 227, + 232, + 232, + 260, + 260, + 270, + 270, + 268, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 206, + 181, + 41, + 121, + 43, + 43, + 143, + 91, + 11, + 11, + 10, + 10, + 87, + 87, + 87, + 342, + 107, + 107, + 107, + 351, + 87, + 400, + 118, + 322, + 322, + 322, + 395, + 106, + 106, + 334, + 334, + 103, + 392, + 323, + 282, + 169, + 169, + 203, + 377, + 377, + 377, + 380, + 4, + 4, + 243, + 243, + 392, + 24, + 300, + 27, + 273, + 60, + 230, + 80, + 80, + 119, + 80, + 237, + 237, + 237, + 237, + 237, + 237, + 237, + 133, + 219, + 219, + 219, + 58, + 58, + 220, + 220, + 256, + 256, + 256, + 324, + 264, + 93, + 346, + 205, + 205, + 205, + 33, + 398, + 398, + 398, + 398, + 334, + 334, + 225, + 225, + 339, + 339, + 283, + 281, + 281, + 281, + 281, + 281, + 281, + 53, + 364, + 364, + 226, + 217, + 380, + 380, + 200, + 200, + 328, + 328, + 56, + 56, + 56, + 56, + 268, + 1, + 1, + 280, + 280, + 280, + 280, + 280, + 280, + 137, + 224, + 140, + 140, + 140, + 140, + 287, + 169, + 120, + 120, + 155, + 155, + 37, + 37, + 37, + 146, + 40, + 334, + 187, + 88, + 70, + 70, + 233, + 233, + 70, + 237, + 237, + 97, + 97, + 70, + 209, + 38, + 38, + 38, + 38, + 38, + 164, + 164, + 164, + 261, + 261, + 261, + 38, + 38, + 38, + 255, + 198, + 246, + 246, + 246, + 33, + 301, + 301, + 142, + 142, + 45, + 190, + 365, + 64, + 138, + 138, + 388, + 138, + 138, + 138, + 9, + 276, + 276, + 276, + 276, + 150, + 374, + 37, + 165, + 59, + 59, + 239, + 59, + 59, + 119, + 231, + 231, + 119, + 27, + 62, + 62, + 62, + 62, + 62, + 62, + 7, + 229, + 229, + 229, + 143, + 143, + 143, + 143, + 34, + 21, + 21, + 35, + 232, + 188, + 188, + 188, + 188, + 35, + 35, + 35, + 195, + 168, + 168, + 168, + 168, + 338, + 71, + 168, + 168, + 174, + 6, + 102, + 102, + 102, + 272, + 102, + 238, + 91, + 91, + 91, + 317, + 137, + 383, + 89, + 89, + 217, + 217, + 181, + 92, + 248, + 178, + 178, + 352, + 42, + 280, + 353, + 399, + 96, + 96, + 399, + 399, + 399, + 399, + 399, + 143, + 143, + 353, + 353, + 353, + 353, + 89, + 325, + 325, + 325, + 325, + 180, + 395, + 395, + 395, + 395, + 45, + 45, + 45, + 282, + 282, + 282, + 282, + 282, + 163, + 163, + 271, + 65, + 378, + 378, + 378, + 183, + 331, + 18, + 242, + 191, + 270, + 270, + 270, + 39, + 39, + 104, + 104, + 93, + 22, + 22, + 22, + 287, + 103, + 272, + 53, + 44, + 378, + 156, + 306, + 306, + 31, + 31, + 72, + 236, + 388, + 388, + 388, + 14, + 14, + 172, + 57, + 133, + 262, + 262, + 87, + 201, + 59, + 59, + 224, + 224, + 29, + 155, + 155, + 305, + 305, + 155, + 22, + 149, + 23, + 127, + 95, + 95, + 350, + 375, + 46, + 46, + 375, + 147, + 147, + 147, + 147, + 330, + 105, + 105, + 331, + 390, + 390, + 347, + 347, + 319, + 60, + 319, + 64, + 201, + 391, + 391, + 241, + 241, + 204, + 195, + 253, + 253, + 61, + 321, + 108, + 312, + 312, + 44, + 44, + 44, + 44, + 44, + 136, + 221, + 123, + 123, + 65, + 166, + 166, + 166, + 166, + 166, + 259, + 259, + 166, + 166, + 40, + 40, + 254, + 115, + 348, + 348, + 348, + 348, + 68, + 4, + 2, + 356, + 356, + 356, + 356, + 174, + 257, + 257, + 26, + 26, + 394, + 394, + 106, + 299, + 299, + 299, + 299, + 100, + 100, + 100, + 100, + 100, + 284, + 284, + 284, + 284, + 284, + 198, + 198, + 251, + 251, + 251, + 251, + 83, + 355, + 355, + 355, + 108, + 385, + 385, + 61, + 61, + 61, + 61, + 350, + 350, + 350, + 350, + 350, + 181, + 181, + 7, + 7, + 142, + 142, + 367, + 367, + 17, + 306, + 306, + 136, + 387, + 91, + 91, + 331, + 130, + 130, + 237, + 237, + 237, + 5, + 5, + 5, + 5, + 5, + 361, + 190, + 334, + 59, + 59, + 59, + 59, + 59, + 338, + 146, + 223, + 233, + 68, + 68, + 68, + 233, + 233, + 60, + 60, + 60, + 339, + 339, + 49, + 49, + 49, + 49, + 371, + 71, + 230, + 69, + 285, + 285, + 285, + 190, + 276, + 147, + 147, + 147, + 230, + 195, + 69, + 253, + 195, + 195, + 195, + 195, + 380, + 380, + 16, + 16, + 398, + 398, + 398, + 149, + 207, + 207, + 207, + 80, + 80, + 80, + 80, + 351, + 100, + 224, + 224, + 224, + 224, + 224, + 116, + 116, + 238, + 238, + 68, + 271, + 271, + 123, + 296, + 68, + 68, + 288, + 163, + 342, + 68, + 68, + 68, + 274, + 138, + 138, + 263, + 263, + 263, + 263, + 263, + 75, + 358, + 149, + 163, + 163, + 163, + 163, + 347, + 60, + 163, + 307, + 49, + 49, + 204, + 170, + 170, + 170, + 362, + 362, + 362, + 362, + 2, + 276, + 276, + 276, + 276, + 276, + 163, + 262, + 35, + 257, + 257, + 120, + 120, + 53, + 53, + 53, + 320, + 320, + 185, + 120, + 57, + 394, + 394, + 394, + 394, + 165, + 335, + 151, + 151, + 252, + 106, + 106, + 389, + 389, + 389, + 389, + 389, + 389, + 62, + 62, + 316, + 316, + 135, + 135, + 262, + 103, + 254, + 178, + 178, + 328, + 105, + 105, + 105, + 203, + 166, + 166, + 387, + 387, + 43, + 282, + 154, + 260, + 91, + 91, + 289, + 289, + 289, + 289, + 289, + 289, + 137, + 137, + 98, + 98, + 100, + 100, + 100, + 117, + 117, + 100, + 169, + 169, + 24, + 24, + 322, + 24, + 24, + 312, + 312, + 110, + 247, + 92, + 92, + 92, + 153, + 220, + 153, + 153, + 153, + 153, + 153, + 284, + 69, + 69, + 392, + 150, + 150, + 33, + 33, + 169, + 48, + 48, + 217, + 48, + 48, + 181, + 314, + 314, + 314, + 62, + 230, + 141, + 285, + 188, + 188, + 364, + 364, + 364, + 364, + 364, + 62, + 62, + 331, + 331, + 331, + 331, + 117, + 254, + 254, + 69, + 69, + 310, + 310, + 310, + 200, + 200, + 228, + 22, + 288, + 110, + 110, + 110, + 333, + 333, + 333, + 333, + 333, + 333, + 333, + 333, + 98, + 98, + 98, + 201, + 201, + 143, + 143, + 360, + 22, + 22, + 298, + 298, + 190, + 324, + 324, + 67, + 67, + 67, + 67, + 67, + 67, + 299, + 150, + 150, + 247, + 14, + 307, + 103, + 103, + 103, + 103, + 299, + 299, + 46, + 322, + 322, + 322, + 322, + 161, + 236, + 236, + 38, + 357, + 357, + 159, + 159, + 385, + 385, + 385, + 4, + 302, + 302, + 302, + 112, + 112, + 336, + 46, + 272, + 111, + 111, + 111, + 319, + 22, + 339, + 148, + 395, + 395, + 17, + 17, + 332, + 332, + 83, + 83, + 146, + 214, + 214, + 214, + 146, + 347, + 33, + 33, + 278, + 177, + 248, + 248, + 248, + 12, + 264, + 107, + 219, + 219, + 219, + 219, + 45, + 363, + 363, + 179, + 179, + 179, + 384, + 137, + 137, + 137, + 137, + 201, + 164, + 303, + 131, + 131, + 370, + 370, + 96, + 96, + 212, + 174, + 274, + 189, + 189, + 315, + 97, + 97, + 314, + 141, + 141, + 220, + 220, + 35, + 364, + 364, + 364, + 178, + 286, + 26, + 187, + 187, + 187, + 187, + 284, + 284, + 187, + 187, + 83, + 83, + 189, + 64, + 324, + 324, + 324, + 64, + 64, + 162, + 108, + 8, + 8, + 8, + 108, + 108, + 19, + 19, + 19, + 325, + 325, + 199, + 335, + 335, + 335, + 335, + 58, + 58, + 58, + 58, + 58, + 58, + 58, + 58, + 328, + 171, + 355, + 20, + 390, + 134, + 336, + 73, + 120, + 120, + 276, + 276, + 120, + 240, + 93, + 93, + 277, + 183, + 183, + 53, + 170, + 34, + 181, + 181, + 181, + 4, + 4, + 227, + 4, + 107, + 40, + 96, + 295, + 295, + 160, + 96, + 96, + 96, + 18, + 16, + 16, + 16, + 368, + 134, + 134, + 268, + 16, + 205, + 205, + 205, + 205, + 205, + 134, + 302, + 302, + 57, + 57, + 128, + 88, + 88, + 88, + 150, + 382, + 56, + 329, + 329, + 329, + 42, + 334, + 177, + 177, + 51, + 51, + 16, + 7, + 140, + 7, + 22, + 186, + 21, + 235, + 21, + 21, + 351, + 351, + 347, + 347, + 58, + 347, + 322, + 322, + 252, + 252, + 252, + 142, + 215, + 215, + 215, + 124, + 124, + 371, + 371, + 62, + 62, + 62, + 261, + 261, + 261, + 32, + 32, + 210, + 210, + 210, + 139, + 284, + 58, + 244, + 142, + 208, + 25, + 25, + 25, + 303, + 289, + 394, + 394, + 133, + 133, + 292, + 292, + 292, + 292, + 292, + 93, + 272, + 189, + 206, + 206, + 206, + 206, + 206, + 46, + 305, + 168, + 168, + 347, + 213, + 61, + 255, + 107, + 107, + 107, + 341, + 150, + 150, + 208, + 395, + 395, + 333, + 358, + 351, + 355, + 355, + 244, + 244, + 138, + 138, + 29, + 29, + 29, + 29, + 300, + 138, + 138, + 138, + 301, + 13, + 13, + 233, + 233, + 233, + 233, + 181, + 266, + 266, + 266, + 266, + 100, + 100, + 322, + 141, + 397, + 397, + 51, + 274, + 274, + 159, + 159, + 159, + 159, + 159, + 159, + 159, + 159, + 86, + 138, + 138, + 138, + 138, + 138, + 41, + 41, + 184, + 184, + 218, + 184, + 184, + 184, + 184, + 367, + 367, + 43, + 380, + 380, + 144, + 144, + 144, + 218, + 218, + 65, + 65, + 343, + 343, + 141, + 251, + 251, + 251, + 49, + 211, + 113, + 23, + 102, + 102, + 77, + 77, + 77, + 1, + 364, + 176, + 176, + 372, + 6, + 356, + 374, + 374, + 252, + 252, + 101, + 252, + 10, + 10, + 10, + 361, + 98, + 289, + 48, + 48, + 311, + 206, + 256, + 183, + 256, + 256, + 256, + 35, + 240, + 240, + 240, + 240, + 32, + 32, + 340, + 340, + 340, + 2, + 2, + 2, + 266, + 266, + 389, + 319, + 319, + 319, + 362, + 283, + 183, + 183, + 157, + 317, + 91, + 91, + 381, + 157, + 347, + 347, + 246, + 246, + 246, + 188, + 246, + 133, + 318, + 201, + 201, + 201, + 193, + 193, + 201, + 201, + 201, + 201, + 77, + 282, + 124, + 124, + 124, + 124, + 215, + 215, + 76, + 76, + 328, + 328, + 127, + 251, + 251, + 251, + 251, + 44, + 44, + 280, + 158, + 158, + 158, + 334, + 59, + 373, + 373, + 373, + 152, + 359, + 92, + 92, + 324, + 324, + 25, + 334, + 87, + 87, + 392, + 102, + 102, + 323, + 236, + 20, + 236, + 236, + 236, + 131, + 323, + 372, + 260, + 288, + 288, + 288, + 256, + 264, + 311, + 311, + 40, + 311, + 311, + 283, + 393, + 57, + 393, + 345, + 35, + 35, + 362, + 66, + 42, + 42, + 42, + 325, + 325, + 325, + 42, + 72, + 360, + 399, + 399, + 399, + 399, + 117, + 267, + 267, + 74, + 366, + 366, + 366, + 366, + 166, + 166, + 166, + 253, + 389, + 355, + 273, + 194, + 194, + 57, + 126, + 345, + 345, + 250, + 346, + 70, + 240, + 41, + 32, + 32, + 351, + 351, + 252, + 252, + 252, + 120, + 120, + 252, + 32, + 32, + 16, + 16, + 16, + 76, + 396, + 396, + 389, + 389, + 389, + 307, + 307, + 284, + 89, + 374, + 58, + 342, + 342, + 342, + 342, + 342, + 342, + 3, + 339, + 131, + 51, + 51, + 198, + 212, + 212, + 41, + 84, + 84, + 359, + 359, + 359, + 132, + 132, + 132, + 310, + 310, + 9, + 9, + 9, + 348, + 348, + 348, + 348, + 117, + 117, + 117, + 245, + 66, + 66, + 218, + 198, + 389, + 72, + 255, + 255, + 255, + 255, + 255, + 171, + 289, + 289, + 32, + 32, + 32, + 233, + 23, + 316, + 370, + 90, + 90, + 370, + 370, + 370, + 370, + 370, + 370, + 323, + 91, + 91, + 218, + 254, + 254, + 254, + 254, + 80, + 80, + 314, + 396, + 396, + 396, + 396, + 322, + 322, + 206, + 206, + 206, + 300, + 287, + 331, + 331, + 250, + 343, + 343, + 18, + 18, + 132, + 343, + 343, + 343, + 343, + 18, + 370, + 370, + 222, + 275, + 218, + 250, + 387, + 387, + 387, + 387, + 274, + 34, + 34, + 34, + 34, + 34, + 34, + 274, + 274, + 274, + 340, + 340, + 340, + 340, + 340, + 220, + 286, + 326, + 136, + 326, + 326, + 326, + 38, + 38, + 38, + 38, + 368, + 141, + 400, + 400, + 50, + 50, + 246, + 246, + 246, + 184, + 184, + 360, + 25, + 25, + 25, + 317, + 317, + 317, + 169, + 169, + 169, + 260, + 260, + 73, + 282, + 282, + 282, + 101, + 101, + 92, + 327, + 92, + 92, + 92, + 92, + 226, + 226, + 181, + 252, + 80, + 251, + 251, + 198, + 198, + 314, + 85, + 249, + 249, + 249, + 249, + 130, + 130, + 320, + 320, + 172, + 270, + 189, + 189, + 241, + 241, + 241, + 193, + 366, + 366, + 139, + 347, + 347, + 347, + 185, + 302, + 158, + 304, + 304, + 186, + 56, + 325, + 186, + 360, + 360, + 80, + 317, + 175, + 175, + 346, + 27, + 395, + 180, + 341, + 341, + 55, + 55, + 364, + 364, + 178, + 178, + 178, + 261, + 261, + 87, + 87, + 248, + 153, + 153, + 153, + 153, + 321, + 17, + 17, + 17, + 362, + 135, + 277, + 277, + 63, + 63, + 63, + 63, + 63, + 284, + 149, + 340, + 340, + 17, + 17, + 17, + 17, + 264, + 55, + 203, + 61, + 61, + 385, + 385, + 385, + 54, + 359, + 359, + 359, + 111, + 111, + 257, + 145, + 145, + 145, + 145, + 398, + 201, + 201, + 201, + 386, + 386, + 35, + 321, + 321, + 310, + 228, + 79, + 238, + 238, + 238, + 238, + 238, + 238, + 238, + 121, + 258, + 77, + 77, + 77, + 77, + 374, + 189, + 189, + 189, + 189, + 344, + 344, + 344, + 344, + 344, + 58, + 251, + 143, + 60, + 60, + 157, + 157, + 157, + 157, + 157, + 360, + 360, + 360, + 360, + 157, + 157, + 260, + 260, + 260, + 260, + 10, + 246, + 119, + 119, + 386, + 78, + 78, + 78, + 78, + 238, + 150, + 150, + 150, + 386, + 386, + 386, + 386, + 386, + 39, + 39, + 39, + 210, + 210, + 210, + 185, + 185, + 185, + 185, + 185, + 185, + 354, + 82, + 82, + 267, + 267, + 133, + 133, + 288, + 288, + 288, + 288, + 45, + 324, + 324, + 120, + 61, + 341, + 341, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 61, + 348, + 126, + 315, + 315, + 315, + 315, + 315, + 315, + 315, + 19, + 19, + 267, + 267, + 267, + 267, + 124, + 124, + 124, + 124, + 311, + 311, + 311, + 311, + 311, + 61, + 386, + 103, + 103, + 365, + 74, + 74, + 381, + 170, + 312, + 312, + 32, + 32, + 32, + 32, + 32, + 32, + 32, + 357, + 138, + 138, + 138, + 359, + 34, + 34, + 34, + 34, + 34, + 322, + 322, + 200, + 200, + 287, + 99, + 368, + 368, + 168, + 168, + 168, + 168, + 168, + 347, + 347, + 347, + 59, + 262, + 165, + 165, + 165, + 324, + 324, + 23, + 23, + 23, + 336, + 114, + 255, + 255, + 255, + 31, + 31, + 54, + 257, + 156, + 222, + 71, + 71, + 387, + 191, + 191, + 261, + 261, + 99, + 99, + 178, + 57, + 57, + 57, + 142, + 308, + 308, + 308, + 109, + 313, + 313, + 313, + 313, + 313, + 45, + 45, + 252, + 252, + 138, + 138, + 138, + 138, + 262, + 262, + 37, + 37, + 332, + 115, + 115, + 115, + 115, + 115, + 115, + 374, + 374, + 97, + 97, + 97, + 317, + 179, + 179, + 179, + 319, + 17, + 365, + 365, + 194, + 228, + 228, + 76, + 76, + 273, + 273, + 93, + 93, + 356, + 356, + 61, + 215, + 215, + 77, + 267, + 267, + 267, + 267, + 121, + 373, + 32, + 337, + 337, + 337, + 126, + 390, + 390, + 390, + 52, + 52, + 360, + 156, + 385, + 385, + 385, + 105, + 267, + 111, + 302, + 302, + 302, + 302, + 32, + 32, + 350, + 350, + 350, + 161, + 380, + 41, + 41, + 41, + 41, + 41, + 313, + 191, + 191, + 216, + 73, + 73, + 305, + 139, + 139, + 312, + 7, + 7, + 7, + 377, + 143, + 297, + 29, + 29, + 29, + 29, + 329, + 137, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 50, + 50, + 50, + 272, + 117, + 117, + 287, + 90, + 90, + 90, + 90, + 297, + 297, + 297, + 297, + 297, + 154, + 354, + 59, + 373, + 373, + 107, + 107, + 107, + 107, + 107, + 107, + 107, + 348, + 348, + 39, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 244, + 194, + 194, + 385, + 385, + 385, + 385, + 60, + 60, + 60, + 373, + 373, + 373, + 193, + 263, + 85, + 85, + 85, + 272, + 142, + 142, + 142, + 237, + 237, + 43, + 43, + 43, + 43, + 373, + 187, + 187, + 187, + 187, + 187, + 359, + 47, + 47, + 47, + 260, + 178, + 220, + 22, + 22, + 22, + 22, + 384, + 185, + 185, + 266, + 266, + 266, + 83, + 218, + 218, + 218, + 167, + 284, + 93, + 336, + 336, + 175, + 175, + 343, + 12, + 379, + 379, + 49, + 49, + 49, + 316, + 316, + 316, + 316, + 2, + 213, + 91, + 91, + 222, + 222, + 136, + 357, + 67, + 345, + 310, + 242, + 202, + 141, + 141, + 141, + 141, + 202, + 202, + 23, + 23, + 330, + 330, + 163, + 283, + 20, + 20, + 375, + 375, + 216, + 216, + 223, + 179, + 179, + 322, + 385, + 143, + 305, + 305, + 305, + 17, + 17, + 239, + 178, + 178, + 373, + 373, + 373, + 44, + 261, + 261, + 261, + 261, + 142, + 66, + 189, + 189, + 189, + 189, + 47, + 282, + 132, + 99, + 99, + 99, + 99, + 99, + 273, + 273, + 99, + 99, + 99, + 222, + 222, + 222, + 102, + 102, + 250, + 77, + 77, + 321, + 321, + 186, + 186, + 39, + 345, + 345, + 345, + 345, + 125, + 125, + 224, + 224, + 43, + 43, + 43, + 43, + 158, + 158, + 49, + 335, + 182, + 182, + 182, + 360, + 29, + 300, + 176, + 317, + 2, + 237, + 237, + 107, + 341, + 341, + 341, + 341, + 93, + 93, + 93, + 93, + 371, + 101, + 101, + 101, + 101, + 372, + 372, + 41, + 41, + 41, + 216, + 216, + 216, + 182, + 182, + 243, + 29, + 29, + 114, + 45, + 206, + 206, + 121, + 121, + 121, + 283, + 16, + 399, + 399, + 399, + 399, + 399, + 176, + 176, + 176, + 176, + 34, + 154, + 154, + 322, + 154, + 154, + 3, + 28, + 96, + 96, + 82, + 123, + 123, + 18, + 25, + 253, + 168, + 168, + 168, + 83, + 83, + 83, + 5, + 294, + 10, + 341, + 341, + 341, + 341, + 56, + 56, + 299, + 235, + 235, + 364, + 364, + 72, + 369, + 185, + 261, + 261, + 37, + 37, + 37, + 211, + 211, + 151, + 310, + 310, + 16, + 380, + 380, + 380, + 380, + 146, + 205, + 96, + 96, + 96, + 218, + 218, + 6, + 6, + 268, + 220, + 288, + 295, + 295, + 250, + 250, + 250, + 155, + 155, + 250, + 279, + 8, + 8, + 8, + 279, + 170, + 170, + 204, + 204, + 23, + 23, + 221, + 221, + 221, + 221, + 195, + 195, + 363, + 363, + 363, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 320, + 320, + 320, + 320, + 320, + 320, + 320, + 144, + 144, + 287, + 287, + 287, + 58, + 379, + 152, + 152, + 238, + 95, + 95, + 237, + 237, + 237, + 112, + 207, + 81, + 297, + 297, + 297, + 146, + 146, + 228, + 77, + 77, + 151, + 151, + 151, + 81, + 81, + 81, + 81, + 112, + 36, + 138, + 138, + 255, + 74, + 74, + 193, + 314, + 314, + 314, + 56, + 56, + 240, + 240, + 163, + 208, + 87, + 87, + 366, + 366, + 60, + 60, + 395, + 155, + 155, + 275, + 275, + 190, + 190, + 52, + 52, + 52, + 52, + 176, + 361, + 337, + 32, + 32, + 32, + 137, + 72, + 72, + 72, + 149, + 113, + 113, + 351, + 351, + 44, + 139, + 139, + 377, + 377, + 139, + 139, + 139, + 382, + 168, + 385, + 41, + 41, + 287, + 190, + 237, + 237, + 237, + 237, + 119, + 119, + 9, + 258, + 258, + 258, + 119, + 119, + 272, + 136, + 136, + 242, + 96, + 353, + 125, + 125, + 368, + 254, + 320, + 347, + 285, + 285, + 280, + 280, + 75, + 393, + 393, + 393, + 172, + 172, + 225, + 62, + 305, + 81, + 81, + 81, + 244, + 75, + 271, + 271, + 271, + 271, + 271, + 271, + 69, + 69, + 373, + 373, + 86, + 86, + 219, + 219, + 219, + 182, + 258, + 258, + 258, + 258, + 258, + 258, + 70, + 70, + 70, + 203, + 190, + 190, + 190, + 190, + 254, + 36, + 358, + 358, + 358, + 358, + 358, + 358, + 126, + 126, + 332, + 166, + 271, + 113, + 386, + 168, + 168, + 334, + 39, + 234, + 234, + 234, + 234, + 121, + 121, + 121, + 121, + 357, + 177, + 294, + 189, + 37, + 37, + 189, + 374, + 374, + 189, + 129, + 84, + 280, + 280, + 280, + 84, + 297, + 297, + 297, + 117, + 117, + 117, + 117, + 240, + 22, + 178, + 356, + 38, + 101, + 175, + 175, + 239, + 81, + 81, + 81, + 81, + 81, + 377, + 167, + 91, + 353, + 353, + 91, + 91, + 91, + 233, + 157, + 157, + 342, + 77, + 77, + 377, + 377, + 377, + 377, + 377, + 122, + 352, + 352, + 10, + 366, + 173, + 173, + 326, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 326, + 326, + 326, + 191, + 191, + 191, + 213, + 62, + 62, + 62, + 62, + 62, + 290, + 190, + 222, + 6, + 6, + 173, + 371, + 371, + 173, + 8, + 8, + 289, + 289, + 8, + 128, + 61, + 138, + 309, + 138, + 138, + 138, + 138, + 138, + 241, + 241, + 5, + 318, + 318, + 318, + 194, + 275, + 37, + 37, + 37, + 229, + 137, + 137, + 265, + 265, + 265, + 265, + 265, + 34, + 34, + 34, + 34, + 34, + 34, + 293, + 112, + 334, + 53, + 240, + 199, + 199, + 199, + 199, + 390, + 32, + 239, + 109, + 109, + 109, + 187, + 133, + 388, + 388, + 59, + 337, + 337, + 337, + 133, + 133, + 252, + 35, + 35, + 259, + 23, + 248, + 248, + 248, + 248, + 77, + 77, + 77, + 77, + 248, + 248, + 248, + 117, + 371, + 371, + 177, + 388, + 388, + 381, + 73, + 262, + 163, + 163, + 218, + 218, + 218, + 397, + 360, + 68, + 68, + 360, + 360, + 360, + 43, + 43, + 43, + 43, + 187, + 201, + 201, + 43, + 331, + 331, + 331, + 331, + 64, + 64, + 64, + 64, + 106, + 298, + 64, + 64, + 64, + 64, + 227, + 82, + 82, + 82, + 82, + 297, + 272, + 164, + 272, + 336, + 217, + 217, + 377, + 103, + 103, + 377, + 212, + 320, + 320, + 155, + 316, + 316, + 208, + 208, + 250, + 155, + 155, + 155, + 155, + 155, + 348, + 165, + 165, + 165, + 320, + 320, + 320, + 320, + 156, + 334, + 286, + 301, + 289, + 208, + 338, + 109, + 109, + 25, + 25, + 25, + 25, + 353, + 353, + 25, + 354, + 181, + 281, + 281, + 281, + 36, + 304, + 304, + 304, + 304, + 193, + 395, + 96, + 337, + 337, + 337, + 337, + 131, + 131, + 341, + 341, + 341, + 341, + 341, + 341, + 72, + 72, + 72, + 72, + 392, + 145, + 290, + 72, + 348, + 63, + 302, + 85, + 221, + 221, + 221, + 221, + 137, + 91, + 291, + 55, + 229, + 229, + 52, + 384, + 384, + 47, + 196, + 196, + 234, + 47, + 364, + 122, + 122, + 122, + 272, + 36, + 36, + 243, + 49, + 49, + 160, + 49, + 49, + 192, + 192, + 22, + 148, + 148, + 148, + 89, + 180, + 172, + 101, + 101, + 304, + 304, + 56, + 56, + 349, + 101, + 225, + 47, + 47, + 123, + 51, + 387, + 126, + 45, + 199, + 153, + 153, + 153, + 153, + 347, + 55, + 55, + 223, + 223, + 196, + 196, + 266, + 84, + 126, + 283, + 396, + 396, + 396, + 261, + 39, + 39, + 220, + 220, + 220, + 300, + 300, + 380, + 380, + 109, + 109, + 109, + 29, + 29, + 29, + 29, + 189, + 86, + 86, + 5, + 391, + 391, + 391, + 123, + 123, + 305, + 305, + 305, + 251, + 156, + 156, + 72, + 322, + 322, + 156, + 292, + 43, + 328, + 393, + 130, + 130, + 319, + 47, + 31, + 300, + 300, + 363, + 363, + 306, + 225, + 225, + 219, + 267, + 267, + 284, + 46, + 226, + 265, + 133, + 133, + 235, + 99, + 398, + 398, + 398, + 398, + 398, + 181, + 181, + 181, + 238, + 124, + 214, + 214, + 82, + 82, + 82, + 82, + 82, + 82, + 82, + 310, + 134, + 134, + 201, + 63, + 339, + 107, + 107, + 377, + 139, + 139, + 139, + 228, + 228, + 33, + 246, + 152, + 152, + 152, + 152, + 152, + 152, + 152, + 152, + 152, + 152, + 152, + 304, + 304, + 31, + 319, + 186, + 186, + 78, + 241, + 181, + 376, + 376, + 376, + 376, + 120, + 120, + 120, + 374, + 374, + 374, + 62, + 368, + 368, + 115, + 115, + 299, + 92, + 92, + 370, + 370, + 370, + 370, + 370, + 183, + 183, + 399, + 34, + 34, + 34, + 244, + 244, + 178, + 240, + 240, + 240, + 240, + 71, + 242, + 166, + 317, + 74, + 347, + 347, + 347, + 104, + 104, + 104, + 274, + 79, + 248, + 166, + 184, + 184, + 166, + 166, + 166, + 281, + 281, + 281, + 281, + 281, + 166, + 253, + 166, + 235, + 139, + 139, + 286, + 286, + 100, + 100, + 100, + 100, + 100, + 100, + 242, + 242, + 190, + 190, + 285, + 55, + 291, + 291, + 291, + 291, + 291, + 160, + 160, + 114, + 210, + 153, + 139, + 139, + 139, + 97, + 97, + 278, + 80, + 318, + 318, + 318, + 318, + 318, + 318, + 156, + 156, + 156, + 268, + 268, + 36, + 36, + 327, + 327, + 387, + 387, + 263, + 231, + 294, + 270, + 160, + 160, + 270, + 270, + 270, + 141, + 204, + 21, + 61, + 267, + 122, + 122, + 346, + 346, + 253, + 307, + 221, + 221, + 221, + 221, + 367, + 367, + 169, + 367, + 367, + 290, + 45, + 329, + 329, + 103, + 369, + 369, + 125, + 48, + 392, + 125, + 96, + 147, + 147, + 98, + 98, + 98, + 98, + 276, + 98, + 353, + 369, + 369, + 301, + 252, + 252, + 252, + 252, + 184, + 252, + 252, + 252, + 23, + 23, + 202, + 169, + 169, + 169, + 169, + 169, + 388, + 388, + 388, + 388, + 388, + 388, + 388, + 78, + 229, + 17, + 17, + 141, + 141, + 279, + 279, + 17, + 17, + 391, + 391, + 85, + 85, + 327, + 165, + 165, + 165, + 165, + 165, + 165, + 165, + 165, + 307, + 400, + 257, + 257, + 244, + 312, + 229, + 234, + 23, + 189, + 189, + 36, + 36, + 36, + 36, + 119, + 149, + 149, + 149, + 149, + 149, + 50, + 50, + 50, + 226, + 149, + 315, + 55, + 327, + 327, + 327, + 143, + 143, + 251, + 76, + 76, + 165, + 377, + 160, + 160, + 160, + 339, + 339, + 339, + 339, + 44, + 233, + 197, + 237, + 98, + 98, + 180, + 180, + 180, + 180, + 180, + 180, + 180, + 180, + 30, + 166, + 315, + 315, + 315, + 315, + 315, + 166, + 100, + 100, + 188, + 188, + 327, + 327, + 99, + 99, + 322, + 322, + 322, + 167, + 284, + 52, + 52, + 52, + 293, + 293, + 293, + 293, + 293, + 293, + 195, + 195, + 242, + 8, + 8, + 322, + 322, + 322, + 173, + 173, + 225, + 50, + 50, + 227, + 227, + 128, + 332, + 332, + 46, + 337, + 169, + 365, + 365, + 21, + 259, + 259, + 259, + 259, + 163, + 163, + 163, + 285, + 285, + 285, + 11, + 390, + 194, + 256, + 75, + 233, + 170, + 170, + 241, + 241, + 77, + 77, + 252, + 252, + 252, + 252, + 252, + 140, + 318, + 318, + 318, + 46, + 377, + 108, + 345, + 345, + 345, + 23, + 328, + 328, + 328, + 83, + 86, + 50, + 185, + 185, + 166, + 166, + 63, + 229, + 229, + 229, + 229, + 79, + 26, + 26, + 303, + 222, + 297, + 354, + 370, + 224, + 224, + 317, + 225, + 42, + 42, + 42, + 225, + 107, + 242, + 241, + 271, + 367, + 367, + 367, + 258, + 258, + 258, + 258, + 221, + 97, + 97, + 221, + 221, + 221, + 170, + 57, + 224, + 196, + 196, + 196, + 323, + 323, + 87, + 87, + 87, + 310, + 136, + 292, + 146, + 146, + 146, + 146, + 146, + 309, + 309, + 202, + 202, + 355, + 355, + 301, + 208, + 208, + 233, + 63, + 233, + 233, + 131, + 279, + 353, + 353, + 353, + 392, + 392, + 236, + 58, + 58, + 58, + 58, + 58, + 236, + 131, + 131, + 131, + 131, + 307, + 307, + 307, + 307, + 162, + 244, + 244, + 244, + 62, + 331, + 331, + 108, + 108, + 258, + 105, + 237, + 371, + 371, + 371, + 254, + 251, + 251, + 212, + 367, + 367, + 91, + 249, + 249, + 249, + 89, + 89, + 256, + 67, + 340, + 91, + 91, + 91, + 398, + 398, + 398, + 398, + 153, + 393, + 393, + 98, + 255, + 255, + 255, + 128, + 128, + 128, + 128, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 398, + 56, + 56, + 231, + 39, + 366, + 366, + 366, + 366, + 241, + 241, + 241, + 153, + 276, + 63, + 63, + 380, + 380, + 256, + 256, + 256, + 162, + 7, + 7, + 7, + 7, + 117, + 117, + 90, + 244, + 244, + 90, + 328, + 168, + 168, + 168, + 168, + 78, + 78, + 327, + 78, + 78, + 78, + 181, + 181, + 181, + 181, + 181, + 66, + 195, + 195, + 40, + 213, + 40, + 40, + 108, + 255, + 255, + 255, + 255, + 255, + 296, + 296, + 212, + 212, + 223, + 200, + 223, + 90, + 370, + 370, + 226, + 22, + 22, + 226, + 323, + 24, + 24, + 323, + 11, + 11, + 349, + 89, + 142, + 41, + 41, + 41, + 41, + 260, + 260, + 41, + 146, + 193, + 154, + 35, + 235, + 235, + 156, + 392, + 392, + 392, + 115, + 115, + 355, + 355, + 131, + 73, + 357, + 73, + 73, + 73, + 299, + 299, + 299, + 268, + 268, + 268, + 64, + 64, + 175, + 175, + 175, + 64, + 70, + 17, + 17, + 296, + 296, + 296, + 138, + 274, + 13, + 391, + 144, + 144, + 144, + 144, + 187, + 127, + 7, + 145, + 285, + 285, + 145, + 116, + 116, + 116, + 126, + 126, + 126, + 217, + 217, + 69, + 69, + 69, + 69, + 69, + 256, + 256, + 126, + 385, + 385, + 385, + 385, + 385, + 385, + 385, + 385, + 43, + 43, + 43, + 258, + 258, + 176, + 219, + 219, + 219, + 50, + 329, + 163, + 361, + 361, + 110, + 110, + 110, + 110, + 337, + 81, + 204, + 204, + 204, + 204, + 192, + 260, + 74, + 74, + 74, + 288, + 178, + 315, + 315, + 315, + 315, + 28, + 334, + 125, + 125, + 391, + 391, + 391, + 391, + 70, + 275, + 275, + 275, + 182, + 182, + 182, + 246, + 246, + 132, + 393, + 139, + 246, + 42, + 42, + 42, + 42, + 42, + 250, + 250, + 169, + 367, + 367, + 98, + 153, + 24, + 24, + 24, + 24, + 112, + 112, + 112, + 112, + 112, + 244, + 244, + 112, + 112, + 112, + 112, + 112, + 112, + 112, + 394, + 394, + 44, + 203, + 203, + 106, + 106, + 400, + 400, + 48, + 301, + 187, + 187, + 21, + 361, + 21, + 21, + 210, + 210, + 210, + 210, + 134, + 239, + 25, + 311, + 311, + 37, + 37, + 37, + 37, + 255, + 311, + 212, + 196, + 355, + 33, + 33, + 290, + 174, + 247, + 9, + 9, + 9, + 9, + 357, + 106, + 303, + 17, + 197, + 257, + 197, + 197, + 330, + 330, + 2, + 106, + 3, + 103, + 103, + 59, + 78, + 83, + 83, + 299, + 112, + 112, + 360, + 360, + 360, + 360, + 360, + 360, + 18, + 231, + 231, + 198, + 334, + 334, + 23, + 223, + 223, + 223, + 223, + 223, + 114, + 114, + 224, + 224, + 224, + 105, + 105, + 105, + 105, + 105, + 240, + 240, + 186, + 284, + 284, + 396, + 288, + 129, + 162, + 298, + 298, + 298, + 3, + 3, + 3, + 3, + 3, + 3, + 226, + 226, + 226, + 226, + 131, + 12, + 12, + 12, + 12, + 10, + 17, + 21, + 21, + 21, + 21, + 236, + 83, + 98, + 200, + 200, + 200, + 314, + 314, + 138, + 14, + 138, + 58, + 209, + 209, + 209, + 209, + 58, + 239, + 142, + 142, + 142, + 142, + 142, + 396, + 48, + 48, + 376, + 186, + 186, + 377, + 169, + 169, + 169, + 284, + 162, + 162, + 264, + 264, + 30, + 380, + 380, + 380, + 380, + 114, + 319, + 17, + 17, + 328, + 328, + 328, + 328, + 181, + 393, + 156, + 275, + 275, + 133, + 133, + 41, + 273, + 273, + 133, + 349, + 60, + 228, + 228, + 228, + 228, + 228, + 228, + 166, + 290, + 290, + 59, + 311, + 311, + 144, + 144, + 144, + 194, + 194, + 253, + 253, + 253, + 253, + 253, + 110, + 110, + 110, + 92, + 92, + 254, + 254, + 254, + 254, + 110, + 110, + 253, + 114, + 374, + 164, + 397, + 397, + 29, + 142, + 142, + 60, + 60, + 191, + 191, + 186, + 186, + 165, + 153, + 293, + 155, + 155, + 88, + 228, + 228, + 155, + 331, + 187, + 387, + 387, + 376, + 394, + 253, + 253, + 79, + 367, + 367, + 367, + 367, + 195, + 217, + 22, + 22, + 22, + 22, + 22, + 22, + 202, + 124, + 124, + 124, + 124, + 230, + 230, + 230, + 230, + 47, + 47, + 47, + 235, + 156, + 330, + 82, + 297, + 184, + 184, + 283, + 283, + 283, + 283, + 4, + 4, + 337, + 337, + 174, + 174, + 174, + 209, + 209, + 209, + 209, + 10, + 10, + 262, + 262, + 150, + 150, + 150, + 390, + 162, + 162, + 153, + 153, + 132, + 13, + 395, + 122, + 357, + 7, + 7, + 64, + 64, + 180, + 390, + 390, + 70, + 383, + 383, + 383, + 178, + 360, + 360, + 34, + 34, + 34, + 376, + 189, + 290, + 61, + 383, + 9, + 175, + 17, + 371, + 31, + 76, + 259, + 259, + 353, + 353, + 138, + 138, + 138, + 353, + 353, + 353, + 361, + 204, + 297, + 297, + 180, + 48, + 297, + 297, + 180, + 180, + 294, + 294, + 80, + 80, + 80, + 267, + 120, + 120, + 307, + 307, + 78, + 78, + 221, + 221, + 221, + 129, + 129, + 129, + 274, + 4, + 4, + 4, + 4, + 237, + 15, + 396, + 396, + 396, + 296, + 296, + 22, + 241, + 241, + 241, + 174, + 382, + 382, + 83, + 83, + 298, + 274, + 274, + 84, + 351, + 87, + 378, + 378, + 123, + 325, + 12, + 201, + 201, + 201, + 90, + 90, + 90, + 199, + 90, + 107, + 107, + 71, + 71, + 136, + 312, + 312, + 312, + 312, + 312, + 280, + 169, + 169, + 23, + 252, + 252, + 315, + 315, + 141, + 141, + 315, + 315, + 235, + 235, + 235, + 235, + 235, + 88, + 284, + 116, + 116, + 288, + 288, + 75, + 248, + 35, + 35, + 287, + 48, + 48, + 48, + 48, + 263, + 263, + 23, + 273, + 273, + 144, + 305, + 305, + 72, + 235, + 91, + 104, + 91, + 54, + 209, + 209, + 209, + 209, + 145, + 145, + 205, + 205, + 205, + 205, + 49, + 345, + 345, + 193, + 193, + 338, + 181, + 227, + 115, + 233, + 164, + 272, + 272, + 178, + 178, + 173, + 173, + 173, + 334, + 173, + 280, + 280, + 22, + 22, + 22, + 22, + 22, + 274, + 274, + 167, + 277, + 277, + 277, + 277, + 277, + 163, + 264, + 61, + 61, + 369, + 199, + 199, + 324, + 324, + 188, + 188, + 37, + 37, + 37, + 146, + 146, + 61, + 61, + 61, + 61, + 219, + 172, + 172, + 50, + 180, + 180, + 92, + 92, + 187, + 326, + 326, + 187, + 187, + 321, + 31, + 31, + 388, + 117, + 215, + 8, + 8, + 8, + 8, + 8, + 327, + 327, + 327, + 327, + 155, + 245, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 369, + 369, + 198, + 289, + 289, + 64, + 241, + 241, + 147, + 283, + 243, + 243, + 389, + 58, + 337, + 337, + 337, + 337, + 204, + 365, + 365, + 385, + 385, + 385, + 385, + 385, + 5, + 319, + 149, + 149, + 149, + 273, + 194, + 161, + 268, + 161, + 161, + 161, + 161, + 228, + 228, + 228, + 117, + 253, + 199, + 358, + 58, + 58, + 58, + 58, + 58, + 58, + 340, + 135, + 275, + 275, + 275, + 87, + 87, + 262, + 38, + 38, + 38, + 263, + 8, + 8, + 8, + 217, + 217, + 217, + 217, + 357, + 303, + 303, + 242, + 242, + 25, + 25, + 25, + 247, + 247, + 337, + 206, + 373, + 357, + 357, + 148, + 357, + 31, + 329, + 293, + 210, + 392, + 255, + 255, + 394, + 394, + 161, + 161, + 161, + 161, + 394, + 105, + 105, + 105, + 290, + 290, + 125, + 125, + 248, + 248, + 315, + 332, + 332, + 332, + 143, + 258, + 258, + 258, + 4, + 4, + 81, + 81, + 252, + 152, + 81, + 81, + 81, + 81, + 81, + 81, + 342, + 342, + 126, + 126, + 318, + 318, + 318, + 61, + 394, + 126, + 126, + 126, + 304, + 304, + 304, + 304, + 91, + 91, + 91, + 91, + 266, + 266, + 163, + 3, + 3, + 143, + 143, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 14, + 199, + 97, + 97, + 175, + 175, + 29, + 381, + 148, + 148, + 79, + 130, + 130, + 130, + 10, + 229, + 150, + 150, + 47, + 47, + 137, + 17, + 298, + 298, + 298, + 298, + 298, + 298, + 155, + 286, + 44, + 203, + 293, + 293, + 196, + 276, + 276, + 276, + 276, + 27, + 27, + 27, + 27, + 396, + 396, + 396, + 330, + 330, + 352, + 274, + 270, + 59, + 316, + 13, + 13, + 63, + 329, + 36, + 36, + 254, + 88, + 88, + 88, + 88, + 88, + 88, + 88, + 296, + 154, + 154, + 266, + 2, + 2, + 29, + 91, + 219, + 385, + 87, + 385, + 385, + 385, + 385, + 168, + 168, + 168, + 225, + 225, + 25, + 294, + 294, + 345, + 109, + 109, + 345, + 29, + 383, + 263, + 37, + 168, + 331, + 37, + 369, + 369, + 228, + 278, + 90, + 90, + 90, + 278, + 273, + 7, + 7, + 7, + 7, + 273, + 273, + 259, + 259, + 358, + 372, + 372, + 115, + 55, + 316, + 170, + 387, + 387, + 387, + 387, + 25, + 25, + 25, + 25, + 350, + 350, + 112, + 319, + 319, + 139, + 344, + 344, + 344, + 344, + 344, + 344, + 344, + 67, + 67, + 217, + 217, + 217, + 163, + 163, + 163, + 292, + 148, + 148, + 226, + 198, + 198, + 198, + 198, + 294, + 294, + 294, + 294, + 181, + 181, + 85, + 85, + 85, + 85, + 85, + 248, + 248, + 248, + 181, + 328, + 81, + 331, + 195, + 396, + 396, + 396, + 396, + 396, + 87, + 87, + 87, + 299, + 200, + 200, + 256, + 256, + 256, + 256, + 87, + 87, + 87, + 353, + 163, + 163, + 260, + 260, + 54, + 229, + 229, + 229, + 229, + 118, + 328, + 328, + 328, + 328, + 44, + 385, + 385, + 385, + 103, + 103, + 59, + 59, + 149, + 344, + 149, + 149, + 149, + 149, + 149, + 149, + 38, + 43, + 2, + 205, + 205, + 205, + 205, + 193, + 331, + 2, + 135, + 265, + 135, + 46, + 5, + 2, + 47, + 47, + 260, + 47, + 179, + 231, + 231, + 231, + 47, + 243, + 172, + 172, + 172, + 172, + 172, + 359, + 359, + 45, + 45, + 45, + 45, + 45, + 166, + 166, + 166, + 238, + 78, + 192, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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 + ], + "commands": [ + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 2, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 2, + 1, + 1, + 1, + 1, + 2, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 1, + 1, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 1, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 2, + 0, + 0, + 0, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 2, + 0, + 2, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 1, + 2, + 1, + 2, + 1, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 0, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 1, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 2, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 2, + 0, + 1, + 2, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 1, + 0, + 2, + 2, + 2, + 1, + 1, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 2, + 1, + 1, + 1, + 0, + 2, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 2, + 0, + 0, + 1, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 0, + 2, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 1, + 2, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 1, + 2, + 1, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 2, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 2, + 0, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 0, + 2, + 0, + 1, + 1, + 0, + 1, + 0, + 2, + 1, + 0, + 1, + 0, + 1, + 0, + 2, + 0, + 2, + 1, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 1, + 1, + 0, + 2, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 1, + 2, + 2, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 1, + 2, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 2, + 2, + 1, + 1, + 2, + 2, + 0, + 1, + 0, + 0, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 2, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 2, + 2, + 2, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 2, + 2, + 1, + 1, + 1, + 2, + 1, + 1, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 2, + 1, + 1, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 0, + 0, + 2, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 1, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 2, + 1, + 2, + 0, + 1, + 1, + 0, + 1, + 2, + 0, + 2, + 0, + 1, + 2, + 0, + 2, + 1, + 2, + 1, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 1, + 2, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 1, + 1, + 2, + 1, + 2, + 2, + 1, + 1, + 2, + 0, + 0, + 1, + 2, + 1, + 1, + 1, + 0, + 1, + 2, + 0, + 1, + 0, + 0, + 0, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, 0, + 2, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 1, + 2, + 0, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 1, + 0, + 1, + 0, + 2, + 1, + 1, + 2, + 0, + 2, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 2, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 2, + 1, + 2, + 1, + 2, + 1, + 0, + 1, + 2, + 2, + 1, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 2, + 2, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 0, + 2, + 2, + 1, + 2, + 2, + 1, + 1, + 0, + 1, + 2, + 2, + 2, + 1, + 0, + 2, + 2, + 0, + 2, + 1, + 0, + 2, + 2, + 1, + 2, + 0, + 2, + 0, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 1, + 1, + 1, + 0, + 0, + 2, + 2, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 2, + 1, + 1, + 2, + 1, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 1, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 1, + 2, + 1, + 2, + 0, + 1, + 2, + 2, + 2, + 2, + 0, + 1, + 1, + 2, + 0, + 0, + 2, + 0, + 2, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 2, + 1, + 0, + 1, + 1, + 0, + 2, + 0, + 2, + 0, + 0 + ], + "values": [ + 276, + 293, + 244, + 138, + 122, + 331, + 330, + 204, + 191, + 307, + 313, + 311, + 161, + 39, + 110, + 182, + 201, + 164, + 197, + 292, + 104, + 257, + 135, + 83, + 269, + 40, + 311, + 79, + 116, + 249, + 255, + 95, + 100, + 355, + 381, + 176, + 73, + 222, + 295, + 378, + 399, + 283, + 208, + 306, + 190, + 210, + 145, + 308, + 263, + 131, + 112, + 183, + 81, + 119, + 399, + 77, + 264, + 298, + 365, + 331, + 311, + 124, + 276, + 13, + 229, + 364, + 389, + 305, + 41, + 107, + 243, + 244, + 284, + 211, + 377, + 209, + 130, + 300, + 295, + 52, + 214, + 127, + 326, + 187, + 158, + 155, + 393, + 244, + 389, + 149, + 204, + 288, + 152, + 199, + 15, + 177, + 325, + 284, + 287, + 322, + 374, + 62, + 263, + 179, + 336, + 76, + 338, + 126, + 389, + 96, + 255, + 6, + 250, + 307, + 297, + 386, + 109, + 271, + 346, + 181, + 271, + 151, + 146, + 206, + 78, + 255, + 136, + 266, + 310, + 172, + 59, + 147, + 84, + 214, + 21, + 390, + 369, + 80, + 212, + 126, + 342, + 141, + 393, + 296, + 213, + 363, + 182, + 134, + 216, + 215, + 252, + 265, + 239, + 319, + 131, + 103, + 275, + 222, + 66, + 398, + 31, + 217, + 39, + 379, + 297, + 356, + 335, + 307, + 81, + 36, + 222, + 16, + 14, + 107, + 392, + 198, + 343, + 69, + 110, + 1, + 60, + 201, + 362, + 245, + 169, + 241, + 175, + 6, + 232, + 270, + 191, + 370, + 109, + 333, + 215, + 31, + 337, + 353, + 12, + 292, + 242, + 152, + 107, + 24, + 22, + 363, + 192, + 182, + 313, + 99, + 175, + 189, + 282, + 13, + 301, + 353, + 132, + 316, + 168, + 255, + 217, + 234, + 181, + 199, + 315, + 239, + 292, + 135, + 367, + 239, + 163, + 117, + 240, + 83, + 218, + 185, + 4, + 254, + 50, + 331, + 294, + 178, + 187, + 56, + 183, + 70, + 111, + 37, + 12, + 112, + 98, + 254, + 115, + 327, + 384, + 130, + 196, + 373, + 386, + 102, + 236, + 299, + 120, + 184, + 149, + 379, + 220, + 143, + 372, + 186, + 61, + 22, + 241, + 300, + 398, + 238, + 252, + 154, + 40, + 326, + 165, + 299, + 135, + 180, + 324, + 271, + 151, + 83, + 189, + 127, + 252, + 343, + 392, + 91, + 293, + 339, + 79, + 58, + 326, + 241, + 83, + 104, + 363, + 70, + 5, + 268, + 265, + 374, + 314, + 110, + 24, + 22, + 220, + 342, + 251, + 31, + 69, + 130, + 91, + 173, + 32, + 110, + 284, + 343, + 120, + 67, + 306, + 10, + 262, + 99, + 319, + 216, + 238, + 354, + 91, + 333, + 304, + 204, + 75, + 213, + 322, + 395, + 3, + 344, + 291, + 22, + 313, + 85, + 121, + 137, + 120, + 52, + 1, + 315, + 184, + 325, + 77, + 181, + 339, + 152, + 104, + 367, + 305, + 188, + 277, + 309, + 357, + 97, + 117, + 355, + 210, + 214, + 194, + 18, + 48, + 242, + 31, + 211, + 347, + 209, + 27, + 284, + 307, + 90, + 21, + 354, + 316, + 165, + 147, + 265, + 16, + 161, + 108, + 349, + 45, + 9, + 277, + 64, + 70, + 12, + 218, + 64, + 162, + 361, + 107, + 308, + 122, + 104, + 346, + 221, + 247, + 169, + 136, + 331, + 80, + 111, + 177, + 76, + 210, + 114, + 130, + 270, + 122, + 171, + 24, + 375, + 209, + 311, + 19, + 100, + 291, + 214, + 371, + 134, + 298, + 162, + 282, + 184, + 151, + 110, + 121, + 347, + 279, + 112, + 299, + 92, + 132, + 220, + 187, + 101, + 170, + 326, + 82, + 137, + 192, + 153, + 389, + 379, + 9, + 31, + 325, + 279, + 311, + 333, + 87, + 130, + 99, + 240, + 370, + 210, + 105, + 263, + 383, + 174, + 132, + 311, + 256, + 177, + 303, + 96, + 361, + 163, + 399, + 304, + 197, + 157, + 392, + 84, + 365, + 64, + 161, + 382, + 258, + 194, + 73, + 256, + 263, + 295, + 363, + 87, + 263, + 262, + 138, + 220, + 301, + 129, + 364, + 7, + 49, + 9, + 104, + 121, + 235, + 122, + 340, + 18, + 178, + 360, + 257, + 302, + 352, + 224, + 204, + 279, + 127, + 317, + 151, + 126, + 284, + 200, + 44, + 224, + 23, + 181, + 239, + 335, + 223, + 176, + 158, + 19, + 229, + 38, + 333, + 46, + 200, + 381, + 69, + 221, + 50, + 315, + 387, + 64, + 282, + 270, + 302, + 267, + 307, + 291, + 181, + 399, + 225, + 271, + 313, + 79, + 238, + 324, + 104, + 122, + 249, + 387, + 55, + 42, + 398, + 75, + 300, + 50, + 253, + 333, + 241, + 163, + 155, + 99, + 242, + 150, + 347, + 297, + 2, + 270, + 16, + 183, + 149, + 219, + 153, + 1, + 88, + 166, + 250, + 245, + 220, + 8, + 196, + 276, + 300, + 215, + 233, + 141, + 145, + 145, + 388, + 228, + 196, + 229, + 255, + 369, + 155, + 381, + 102, + 153, + 320, + 148, + 13, + 252, + 46, + 389, + 129, + 256, + 221, + 251, + 46, + 373, + 368, + 199, + 234, + 112, + 135, + 142, + 287, + 29, + 202, + 186, + 9, + 56, + 192, + 41, + 290, + 150, + 42, + 68, + 338, + 191, + 54, + 205, + 287, + 43, + 30, + 389, + 350, + 202, + 281, + 393, + 107, + 311, + 7, + 102, + 297, + 295, + 356, + 37, + 348, + 142, + 278, + 318, + 167, + 109, + 6, + 52, + 4, + 206, + 250, + 335, + 239, + 285, + 155, + 271, + 106, + 144, + 292, + 333, + 238, + 221, + 253, + 41, + 142, + 379, + 183, + 167, + 336, + 45, + 398, + 398, + 219, + 358, + 25, + 319, + 245, + 270, + 11, + 153, + 128, + 18, + 102, + 345, + 192, + 388, + 241, + 179, + 84, + 122, + 166, + 173, + 257, + 375, + 31, + 377, + 165, + 391, + 377, + 175, + 114, + 103, + 260, + 363, + 257, + 307, + 114, + 63, + 33, + 235, + 64, + 264, + 375, + 138, + 70, + 193, + 258, + 375, + 141, + 52, + 37, + 177, + 384, + 382, + 165, + 263, + 124, + 315, + 383, + 66, + 239, + 15, + 280, + 192, + 14, + 343, + 120, + 324, + 143, + 385, + 123, + 155, + 321, + 42, + 116, + 88, + 268, + 38, + 169, + 21, + 83, + 138, + 388, + 371, + 119, + 182, + 190, + 322, + 12, + 67, + 93, + 49, + 156, + 381, + 157, + 309, + 358, + 33, + 314, + 73, + 26, + 230, + 161, + 226, + 278, + 44, + 89, + 211, + 341, + 349, + 355, + 238, + 388, + 210, + 207, + 110, + 242, + 81, + 115, + 246, + 328, + 334, + 352, + 67, + 67, + 372, + 248, + 283, + 241, + 327, + 172, + 261, + 342, + 11, + 323, + 240, + 140, + 40, + 26, + 59, + 283, + 221, + 305, + 190, + 152, + 223, + 56, + 297, + 57, + 23, + 262, + 236, + 37, + 253, + 83, + 357, + 22, + 152, + 159, + 305, + 172, + 5, + 185, + 66, + 75, + 206, + 208, + 330, + 9, + 58, + 80, + 162, + 96, + 47, + 367, + 339, + 221, + 117, + 109, + 302, + 3, + 112, + 308, + 85, + 144, + 254, + 14, + 295, + 220, + 367, + 218, + 14, + 141, + 270, + 241, + 308, + 240, + 301, + 67, + 192, + 282, + 392, + 281, + 316, + 268, + 128, + 226, + 40, + 127, + 101, + 160, + 252, + 4, + 158, + 268, + 4, + 20, + 205, + 375, + 106, + 120, + 354, + 52, + 248, + 102, + 39, + 93, + 5, + 360, + 230, + 11, + 374, + 329, + 242, + 189, + 119, + 333, + 132, + 83, + 101, + 186, + 23, + 320, + 201, + 146, + 65, + 18, + 178, + 10, + 375, + 173, + 320, + 44, + 165, + 219, + 258, + 181, + 58, + 51, + 136, + 10, + 269, + 73, + 250, + 343, + 1, + 244, + 215, + 210, + 166, + 230, + 98, + 278, + 274, + 343, + 334, + 320, + 288, + 190, + 39, + 227, + 330, + 87, + 161, + 309, + 201, + 347, + 52, + 73, + 313, + 127, + 273, + 165, + 120, + 146, + 3, + 136, + 147, + 273, + 25, + 210, + 51, + 263, + 241, + 209, + 334, + 256, + 298, + 24, + 194, + 349, + 224, + 294, + 75, + 262, + 43, + 172, + 348, + 210, + 257, + 361, + 362, + 265, + 138, + 190, + 214, + 261, + 349, + 348, + 340, + 307, + 374, + 216, + 82, + 303, + 204, + 110, + 180, + 319, + 111, + 232, + 158, + 362, + 375, + 361, + 145, + 364, + 228, + 113, + 367, + 36, + 86, + 303, + 191, + 306, + 27, + 10, + 269, + 381, + 176, + 383, + 224, + 108, + 399, + 356, + 299, + 60, + 317, + 369, + 99, + 181, + 236, + 393, + 63, + 95, + 383, + 367, + 375, + 238, + 41, + 31, + 258, + 189, + 283, + 26, + 41, + 77, + 332, + 317, + 321, + 394, + 333, + 280, + 279, + 75, + 300, + 76, + 215, + 137, + 72, + 344, + 66, + 348, + 27, + 182, + 266, + 58, + 195, + 109, + 236, + 65, + 250, + 150, + 326, + 169, + 393, + 298, + 47, + 93, + 19, + 310, + 159, + 57, + 298, + 242, + 99, + 338, + 185, + 105, + 118, + 246, + 88, + 68, + 8, + 285, + 258, + 300, + 240, + 257, + 51, + 249, + 342, + 228, + 102, + 211, + 133, + 93, + 193, + 207, + 190, + 327, + 277, + 267, + 25, + 152, + 306, + 8, + 47, + 255, + 153, + 6, + 182, + 306, + 272, + 153, + 176, + 140, + 155, + 173, + 33, + 311, + 369, + 156, + 119, + 314, + 172, + 106, + 78, + 113, + 341, + 320, + 202, + 88, + 261, + 87, + 396, + 30, + 181, + 289, + 189, + 144, + 99, + 141, + 271, + 73, + 380, + 35, + 75, + 94, + 189, + 321, + 320, + 108, + 97, + 109, + 17, + 224, + 236, + 223, + 187, + 79, + 268, + 362, + 216, + 231, + 257, + 21, + 96, + 332, + 192, + 159, + 360, + 376, + 317, + 388, + 153, + 187, + 12, + 339, + 246, + 56, + 313, + 239, + 77, + 188, + 303, + 31, + 260, + 23, + 142, + 229, + 24, + 381, + 69, + 200, + 134, + 109, + 34, + 55, + 5, + 210, + 298, + 314, + 200, + 8, + 168, + 99, + 190, + 339, + 365, + 304, + 243, + 70, + 76, + 26, + 186, + 278, + 240, + 165, + 208, + 14, + 117, + 282, + 305, + 251, + 183, + 187, + 283, + 195, + 337, + 78, + 332, + 174, + 157, + 302, + 143, + 384, + 288, + 75, + 37, + 130, + 248, + 122, + 311, + 273, + 347, + 240, + 89, + 8, + 227, + 240, + 332, + 242, + 123, + 18, + 29, + 47, + 302, + 282, + 5, + 219, + 46, + 61, + 97, + 29, + 139, + 74, + 105, + 126, + 300, + 20, + 375, + 52, + 275, + 146, + 44, + 129, + 53, + 167, + 349, + 398, + 81, + 161, + 58, + 338, + 246, + 277, + 400, + 397, + 259, + 104, + 321, + 23, + 319, + 362, + 126, + 317, + 43, + 350, + 36, + 319, + 95, + 154, + 3, + 37, + 99, + 56, + 165, + 165, + 124, + 235, + 160, + 184, + 265, + 66, + 214, + 160, + 78, + 309, + 248, + 154, + 380, + 293, + 86, + 45, + 43, + 71, + 27, + 207, + 387, + 48, + 308, + 148, + 154, + 180, + 103, + 239, + 312, + 188, + 226, + 274, + 82, + 307, + 76, + 365, + 5, + 64, + 321, + 249, + 177, + 242, + 180, + 88, + 238, + 260, + 354, + 263, + 41, + 400, + 353, + 223, + 148, + 176, + 313, + 96, + 89, + 251, + 81, + 12, + 115, + 72, + 30, + 191, + 296, + 243, + 167, + 395, + 201, + 126, + 202, + 22, + 132, + 393, + 176, + 351, + 17, + 154, + 382, + 76, + 221, + 235, + 220, + 369, + 306, + 151, + 393, + 395, + 24, + 333, + 228, + 25, + 352, + 221, + 209, + 189, + 344, + 36, + 399, + 322, + 63, + 371, + 387, + 193, + 145, + 213, + 186, + 70, + 19, + 289, + 347, + 5, + 270, + 285, + 114, + 376, + 384, + 175, + 180, + 307, + 335, + 38, + 286, + 54, + 21, + 256, + 267, + 145, + 323, + 334, + 234, + 170, + 363, + 204, + 162, + 76, + 191, + 225, + 162, + 285, + 56, + 324, + 332, + 275, + 198, + 73, + 126, + 382, + 38, + 204, + 223, + 315, + 223, + 267, + 310, + 133, + 174, + 257, + 115, + 243, + 93, + 30, + 1, + 338, + 182, + 114, + 87, + 167, + 136, + 97, + 275, + 27, + 196, + 155, + 270, + 133, + 309, + 387, + 151, + 168, + 348, + 170, + 196, + 33, + 12, + 287, + 12, + 268, + 364, + 367, + 46, + 355, + 261, + 336, + 230, + 179, + 300, + 70, + 87, + 282, + 51, + 280, + 217, + 370, + 245, + 214, + 1, + 161, + 373, + 183, + 52, + 78, + 22, + 139, + 165, + 20, + 236, + 274, + 326, + 268, + 128, + 330, + 322, + 245, + 137, + 1, + 229, + 302, + 1, + 238, + 325, + 143, + 108, + 47, + 207, + 87, + 358, + 274, + 366, + 389, + 383, + 228, + 100, + 221, + 272, + 169, + 153, + 197, + 163, + 358, + 247, + 239, + 300, + 237, + 250, + 307, + 363, + 35, + 268, + 25, + 33, + 288, + 36, + 381, + 148, + 229, + 371, + 276, + 381, + 221, + 22, + 175, + 128, + 244, + 28, + 349, + 133, + 77, + 102, + 238, + 320, + 27, + 389, + 223, + 130, + 196, + 293, + 29, + 101, + 331, + 71, + 213, + 151, + 353, + 251, + 373, + 307, + 98, + 289, + 349, + 125, + 298, + 294, + 204, + 282, + 125, + 398, + 387, + 137, + 171, + 225, + 192, + 370, + 241, + 91, + 338, + 99, + 24, + 223, + 210, + 55, + 129, + 238, + 149, + 110, + 277, + 123, + 394, + 283, + 187, + 361, + 59, + 256, + 184, + 171, + 294, + 105, + 166, + 314, + 66, + 137, + 5, + 180, + 41, + 243, + 282, + 158, + 89, + 313, + 226, + 214, + 332, + 294, + 98, + 265, + 130, + 22, + 319, + 258, + 69, + 30, + 387, + 143, + 80, + 400, + 325, + 47, + 385, + 327, + 155, + 7, + 347, + 324, + 133, + 276, + 337, + 85, + 70, + 371, + 327, + 321, + 326, + 33, + 328, + 177, + 186, + 107, + 15, + 184, + 273, + 158, + 179, + 183, + 70, + 305, + 187, + 2, + 71, + 215, + 102, + 73, + 118, + 123, + 114, + 23, + 266, + 156, + 110, + 352, + 168, + 72, + 366, + 339, + 156, + 359, + 121, + 312, + 217, + 382, + 92, + 224, + 249, + 369, + 360, + 371, + 22, + 334, + 175, + 24, + 273, + 76, + 163, + 100, + 37, + 33, + 189, + 398, + 170, + 262, + 189, + 364, + 179, + 88, + 11, + 392, + 244, + 382, + 243, + 224, + 77, + 48, + 80, + 271, + 219, + 231, + 133, + 389, + 16, + 51, + 271, + 18, + 185, + 157, + 176, + 158, + 68, + 185, + 62, + 389, + 276, + 73, + 298, + 385, + 187, + 82, + 386, + 201, + 161, + 364, + 300, + 262, + 46, + 23, + 171, + 185, + 47, + 200, + 340, + 159, + 161, + 242, + 227, + 90, + 86, + 240, + 345, + 256, + 93, + 156, + 355, + 152, + 288, + 209, + 313, + 179, + 281, + 152, + 360, + 377, + 321, + 142, + 136, + 122, + 151, + 41, + 129, + 362, + 15, + 24, + 197, + 80, + 58, + 187, + 261, + 12, + 200, + 141, + 126, + 333, + 156, + 64, + 123, + 377, + 385, + 305, + 210, + 331, + 176, + 268, + 232, + 243, + 396, + 141, + 281, + 322, + 248, + 136, + 31, + 86, + 317, + 156, + 265, + 369, + 370, + 387, + 98, + 281, + 300, + 347, + 331, + 293, + 151, + 293, + 355, + 362, + 185, + 305, + 205, + 240, + 356, + 264, + 136, + 195, + 112, + 64, + 129, + 398, + 215, + 242, + 45, + 336, + 162, + 305, + 168, + 340, + 299, + 296, + 97, + 81, + 75, + 270, + 263, + 72, + 198, + 286, + 215, + 42, + 227, + 265, + 167, + 259, + 75, + 152, + 328, + 196, + 209, + 278, + 190, + 174, + 338, + 281, + 356, + 319, + 7, + 58, + 333, + 367, + 76, + 282, + 119, + 63, + 311, + 216, + 33, + 22, + 308, + 137, + 133, + 229, + 394, + 44, + 4, + 73, + 322, + 80, + 399, + 353, + 236, + 111, + 27, + 383, + 276, + 234, + 121, + 311, + 340, + 238, + 164, + 358, + 288, + 395, + 275, + 189, + 352, + 241, + 20, + 53, + 273, + 352, + 56, + 28, + 48, + 24, + 203, + 156, + 75, + 326, + 233, + 229, + 361, + 311, + 59, + 289, + 147, + 315, + 154, + 187, + 84, + 324, + 339, + 349, + 105, + 159, + 3, + 95, + 313, + 112, + 266, + 34, + 393, + 72, + 147, + 66, + 3, + 340, + 350, + 343, + 227, + 97, + 121, + 230, + 249, + 94, + 55, + 115, + 61, + 295, + 64, + 10, + 391, + 359, + 87, + 383, + 194, + 81, + 196, + 107, + 22, + 208, + 380, + 328, + 216, + 236, + 318, + 172, + 202, + 237, + 19, + 81, + 347, + 395, + 199, + 193, + 373, + 183, + 246, + 354, + 61, + 305, + 75, + 141, + 224, + 50, + 252, + 351, + 35, + 287, + 269, + 54, + 259, + 298, + 394, + 3, + 51, + 214, + 17, + 83, + 165, + 137, + 299, + 21, + 161, + 31, + 148, + 27, + 7, + 293, + 120, + 232, + 179, + 135, + 135, + 103, + 258, + 365, + 267, + 179, + 70, + 19, + 240, + 177, + 244, + 11, + 260, + 196, + 383, + 292, + 347, + 125, + 319, + 149, + 50, + 226, + 16, + 358, + 400, + 141, + 148, + 385, + 83, + 262, + 44, + 63, + 239, + 341, + 296, + 209, + 16, + 132, + 349, + 268, + 102, + 341, + 1, + 219, + 143, + 23, + 9, + 130, + 291, + 241, + 348, + 13, + 333, + 208, + 281, + 301, + 297, + 261, + 359, + 18, + 209, + 143, + 306, + 146, + 58, + 183, + 352, + 189, + 396, + 153, + 369, + 274, + 149, + 169, + 90, + 29, + 300, + 326, + 161, + 23, + 19, + 6, + 143, + 283, + 110, + 342, + 177, + 103, + 185, + 163, + 320, + 342, + 257, + 95, + 186, + 65, + 20, + 217, + 191, + 138, + 383, + 306, + 355, + 388, + 152, + 358, + 66, + 275, + 202, + 331, + 193, + 47, + 45, + 310, + 186, + 115, + 184, + 122, + 252, + 68, + 341, + 308, + 74, + 225, + 273, + 40, + 195, + 31, + 222, + 379, + 383, + 54, + 142, + 211, + 190, + 19, + 308, + 368, + 131, + 49, + 16, + 362, + 394, + 144, + 329, + 247, + 335, + 241, + 53, + 301, + 167, + 238, + 72, + 255, + 289, + 208, + 28, + 92, + 123, + 29, + 353, + 62, + 57, + 246, + 92, + 250, + 100, + 296, + 70, + 276, + 241, + 385, + 29, + 257, + 67, + 325, + 325, + 76, + 391, + 350, + 159, + 170, + 334, + 228, + 188, + 123, + 265, + 90, + 267, + 300, + 367, + 257, + 124, + 283, + 109, + 341, + 199, + 104, + 255, + 281, + 138, + 67, + 359, + 99, + 284, + 363, + 299, + 103, + 165, + 238, + 11, + 151, + 96, + 316, + 56, + 246, + 104, + 399, + 388, + 275, + 268, + 342, + 318, + 353, + 191, + 181, + 230, + 321, + 326, + 115, + 144, + 144, + 310, + 345, + 297, + 279, + 173, + 214, + 202, + 154, + 30, + 368, + 183, + 200, + 217, + 165, + 75, + 93, + 21, + 180, + 399, + 5, + 260, + 288, + 383, + 15, + 108, + 396, + 62, + 242, + 189, + 278, + 10, + 237, + 156, + 47, + 288, + 277, + 379, + 146, + 89, + 225, + 148, + 270, + 52, + 133, + 232, + 272, + 358, + 24, + 162, + 79, + 201, + 358, + 298, + 309, + 39, + 44, + 298, + 211, + 112, + 253, + 260, + 245, + 338, + 232, + 16, + 278, + 35, + 235, + 247, + 125, + 121, + 400, + 156, + 395, + 56, + 192, + 6, + 279, + 37, + 196, + 275, + 150, + 203, + 73, + 65, + 49, + 73, + 75, + 34, + 255, + 141, + 310, + 378, + 108, + 25, + 54, + 12, + 5, + 360, + 354, + 195, + 292, + 368, + 27, + 150, + 304, + 320, + 84, + 283, + 280, + 51, + 18, + 312, + 398, + 354, + 32, + 124, + 224, + 265, + 16, + 156, + 89, + 375, + 210, + 331, + 116, + 341, + 10, + 368, + 351, + 204, + 380, + 361, + 324, + 352, + 19, + 358, + 162, + 207, + 83, + 388, + 164, + 42, + 379, + 24, + 315, + 64, + 315, + 64, + 293, + 120, + 344, + 53, + 17, + 5, + 337, + 161, + 339, + 280, + 360, + 132, + 26, + 338, + 6, + 119, + 38, + 24, + 9, + 292, + 83, + 348, + 171, + 155, + 61, + 61, + 247, + 286, + 355, + 298, + 320, + 11, + 291, + 260, + 188, + 167, + 85, + 259, + 363, + 289, + 239, + 188, + 58, + 231, + 304, + 102, + 400, + 82, + 103, + 319, + 283, + 166, + 35, + 234, + 287, + 157, + 26, + 266, + 154, + 108, + 6, + 381, + 210, + 326, + 209, + 335, + 372, + 38, + 116, + 104, + 211, + 300, + 25, + 280, + 329, + 42, + 393, + 318, + 362, + 186, + 358, + 212, + 109, + 144, + 42, + 72, + 219, + 65, + 85, + 276, + 175, + 161, + 283, + 230, + 378, + 362, + 328, + 206, + 351, + 98, + 397, + 133, + 305, + 109, + 197, + 354, + 361, + 11, + 331, + 79, + 224, + 336, + 370, + 356, + 216, + 77, + 296, + 16, + 24, + 83, + 26, + 220, + 225, + 314, + 277, + 99, + 132, + 16, + 167, + 149, + 260, + 186, + 175, + 239, + 142, + 93, + 334, + 227, + 264, + 332, + 133, + 372, + 102, + 2, + 341, + 363, + 111, + 47, + 79, + 342, + 77, + 31, + 128, + 57, + 282, + 198, + 101, + 392, + 192, + 298, + 7, + 194, + 49, + 63, + 253, + 235, + 152, + 181, + 139, + 249, + 265, + 227, + 285, + 128, + 72, + 351, + 369, + 54, + 323, + 234, + 104, + 94, + 52, + 132, + 279, + 136, + 182, + 27, + 149, + 78, + 331, + 150, + 339, + 302, + 83, + 125, + 166, + 41, + 134, + 262, + 153, + 151, + 197, + 82, + 385, + 319, + 4, + 124, + 195, + 94, + 318, + 5, + 56, + 24, + 84, + 123, + 27, + 132, + 277, + 200, + 347, + 312, + 274, + 179, + 274, + 124, + 140, + 81, + 20, + 270, + 139, + 217, + 310, + 218, + 326, + 334, + 62, + 367, + 376, + 295, + 124, + 208, + 371, + 284, + 69, + 125, + 376, + 68, + 215, + 202, + 16, + 313, + 55, + 223, + 277, + 60, + 80, + 278, + 41, + 322, + 392, + 391, + 1, + 400, + 213, + 108, + 12, + 178, + 105, + 367, + 367, + 181, + 329, + 10, + 159, + 217, + 272, + 326, + 400, + 90, + 204, + 148, + 386, + 393, + 51, + 273, + 309, + 355, + 335, + 136, + 131, + 366, + 144, + 376, + 326, + 304, + 62, + 179, + 78, + 68, + 31, + 38, + 398, + 90, + 218, + 381, + 170, + 300, + 193, + 291, + 57, + 328, + 126, + 377, + 320, + 175, + 116, + 383, + 344, + 346, + 316, + 351, + 366, + 112, + 293, + 294, + 64, + 51, + 124, + 173, + 217, + 290, + 369, + 218, + 396, + 288, + 15, + 53, + 102, + 165, + 89, + 94, + 224, + 230, + 333, + 52, + 59, + 6, + 286, + 256, + 175, + 181, + 197, + 170, + 93, + 245, + 13, + 177, + 331, + 362, + 87, + 34, + 53, + 106, + 75, + 337, + 2, + 151, + 8, + 225, + 21, + 361, + 273, + 5, + 70, + 229, + 221, + 261, + 303, + 223, + 186, + 227, + 373, + 31, + 17, + 302, + 86, + 91, + 159, + 28, + 114, + 65, + 147, + 247, + 132, + 369, + 399, + 227, + 305, + 376, + 250, + 228, + 385, + 40, + 298, + 361, + 3, + 310, + 118, + 172, + 72, + 149, + 66, + 82, + 142, + 139, + 234, + 166, + 87, + 150, + 368, + 353, + 213, + 232, + 397, + 259, + 281, + 136, + 150, + 157, + 95, + 345, + 342, + 379, + 175, + 60, + 375, + 257, + 209, + 45, + 10, + 236, + 226, + 123, + 1, + 294, + 267, + 152, + 126, + 40, + 154, + 85, + 27, + 336, + 345, + 342, + 351, + 114, + 92, + 82, + 365, + 323, + 200, + 302, + 275, + 68, + 225, + 14, + 261, + 228, + 252, + 384, + 396, + 98, + 305, + 289, + 125, + 368, + 350, + 218, + 293, + 282, + 37, + 102, + 285, + 312, + 387, + 373, + 377, + 205, + 209, + 386, + 345, + 297, + 337, + 104, + 59, + 260, + 120, + 327, + 368, + 375, + 222, + 37, + 160, + 318, + 182, + 37, + 395, + 99, + 69, + 238, + 4, + 254, + 91, + 395, + 19, + 165, + 368, + 166, + 66, + 372, + 1, + 76, + 249, + 28, + 354, + 277, + 58, + 369, + 193, + 66, + 160, + 323, + 15, + 264, + 193, + 355, + 90, + 100, + 243, + 31, + 332, + 148, + 142, + 392, + 367, + 48, + 236, + 361, + 343, + 237, + 86, + 288, + 56, + 246, + 284, + 312, + 254, + 363, + 190, + 262, + 339, + 290, + 126, + 268, + 385, + 367, + 154, + 376, + 290, + 88, + 108, + 202, + 2, + 322, + 278, + 89, + 113, + 3, + 66, + 83, + 249, + 66, + 288, + 231, + 234, + 384, + 226, + 373, + 34, + 50, + 110, + 35, + 165, + 288, + 35, + 307, + 272, + 195, + 202, + 293, + 208, + 8, + 380, + 183, + 148, + 188, + 216, + 35, + 92, + 33, + 400, + 119, + 266, + 62, + 379, + 74, + 11, + 355, + 305, + 264, + 138, + 50, + 233, + 319, + 193, + 53, + 112, + 199, + 18, + 185, + 372, + 67, + 80, + 10, + 163, + 385, + 155, + 83, + 131, + 197, + 97, + 366, + 270, + 375, + 373, + 389, + 190, + 336, + 104, + 56, + 302, + 41, + 74, + 90, + 44, + 156, + 273, + 326, + 88, + 5, + 198, + 297, + 283, + 226, + 294, + 158, + 80, + 350, + 121, + 397, + 107, + 260, + 223, + 153, + 84, + 323, + 197, + 232, + 298, + 254, + 226, + 199, + 107, + 264, + 333, + 383, + 186, + 118, + 19, + 46, + 29, + 37, + 169, + 396, + 111, + 351, + 133, + 376, + 142, + 306, + 146, + 327, + 107, + 91, + 197, + 136, + 315, + 376, + 295, + 17, + 368, + 335, + 110, + 220, + 174, + 252, + 120, + 377, + 253, + 138, + 81, + 32, + 289, + 118, + 291, + 309, + 175, + 125, + 341, + 53, + 168, + 63, + 56, + 54, + 10, + 200, + 236, + 130, + 1, + 63, + 351, + 297, + 341, + 198, + 355, + 135, + 343, + 129, + 169, + 352, + 165, + 145, + 109, + 28, + 9, + 390, + 130, + 221, + 42, + 206, + 267, + 395, + 15, + 247, + 377, + 264, + 156, + 253, + 303, + 310, + 347, + 45, + 150, + 119, + 325, + 354, + 19, + 124, + 261, + 328, + 27, + 234, + 311, + 376, + 199, + 13, + 266, + 223, + 273, + 6, + 187, + 97, + 385, + 96, + 350, + 207, + 209, + 308, + 238, + 382, + 393, + 183, + 256, + 13, + 163, + 291, + 203, + 312, + 13, + 237, + 151, + 233, + 171, + 277, + 359, + 305, + 59, + 218, + 141, + 388, + 369, + 389, + 133, + 217, + 347, + 208, + 266, + 133, + 126, + 126, + 269, + 178, + 158, + 92, + 198, + 60, + 247, + 397, + 94, + 297, + 387, + 232, + 165, + 306, + 70, + 115, + 134, + 344, + 392, + 59, + 227, + 52, + 176, + 120, + 67, + 53, + 398, + 77, + 254, + 188, + 90, + 139, + 219, + 102, + 200, + 125, + 367, + 313, + 81, + 305, + 337, + 25, + 356, + 164, + 14, + 306, + 191, + 136, + 24, + 205, + 161, + 376, + 316, + 361, + 18, + 101, + 344, + 259, + 93, + 300, + 383, + 122, + 400, + 56, + 183, + 201, + 46, + 219, + 300, + 65, + 309, + 106, + 93, + 79, + 40, + 367, + 212, + 138, + 125, + 340, + 348, + 97, + 11, + 119, + 11, + 336, + 45, + 255, + 61, + 103, + 33, + 223, + 287, + 164, + 380, + 368, + 80, + 278, + 126, + 62, + 44, + 396, + 149, + 139, + 394, + 343, + 86, + 371, + 211, + 286, + 168, + 272, + 232, + 106, + 177, + 147, + 131, + 116, + 174, + 4, + 54, + 27, + 263, + 368, + 113, + 191, + 395, + 71, + 161, + 178, + 177, + 392, + 77, + 346, + 81, + 241, + 322, + 241, + 287, + 132, + 357, + 231, + 346, + 387, + 212, + 354, + 173, + 26, + 141, + 42, + 99, + 282, + 69, + 58, + 223, + 314, + 286, + 320, + 275, + 332, + 10, + 242, + 366, + 131, + 318, + 70, + 135, + 160, + 352, + 105, + 370, + 140, + 226, + 336, + 311, + 255, + 215, + 24, + 149, + 65, + 15, + 3, + 394, + 86, + 87, + 45, + 304, + 241, + 94, + 277, + 380, + 273, + 239, + 200, + 124, + 30, + 73, + 373, + 209, + 396, + 179, + 133, + 166, + 240, + 221, + 115, + 233, + 136, + 240, + 356, + 114, + 159, + 270, + 89, + 39, + 392, + 384, + 362, + 284, + 379, + 106, + 383, + 160, + 314, + 98, + 80, + 15, + 251, + 108, + 384, + 227, + 327, + 331, + 263, + 147, + 219, + 3, + 367, + 203, + 188, + 17, + 68, + 114, + 160, + 182, + 20, + 82, + 384, + 391, + 372, + 172, + 296, + 214, + 247, + 341, + 305, + 261, + 17, + 60, + 115, + 125, + 384, + 194, + 395, + 144, + 251, + 288, + 153, + 89, + 336, + 320, + 92, + 400, + 374, + 323, + 254, + 371, + 316, + 198, + 190, + 97, + 128, + 52, + 23, + 199, + 388, + 27, + 94, + 271, + 16, + 346, + 326, + 317, + 168, + 357, + 300, + 35, + 195, + 155, + 87, + 215, + 202, + 132, + 182, + 26, + 199, + 5, + 118, + 188, + 4, + 317, + 295, + 251, + 92, + 33, + 187, + 74, + 70, + 149, + 217, + 373, + 239, + 170, + 387, + 202, + 123, + 222, + 271, + 250, + 188, + 345, + 183, + 234, + 53, + 301, + 120, + 277, + 215, + 336, + 351, + 216, + 155, + 25, + 254, + 333, + 246, + 198, + 39, + 231, + 185, + 220, + 281, + 345, + 65, + 275, + 104, + 134, + 395, + 387, + 279, + 147, + 58, + 8, + 67, + 292, + 215, + 213, + 215, + 1, + 177, + 396, + 197, + 149, + 166, + 280, + 277, + 367, + 191, + 33, + 337, + 107, + 22, + 281, + 76, + 107, + 359, + 224, + 369, + 76, + 135, + 104, + 398, + 100, + 151, + 72, + 212, + 323, + 297, + 399, + 173, + 76, + 197, + 120, + 208, + 206, + 126, + 376, + 366, + 51, + 24, + 234, + 55, + 142, + 28, + 277, + 348, + 191, + 390, + 251, + 140, + 219, + 284, + 69, + 366, + 3, + 82, + 27, + 274, + 12, + 140, + 181, + 375, + 242, + 264, + 39, + 115, + 301, + 97, + 226, + 333, + 161, + 331, + 172, + 112, + 112, + 91, + 167, + 244, + 159, + 250, + 375, + 382, + 6, + 340, + 392, + 374, + 17, + 296, + 73, + 357, + 56, + 169, + 109, + 299, + 153, + 126, + 143, + 323, + 180, + 268, + 351, + 381, + 319, + 136, + 24, + 262, + 73, + 222, + 297, + 328, + 340, + 262, + 296, + 355, + 281, + 300, + 326, + 374, + 267, + 297, + 331, + 315, + 117, + 24, + 306, + 396, + 212, + 244, + 161, + 320, + 265, + 393, + 305, + 132, + 231, + 251, + 60, + 384, + 350, + 29, + 378, + 247, + 354, + 267, + 262, + 148, + 224, + 259, + 181, + 16, + 344, + 358, + 263, + 54, + 352, + 262, + 125, + 342, + 361, + 91, + 235, + 339, + 224, + 364, + 157, + 169, + 172, + 344, + 102, + 356, + 230, + 43, + 331, + 213, + 327, + 11, + 302, + 381, + 27, + 43, + 376, + 25, + 264, + 34, + 395, + 325, + 399, + 263, + 158, + 147, + 123, + 301, + 154, + 309, + 249, + 237, + 276, + 201, + 318, + 63, + 298, + 314, + 291, + 83, + 353, + 82, + 205, + 115, + 134, + 184, + 224, + 387, + 25, + 263, + 275, + 78, + 215, + 195, + 219, + 92, + 140, + 129, + 173, + 217, + 77, + 180, + 343, + 312, + 27, + 317, + 213, + 37, + 373, + 392, + 275, + 52, + 378, + 113, + 363, + 24, + 293, + 131, + 63, + 373, + 162, + 197, + 173, + 192, + 155, + 99, + 214, + 40, + 80, + 166, + 208, + 368, + 167, + 34, + 273, + 305, + 32, + 243, + 139, + 359, + 345, + 345, + 322, + 67, + 33, + 192, + 203, + 33, + 265, + 123, + 343, + 157, + 90, + 345, + 351, + 355, + 115, + 111, + 245, + 138, + 189, + 125, + 363, + 396, + 340, + 203, + 258, + 149, + 310, + 377, + 360, + 247, + 44, + 276, + 305, + 252, + 313, + 309, + 114, + 158, + 93, + 44, + 240, + 266, + 349, + 384, + 365, + 386, + 341, + 91, + 366, + 242, + 249, + 239, + 114, + 170, + 71, + 206, + 247, + 314, + 260, + 3, + 60, + 391, + 277, + 264, + 252, + 390, + 278, + 281, + 261, + 335, + 92, + 371, + 329, + 205, + 259, + 320, + 255, + 10, + 239, + 293, + 203, + 15, + 347, + 158, + 96, + 195, + 150, + 274, + 36, + 182, + 242, + 214, + 30, + 161, + 288, + 313, + 122, + 258, + 343, + 141, + 159, + 74, + 345, + 17, + 2, + 69, + 50, + 150, + 86, + 334, + 104, + 139, + 154, + 63, + 258, + 292, + 308, + 325, + 174, + 69, + 393, + 33, + 175, + 150, + 366, + 302, + 216, + 317, + 21, + 206, + 212, + 154, + 119, + 102, + 146, + 196, + 203, + 136, + 289, + 260, + 23, + 274, + 182, + 284, + 316, + 204, + 247, + 56, + 153, + 213, + 38, + 13, + 255, + 399, + 71, + 30, + 91, + 138, + 289, + 267, + 189, + 395, + 344, + 137, + 40, + 374, + 220, + 378, + 143, + 286, + 101, + 229, + 218, + 68, + 266, + 317, + 6, + 93, + 224, + 322, + 320, + 149, + 53, + 287, + 1, + 74, + 38, + 288, + 124, + 218, + 13, + 230, + 29, + 185, + 3, + 286, + 344, + 7, + 336, + 177, + 27, + 212, + 369, + 218, + 117, + 213, + 149, + 301, + 37, + 221, + 205, + 325, + 163, + 235, + 79, + 199, + 175, + 146, + 89, + 172, + 318, + 208, + 381, + 213, + 349, + 92, + 17, + 391, + 297, + 10, + 180, + 328, + 288, + 220, + 146, + 386, + 68, + 148, + 376, + 369, + 39, + 125, + 50, + 190, + 26, + 293, + 307, + 254, + 35, + 7, + 133, + 205, + 61, + 380, + 168, + 154, + 250, + 317, + 116, + 232, + 293, + 364, + 63, + 176, + 289, + 396, + 350, + 339, + 390, + 209, + 223, + 23, + 201, + 151, + 158, + 352, + 344, + 342, + 298, + 339, + 393, + 124, + 190, + 249, + 324, + 181, + 318, + 290, + 337, + 326, + 242, + 286, + 310, + 82, + 141, + 244, + 130, + 26, + 382, + 259, + 219, + 361, + 185, + 60, + 351, + 339, + 165, + 85, + 201, + 291, + 271, + 177, + 381, + 218, + 392, + 4, + 190, + 398, + 91, + 29, + 283, + 232, + 240, + 303, + 98, + 55, + 315, + 39, + 337, + 360, + 284, + 310, + 190, + 349, + 366, + 119, + 266, + 74, + 379, + 9, + 186, + 317, + 378, + 38, + 262, + 102, + 325, + 39, + 322, + 394, + 302, + 151, + 123, + 225, + 280, + 226, + 118, + 330, + 199, + 26, + 344, + 297, + 169, + 86, + 309, + 293, + 288, + 375, + 103, + 232, + 59, + 187, + 190, + 238, + 143, + 284, + 366, + 148, + 152, + 122, + 117, + 250, + 13, + 90, + 235, + 12, + 116, + 122, + 146, + 43, + 13, + 235, + 395, + 104, + 142, + 116, + 52, + 189, + 372, + 216, + 9, + 14, + 366, + 114, + 332, + 339, + 235, + 83, + 126, + 261, + 296, + 184, + 141, + 219, + 27, + 130, + 337, + 187, + 3, + 123, + 331, + 159, + 267, + 347, + 299, + 95, + 385, + 3, + 387, + 212, + 374, + 309, + 113, + 177, + 57, + 395, + 286, + 307, + 103, + 230, + 302, + 328, + 386, + 325, + 374, + 297, + 181, + 344, + 290, + 210, + 234, + 260, + 331, + 120, + 309, + 79, + 261, + 65, + 283, + 108, + 323, + 280, + 198, + 28, + 69, + 243, + 261, + 352, + 237, + 88, + 210, + 115, + 75, + 12, + 242, + 106, + 91, + 22, + 17, + 123, + 395, + 92, + 356, + 31, + 229, + 141, + 191, + 384, + 377, + 266, + 180, + 13, + 94, + 19, + 13, + 8, + 232, + 96, + 184, + 394, + 91, + 213, + 275, + 315, + 381, + 28, + 61, + 253, + 387, + 218, + 241, + 300, + 341, + 355, + 106, + 389, + 243, + 59, + 275, + 120, + 305, + 119, + 354, + 275, + 111, + 117, + 10, + 217, + 303, + 125, + 146, + 168, + 319, + 173, + 301, + 186, + 7, + 305, + 104, + 146, + 127, + 255, + 221, + 332, + 7, + 138, + 336, + 277, + 197, + 94, + 278, + 241, + 173, + 260, + 293, + 343, + 9, + 249, + 368, + 208, + 365, + 34, + 6, + 286, + 147, + 149, + 379, + 227, + 21, + 133, + 223, + 372, + 38, + 331, + 34, + 266, + 80, + 257, + 225, + 376, + 134, + 357, + 349, + 320, + 310, + 361, + 80, + 139, + 127, + 360, + 154, + 14, + 164, + 344, + 238, + 367, + 52, + 364, + 142, + 167, + 98, + 86, + 105, + 102, + 194, + 351, + 7, + 233, + 370, + 21, + 100, + 188, + 232, + 41, + 284, + 197, + 116, + 46, + 13, + 325, + 49, + 47, + 180, + 136, + 234, + 397, + 316, + 200, + 303, + 357, + 289, + 121, + 160, + 189, + 204, + 383, + 300, + 326, + 62, + 56, + 208, + 78, + 144, + 181, + 37, + 172, + 69, + 164, + 325, + 233, + 339, + 302, + 183, + 70, + 238, + 331, + 272, + 245, + 204, + 177, + 21, + 101, + 138, + 371, + 17, + 106, + 167, + 234, + 201, + 227, + 87, + 92, + 120, + 316, + 32, + 18, + 251, + 283, + 187, + 246, + 33, + 214, + 376, + 125, + 277, + 358, + 307, + 334, + 264, + 152, + 163, + 375, + 142, + 18, + 274, + 243, + 252, + 110, + 120, + 342, + 251, + 242, + 192, + 8, + 151, + 196, + 68, + 334, + 349, + 378, + 73, + 148, + 147, + 134, + 268, + 329, + 241, + 237, + 150, + 80, + 49, + 93, + 19, + 111, + 350, + 204, + 348, + 163, + 204, + 199, + 56, + 383, + 216, + 42, + 283, + 260, + 113, + 317, + 57, + 220, + 250, + 131, + 235, + 148, + 346, + 273, + 95, + 259, + 282, + 238, + 31, + 313, + 357, + 363, + 13, + 58, + 280, + 181, + 20, + 39, + 137, + 75, + 217, + 144, + 343, + 235, + 375, + 369, + 232, + 199, + 17, + 214, + 166, + 152, + 224, + 334, + 128, + 100, + 312, + 81, + 373, + 284, + 339, + 50, + 215, + 350, + 281, + 28, + 290, + 102, + 176, + 22, + 152, + 204, + 225, + 199, + 345, + 325, + 317, + 124, + 259, + 64, + 360, + 5, + 392, + 261, + 342, + 184, + 119, + 218, + 350, + 201, + 295, + 135, + 321, + 47, + 334, + 156, + 376, + 218, + 135, + 136, + 149, + 227, + 48, + 53, + 359, + 217, + 228, + 352, + 258, + 98, + 66, + 333, + 178, + 124, + 259, + 62, + 53, + 80, + 155, + 113, + 258, + 284, + 263, + 286, + 154, + 300, + 121, + 176, + 193, + 249, + 117, + 269, + 201, + 27, + 333, + 90, + 355, + 241, + 345, + 365, + 244, + 298, + 362, + 113, + 45, + 360, + 156, + 169, + 66, + 239, + 28, + 383, + 356, + 280, + 25, + 154, + 182, + 250, + 225, + 25, + 272, + 250, + 316, + 282, + 102, + 180, + 216, + 110, + 358, + 215, + 79, + 399, + 334, + 358, + 135, + 397, + 256, + 400, + 180, + 269, + 245, + 328, + 326, + 324, + 271, + 265, + 34, + 108, + 190, + 375, + 166, + 39, + 111, + 197, + 391, + 322, + 117, + 200, + 270, + 78, + 123, + 193, + 57, + 236, + 325, + 135, + 193, + 225, + 287, + 289, + 167, + 14, + 71, + 280, + 250, + 287, + 169, + 82, + 234, + 43, + 94, + 179, + 114, + 131, + 240, + 27, + 193, + 27, + 286, + 216, + 304, + 53, + 362, + 375, + 47, + 108, + 350, + 294, + 295, + 109, + 71, + 248, + 389, + 26, + 377, + 127, + 35, + 162, + 232, + 284, + 46, + 115, + 143, + 327, + 144, + 314, + 356, + 376, + 277, + 15, + 185, + 123, + 86, + 119, + 162, + 386, + 69, + 329, + 225, + 32, + 225, + 98, + 240, + 259, + 343, + 317, + 1, + 97, + 5, + 397, + 10, + 338, + 32, + 157, + 329, + 207, + 172, + 216, + 292, + 173, + 353, + 296, + 299, + 356, + 232, + 79, + 1, + 357, + 141, + 84, + 339, + 46, + 290, + 81, + 159, + 178, + 267, + 268, + 219, + 181, + 341, + 177, + 55, + 119, + 2, + 296, + 99, + 398, + 59, + 347, + 224, + 175, + 2, + 400, + 371, + 184, + 119, + 375, + 346, + 275, + 228, + 296, + 299, + 361, + 399, + 98, + 12, + 338, + 287, + 366, + 216, + 95, + 217, + 129, + 328, + 72, + 274, + 329, + 396, + 13, + 41, + 362, + 356, + 199, + 369, + 193, + 328, + 289, + 165, + 248, + 50, + 118, + 14, + 113, + 379, + 370, + 170, + 254, + 188, + 39, + 19, + 145, + 165, + 239, + 362, + 43, + 20, + 265, + 253, + 25, + 122, + 230, + 134, + 162, + 220, + 124, + 135, + 331, + 176, + 303, + 63, + 327, + 279, + 339, + 123, + 179, + 161, + 87, + 208, + 130, + 343, + 140, + 239, + 374, + 195, + 137, + 269, + 101, + 225, + 269, + 310, + 102, + 239, + 212, + 130, + 184, + 18, + 333, + 326, + 124, + 146, + 231, + 250, + 399, + 284, + 308, + 312, + 114, + 78, + 94, + 29, + 76, + 118, + 205, + 132, + 305, + 134, + 265, + 110, + 92, + 299, + 72, + 132, + 30, + 134, + 79, + 262, + 310, + 339, + 38, + 244, + 248, + 131, + 328, + 194, + 231, + 60, + 246, + 395, + 130, + 101, + 86, + 332, + 282, + 81, + 199, + 110, + 171, + 310, + 326, + 291, + 169, + 387, + 322, + 186, + 333, + 45, + 196, + 318, + 302, + 267, + 273, + 385, + 286, + 84, + 26, + 40, + 22, + 210, + 389, + 337, + 53, + 248, + 298, + 61, + 270, + 376, + 306, + 331, + 134, + 125, + 157, + 274, + 113, + 119, + 46, + 164, + 373, + 84, + 211, + 79, + 394, + 364, + 68, + 246, + 248, + 391, + 393, + 374, + 15, + 272, + 49, + 391, + 210, + 290, + 218, + 111, + 100, + 255, + 150, + 215, + 285, + 109, + 380, + 183, + 12, + 135, + 225, + 144, + 293, + 144, + 356, + 365, + 237, + 165, + 70, + 339, + 159, + 188, + 203, + 63, + 324, + 146, + 239, + 269, + 273, + 300, + 148, + 94, + 88, + 349, + 5, + 92, + 378, + 223, + 226, + 237, + 317, + 155, + 105, + 92, + 305, + 74, + 237, + 144, + 248, + 186, + 89, + 18, + 295, + 5, + 262, + 91, + 84, + 275, + 393, + 241, + 77, + 26, + 298, + 215, + 275, + 54, + 117, + 72, + 235, + 284, + 385, + 150, + 142, + 162, + 190, + 271, + 9, + 230, + 222, + 224, + 226, + 385, + 115, + 47, + 126, + 348, + 372, + 126, + 27, + 203, + 81, + 302, + 289, + 46, + 86, + 160, + 398, + 164, + 1, + 41, + 156, + 125, + 146, + 217, + 261, + 282, + 318, + 381, + 167, + 253, + 337, + 108, + 172, + 198, + 113, + 365, + 143, + 7, + 239, + 23, + 256, + 126, + 360, + 192, + 40, + 6, + 101, + 142, + 172, + 89, + 90, + 59, + 253, + 181, + 246, + 113, + 27, + 176, + 124, + 389, + 356, + 64, + 48, + 60, + 121, + 282, + 250, + 22, + 228, + 28, + 379, + 247, + 290, + 55, + 70, + 268, + 277, + 168, + 116, + 63, + 235, + 257, + 340, + 291, + 345, + 139, + 78, + 223, + 226, + 14, + 356, + 255, + 79, + 157, + 298, + 127, + 293, + 396, + 280, + 271, + 185, + 79, + 359, + 112, + 171, + 275, + 228, + 50, + 50, + 313, + 181, + 324, + 352, + 60, + 182, + 90, + 263, + 177, + 54, + 271, + 399, + 383, + 288, + 161, + 276, + 117, + 253, + 206, + 395, + 49, + 302, + 77, + 288, + 122, + 80, + 189, + 121, + 276, + 60, + 124, + 313, + 177, + 218, + 262, + 3, + 330, + 178, + 147, + 264, + 343, + 241, + 211, + 94, + 48, + 242, + 13, + 46, + 249, + 134, + 181, + 44, + 143, + 373, + 116, + 225, + 93, + 220, + 93, + 167, + 100, + 5, + 379, + 337, + 203, + 58, + 27, + 60, + 285, + 226, + 146, + 94, + 11, + 137, + 388, + 84, + 237, + 277, + 56, + 7, + 142, + 201, + 386, + 250, + 280, + 129, + 174, + 335, + 349, + 167, + 321, + 268, + 246, + 48, + 259, + 255, + 301, + 301, + 154, + 369, + 208, + 339, + 181, + 303, + 129, + 301, + 138, + 130, + 202, + 191, + 338, + 166, + 198, + 230, + 107, + 37, + 39, + 96, + 18, + 301, + 37, + 269, + 139, + 215, + 150, + 197, + 90, + 124, + 381, + 370, + 297, + 238, + 238, + 307, + 235, + 285, + 39, + 303, + 142, + 231, + 176, + 251, + 182, + 132, + 122, + 137, + 342, + 379, + 98, + 384, + 286, + 136, + 16, + 228, + 110, + 219, + 57, + 177, + 310, + 351, + 147, + 31, + 335, + 253, + 333, + 286, + 93, + 74, + 184, + 359, + 392, + 5, + 132, + 130, + 24, + 233, + 124, + 231, + 335, + 23, + 151, + 59, + 99, + 54, + 343, + 180, + 80, + 133, + 147, + 150, + 86, + 281, + 68, + 194, + 45, + 131, + 333, + 3, + 12, + 148, + 188, + 109, + 273, + 104, + 111, + 296, + 177, + 298, + 49, + 44, + 75, + 301, + 225, + 163, + 244, + 113, + 399, + 266, + 140, + 255, + 93, + 31, + 196, + 209, + 327, + 7, + 269, + 17, + 150, + 297, + 196, + 341, + 393, + 219, + 340, + 322, + 242, + 216, + 336, + 277, + 158, + 104, + 304, + 311, + 125, + 32, + 193, + 300, + 287, + 84, + 324, + 183, + 90, + 69, + 346, + 75, + 277, + 124, + 351, + 11, + 271, + 203, + 379, + 121, + 233, + 217, + 356, + 129, + 8, + 30, + 51, + 210, + 162, + 100, + 274, + 384, + 17, + 24, + 239, + 246, + 101, + 184, + 237, + 265, + 272, + 331, + 34, + 302, + 317, + 137, + 378, + 205, + 268, + 29, + 42, + 88, + 389, + 210, + 187, + 144, + 308, + 205, + 260, + 176, + 222, + 197, + 256, + 160, + 125, + 249, + 352, + 82, + 145, + 190, + 355, + 278, + 349, + 356, + 131, + 117, + 398, + 115, + 231, + 239, + 150, + 33, + 108, + 189, + 251, + 59, + 350, + 142, + 178, + 95, + 380, + 289, + 220, + 345, + 379, + 311, + 395, + 291, + 31, + 224, + 24, + 345, + 305, + 64, + 169, + 9, + 9, + 59, + 98, + 379, + 199, + 353, + 247, + 102, + 303, + 380, + 258, + 320, + 360, + 208, + 359, + 130, + 261, + 58, + 241, + 369, + 391, + 96, + 285, + 49, + 189, + 54, + 136, + 364, + 323, + 391, + 309, + 312, + 305, + 75, + 358, + 170, + 330, + 386, + 179, + 382, + 143, + 146, + 42, + 212, + 162, + 135, + 187, + 224, + 162, + 378, + 360, + 184, + 271, + 284, + 348, + 280, + 113, + 105, + 130, + 246, + 195, + 379, + 259, + 318, + 60, + 3, + 245, + 162, + 357, + 131, + 157, + 130, + 36, + 52, + 93, + 113, + 228, + 210, + 327, + 38, + 207, + 172, + 267, + 377, + 109, + 367, + 29, + 82, + 346, + 41, + 79, + 56, + 374, + 128, + 308, + 26, + 366, + 77, + 8, + 278, + 175, + 239, + 7, + 18, + 113, + 342, + 365, + 96, + 258, + 383, + 381, + 193, + 218, + 358, + 198, + 176, + 297, + 60, + 220, + 206, + 26, + 335, + 145, + 154, + 349, + 120, + 249, + 196, + 181, + 345, + 166, + 226, + 196, + 196, + 74, + 391, + 354, + 46, + 378, + 341, + 40, + 172, + 383, + 246, + 63, + 136, + 377, + 336, + 322, + 4, + 278, + 385, + 149, + 277, + 253, + 67, + 309, + 225, + 149, + 201, + 213, + 31, + 281, + 296, + 51, + 267, + 99, + 52, + 205, + 138, + 48, + 262, + 216, + 187, + 127, + 246, + 377, + 52, + 43, + 133, + 319, + 78, + 371, + 259, + 145, + 131, + 14, + 371, + 194, + 190, + 400, + 227, + 226, + 195, + 320, + 266, + 283, + 171, + 134, + 2, + 146, + 148, + 237, + 83, + 155, + 384, + 374, + 184, + 257, + 261, + 234, + 106, + 359, + 274, + 6, + 317, + 155, + 346, + 204, + 88, + 56, + 186, + 183, + 365, + 222, + 256, + 351, + 66, + 163, + 62, + 73, + 201, + 383, + 277, + 202, + 356, + 192, + 78, + 252, + 270, + 22, + 83, + 244, + 383, + 260, + 65, + 197, + 400, + 348, + 389, + 396, + 388, + 19, + 185, + 167, + 30, + 3, + 248, + 276, + 103, + 364, + 1, + 78, + 115, + 218, + 39, + 160, + 354, + 130, + 157, + 102, + 350, + 43, + 52, + 246, + 198, + 76, + 357, + 189, + 356, + 46, + 56, + 242, + 216, + 211, + 322, + 341, + 362, + 10, + 157, + 22, + 318, + 111, + 346, + 128, + 395, + 61, + 146, + 249, + 345, + 27, + 377, + 366, + 290, + 218, + 54, + 81, + 128, + 39, + 213, + 177, + 9, + 199, + 13, + 5, + 339, + 101, + 205, + 331, + 354, + 357, + 186, + 356, + 206, + 341, + 319, + 282, + 326, + 162, + 151, + 222, + 89, + 180, + 56, + 282, + 86, + 223, + 185, + 324, + 257, + 367, + 327, + 358, + 11, + 16, + 355, + 158, + 150, + 266, + 264, + 119, + 389, + 151, + 61, + 389, + 345, + 251, + 291, + 262, + 396, + 346, + 334, + 324, + 257, + 383, + 139, + 196, + 6, + 324, + 7, + 232, + 355, + 48, + 42, + 77, + 270, + 58, + 341, + 330, + 191, + 180, + 335, + 383, + 31, + 289, + 151, + 354, + 327, + 211, + 361, + 209, + 253, + 310, + 211, + 66, + 366, + 330, + 159, + 374, + 310, + 60, + 370, + 102, + 187, + 28, + 323, + 176, + 161, + 68, + 44, + 297, + 174, + 335, + 215, + 50, + 374, + 165, + 300, + 111, + 186, + 148, + 322, + 258, + 203, + 205, + 291, + 311, + 86, + 314, + 151, + 114, + 197, + 159, + 5, + 184, + 75, + 231, + 220, + 329, + 237, + 380, + 170, + 316, + 128, + 283, + 135, + 16, + 371, + 300, + 18, + 161, + 399, + 164, + 313, + 147, + 217, + 86, + 139, + 71, + 34, + 64, + 225, + 275, + 11, + 45, + 194, + 232, + 265, + 7, + 130, + 110, + 331, + 395, + 287, + 284, + 155, + 197, + 183, + 149, + 56, + 367, + 300, + 95, + 22, + 65, + 19, + 175, + 134, + 184, + 318, + 154, + 46, + 123, + 143, + 369, + 295, + 139, + 123, + 387, + 257, + 9, + 22, + 175, + 369, + 370, + 106, + 380, + 127, + 102, + 68, + 112, + 312, + 274, + 250, + 145, + 20, + 212, + 277, + 266, + 357, + 319, + 212, + 158, + 68, + 243, + 9, + 151, + 112, + 260, + 319, + 157, + 219, + 258, + 367, + 201, + 332, + 163, + 258, + 190, + 242, + 339, + 58, + 186, + 256, + 16, + 253, + 63, + 71, + 87, + 38, + 58, + 332, + 55, + 349, + 178, + 248, + 381, + 311, + 288, + 11, + 87, + 266, + 310, + 11, + 24, + 268, + 376, + 137, + 304, + 252, + 322, + 246, + 10, + 281, + 232, + 218, + 103, + 35, + 250, + 399, + 365, + 340, + 306, + 397, + 74, + 350, + 170, + 7, + 301, + 331, + 252, + 10, + 170, + 137, + 9, + 5, + 191, + 352, + 182, + 167, + 98, + 381, + 101, + 170, + 225, + 51, + 208, + 70, + 328, + 177, + 129, + 90, + 41, + 24, + 333, + 155, + 208, + 153, + 214, + 92, + 270, + 386, + 164, + 261, + 74, + 158, + 236, + 394, + 247, + 300, + 392, + 128, + 33, + 344, + 221, + 325, + 394, + 216, + 254, + 22, + 335, + 214, + 259, + 146, + 394, + 96, + 228, + 207, + 376, + 393, + 178, + 388, + 362, + 204, + 16, + 109, + 261, + 303, + 318, + 133, + 90, + 41, + 234, + 41, + 214, + 392, + 200, + 253, + 135, + 184, + 246, + 36, + 239, + 273, + 230, + 154, + 234, + 380, + 121, + 160, + 308, + 356, + 174, + 69, + 340, + 27, + 336, + 239, + 56, + 260, + 122, + 148, + 374, + 297, + 191, + 296, + 289, + 208, + 363, + 334, + 150, + 230, + 283, + 9, + 324, + 170, + 57, + 268, + 36, + 365, + 180, + 275, + 373, + 276, + 99, + 272, + 373, + 57, + 217, + 259, + 286, + 126, + 96, + 245, + 230, + 154, + 366, + 41, + 55, + 159, + 278, + 224, + 151, + 334, + 327, + 216, + 361, + 344, + 224, + 345, + 211, + 100, + 255, + 326, + 357, + 206, + 377, + 153, + 131, + 71, + 45, + 86, + 228, + 331, + 245, + 338, + 166, + 282, + 183, + 392, + 326, + 85, + 155, + 248, + 131, + 257, + 91, + 275, + 269, + 46, + 65, + 338, + 229, + 333, + 178, + 384, + 317, + 245, + 145, + 111, + 211, + 270, + 214, + 17, + 364, + 164, + 99, + 299, + 251, + 146, + 140, + 301, + 318, + 188, + 113, + 270, + 207, + 47, + 85, + 133, + 53, + 369, + 152, + 336, + 327, + 399, + 296, + 189, + 27, + 298, + 79, + 271, + 97, + 14, + 145, + 112, + 310, + 292, + 157, + 43, + 18, + 197, + 121, + 386, + 357, + 192, + 116, + 281, + 138, + 302, + 86, + 375, + 73, + 76, + 192, + 16, + 335, + 154, + 54, + 92, + 295, + 369, + 341, + 57, + 275, + 385, + 117, + 10, + 182, + 120, + 284, + 16, + 63, + 308, + 335, + 336, + 322, + 353, + 60, + 207, + 287, + 35, + 265, + 215, + 275, + 234, + 367, + 256, + 251, + 340, + 127, + 359, + 328, + 280, + 337, + 111, + 255, + 104, + 127, + 195, + 44, + 129, + 64, + 317, + 4, + 348, + 251, + 337, + 73, + 23, + 158, + 118, + 67, + 293, + 253, + 346, + 398, + 207, + 81, + 78, + 125, + 45, + 204, + 269, + 267, + 176, + 397, + 317, + 206, + 253, + 241, + 371, + 243, + 310, + 172, + 2, + 275, + 352, + 31, + 203, + 142, + 156, + 62, + 23, + 337, + 137, + 100, + 351, + 187, + 70, + 281, + 231, + 220, + 67, + 330, + 199, + 167, + 105, + 98, + 64, + 86, + 280, + 214, + 76, + 242, + 360, + 156, + 261, + 229, + 117, + 55, + 379, + 76, + 290, + 181, + 65, + 194, + 23, + 126, + 145, + 255, + 157, + 335, + 52, + 27, + 311, + 158, + 233, + 322, + 299, + 131, + 249, + 378, + 170, + 128, + 77, + 194, + 68, + 262, + 364, + 267, + 4, + 182, + 56, + 69, + 267, + 39, + 17, + 165, + 101, + 246, + 322, + 57, + 148, + 64, + 37, + 339, + 91, + 245, + 46, + 231, + 263, + 71, + 306, + 231, + 125, + 35, + 306, + 141, + 108, + 223, + 6, + 262, + 162, + 81, + 132, + 108, + 8, + 111, + 262, + 274, + 4, + 201, + 43, + 314, + 208, + 210, + 366, + 271, + 279, + 93, + 328, + 110, + 57, + 327, + 116, + 268, + 191, + 27, + 364, + 119, + 346, + 268, + 287, + 307, + 153, + 305, + 151, + 378, + 376, + 27, + 20, + 395, + 327, + 147, + 266, + 217, + 285, + 127, + 163, + 203, + 305, + 253, + 165, + 91, + 379, + 265, + 128, + 247, + 96, + 340, + 353, + 187, + 358, + 387, + 357, + 198, + 63, + 162, + 299, + 212, + 58, + 356, + 355, + 285, + 377, + 191, + 396, + 257, + 85, + 35, + 205, + 167, + 74, + 365, + 143, + 122, + 252, + 222, + 109, + 291, + 367, + 184, + 232, + 176, + 273, + 226, + 39, + 37, + 232, + 96, + 186, + 48, + 180, + 147, + 192, + 47, + 326, + 261, + 198, + 200, + 164, + 157, + 102, + 210, + 21, + 120, + 254, + 95, + 379, + 341, + 27, + 341, + 206, + 30, + 155, + 47, + 230, + 105, + 192, + 396, + 60, + 109, + 64, + 1, + 197, + 316, + 236, + 95, + 302, + 156, + 7, + 264, + 276, + 25, + 64, + 26, + 225, + 258, + 13, + 49, + 243, + 254, + 137, + 26, + 45, + 230, + 157, + 117, + 29, + 332, + 344, + 23, + 284, + 309, + 271, + 85, + 180, + 271, + 88, + 77, + 100, + 135, + 79, + 230, + 122, + 141, + 76, + 101, + 282, + 243, + 34, + 242, + 262, + 274, + 2, + 23, + 106, + 394, + 142, + 22, + 186, + 208, + 121, + 396, + 101, + 366, + 158, + 349, + 392, + 68, + 112, + 109, + 293, + 100, + 174, + 24, + 394, + 222, + 296, + 204, + 55, + 249, + 2, + 24, + 46, + 38, + 76, + 295, + 227, + 113, + 116, + 134, + 348, + 54, + 120, + 4, + 235, + 184, + 26, + 282, + 347, + 368, + 115, + 83, + 144, + 230, + 173, + 237, + 299, + 336, + 384, + 122, + 305, + 318, + 241, + 317, + 53, + 258, + 279, + 48, + 101, + 204, + 114, + 147, + 309, + 148, + 16, + 87, + 81, + 344, + 24, + 116, + 341, + 122, + 377, + 136, + 145, + 186, + 376, + 302, + 254, + 62, + 228, + 6, + 353, + 272, + 55, + 299, + 176, + 375, + 377, + 377, + 103, + 231, + 363, + 221, + 317, + 16, + 381, + 86, + 36, + 204, + 295, + 13, + 25, + 232, + 11, + 341, + 214, + 86, + 37, + 254, + 242, + 15, + 84, + 11, + 184, + 16, + 370, + 284, + 267, + 213, + 35, + 383, + 191, + 297, + 162, + 152, + 84, + 33, + 355, + 264, + 341, + 169, + 111, + 98, + 184, + 215, + 274, + 318, + 28, + 377, + 24, + 317, + 378, + 41, + 242, + 119, + 85, + 286, + 125, + 238, + 303, + 373, + 288, + 188, + 353, + 152, + 311, + 396, + 81, + 186, + 285, + 117, + 48, + 228, + 319, + 365, + 207, + 152, + 69, + 235, + 365, + 398, + 241, + 121, + 97, + 85, + 28, + 302, + 15, + 161, + 365, + 353, + 156, + 393, + 154, + 89, + 251, + 342, + 262, + 33, + 26, + 43, + 326, + 146, + 251, + 191, + 398, + 326, + 284, + 325, + 281, + 292, + 318, + 112, + 31, + 217, + 332, + 330, + 70, + 284, + 372, + 165, + 324, + 302, + 45, + 1, + 289, + 217, + 350, + 173, + 165, + 60, + 233, + 391, + 42, + 327, + 307, + 187, + 29, + 20, + 222, + 217, + 126, + 276, + 313, + 32, + 289, + 173, + 379, + 332, + 288, + 181, + 353, + 129, + 272, + 211, + 315, + 188, + 126, + 118, + 94, + 386, + 114, + 231, + 45, + 198, + 397, + 31, + 207, + 335, + 344, + 274, + 38, + 9, + 94, + 368, + 198, + 61, + 278, + 357, + 229, + 136, + 287, + 172, + 266, + 119, + 225, + 240, + 40, + 36, + 102, + 156, + 337, + 219, + 222, + 27, + 148, + 285, + 342, + 20, + 337, + 160, + 294, + 178, + 42, + 382, + 62, + 350, + 95, + 267, + 55, + 138, + 180, + 153, + 388, + 2, + 338, + 54, + 40, + 278, + 361, + 213, + 124, + 183, + 239, + 377, + 386, + 377, + 19, + 225, + 56, + 86, + 61, + 177, + 310, + 138, + 323, + 156, + 34, + 182, + 226, + 339, + 185, + 5, + 40, + 352, + 243, + 57, + 188, + 218, + 201, + 209, + 180, + 326, + 234, + 230, + 142, + 224, + 102, + 169, + 6, + 276, + 18, + 105, + 192, + 336, + 275, + 50, + 137, + 344, + 217, + 364, + 109, + 308, + 389, + 64, + 365, + 390, + 323, + 20, + 82, + 261, + 289, + 175, + 218, + 99, + 392, + 248, + 16, + 105, + 239, + 173, + 3, + 292, + 131, + 12, + 250, + 200, + 207, + 205, + 206, + 271, + 77, + 346, + 375, + 32, + 326, + 64, + 115, + 344, + 43, + 103, + 212, + 386, + 168, + 277, + 243, + 31, + 178, + 373, + 160, + 114, + 346, + 300, + 276, + 370, + 337, + 186, + 308, + 33, + 12, + 107, + 261, + 165, + 209, + 337, + 130, + 1, + 40, + 194, + 205, + 29, + 146, + 26, + 254, + 283, + 143, + 136, + 57, + 229, + 99, + 110, + 95, + 255, + 305, + 308, + 199, + 142, + 25, + 13, + 51, + 64, + 88, + 293, + 229, + 95, + 394, + 114, + 311, + 298, + 284, + 242, + 383, + 206, + 243, + 124, + 151, + 377, + 278, + 187, + 107, + 154, + 272, + 207, + 254, + 317, + 286, + 126, + 262, + 320, + 274, + 221, + 90, + 150, + 181, + 114, + 303, + 119, + 89, + 214, + 344, + 322, + 256, + 130, + 336, + 4, + 249, + 141, + 165, + 199, + 164, + 183, + 229, + 305, + 109, + 226, + 280, + 124, + 353, + 271, + 388, + 249, + 344, + 250, + 264, + 4, + 381, + 128, + 101, + 245, + 181, + 13, + 202, + 324, + 362, + 5, + 318, + 179, + 183, + 60, + 16, + 261, + 82, + 13, + 315, + 50, + 268, + 214, + 358, + 239, + 138, + 397, + 353, + 126, + 390, + 280, + 217, + 139, + 242, + 22, + 33, + 340, + 232, + 80, + 34, + 96, + 130, + 384, + 329, + 343, + 210, + 69, + 299, + 149, + 283, + 16, + 378, + 93, + 238, + 274, + 332, + 55, + 367, + 298, + 270, + 57, + 350, + 221, + 97, + 342, + 79, + 155, + 203, + 388, + 158, + 76, + 362, + 310, + 197, + 320, + 66, + 390, + 335, + 8, + 72, + 171, + 37, + 239, + 188, + 223, + 37, + 303, + 211, + 340, + 77, + 78, + 242, + 180, + 295, + 147, + 220, + 166, + 49, + 39, + 130, + 311, + 112, + 361, + 110, + 137, + 198, + 71, + 365, + 302, + 359, + 138, + 111, + 140, + 290, + 56, + 155, + 90, + 299, + 141, + 231, + 11, + 305, + 58, + 397, + 21, + 398, + 340, + 28, + 229, + 341, + 55, + 288, + 6, + 330, + 235, + 154, + 106, + 362, + 256, + 3, + 320, + 1, + 268, + 262, + 335, + 153, + 232, + 218, + 340, + 235, + 308, + 57, + 343, + 7, + 44, + 112, + 246, + 90, + 121, + 360, + 224, + 171, + 205, + 399, + 214, + 270, + 222, + 115, + 316, + 49, + 107, + 234, + 314, + 222, + 75, + 221, + 299, + 395, + 346, + 377, + 22, + 52, + 204, + 380, + 329, + 228, + 126, + 156, + 285, + 25, + 189, + 312, + 213, + 107, + 23, + 176, + 263, + 215, + 289, + 345, + 253, + 203, + 309, + 341, + 16, + 312, + 66, + 108, + 215, + 70, + 92, + 208, + 107, + 187, + 133, + 160, + 228, + 25, + 97, + 25, + 170, + 80, + 8, + 337, + 160, + 46, + 361, + 400, + 234, + 10, + 226, + 399, + 353, + 189, + 322, + 171, + 252, + 21, + 165, + 300, + 102, + 91, + 55, + 134, + 308, + 155, + 211, + 201, + 328, + 267, + 258, + 87, + 33, + 253, + 147, + 187, + 94, + 66, + 149, + 343, + 257, + 122, + 366, + 95, + 381, + 262, + 213, + 242, + 220, + 386, + 329, + 79, + 340, + 7, + 182, + 164, + 324, + 164, + 240, + 384, + 63, + 50, + 359, + 8, + 83, + 236, + 231, + 72, + 25, + 195, + 199, + 300, + 333, + 209, + 32, + 105, + 116, + 325, + 149, + 123, + 368, + 164, + 21, + 228, + 134, + 92, + 365, + 241, + 235, + 47, + 299, + 170, + 18, + 171, + 80, + 290, + 109, + 51, + 86, + 378, + 159, + 177, + 177, + 391, + 92, + 238, + 214, + 11, + 368, + 394, + 86, + 283, + 260, + 309, + 248, + 261, + 218, + 73, + 169, + 68, + 321, + 192, + 384, + 163, + 305, + 104, + 301, + 366, + 204, + 77, + 23, + 55, + 230, + 237, + 55, + 166, + 367, + 286, + 134, + 361, + 190, + 108, + 306, + 396, + 136, + 298, + 367, + 336, + 86, + 18, + 195, + 41, + 272, + 171, + 216, + 123, + 143, + 267, + 199, + 6, + 238, + 128, + 379, + 164, + 132, + 115, + 207, + 23, + 216, + 107, + 396, + 189, + 212, + 123, + 285, + 237, + 289, + 376, + 304, + 72, + 109, + 106, + 201, + 108, + 87, + 183, + 364, + 20, + 288, + 97, + 297, + 17, + 189, + 243, + 282, + 265, + 304, + 311, + 225, + 121, + 190, + 213, + 316, + 273, + 369, + 354, + 241, + 104, + 373, + 211, + 38, + 158, + 168, + 196, + 387, + 194, + 178, + 4, + 37, + 285, + 121, + 395, + 6, + 390, + 4, + 195, + 278, + 294, + 215, + 188, + 236, + 397, + 44, + 259, + 316, + 148, + 350, + 254, + 214, + 364, + 150, + 377, + 110, + 169, + 186, + 53, + 284, + 269, + 374, + 167, + 190, + 120, + 330, + 129, + 379, + 153, + 379, + 344, + 149, + 179, + 79, + 156, + 307, + 265, + 131, + 73, + 204, + 287, + 32, + 119, + 246, + 302, + 110, + 230, + 348, + 385, + 371, + 255, + 174, + 109, + 74, + 108, + 6, + 267, + 270, + 396, + 163, + 19, + 162, + 176, + 66, + 354, + 311, + 330, + 242, + 210, + 111, + 195, + 149, + 377, + 109, + 389, + 329, + 397, + 400, + 233, + 359, + 369, + 306, + 167, + 380, + 84, + 201, + 312, + 66, + 88, + 257, + 237, + 77, + 346, + 156, + 33, + 369, + 130, + 231, + 162, + 15, + 185, + 221, + 52, + 124, + 391, + 324, + 274, + 287, + 150, + 326, + 80, + 359, + 33, + 285, + 205, + 63, + 267, + 193, + 287, + 218, + 301, + 128, + 106, + 97, + 195, + 190, + 353, + 209, + 23, + 50, + 50, + 153, + 298, + 360, + 38, + 231, + 59, + 390, + 277, + 282, + 255, + 321, + 331, + 18, + 292, + 222, + 206, + 371, + 81, + 344, + 182, + 223, + 32, + 97, + 92, + 30, + 101, + 123, + 347, + 136, + 317, + 15, + 288, + 47, + 171, + 142, + 312, + 111, + 297, + 173, + 331, + 216, + 97, + 33, + 189, + 78, + 141, + 130, + 255, + 118, + 340, + 192, + 217, + 204, + 182, + 103, + 6, + 270, + 84, + 82, + 199, + 36, + 11, + 264, + 158, + 57, + 323, + 32, + 246, + 38, + 144, + 398, + 150, + 103, + 254, + 191, + 303, + 249, + 320, + 247, + 123, + 106, + 360, + 151, + 301, + 167, + 320, + 169, + 29, + 150, + 168, + 201, + 2, + 168, + 139, + 58, + 82, + 19, + 369, + 259, + 147, + 369, + 319, + 20, + 132, + 349, + 26, + 130, + 309, + 187, + 87, + 247, + 26, + 189, + 263, + 55, + 286, + 129, + 91, + 202, + 360, + 352, + 196, + 39, + 153, + 241, + 143, + 307, + 105, + 117, + 397, + 288, + 163, + 18, + 339, + 128, + 252, + 364, + 27, + 341, + 191, + 290, + 53, + 370, + 382, + 19, + 131, + 316, + 244, + 59, + 149, + 10, + 269, + 194, + 286, + 183, + 48, + 77, + 273, + 86, + 228, + 169, + 141, + 241, + 133, + 6, + 390, + 205, + 352, + 166, + 339, + 55, + 78, + 72, + 140, + 316, + 349, + 121, + 38, + 154, + 46, + 116, + 134, + 148, + 281, + 335, + 21, + 383, + 395, + 246, + 17, + 15, + 174, + 301, + 127, + 324, + 373, + 304, + 333, + 133, + 393, + 310, + 252, + 287, + 21, + 321, + 254, + 364, + 186, + 196, + 238, + 205, + 158, + 189, + 155, + 341, + 168, + 132, + 295, + 246, + 199, + 161, + 205, + 363, + 260, + 15, + 310, + 1, + 287, + 273, + 334, + 267, + 230, + 21, + 329, + 241, + 251, + 204, + 308, + 111, + 305, + 149, + 257, + 153, + 235, + 335, + 386, + 10, + 181, + 196, + 48, + 383, + 265, + 297, + 209, + 121, + 130, + 176, + 174, + 198, + 210, + 217, + 196, + 362, + 367, + 68, + 119, + 303, + 71, + 121, + 17, + 363, + 50, + 351, + 221, + 271, + 304, + 395, + 343, + 185, + 127, + 226, + 353, + 240, + 134, + 55, + 157, + 47, + 267, + 87, + 105, + 311, + 218, + 203, + 172, + 85, + 86, + 372, + 370, + 244, + 309, + 246, + 48, + 188, + 13, + 55, + 134, + 186, + 354, + 192, + 371, + 10, + 373, + 347, + 178, + 49, + 217, + 92, + 9, + 46, + 352, + 37, + 30, + 102, + 107, + 309, + 150, + 170, + 71, + 13, + 97, + 118, + 369, + 70, + 73, + 162, + 220, + 400, + 320, + 13, + 143, + 217, + 87, + 359, + 287, + 323, + 188, + 257, + 128, + 183, + 243, + 369, + 37, + 73, + 91, + 266, + 239, + 99, + 125, + 55, + 193, + 271, + 331, + 367, + 276, + 19, + 76, + 256, + 289, + 369, + 58, + 20, + 110, + 238, + 198, + 163, + 33, + 154, + 138, + 76, + 10, + 171, + 356, + 200, + 396, + 103, + 50, + 65, + 204, + 330, + 69, + 89, + 298, + 30, + 214, + 40, + 162, + 1, + 135, + 144, + 283, + 360, + 19, + 65, + 175, + 88, + 304, + 227, + 183, + 235, + 357, + 132, + 82, + 315, + 190, + 232, + 12, + 374, + 397, + 259, + 12, + 288, + 302, + 110, + 39, + 166, + 363, + 150, + 248, + 204, + 237, + 15, + 121, + 321, + 383, + 242, + 393, + 55, + 122, + 291, + 14, + 157, + 343, + 247, + 176, + 371, + 322, + 173, + 390, + 53, + 252, + 252, + 390, + 11, + 23, + 102, + 30, + 58, + 170, + 63, + 223, + 77, + 305, + 322, + 356, + 212, + 276, + 244, + 172, + 123, + 380, + 80, + 72, + 369, + 297, + 151, + 357, + 29, + 352, + 235, + 219, + 171, + 398, + 136, + 199, + 274, + 284, + 284, + 116, + 339, + 362, + 355, + 345, + 89, + 228, + 12, + 312, + 368, + 69, + 215, + 77, + 59, + 239, + 20, + 148, + 364, + 241, + 210, + 234, + 302, + 20, + 131, + 317, + 331, + 375, + 102, + 188, + 56, + 253, + 309, + 174, + 382, + 312, + 398, + 132, + 172, + 166, + 27, + 82, + 298, + 369, + 363, + 239, + 341, + 55, + 135, + 247, + 122, + 357, + 244, + 220, + 38, + 66, + 340, + 119, + 195, + 299, + 287, + 126, + 331, + 251, + 35, + 243, + 261, + 117, + 86, + 14, + 396, + 181, + 329, + 254, + 246, + 328, + 1, + 159, + 12, + 262, + 275, + 378, + 335, + 336, + 99, + 202, + 293, + 173, + 39, + 292, + 202, + 135, + 188, + 381, + 267, + 278, + 256, + 364, + 348, + 131, + 109, + 355, + 48, + 184, + 128, + 181, + 149, + 65, + 276, + 39, + 267, + 76, + 221, + 320, + 194, + 351, + 200, + 274, + 192, + 25, + 142, + 272, + 323, + 245, + 3, + 137, + 379, + 85, + 208, + 164, + 370, + 124, + 53, + 138, + 68, + 54, + 134, + 394, + 130, + 258, + 274, + 327, + 293, + 84, + 21, + 213, + 77, + 381, + 296, + 166, + 247, + 266, + 49, + 393, + 247, + 22, + 60, + 319, + 223, + 87, + 191, + 171, + 43, + 398, + 261, + 202, + 54, + 380, + 174, + 270, + 127, + 90, + 143, + 159, + 20, + 26, + 354, + 222, + 337, + 38, + 109, + 210, + 329, + 195, + 167, + 347, + 143, + 270, + 41, + 175, + 78, + 129, + 387, + 25, + 252, + 390, + 76, + 13, + 353, + 259, + 172, + 244, + 283, + 37, + 25, + 364, + 132, + 172, + 240, + 161, + 42, + 265, + 40, + 234, + 265, + 206, + 131, + 73, + 25, + 118, + 153, + 36, + 25, + 171, + 115, + 121, + 256, + 44, + 267, + 69, + 332, + 295, + 382, + 172, + 300, + 398, + 274, + 103, + 190, + 371, + 86, + 20, + 38, + 113, + 37, + 59, + 298, + 140, + 49, + 292, + 174, + 53, + 270, + 161, + 151, + 180, + 197, + 300, + 297, + 332, + 148, + 118, + 216, + 201, + 390, + 33, + 124, + 184, + 291, + 279, + 284, + 149, + 400, + 263, + 285, + 159, + 244, + 260, + 366, + 79, + 64, + 351, + 240, + 21, + 392, + 106, + 110, + 94, + 247, + 237, + 396, + 297, + 82, + 325, + 151, + 26, + 45, + 182, + 153, + 325, + 266, + 154, + 160, + 325, + 147, + 117, + 265, + 308, + 233, + 357, + 91, + 109, + 264, + 258, + 353, + 339, + 255, + 222, + 311, + 10, + 30, + 392, + 143, + 58, + 91, + 294, + 84, + 227, + 362, + 162, + 285, + 308, + 99, + 278, + 176, + 376, + 73, + 91, + 103, + 259, + 292, + 398, + 27, + 4, + 164, + 359, + 154, + 81, + 8, + 389, + 52, + 357, + 76, + 272, + 230, + 118, + 172, + 309, + 248, + 161, + 36, + 8, + 235, + 323, + 234, + 103, + 131, + 358, + 108, + 66, + 349, + 315, + 334, + 260, + 196, + 291, + 233, + 233, + 137, + 109, + 367, + 93, + 131, + 259, + 298, + 29, + 91, + 33, + 141, + 278, + 266, + 213, + 151, + 323, + 75, + 58, + 92, + 183, + 41, + 227, + 92, + 118, + 132, + 37, + 358, + 286, + 322, + 62, + 162, + 321, + 5, + 187, + 330, + 256, + 341, + 264, + 290, + 157, + 106, + 24, + 254, + 351, + 151, + 360, + 247, + 71, + 366, + 93, + 203, + 160, + 243, + 170, + 311, + 225, + 372, + 182, + 351, + 373, + 57, + 36, + 146, + 201, + 89, + 115, + 105, + 160, + 271, + 109, + 139, + 296, + 398, + 272, + 279, + 347, + 318, + 386, + 179, + 357, + 325, + 234, + 358, + 58, + 352, + 262, + 397, + 400, + 256, + 391, + 389, + 119, + 169, + 296, + 179, + 335, + 239, + 44, + 152, + 211, + 154, + 130, + 134, + 329, + 345, + 131, + 364, + 237, + 177, + 139, + 108, + 243, + 212, + 344, + 15, + 36, + 267, + 269, + 145, + 122, + 152, + 386, + 291, + 205, + 16, + 214, + 34, + 348, + 364, + 226, + 4, + 191, + 179, + 124, + 41, + 319, + 173, + 389, + 332, + 161, + 114, + 249, + 93, + 398, + 194, + 193, + 122, + 313, + 366, + 272, + 69, + 350, + 80, + 391, + 102, + 215, + 210, + 73, + 67, + 356, + 222, + 17, + 293, + 196, + 368, + 230, + 209, + 348, + 349, + 150, + 139, + 85, + 170, + 170, + 93, + 240, + 112, + 153, + 304, + 126, + 167, + 226, + 304, + 247, + 77, + 173, + 322, + 153, + 65, + 178, + 202, + 130, + 252, + 387, + 254, + 147, + 339, + 230, + 236, + 143, + 243, + 137, + 154, + 286, + 350, + 177, + 354, + 39, + 83, + 105, + 46, + 172, + 311, + 318, + 149, + 102, + 16, + 205, + 73, + 349, + 295, + 278, + 52, + 379, + 355, + 362, + 399, + 378, + 167, + 131, + 127, + 82, + 227, + 385, + 177, + 388, + 320, + 308, + 194, + 141, + 6, + 103, + 96, + 183, + 302, + 144, + 238, + 210, + 400, + 12, + 30, + 103, + 156, + 127, + 203, + 351, + 32, + 177, + 3, + 228, + 182, + 321, + 386, + 114, + 301, + 48, + 201, + 388, + 157, + 360, + 207, + 338, + 5, + 200, + 256, + 297, + 155, + 210, + 5, + 23, + 117, + 225, + 319, + 230, + 153, + 66, + 316, + 381, + 295, + 165, + 151, + 217, + 32, + 171, + 81, + 135, + 388, + 12, + 382, + 251, + 86, + 204, + 154, + 87, + 105, + 231, + 198, + 170, + 203, + 129, + 309, + 396, + 91, + 93, + 306, + 91, + 395, + 326, + 369, + 26, + 223, + 330, + 328, + 123, + 272, + 297, + 152, + 150, + 38, + 212, + 316, + 88, + 1, + 28, + 115, + 76, + 73, + 102, + 183, + 94, + 100, + 120, + 264, + 173, + 166, + 354, + 299, + 49, + 354, + 398, + 19, + 129, + 336, + 359, + 73, + 129, + 383, + 189, + 304, + 70, + 334, + 373, + 24, + 23, + 311, + 348, + 349, + 237, + 279, + 78, + 298, + 154, + 337, + 229, + 252, + 226, + 41, + 28, + 291, + 236, + 41, + 338, + 160, + 49, + 58, + 295, + 268, + 75, + 45, + 75, + 211, + 378, + 224, + 371, + 280, + 42, + 256, + 127, + 44, + 244, + 52, + 322, + 338, + 100, + 328, + 177, + 126, + 219, + 214, + 2, + 227, + 349, + 145, + 341, + 67, + 249, + 54, + 285, + 112, + 26, + 153, + 252, + 280, + 136, + 22, + 324, + 240, + 313, + 278, + 299, + 217, + 223, + 292, + 239, + 324, + 284, + 102, + 306, + 133, + 121, + 266, + 119, + 327, + 204, + 339, + 193, + 51, + 277, + 364, + 250, + 29, + 365, + 49, + 100, + 217, + 379, + 78, + 252, + 364, + 155, + 372, + 392, + 374, + 255, + 223, + 161, + 60, + 109, + 27, + 180, + 26, + 203, + 202, + 332, + 38, + 77, + 136, + 323, + 373, + 186, + 109, + 70, + 13, + 197, + 354, + 78, + 232, + 245, + 219, + 272, + 329, + 144, + 158, + 154, + 87, + 376, + 121, + 337, + 178, + 12, + 397, + 198, + 65, + 206, + 208, + 242, + 56, + 262, + 193, + 288, + 342, + 75, + 89, + 195, + 167, + 210, + 255, + 274, + 157, + 374, + 205, + 80, + 98, + 395, + 382, + 349, + 288, + 282, + 217, + 362, + 124, + 238, + 221, + 164, + 246, + 137, + 1, + 65, + 216, + 110, + 92, + 227, + 151, + 286, + 351, + 209, + 210, + 344, + 343, + 231, + 235, + 3, + 222, + 189, + 285, + 230, + 220, + 372, + 214, + 335, + 383, + 145, + 338, + 234, + 395, + 115, + 75, + 329, + 16, + 161, + 179, + 72, + 62, + 139, + 55, + 1, + 319, + 339, + 303, + 336, + 165, + 3, + 394, + 16, + 189, + 318, + 310, + 109, + 210, + 162, + 17, + 122, + 363, + 17, + 209, + 166, + 311, + 393, + 350, + 313, + 26, + 159, + 172, + 379, + 163, + 234, + 50, + 93, + 188, + 253, + 34, + 248, + 60, + 359, + 138, + 370, + 180, + 71, + 175, + 113, + 270, + 259, + 30, + 198, + 315, + 33, + 220, + 75, + 292, + 151, + 171, + 227, + 22, + 198, + 215, + 81, + 208, + 37, + 6, + 127, + 281, + 101, + 357, + 204, + 297, + 162, + 30, + 312, + 165, + 112, + 198, + 254, + 362, + 400, + 119, + 293, + 306, + 26, + 394, + 227, + 206, + 86, + 333, + 324, + 260, + 252, + 349, + 358, + 36, + 180, + 103, + 244, + 118, + 391, + 367, + 6, + 210, + 17, + 143, + 253, + 315, + 177, + 334, + 228, + 396, + 121, + 23, + 147, + 127, + 5, + 124, + 269, + 166, + 355, + 319, + 49, + 228, + 200, + 211, + 389, + 391, + 118, + 196, + 85, + 301, + 288, + 206, + 135, + 233, + 89, + 306, + 9, + 7, + 394, + 348, + 160, + 246, + 364, + 111, + 64, + 286, + 169, + 34, + 52, + 38, + 73, + 76, + 211, + 374, + 91, + 109, + 124, + 45, + 77, + 18, + 164, + 329, + 214, + 388, + 388, + 15, + 304, + 94, + 46, + 362, + 26, + 110, + 124, + 57, + 356, + 209, + 207, + 232, + 359, + 251, + 215, + 52, + 126, + 170, + 169, + 92, + 166, + 372, + 365, + 88, + 259, + 328, + 233, + 397, + 214, + 13, + 255, + 273, + 278, + 229, + 307, + 197, + 379, + 130, + 225, + 43, + 395, + 293, + 185, + 45, + 98, + 258, + 217, + 206, + 341, + 335, + 86, + 172, + 373, + 147, + 120, + 65, + 293, + 299, + 377, + 358, + 110, + 6, + 310, + 270, + 167, + 37, + 92, + 386, + 353, + 171, + 113, + 137, + 42, + 358, + 224, + 103, + 252, + 195, + 140, + 103, + 56, + 153, + 353, + 123, + 376, + 144, + 145, + 385, + 150, + 21, + 70, + 291, + 204, + 299, + 255, + 105, + 116, + 82, + 306, + 396, + 169, + 245, + 364, + 107, + 102, + 398, + 212, + 185, + 89, + 272, + 13, + 200, + 171, + 299, + 45, + 245, + 194, + 318, + 165, + 116, + 75, + 37, + 148, + 238, + 174, + 348, + 257, + 299, + 90, + 334, + 14, + 33, + 18, + 247, + 26, + 208, + 289, + 53, + 206, + 230, + 111, + 330, + 361, + 73, + 150, + 314, + 141, + 39, + 173, + 388, + 309, + 128, + 245, + 280, + 24, + 185, + 320, + 363, + 341, + 329, + 41, + 190, + 298, + 89, + 23, + 12, + 62, + 83, + 185, + 249, + 36, + 367, + 308, + 32, + 228, + 360, + 87, + 335, + 332, + 390, + 87, + 165, + 175, + 292, + 191, + 112, + 73, + 154, + 1, + 314, + 136, + 66, + 30, + 142, + 389, + 57, + 181, + 388, + 32, + 154, + 97, + 320, + 321, + 4, + 109, + 384, + 123, + 163, + 284, + 206, + 334, + 29, + 357, + 226, + 67, + 120, + 108, + 27, + 376, + 14, + 16, + 126, + 142, + 329, + 108, + 276, + 40, + 284, + 230, + 136, + 39, + 260, + 25, + 151, + 282, + 142, + 390, + 332, + 380, + 384, + 346, + 117, + 186, + 146, + 161, + 248, + 191, + 275, + 391, + 182, + 9, + 164, + 87, + 319, + 99, + 280, + 357, + 59, + 339, + 323, + 325, + 5, + 214, + 208, + 275, + 271, + 159, + 369, + 238, + 57, + 15, + 8, + 384, + 112, + 382, + 235, + 131, + 128, + 371, + 307, + 380, + 254, + 363, + 54, + 353, + 171, + 82, + 247, + 13, + 265, + 367, + 287, + 238, + 140, + 229, + 132, + 323, + 34, + 268, + 318, + 390, + 86, + 112, + 274, + 86, + 319, + 83, + 308, + 349, + 113, + 156, + 365, + 173, + 254, + 28, + 256, + 349, + 34, + 316, + 111, + 287, + 25, + 232, + 323, + 163, + 142, + 162, + 374, + 4, + 78, + 78, + 39, + 275, + 67, + 236, + 354, + 324, + 21, + 276, + 43, + 245, + 276, + 280, + 40, + 160, + 298, + 283, + 312, + 295, + 336, + 122, + 54, + 311, + 194, + 382, + 208, + 99, + 173, + 286, + 41, + 385, + 181, + 220, + 378, + 198, + 354, + 223, + 374, + 343, + 57, + 278, + 286, + 363, + 344, + 277, + 284, + 69, + 193, + 204, + 304, + 107, + 276, + 184, + 319, + 136, + 146, + 70, + 54, + 337, + 115, + 165, + 104, + 264, + 8, + 349, + 58, + 269, + 234, + 6, + 38, + 268, + 356, + 104, + 88, + 169, + 105, + 136, + 144, + 36, + 365, + 100, + 220, + 197, + 344, + 276, + 61, + 172, + 397, + 375, + 254, + 390, + 83, + 364, + 325, + 29, + 33, + 60, + 319, + 384, + 60, + 354, + 322, + 122, + 15, + 369, + 297, + 212, + 186, + 295, + 180, + 72, + 132, + 168, + 136, + 129, + 20, + 388, + 90, + 306, + 184, + 53, + 351, + 85, + 84, + 242, + 346, + 252, + 199, + 123, + 250, + 282, + 380, + 244, + 149, + 86, + 262, + 75, + 325, + 384, + 335, + 272, + 322, + 372, + 256, + 355, + 91, + 241, + 112, + 117, + 320, + 272, + 395, + 256, + 141, + 149, + 30, + 22, + 162, + 285, + 247, + 35, + 69, + 309, + 363, + 144, + 301, + 119, + 322, + 399, + 395, + 360, + 75, + 364, + 326, + 305, + 50, + 46, + 307, + 27, + 187, + 22, + 144, + 379, + 190, + 319, + 288, + 183, + 97, + 44, + 380, + 144, + 181, + 197, + 266, + 79, + 399, + 193, + 82, + 105, + 374, + 113, + 200, + 52, + 137, + 325, + 156, + 331, + 178, + 381, + 141, + 271, + 11, + 354, + 48, + 212, + 199, + 24, + 292, + 8, + 306, + 24, + 44, + 193, + 75, + 22, + 119, + 86, + 98, + 192, + 143, + 220, + 135, + 267, + 13, + 126, + 319, + 207, + 31, + 102, + 196, + 325, + 281, + 244, + 142, + 207, + 67, + 225, + 140, + 370, + 216, + 360, + 20, + 88, + 93, + 150, + 51, + 114, + 148, + 237, + 117, + 331, + 215, + 316, + 24, + 195, + 325, + 257, + 240, + 313, + 19, + 200, + 369, + 58, + 201, + 217, + 351, + 136, + 185, + 205, + 327, + 251, + 121, + 17, + 183, + 389, + 377, + 321, + 191, + 98, + 399, + 73, + 125, + 391, + 32, + 57, + 300, + 187, + 399, + 308, + 110, + 60, + 2, + 264, + 367, + 364, + 338, + 298, + 249, + 1, + 360, + 204, + 12, + 344, + 57, + 190, + 171, + 110, + 92, + 210, + 128, + 321, + 215, + 150, + 66, + 184, + 139, + 149, + 221, + 130, + 364, + 39, + 88, + 200, + 342, + 99, + 278, + 188, + 231, + 378, + 373, + 308, + 319, + 382, + 167, + 84, + 242, + 155, + 139, + 150, + 155, + 18, + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, 1, - 0, - 0, - 0, - 2, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, 1, - 0, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, 2, - 0, - 0, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, 2, - 0, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, 1, - 0, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, 1, - 0, - 0, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, 1, - 0, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, 2, - 0, - 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, 1, - 0, - 1, - 1, - 1, - 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, 1, - 0, - 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, 1, - 2, - 0, - 0, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, 1, - 0, - 2, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, 1, - 0, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, 1, - 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, 2, - 0, - 1, - 0, - 2 - ], - "values": [ + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, 319, - 100, - 60, - 386, - 125, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, 236, - 176, - 262, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, 181, - 268, - 128, - 397, - 236, - 55, - 301, - 383, - 399, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, 188, - 151, - 18, - 221, - 46, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, 106, - 174, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, 312, - 185, - 75, - 174, - 141, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, 279, - 47, - 159, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, 162, - 156, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, 90, - 40, - 320, - 76, - 369, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, 352, - 158, - 247, - 82, - 368, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, 24, - 41, - 307, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, 273, - 207, - 16, - 121, - 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, + 87, 326, - 16, - 252, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, 171, - 106, - 66, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, 374, - 288, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, 67, - 322, - 211, - 54, - 86, - 222, - 190, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, 30, - 215, - 150, - 72, - 232, - 317, - 86, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, 267, - 232, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57 + 238, + 161, + 146, + 341, + 351 ] } diff --git a/calyx-py/test/correctness/sdn.data b/calyx-py/test/correctness/sdn.data index b4aca847b..3fbb87182 100644 --- a/calyx-py/test/correctness/sdn.data +++ b/calyx-py/test/correctness/sdn.data @@ -100,6 +100,19906 @@ 2, 0, 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, 0 ], "format": { @@ -110,106 +20010,20006 @@ }, "values": { "data": [ + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, + 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, + 273, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, + 267, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, + 249, + 238, + 161, + 146, + 341, + 351, + 152, + 60, + 318, + 340, + 240, + 326, + 163, + 198, + 230, + 170, + 331, + 12, + 194, + 122, + 125, + 386, + 398, + 314, + 291, + 337, + 398, + 4, + 25, + 143, + 367, + 208, + 383, + 171, + 375, + 147, + 63, + 292, + 157, + 314, + 303, + 2, + 370, + 117, + 144, + 247, + 35, + 38, + 267, + 7, + 81, + 82, + 338, + 123, + 180, + 207, + 319, + 259, + 129, + 329, + 281, + 384, + 283, + 217, + 223, + 394, + 72, + 215, + 304, + 325, + 383, + 364, + 180, + 3, + 158, + 105, + 181, + 209, + 400, + 344, + 62, + 233, + 155, + 225, + 174, + 282, + 225, + 87, + 168, + 184, + 60, + 104, + 231, + 344, + 77, + 69, + 63, + 106, + 63, + 102, + 255, + 363, + 126, + 134, + 212, + 319, + 336, + 32, + 164, + 96, + 87, + 118, + 196, + 36, + 206, + 333, + 315, + 394, + 201, + 99, + 199, + 126, + 113, + 229, + 155, + 375, + 114, + 16, + 74, + 181, + 347, + 265, + 105, + 54, + 121, + 305, + 297, + 179, + 204, + 373, + 377, + 392, + 242, + 322, + 193, + 228, + 385, + 119, + 79, + 305, + 90, + 243, + 332, + 285, + 7, + 37, + 8, + 30, + 294, + 267, + 112, + 205, + 149, + 165, + 196, + 189, + 78, + 346, + 385, + 136, + 112, + 315, + 375, + 376, + 284, + 213, + 202, + 319, + 18, + 121, + 62, + 140, + 232, + 25, + 385, + 369, + 271, + 345, + 321, + 14, + 352, + 83, + 163, + 43, + 257, + 213, + 8, + 176, + 339, + 91, + 101, + 332, + 334, + 248, + 360, + 49, + 16, + 313, + 352, + 88, + 328, + 180, + 294, + 6, + 51, + 334, + 40, + 290, + 69, + 144, + 316, + 340, + 380, + 13, + 167, + 356, + 317, + 379, + 285, + 321, + 370, + 378, + 97, + 187, + 14, + 340, + 236, + 14, + 157, + 202, + 197, + 126, + 349, + 254, + 392, + 288, + 171, + 46, + 7, + 234, + 222, + 41, + 199, + 153, + 82, + 270, + 317, + 323, + 378, + 320, + 392, + 346, + 299, + 271, + 124, + 201, + 375, + 269, + 52, + 246, + 392, + 34, + 298, + 70, + 272, + 78, + 232, + 86, + 338, + 93, + 127, + 218, + 227, + 113, + 39, + 203, + 66, + 51, + 306, + 89, + 242, + 115, + 133, + 226, + 278, + 266, + 135, + 202, + 127, + 314, + 156, + 32, + 26, + 265, + 222, + 110, + 361, + 275, + 361, + 343, + 63, + 225, + 55, + 76, + 386, + 82, + 112, + 10, + 85, + 174, + 310, + 68, + 201, + 344, + 353, + 94, + 122, + 309, + 392, + 396, + 67, + 112, + 225, + 120, + 374, + 119, + 38, + 40, + 17, + 303, + 201, + 1, + 282, + 328, + 277, + 330, + 393, + 90, + 298, + 199, + 21, + 196, + 363, + 244, + 396, + 36, + 336, + 245, + 313, + 158, + 59, + 376, + 155, + 157, + 28, + 205, + 314, + 192, + 342, + 181, + 325, + 388, + 78, + 399, + 343, + 11, + 52, + 400, + 70, + 47, + 162, + 42, + 15, + 209, + 228, + 330, + 305, + 190, + 285, + 389, + 204, + 221, + 289, + 159, + 377, + 148, + 186, + 87, + 188, + 344, + 116, + 320, + 400, + 223, + 70, + 311, + 20, + 166, + 145, + 189, + 45, + 205, + 122, + 245, + 393, + 340, + 230, + 64, + 279, + 170, + 350, + 154, + 206, + 319, + 370, + 316, + 262, + 326, + 396, + 317, + 329, + 262, + 327, + 282, + 197, + 80, + 299, + 353, + 321, + 124, + 121, + 11, + 245, + 317, + 368, + 189, + 221, + 322, + 382, + 159, + 104, + 135, + 155, + 325, + 241, + 183, + 214, + 85, + 211, + 170, + 168, + 327, + 389, + 94, + 157, + 235, + 385, + 335, + 271, + 236, + 22, + 290, + 220, + 163, + 391, + 224, + 140, + 116, + 268, + 309, + 126, + 89, + 220, + 187, + 252, + 277, + 111, + 263, + 297, + 262, + 92, + 51, + 89, + 228, + 400, + 109, + 156, + 233, + 131, + 115, + 394, + 210, + 161, + 243, + 66, + 150, + 359, + 213, + 368, + 98, + 214, + 335, + 332, + 220, + 26, + 209, + 44, + 280, + 282, + 386, + 24, + 213, + 197, + 352, + 5, + 10, + 42, + 2, + 101, + 36, + 208, + 137, + 247, + 397, + 162, + 344, + 26, + 366, + 25, + 271, + 218, + 188, + 75, + 11, + 24, + 45, + 129, + 384, + 134, + 326, + 23, + 193, + 291, + 15, + 62, + 168, + 364, + 345, + 208, + 291, + 112, + 141, + 202, + 17, + 270, + 154, + 61, + 104, + 19, + 98, + 95, + 202, + 225, + 42, + 244, + 15, + 149, + 171, + 270, + 120, + 341, + 302, + 393, + 275, + 34, + 226, + 152, + 94, + 199, + 392, + 251, + 188, + 340, + 389, + 393, + 216, + 87, + 111, + 359, + 114, + 46, + 165, + 333, + 266, + 358, + 74, + 363, + 134, + 168, + 388, + 145, + 184, + 366, + 376, + 89, + 277, + 259, + 374, + 25, + 346, + 107, + 139, + 42, + 212, + 208, + 129, + 319, + 298, + 275, + 58, + 376, + 93, + 207, + 351, + 268, + 282, + 213, + 125, + 81, + 243, + 238, + 246, + 347, + 188, + 166, + 126, + 110, + 214, + 265, + 234, + 395, + 343, + 119, + 108, + 303, + 4, + 306, + 307, + 196, + 86, + 345, + 112, + 81, + 390, + 297, + 80, + 104, + 212, + 234, + 132, + 316, + 136, + 102, + 83, + 276, + 393, + 29, + 164, + 334, + 386, + 171, + 242, + 246, + 65, + 175, + 333, + 73, + 54, + 173, + 138, + 203, + 260, + 381, + 163, + 196, + 283, + 123, + 169, + 106, + 316, + 156, + 222, + 126, + 115, + 299, + 391, + 251, + 391, + 246, + 330, + 195, + 263, + 238, + 242, + 197, + 62, + 71, + 140, + 312, + 282, + 76, + 105, + 219, + 368, + 240, + 15, + 41, + 53, + 135, + 134, + 207, + 371, + 388, + 82, + 311, + 184, + 147, + 11, + 86, + 293, + 279, + 58, + 258, + 400, + 321, + 330, + 100, + 182, + 28, + 50, + 31, + 166, + 163, + 94, + 172, + 206, + 47, + 191, + 242, + 112, + 313, + 75, + 362, + 187, + 116, + 295, + 332, + 387, + 23, + 183, + 296, + 65, + 228, + 251, + 289, + 161, + 340, + 274, + 214, + 56, + 75, + 36, + 379, + 23, + 211, + 329, + 71, + 80, + 350, + 86, + 107, + 174, + 104, + 367, + 80, + 269, + 273, + 273, + 46, + 331, + 374, + 154, + 135, + 330, + 41, + 82, + 206, + 348, + 118, + 61, + 36, + 315, + 189, + 371, + 218, + 223, + 130, + 1, + 18, + 113, + 73, + 134, + 118, + 17, + 33, + 15, + 266, + 379, + 145, + 185, + 379, + 180, + 75, + 208, + 21, + 327, + 163, + 359, + 193, + 286, + 354, + 205, + 102, + 336, + 394, + 133, + 89, + 178, + 84, + 9, + 151, + 71, + 261, + 283, + 207, + 379, + 99, + 155, + 108, + 374, + 96, + 331, + 363, + 146, + 115, + 246, + 342, + 327, + 176, + 358, + 234, + 104, + 158, + 351, + 350, + 339, + 114, + 88, + 202, + 349, + 217, + 277, + 196, + 16, + 268, + 168, + 202, + 129, + 175, + 22, + 323, + 105, + 143, + 241, + 30, + 215, + 172, + 45, + 22, + 284, + 86, + 20, + 374, + 160, + 244, + 392, + 265, + 319, + 86, + 347, + 188, + 130, + 179, + 136, + 27, + 189, + 288, + 234, + 253, + 19, + 217, + 265, + 127, + 316, + 161, + 37, + 84, + 376, + 382, + 181, + 195, + 85, + 13, + 283, + 111, + 238, + 385, + 291, + 394, + 154, + 80, + 140, + 292, + 132, + 56, + 170, + 209, + 327, + 159, + 216, + 87, + 63, + 123, + 239, + 27, + 184, + 340, + 164, + 177, + 296, + 332, + 340, + 164, + 21, + 87, + 256, + 398, + 143, + 236, + 85, + 359, + 114, + 144, + 356, + 295, + 148, + 43, + 204, + 212, + 48, + 156, + 260, + 287, + 173, + 126, + 147, + 354, + 142, + 274, + 66, + 398, + 150, + 274, + 30, + 342, + 28, + 65, + 177, + 363, + 283, + 268, + 199, + 372, + 272, + 176, + 250, + 46, + 344, + 224, + 292, + 346, + 112, + 73, + 341, + 390, + 344, + 43, + 276, + 17, + 327, + 89, + 39, + 42, + 299, + 202, + 289, + 357, + 288, + 122, + 64, + 6, + 54, + 154, + 235, + 336, + 19, + 311, + 41, + 192, + 303, + 347, + 387, + 201, + 132, + 325, + 273, + 202, + 162, + 214, + 90, + 78, + 118, + 273, + 121, + 225, + 36, + 126, + 370, + 258, + 315, + 288, + 323, + 229, + 52, + 351, + 379, + 128, + 391, + 339, + 138, + 73, + 266, + 393, + 99, + 74, + 378, + 109, + 229, + 293, + 366, + 355, + 219, + 377, + 219, + 246, + 353, + 226, + 241, + 375, + 39, + 229, + 188, + 275, + 240, + 115, + 234, + 352, + 22, + 306, + 302, + 317, + 221, + 224, + 140, + 219, + 155, + 166, + 343, + 313, + 326, + 99, + 168, + 79, + 149, + 57, + 144, + 228, + 28, + 38, + 352, + 112, + 16, + 350, + 66, + 158, + 25, + 292, + 376, + 285, + 163, + 43, + 214, + 395, + 15, + 122, + 365, + 4, + 308, + 16, + 13, + 205, + 256, + 335, + 252, + 301, + 149, + 170, + 206, + 121, + 397, + 387, + 174, + 348, + 72, + 233, + 218, + 254, + 139, + 271, + 101, + 321, + 188, + 366, + 86, + 265, + 182, + 350, + 202, + 393, + 160, + 134, + 312, + 206, + 112, + 28, + 301, + 374, + 312, + 104, + 262, + 100, + 104, + 276, + 199, + 90, + 232, + 124, + 363, + 26, + 269, + 188, + 227, + 344, + 380, + 35, + 67, + 161, + 125, + 386, + 358, + 289, + 276, + 25, + 398, + 105, + 334, + 360, + 273, + 293, + 50, + 350, + 94, + 326, + 23, + 380, + 349, + 123, + 132, + 283, + 121, + 211, + 327, + 186, + 146, + 362, + 307, + 31, + 74, + 338, + 177, + 173, + 132, + 336, + 35, + 273, + 46, + 265, + 110, + 262, + 229, + 197, + 166, + 122, + 13, + 289, + 312, + 229, + 58, + 347, + 2, + 49, + 303, + 195, + 69, + 312, + 223, + 319, + 278, + 151, + 97, + 216, + 197, + 295, + 84, + 204, + 179, + 157, + 380, + 224, + 93, + 58, + 287, + 378, + 56, + 37, + 168, + 370, + 33, + 4, + 362, + 347, + 132, + 351, + 163, + 207, + 109, + 214, + 170, + 327, + 383, + 218, + 64, + 105, + 345, + 212, + 318, + 395, + 384, + 237, + 387, + 83, + 203, + 55, + 163, + 226, + 131, + 203, + 260, + 132, + 214, + 16, + 210, + 239, + 25, + 280, + 295, + 363, + 315, + 326, + 274, + 211, + 272, + 202, + 239, + 63, + 357, + 366, + 181, + 267, + 170, + 378, + 318, + 195, + 178, + 97, + 56, + 354, + 96, + 212, + 376, + 138, + 229, + 261, + 32, + 49, + 256, + 52, + 190, + 227, + 164, + 342, + 228, + 393, + 290, + 24, + 95, + 385, + 281, + 304, + 130, + 235, + 150, + 10, + 297, + 396, + 61, + 235, + 87, + 116, + 189, + 5, + 231, + 45, + 303, + 297, + 347, + 271, + 37, + 195, + 223, + 270, + 309, + 247, + 247, + 203, + 294, + 307, + 238, + 313, + 41, + 323, + 290, + 84, + 391, + 368, + 160, + 236, + 337, + 61, + 85, + 141, + 54, + 48, + 62, + 168, + 245, + 163, + 66, + 323, + 173, + 145, + 184, + 198, + 154, + 347, + 366, + 284, + 257, + 32, + 281, + 344, + 387, + 18, + 196, + 65, + 52, + 233, + 388, + 35, + 68, + 362, + 78, + 275, + 84, + 59, + 172, + 13, + 283, + 218, + 14, + 206, + 203, + 100, + 234, + 376, + 364, + 240, + 82, + 101, + 336, + 1, + 182, + 354, + 385, + 365, + 154, + 390, + 302, + 239, + 46, + 345, + 353, + 107, + 329, + 292, + 145, + 300, + 135, + 320, + 342, + 107, + 349, + 120, + 233, + 55, + 189, + 390, + 201, + 315, + 289, + 310, + 291, + 315, + 196, + 15, + 92, + 326, + 89, + 196, + 286, + 19, + 265, + 370, + 394, + 67, + 138, + 281, + 98, + 201, + 309, + 154, + 37, + 266, + 32, + 345, + 130, + 98, + 250, + 263, + 24, + 315, + 326, + 375, + 362, + 347, + 85, + 50, + 241, + 344, + 67, + 241, + 302, + 162, + 377, + 179, + 80, + 73, + 155, + 75, + 55, + 35, + 273, + 175, + 370, + 234, + 273, + 57, + 91, + 74, + 8, + 44, + 28, + 118, + 356, + 190, + 359, + 243, + 388, + 273, + 381, + 332, + 12, + 106, + 250, + 155, + 70, + 361, + 15, + 124, + 321, + 337, + 44, + 353, + 35, + 247, + 22, + 84, + 301, + 297, + 132, + 225, + 66, + 105, + 348, + 133, + 212, + 152, + 328, + 79, + 49, + 223, + 121, + 74, + 126, + 320, + 67, + 374, + 228, + 173, + 17, + 236, + 12, + 117, + 218, + 192, + 346, + 370, + 138, + 266, + 270, + 391, + 167, + 132, + 233, + 207, + 162, + 65, + 251, + 14, + 173, + 72, + 191, + 165, + 38, + 8, + 204, + 204, + 376, + 203, + 105, + 182, + 336, + 121, + 20, + 69, + 275, + 254, + 40, + 149, + 343, + 197, + 262, + 21, + 259, + 330, + 246, + 383, + 43, + 325, + 46, + 40, + 338, + 262, + 116, + 75, + 266, + 2, + 389, + 90, + 29, + 101, + 244, + 363, + 58, + 3, + 68, + 137, + 195, + 344, + 105, + 113, + 378, + 19, + 107, + 208, + 83, + 250, + 201, + 238, + 283, + 135, + 372, + 74, + 200, + 159, + 216, + 334, + 29, + 108, + 156, + 303, + 300, + 55, + 37, + 366, + 225, + 323, + 181, + 217, + 388, + 143, + 313, + 369, + 81, + 389, + 128, + 139, + 179, + 222, + 110, + 154, + 166, + 5, + 95, + 294, + 339, + 277, + 171, + 320, + 105, + 216, + 374, + 266, + 8, + 78, + 296, + 119, + 367, + 95, + 357, + 180, + 175, + 43, + 7, + 15, + 348, + 26, + 116, + 327, + 321, + 19, + 297, + 62, + 377, + 112, + 175, + 240, + 1, + 178, + 3, + 90, + 149, + 377, + 103, + 296, + 40, + 22, + 43, + 232, + 212, + 343, + 228, + 276, + 68, + 140, + 112, + 314, + 72, + 7, + 274, + 163, + 252, + 153, + 388, + 304, + 218, + 73, + 107, + 246, + 145, + 200, + 211, + 22, + 85, + 197, + 326, + 200, + 373, + 310, + 263, + 86, + 13, + 388, + 309, + 246, + 248, + 305, + 388, + 304, + 165, + 221, + 303, + 397, + 56, + 245, + 246, + 48, + 87, + 266, + 108, + 56, + 144, + 140, + 93, + 245, + 256, + 97, + 226, + 273, + 347, + 165, + 212, + 228, + 207, + 169, + 305, + 371, + 186, + 334, + 396, + 244, + 100, + 352, + 358, + 326, + 339, + 270, + 396, + 301, + 284, + 11, + 177, + 191, + 126, + 68, + 227, + 33, + 366, + 298, + 359, + 193, + 122, + 393, + 122, + 203, + 30, + 303, + 194, + 392, + 151, + 366, + 31, + 293, + 174, + 53, + 26, + 218, + 85, + 136, + 306, + 113, + 10, + 61, + 173, + 48, + 56, + 97, + 70, + 146, + 399, + 283, + 50, + 278, + 366, + 185, + 35, + 323, + 13, + 344, + 144, + 141, + 33, + 279, + 89, + 383, + 267, + 101, + 396, + 337, + 247, + 341, + 224, + 376, + 360, + 9, + 196, + 136, + 104, + 376, + 263, + 383, + 3, + 124, + 314, + 136, + 23, + 46, + 346, + 318, + 338, + 249, + 270, + 205, + 145, + 179, + 232, + 245, + 228, + 230, + 50, + 263, + 119, + 7, + 240, + 2, + 149, + 158, + 120, + 175, + 163, + 63, + 25, + 16, + 263, + 219, + 340, + 339, + 186, + 128, + 29, + 354, + 195, + 387, + 145, + 121, + 184, + 268, + 344, + 9, + 87, + 242, + 355, + 309, + 99, + 220, + 131, + 247, + 82, + 101, + 373, + 220, + 119, + 373, + 332, + 125, + 264, + 247, + 118, + 307, + 305, + 303, + 348, + 275, + 60, + 325, + 154, + 189, + 374, + 374, + 58, + 365, + 353, + 257, + 372, + 315, + 352, + 259, + 312, + 395, + 320, + 181, + 125, + 206, + 195, + 161, + 322, + 389, + 398, + 113, + 77, + 376, + 162, + 8, + 350, + 14, + 298, + 48, + 217, + 217, + 33, + 86, + 224, + 239, + 206, + 35, + 321, + 330, + 287, + 89, + 7, + 134, + 191, + 149, + 274, + 228, + 229, + 108, + 372, + 313, + 237, + 211, + 178, + 101, + 396, + 55, + 86, + 137, + 61, + 118, + 67, + 336, + 327, + 88, + 317, + 32, + 385, + 275, + 164, + 331, + 286, + 49, + 66, + 242, + 20, + 141, + 11, + 313, + 313, + 2, + 324, + 128, + 172, + 282, + 199, + 384, + 313, + 148, + 73, + 200, + 366, + 75, + 260, + 133, + 299, + 269, + 29, + 399, + 355, + 358, + 174, + 102, + 169, + 194, + 343, + 174, + 170, + 171, + 80, + 395, + 329, + 147, + 64, + 328, + 372, + 364, + 228, + 357, + 151, + 85, + 95, + 185, + 345, + 307, + 300, + 312, + 237, + 125, + 132, + 164, + 392, + 70, + 400, + 67, + 126, + 155, + 317, + 57, + 54, + 276, + 146, + 184, + 137, + 107, + 376, + 362, + 6, + 95, + 273, + 327, + 100, + 110, + 352, + 90, + 144, + 288, + 323, + 126, + 200, + 400, + 220, + 59, + 34, + 289, + 354, + 118, + 241, + 148, + 199, + 322, + 40, + 312, + 140, + 77, + 112, + 223, + 140, + 13, + 1, + 185, + 388, + 24, + 131, + 398, + 318, + 280, + 63, + 175, + 47, + 134, + 327, + 206, + 52, + 48, + 64, + 194, + 178, + 377, + 55, + 55, + 107, + 265, + 338, + 263, + 27, + 92, + 373, + 357, + 295, + 207, + 324, + 133, + 119, + 151, + 175, + 2, + 77, + 288, + 151, + 116, + 168, + 371, + 245, + 20, + 142, + 174, + 112, + 203, + 98, + 209, + 73, + 328, + 15, + 33, + 40, + 377, + 124, + 370, + 396, + 25, + 215, + 368, + 135, + 133, + 151, + 282, + 80, + 304, + 280, + 67, + 327, + 177, + 333, + 178, + 151, + 146, + 56, + 76, + 312, + 186, + 212, + 132, + 31, + 296, + 141, + 60, + 75, + 209, + 382, + 49, + 179, + 389, + 106, + 146, + 103, + 158, + 300, + 91, + 239, + 221, + 305, + 164, + 148, + 351, + 270, + 121, + 129, + 383, + 296, + 375, + 49, + 259, + 231, + 272, + 275, + 352, + 222, + 339, + 299, + 54, + 20, + 348, + 80, + 332, + 342, + 227, + 27, + 286, + 243, + 162, + 147, + 164, + 1, + 259, + 222, + 398, + 371, + 322, + 178, + 327, + 33, + 319, + 175, + 272, + 351, + 245, + 247, + 55, + 154, + 325, + 300, + 344, + 8, + 207, + 79, + 138, + 76, + 159, + 115, + 3, + 166, + 336, + 235, + 300, + 344, + 89, + 276, + 110, + 117, + 37, + 52, + 370, + 20, + 345, + 290, + 198, + 158, + 127, + 226, + 355, + 239, + 381, + 158, + 51, + 62, + 152, + 355, + 148, + 97, + 108, + 238, + 107, + 127, + 103, + 332, + 77, + 238, + 258, + 211, + 86, + 374, + 172, + 60, + 339, + 309, + 220, + 63, + 387, + 132, + 222, + 369, + 243, + 388, + 64, + 375, + 264, + 212, + 33, + 121, + 187, + 326, + 35, + 154, + 292, + 303, + 337, + 25, + 18, + 307, + 136, + 197, + 241, + 150, + 181, + 335, + 306, + 208, + 388, + 379, + 75, + 133, + 295, + 343, + 86, + 255, + 193, + 126, + 128, + 200, + 307, + 76, + 79, + 145, + 213, + 249, + 24, + 240, + 384, + 245, + 333, + 72, + 145, + 21, + 306, + 86, + 173, + 172, + 211, + 258, + 226, + 235, + 109, + 286, + 169, + 25, + 331, + 125, + 369, + 176, + 370, + 310, + 235, + 390, + 179, + 136, + 223, + 129, + 155, + 337, + 82, + 292, + 111, + 332, + 252, + 3, + 178, + 201, + 31, + 143, + 154, + 3, + 92, + 263, + 171, + 6, + 151, + 251, + 267, + 29, + 157, + 153, + 29, + 155, + 360, + 338, + 81, + 96, + 166, + 93, + 382, + 7, + 176, + 53, + 43, + 393, + 210, + 87, + 3, + 92, + 384, + 148, + 152, + 181, + 378, + 353, + 202, + 196, + 212, + 235, + 246, + 227, + 236, + 304, + 180, + 201, + 336, + 19, + 17, + 185, + 255, + 99, + 133, + 98, + 227, + 72, + 260, + 260, + 1, + 331, + 219, + 41, + 32, + 344, + 335, + 326, + 98, + 42, + 86, + 90, + 282, + 381, + 88, + 34, + 191, + 96, + 147, + 378, + 354, + 218, + 251, + 384, + 240, + 337, + 120, + 364, + 51, + 95, + 159, + 230, + 373, + 52, + 81, + 249, + 194, + 368, + 374, + 108, + 380, + 57, + 66, + 393, + 222, + 300, + 147, + 158, + 391, + 226, + 64, + 347, + 241, + 134, + 274, + 162, + 293, + 167, + 372, + 176, + 390, + 232, + 354, + 250, + 311, + 191, + 329, + 177, + 208, + 88, + 204, + 342, + 364, + 296, + 222, + 339, + 247, + 144, + 372, + 342, + 233, + 83, + 223, + 210, + 330, + 68, + 282, + 171, + 177, + 203, + 264, + 383, + 308, + 341, + 246, + 352, + 55, + 143, + 193, + 319, + 54, + 311, + 237, + 52, + 9, + 391, + 294, + 96, + 47, + 46, + 132, + 312, + 120, + 231, + 68, + 134, + 61, + 326, + 323, + 314, + 393, + 288, + 322, + 177, + 326, + 322, + 244, + 117, + 322, + 253, + 385, + 258, + 296, + 48, + 189, + 2, + 329, + 351, + 237, + 92, + 69, + 105, + 388, + 37, + 399, + 165, + 300, + 268, + 143, + 322, + 299, + 376, + 221, + 363, + 158, + 156, + 224, + 336, + 126, + 51, + 205, + 107, + 56, + 289, + 395, + 312, + 48, + 310, + 384, + 190, + 173, + 332, + 346, + 227, + 362, + 48, + 270, + 387, + 232, + 303, + 113, + 368, + 295, + 278, + 200, + 20, + 181, + 111, + 16, + 185, + 225, + 282, + 350, + 380, + 156, + 20, + 135, + 302, + 199, + 180, + 194, + 15, + 4, + 341, + 106, + 353, + 294, + 300, + 208, + 161, + 332, + 224, + 387, + 285, + 236, + 262, + 294, + 90, + 50, + 65, + 215, + 111, + 5, + 191, + 138, + 168, + 139, + 369, + 325, + 137, + 273, + 399, + 54, + 314, + 75, + 286, + 349, + 36, + 276, + 306, + 129, + 7, + 165, + 103, + 373, + 227, + 376, + 173, + 326, + 378, + 347, + 63, + 280, + 319, + 46, + 325, + 232, + 170, + 322, + 288, + 364, + 218, + 260, + 86, + 95, + 393, + 190, + 76, + 48, + 378, + 136, + 316, + 223, + 83, + 314, + 42, + 398, + 252, + 384, + 90, + 76, + 310, + 100, + 209, + 301, + 317, + 120, + 324, + 137, + 324, + 35, + 167, + 215, + 235, + 331, + 316, + 310, + 192, + 395, + 180, + 375, + 142, + 105, + 213, + 183, + 82, + 330, + 336, + 130, + 162, + 166, + 124, + 28, + 222, + 332, + 322, + 246, + 31, + 184, + 85, + 111, + 126, + 373, + 393, + 343, + 80, + 50, + 140, + 394, + 9, + 14, + 345, + 10, + 180, + 375, + 313, + 266, + 95, + 287, + 52, + 93, + 239, + 57, + 397, + 175, + 250, + 52, + 64, + 317, + 112, + 330, + 370, + 150, + 224, + 248, + 134, + 143, + 11, + 221, + 203, + 266, + 46, + 297, + 105, + 276, + 255, + 39, + 112, + 9, + 344, + 94, + 61, + 299, + 16, + 190, + 112, + 83, + 208, + 173, + 19, + 258, + 392, + 106, + 208, + 103, + 280, + 137, + 127, + 193, + 335, + 287, + 314, + 390, + 69, + 121, + 162, + 285, + 55, + 364, + 96, + 376, + 314, + 90, + 43, + 214, + 208, + 190, + 125, + 188, + 233, + 297, + 320, + 210, + 217, + 8, + 149, + 70, + 183, + 365, + 90, + 147, + 244, + 5, + 168, + 235, + 60, + 153, + 128, + 214, + 94, + 227, + 159, + 218, + 277, + 134, + 119, + 383, + 113, + 190, + 144, + 77, + 75, + 224, + 272, + 84, + 240, + 98, + 394, + 394, + 40, + 69, + 24, + 27, + 266, + 26, + 22, + 33, + 196, + 210, + 63, + 226, + 31, + 132, + 199, + 28, + 35, + 22, + 79, + 80, + 59, + 365, + 309, + 112, + 133, + 38, + 396, + 159, + 385, + 375, + 8, + 393, + 144, + 55, + 254, + 246, + 359, + 316, + 126, + 362, + 213, + 81, + 357, + 385, + 104, + 97, + 168, + 273, + 234, + 42, + 223, + 18, + 387, + 139, + 50, + 399, + 387, + 227, + 134, + 199, + 204, + 151, + 318, + 217, + 2, + 141, + 167, + 110, + 247, + 380, + 257, + 205, + 119, + 5, + 186, + 236, + 249, + 358, + 65, + 203, + 379, + 372, + 288, + 359, + 342, + 50, + 350, + 244, + 248, + 348, + 294, + 189, + 369, + 188, + 64, + 65, + 24, + 43, + 45, + 215, + 386, + 108, + 1, + 222, + 137, + 239, + 295, + 74, + 183, + 134, + 252, + 376, + 379, + 361, + 394, + 165, + 234, + 285, + 158, + 181, + 201, + 282, + 116, + 260, + 246, + 317, + 27, + 15, + 144, + 119, + 246, + 94, + 272, + 35, + 250, + 291, + 97, + 350, + 37, + 308, + 267, + 166, + 248, + 36, + 242, + 91, + 177, + 111, + 278, + 15, + 353, + 268, + 45, + 189, + 151, + 23, + 322, + 235, + 328, + 240, + 156, + 176, + 57, + 247, + 8, + 81, + 186, + 15, + 254, + 97, + 66, + 253, + 143, + 18, + 345, + 37, + 86, + 255, + 3, + 45, + 373, + 306, + 102, + 379, + 44, + 398, + 365, + 224, + 312, + 14, + 1, + 313, + 268, + 35, + 227, + 47, + 291, + 154, + 208, + 230, + 348, + 394, + 5, + 338, + 318, + 355, + 87, + 181, + 248, + 97, + 321, + 290, + 135, + 352, + 113, + 119, + 390, + 136, + 51, + 119, + 43, + 141, + 38, + 75, + 137, + 14, + 356, + 70, + 100, + 73, + 168, + 44, + 290, + 342, + 113, + 82, + 333, + 187, + 70, + 46, + 125, + 320, + 96, + 228, + 252, + 151, + 343, + 21, + 22, + 196, + 28, + 354, + 331, + 257, + 305, + 289, + 30, + 237, + 156, + 250, + 88, + 184, + 32, + 272, + 171, + 27, + 97, + 265, + 337, + 197, + 67, + 339, + 133, + 16, + 216, + 324, + 388, + 248, + 131, + 357, + 135, + 371, + 392, + 290, + 230, + 90, + 254, + 40, + 359, + 309, + 357, + 336, + 334, + 173, + 155, + 282, + 1, + 263, + 155, + 369, + 332, + 100, + 147, + 383, + 65, + 351, + 209, + 105, + 331, + 100, + 270, + 114, + 108, + 128, + 220, + 375, + 141, + 69, + 19, + 278, + 352, + 365, + 250, + 278, + 234, + 141, + 380, + 43, + 169, + 2, + 256, + 329, + 97, + 368, + 32, + 240, + 374, + 373, + 48, + 268, + 386, + 149, + 7, + 46, + 277, + 127, + 243, + 102, + 294, + 80, + 28, + 71, + 328, + 193, + 87, + 346, + 122, + 276, + 392, + 175, + 227, + 163, + 29, + 91, + 157, + 379, + 114, + 220, + 141, + 29, + 207, + 248, + 130, + 22, + 51, + 383, + 172, + 61, + 25, + 28, + 102, + 103, + 134, + 364, + 74, + 126, + 261, + 288, + 87, + 311, + 274, + 388, + 58, + 400, + 184, + 53, + 123, + 170, + 366, + 175, + 277, + 348, + 243, + 322, + 315, + 35, + 50, + 20, + 388, + 213, + 82, + 34, + 53, + 297, + 369, + 3, + 68, + 152, + 119, + 393, + 57, + 220, + 129, + 97, + 171, + 338, + 282, + 195, + 176, + 257, + 277, + 47, + 237, + 332, + 151, + 383, + 185, + 185, + 106, + 161, + 327, + 45, + 265, + 236, + 170, + 252, + 172, + 64, + 298, + 144, + 262, + 389, + 179, + 308, + 126, + 189, + 128, + 20, + 272, + 129, + 60, + 166, + 217, + 147, + 250, + 248, + 325, + 177, + 84, + 347, + 305, + 363, + 177, + 93, + 29, + 377, + 350, + 284, + 109, + 363, + 178, + 237, + 145, + 115, + 59, + 166, + 168, + 76, + 35, + 25, + 357, + 56, + 157, + 157, + 302, + 222, + 80, + 265, + 392, + 110, + 163, + 300, + 33, + 57, + 88, + 29, + 66, + 106, + 75, + 210, + 331, + 23, + 291, + 377, + 385, + 369, + 327, + 106, + 193, + 36, + 213, + 231, + 195, + 22, + 123, + 308, + 50, + 256, + 372, + 388, + 240, + 399, + 251, + 360, + 41, + 21, + 304, + 298, + 390, + 196, + 105, + 56, + 396, + 102, + 327, + 39, + 91, + 269, + 317, + 127, + 358, + 322, + 301, + 319, + 94, + 268, + 61, + 301, + 259, + 293, + 234, + 311, + 135, + 233, + 143, + 3, + 380, + 179, + 81, + 102, + 314, + 3, + 43, + 62, + 160, + 86, + 39, + 15, + 333, + 288, + 377, + 10, + 253, + 163, + 5, + 273, + 285, + 183, + 116, + 6, + 259, + 374, + 38, + 365, + 345, + 336, + 103, + 51, + 48, + 92, + 146, + 80, + 205, + 185, + 362, + 228, + 257, + 225, + 176, + 49, + 366, + 371, + 308, + 343, + 386, + 9, + 343, + 265, + 284, + 137, + 373, + 372, + 255, + 233, + 154, + 64, + 136, + 48, + 377, + 179, + 153, + 327, + 385, + 349, + 273, + 130, + 261, + 207, + 215, + 311, + 49, + 117, + 78, + 292, + 315, + 70, + 383, + 160, + 21, + 56, + 201, + 328, + 99, + 181, + 68, + 203, + 114, + 180, + 262, + 378, + 397, + 230, + 165, + 355, + 10, + 296, + 109, + 264, + 80, + 202, + 255, + 381, + 55, + 193, + 334, + 397, + 386, + 216, + 356, + 356, + 45, + 9, + 304, + 186, + 334, + 60, + 128, + 317, + 163, + 151, + 234, + 115, + 386, + 77, + 345, + 149, + 240, + 221, + 84, + 143, + 332, + 344, + 204, + 83, + 22, + 304, + 183, + 337, + 311, + 274, + 93, + 276, + 341, + 94, + 174, + 346, + 74, + 90, + 348, + 120, + 291, + 202, + 220, + 3, + 316, + 19, + 212, + 276, + 388, + 228, + 302, + 120, + 150, + 206, + 30, + 130, + 270, + 263, + 358, + 374, + 84, + 208, + 306, + 187, + 258, + 90, + 6, + 355, + 101, + 239, + 80, + 241, + 285, + 368, + 94, + 118, + 380, + 152, + 164, + 400, + 185, + 115, + 270, + 19, + 271, + 298, + 56, + 118, + 253, + 270, + 184, + 372, + 169, + 382, + 327, + 349, + 352, + 177, + 202, + 24, + 129, + 129, + 93, + 42, + 377, + 2, + 249, + 249, + 188, + 82, + 318, + 72, + 349, + 180, + 103, + 308, + 385, + 189, + 370, + 334, + 348, + 161, + 284, + 17, + 166, + 198, + 307, + 323, + 225, + 170, + 219, + 369, + 81, + 247, + 232, + 138, + 57, + 11, + 142, + 236, + 151, + 308, + 14, + 329, + 184, + 170, + 28, + 13, + 49, + 11, + 163, + 10, + 51, + 140, + 96, + 318, + 258, + 149, + 362, + 133, + 39, + 113, + 47, + 100, + 52, + 364, + 34, + 14, + 181, + 354, + 13, + 226, + 258, + 178, + 371, + 321, + 303, + 310, + 131, + 317, + 199, + 52, + 178, + 204, + 8, + 326, + 63, + 53, + 399, + 64, + 5, + 106, + 177, + 258, + 133, + 283, + 346, + 114, + 185, + 313, + 126, + 101, + 342, + 17, + 99, + 321, + 35, + 102, + 395, + 212, + 129, + 147, + 381, + 301, + 206, + 34, + 380, + 127, + 260, + 136, + 258, + 97, + 387, + 150, + 103, + 281, + 302, + 208, + 18, + 198, + 304, + 337, + 311, + 83, + 393, + 112, + 231, + 378, + 392, + 212, + 267, + 32, + 144, + 78, + 193, + 355, + 263, + 84, + 195, + 116, + 143, + 5, + 109, + 199, + 208, + 381, + 53, + 241, + 353, + 90, + 325, + 51, + 186, + 323, + 273, + 208, + 14, + 69, + 88, + 396, + 380, + 353, + 15, + 170, + 333, + 116, + 373, + 262, + 149, + 222, + 312, + 56, + 190, + 247, + 292, + 10, + 53, + 342, + 87, + 65, + 1, + 394, + 43, + 253, + 107, + 112, + 172, + 108, + 164, + 286, + 358, + 259, + 269, + 362, + 217, + 283, + 284, + 200, + 118, + 55, + 201, + 194, + 324, + 374, + 126, + 329, + 177, + 20, + 187, + 53, + 349, + 115, + 189, + 394, + 183, + 55, + 346, + 175, + 1, + 285, + 351, + 309, + 171, + 17, + 268, + 312, + 50, + 45, + 35, + 43, + 70, + 328, + 55, + 200, + 99, + 306, + 147, + 81, + 74, + 247, + 196, + 307, + 91, + 85, + 186, + 398, + 242, + 118, + 244, + 142, + 309, + 32, + 351, + 221, + 176, + 12, + 83, + 102, + 188, + 353, + 127, + 345, + 164, + 169, + 310, + 93, + 240, + 282, + 80, + 204, + 345, + 127, + 59, + 19, + 31, + 225, + 229, + 209, + 154, + 332, + 243, + 186, + 77, + 7, + 207, + 328, + 363, + 81, + 108, + 194, + 388, + 165, + 300, + 184, + 43, + 102, + 392, + 393, + 377, + 267, + 303, + 249, + 178, + 286, + 351, + 297, + 263, + 153, + 347, + 91, + 18, + 341, + 283, + 129, + 124, + 8, + 263, + 204, + 4, + 156, + 177, + 148, + 228, + 207, + 334, + 338, + 382, + 343, + 137, + 116, + 160, + 270, + 223, + 91, + 53, + 349, + 386, + 346, + 126, + 47, + 233, + 320, + 315, + 309, + 363, + 169, + 75, + 368, + 153, + 118, + 101, + 309, + 186, + 89, + 127, + 293, + 31, + 122, + 340, + 125, + 157, + 142, + 88, + 241, + 180, + 225, + 225, + 132, + 236, + 114, + 223, + 129, + 65, + 40, + 397, + 111, + 261, + 314, + 160, + 203, + 346, + 263, + 142, + 398, + 215, + 1, + 120, + 274, + 285, + 341, + 151, + 38, + 119, + 257, + 314, + 332, + 378, + 64, + 206, + 151, + 311, + 283, + 338, + 362, + 19, + 90, + 293, + 21, + 267, + 102, + 181, + 253, + 80, + 251, + 134, + 254, + 276, + 70, + 308, + 228, + 241, + 235, + 68, + 312, + 394, + 276, + 221, + 372, + 31, + 167, + 262, + 358, + 21, + 159, + 70, + 371, + 149, + 132, + 136, + 66, + 171, + 308, + 148, + 301, + 22, + 368, + 50, + 236, + 219, + 159, + 317, + 387, + 357, + 94, + 199, + 263, + 383, + 330, + 112, + 162, + 323, + 263, + 20, + 70, + 96, + 292, + 17, + 309, + 45, + 297, + 355, + 75, + 260, + 232, + 147, + 277, + 368, + 264, + 101, + 23, + 156, + 24, + 318, + 322, + 153, + 256, + 6, + 188, + 176, + 158, + 160, + 200, + 112, + 384, + 52, + 241, + 128, + 56, + 135, + 306, + 239, + 228, + 263, + 152, + 14, + 274, + 273, + 307, + 374, + 76, + 355, + 91, + 326, + 335, + 314, + 400, + 280, + 267, + 44, + 230, + 61, + 385, + 109, + 31, + 6, + 291, + 298, + 65, + 229, + 30, + 188, + 241, + 151, + 59, + 168, + 105, + 308, + 174, + 340, + 393, + 250, + 180, + 327, + 389, + 395, + 314, + 17, + 310, + 197, + 341, + 90, + 128, + 379, + 175, + 7, + 398, + 150, + 261, + 283, + 196, + 168, + 278, + 277, + 120, + 268, + 138, + 340, + 359, + 333, + 100, + 284, + 50, + 11, + 243, + 6, + 149, + 55, + 11, + 104, + 217, + 88, + 254, + 44, + 306, + 48, + 227, + 30, + 205, + 71, + 175, + 241, + 300, + 203, + 73, + 343, + 269, + 20, + 175, + 122, + 70, + 104, + 105, + 66, + 28, + 22, + 196, + 192, + 150, + 328, + 394, + 400, + 9, + 88, + 75, + 361, + 9, + 199, + 228, + 275, + 45, + 399, + 390, + 59, + 144, + 341, + 179, + 11, + 323, + 400, + 392, + 223, + 396, + 304, + 131, + 295, + 136, + 391, + 298, + 390, + 228, + 343, + 390, + 183, + 137, + 129, + 8, + 315, + 27, + 9, + 330, + 9, + 342, + 14, + 86, + 243, + 303, + 133, + 229, + 46, + 144, + 317, + 243, + 219, + 196, + 203, + 244, + 92, + 364, + 85, + 180, + 172, + 346, + 127, + 133, + 224, + 151, + 199, + 243, + 53, + 138, + 165, + 314, + 248, + 248, + 12, + 173, + 273, + 345, + 168, + 70, + 346, + 94, + 364, + 206, + 170, + 244, + 230, + 300, + 387, + 195, + 206, + 185, + 165, + 100, + 133, + 400, + 259, + 373, + 46, + 104, + 352, + 335, + 208, + 297, + 93, + 361, + 119, + 99, + 54, + 63, + 222, + 106, + 91, + 391, + 171, + 268, + 36, + 304, + 284, + 288, + 249, + 233, + 235, + 371, + 226, + 235, + 112, + 42, + 274, + 108, + 101, + 123, + 123, + 167, + 259, + 149, + 133, + 98, + 223, + 78, + 106, + 39, + 220, + 254, + 186, + 12, + 270, + 291, + 273, + 369, + 336, + 44, + 184, + 281, + 30, + 15, + 64, + 231, + 280, + 57, + 110, + 182, + 250, + 326, + 75, + 140, + 110, + 21, + 130, + 278, + 127, + 389, + 60, + 61, + 114, + 259, + 125, + 98, + 327, + 128, + 144, + 317, + 213, + 53, + 231, + 299, + 170, + 312, + 170, + 348, + 72, + 128, + 60, + 173, + 163, + 235, + 149, + 25, + 62, + 385, + 328, + 79, + 155, + 218, + 45, + 171, + 92, + 254, + 42, + 152, + 263, + 22, + 129, + 257, + 253, + 365, + 296, + 388, + 1, + 385, + 366, + 58, + 228, + 172, + 73, + 349, + 207, + 292, + 1, + 208, + 392, + 315, + 18, + 73, + 119, + 326, + 344, + 194, + 90, + 73, + 88, + 26, + 230, + 288, + 342, + 123, + 97, + 286, + 302, + 114, + 88, + 197, + 209, + 360, + 219, + 37, + 143, + 99, + 14, + 27, + 57, + 272, + 26, + 169, + 316, + 209, + 165, + 243, + 377, + 245, + 339, + 100, + 238, + 330, + 110, + 350, + 67, + 213, + 122, + 355, + 55, + 137, + 350, + 172, + 300, + 142, + 214, + 288, + 296, + 154, + 107, + 47, + 226, + 262, + 79, + 305, + 355, + 155, + 137, + 211, + 169, + 91, + 278, + 69, + 314, + 336, + 373, + 383, + 373, + 68, + 166, + 362, + 346, + 6, + 65, + 395, + 94, + 337, + 318, + 87, + 274, + 73, + 389, + 137, + 71, + 369, + 197, + 36, + 19, + 286, + 336, + 98, + 74, + 95, + 205, + 53, + 255, + 256, + 158, + 201, + 54, + 343, + 344, + 30, + 380, + 124, + 344, + 74, + 269, + 346, + 225, + 49, + 172, + 371, + 355, + 103, + 275, + 118, + 365, + 196, + 186, + 180, + 159, + 2, + 110, + 189, + 183, + 362, + 314, + 196, + 304, + 171, + 380, + 63, + 196, + 364, + 118, + 371, + 220, + 163, + 128, + 177, + 326, + 77, + 77, + 296, + 330, + 380, + 304, + 36, + 340, + 314, + 309, + 258, + 238, + 138, + 26, + 15, + 351, + 88, + 84, + 101, + 98, + 224, + 376, + 376, + 243, + 249, + 399, + 221, + 224, + 18, + 177, + 163, + 150, + 378, + 353, + 285, + 45, + 243, + 24, + 344, + 202, + 335, + 248, + 241, + 122, + 371, + 209, + 178, + 232, + 218, + 183, + 72, + 400, + 212, + 379, + 180, + 178, + 284, + 107, + 393, + 151, + 277, + 262, + 162, + 293, + 135, + 357, + 97, + 343, + 9, + 181, + 95, + 347, + 120, + 363, + 88, + 311, + 320, + 64, + 21, + 43, + 354, + 184, + 343, + 387, + 195, + 381, + 262, + 320, + 377, + 188, + 284, + 225, + 316, + 327, + 321, + 368, + 276, + 232, + 119, + 124, + 59, + 284, + 84, + 201, + 289, + 253, + 301, + 233, + 5, + 316, + 300, + 242, + 343, + 30, + 50, + 101, + 51, + 294, + 387, + 292, + 245, + 27, + 210, + 226, + 273, + 232, + 24, + 275, + 122, + 154, + 138, + 221, + 386, + 355, + 44, + 95, + 32, + 136, + 12, + 277, + 260, + 301, + 292, + 172, + 112, + 96, + 217, + 72, + 304, + 89, + 29, + 33, + 35, + 8, + 378, + 94, + 327, + 35, + 279, + 396, + 368, + 251, + 85, + 138, + 357, + 60, + 1, + 209, + 171, + 363, + 324, + 203, + 355, + 98, + 120, + 392, + 285, + 297, + 105, + 134, + 123, + 167, + 134, + 304, + 61, + 257, + 166, + 40, + 214, + 328, + 179, + 330, + 261, + 325, + 78, + 67, + 167, + 395, + 306, + 89, + 305, + 386, + 115, + 4, + 121, + 69, + 41, + 83, + 3, + 10, + 56, + 94, + 338, + 233, + 179, + 378, + 8, + 101, + 216, + 59, + 49, + 95, + 366, + 117, + 355, + 356, + 15, + 287, + 266, + 268, + 189, + 289, + 392, + 204, + 69, + 310, + 264, + 240, + 171, + 277, + 397, + 173, + 397, + 218, + 81, + 124, + 354, + 240, + 166, + 100, + 73, + 274, + 302, + 110, + 268, + 17, + 74, + 62, + 41, + 86, + 106, + 363, + 200, + 67, + 94, + 56, + 161, + 12, + 127, + 184, + 355, + 259, + 95, + 299, + 316, + 247, + 84, + 35, + 33, + 235, + 280, + 376, + 295, + 394, + 179, + 299, + 174, + 325, + 131, + 54, + 295, + 13, + 327, + 231, + 367, + 67, + 353, + 104, + 66, + 381, + 87, + 63, + 45, + 89, + 21, + 263, + 357, + 331, + 183, + 264, + 367, + 250, + 44, + 149, + 94, + 147, + 131, + 327, + 189, + 212, + 172, + 360, + 244, + 206, + 177, + 115, + 79, + 38, + 349, + 152, + 104, + 261, + 265, + 299, + 328, + 242, + 1, + 305, + 216, + 182, + 127, + 332, + 192, + 162, + 225, + 35, + 11, + 390, + 66, + 41, + 266, + 175, + 397, + 156, + 365, + 57, + 363, + 50, + 56, + 301, + 233, + 22, + 136, + 381, + 300, + 4, + 7, + 18, + 359, + 341, + 229, + 29, + 1, + 399, + 146, + 242, + 289, + 230, + 352, + 92, + 105, + 382, + 334, + 233, + 229, + 326, + 50, + 335, + 276, + 196, + 354, + 6, + 104, + 156, + 75, + 301, + 265, + 179, + 383, + 34, + 112, + 29, + 294, + 69, + 249, + 246, + 143, + 191, + 301, + 163, + 309, + 244, + 321, + 78, + 13, + 179, + 236, + 275, + 240, + 283, + 186, + 317, + 105, + 84, + 160, + 308, + 138, + 87, + 37, + 211, + 7, + 85, + 333, + 195, + 265, + 246, + 56, + 16, + 226, + 102, + 171, + 310, + 328, + 63, + 300, + 160, + 136, + 114, + 386, + 247, + 43, + 95, + 217, + 223, + 186, + 130, + 354, + 398, + 132, + 341, + 34, + 249, + 218, + 51, + 197, + 97, + 80, + 25, + 61, + 119, + 28, + 137, + 160, + 222, + 119, + 132, + 44, + 273, + 61, + 110, + 217, + 12, + 32, + 15, + 47, + 260, + 149, + 132, + 92, + 238, + 330, + 116, + 203, + 317, + 306, + 227, + 79, + 193, + 245, + 309, + 54, + 282, + 199, + 108, + 185, + 48, + 73, + 18, + 154, + 379, + 186, + 244, + 209, + 191, + 69, + 187, + 13, + 192, + 45, + 170, + 300, + 23, + 274, + 143, + 128, + 341, + 91, + 65, + 186, + 48, + 154, + 291, + 350, + 301, + 179, + 245, + 33, + 395, + 333, + 155, + 364, + 83, + 79, + 268, + 306, + 252, + 335, + 398, + 90, + 128, + 267, + 146, + 185, + 127, + 300, + 2, + 376, + 345, + 368, + 95, + 287, + 143, + 159, + 216, + 150, + 95, + 272, + 393, + 376, + 355, + 244, + 191, + 270, + 20, + 366, + 235, + 121, + 75, + 40, + 398, + 67, + 354, + 267, + 87, + 336, + 231, + 24, + 111, + 247, + 306, + 400, + 225, + 50, + 329, + 330, + 101, + 97, + 331, + 244, + 323, + 146, + 214, + 63, + 253, + 44, + 6, + 21, + 334, + 60, + 286, + 130, + 11, + 316, + 346, + 232, + 301, + 63, + 24, + 272, + 289, + 60, + 232, + 292, + 333, + 256, + 302, + 305, + 80, + 330, + 13, + 310, + 222, + 358, + 103, + 148, + 277, + 292, + 109, + 90, + 191, + 76, + 277, + 52, + 200, + 184, + 163, + 359, + 323, + 326, + 219, + 295, + 173, + 57, + 351, + 236, + 346, + 254, + 221, + 304, + 91, + 327, + 310, + 345, + 355, + 18, + 19, + 206, + 267, + 356, + 108, + 113, + 173, + 8, + 180, + 374, + 30, + 270, + 249, + 335, + 375, + 350, + 326, + 169, + 343, + 383, + 340, + 54, + 104, + 160, + 6, + 37, + 46, + 36, + 215, + 146, + 324, + 354, + 130, + 156, + 331, + 204, + 235, + 310, + 85, + 102, + 6, + 63, + 98, + 323, + 241, + 191, + 400, + 32, + 399, + 290, + 93, + 70, + 215, + 113, + 349, + 321, + 71, + 60, + 137, + 209, + 135, + 234, + 11, + 94, + 108, + 139, + 66, + 43, + 73, + 280, + 336, + 58, + 329, + 143, + 269, + 39, + 141, + 23, + 133, + 225, + 43, + 323, + 19, + 317, + 342, + 23, + 63, + 177, + 85, + 180, + 153, + 252, + 3, + 186, + 202, + 303, + 338, + 317, + 9, + 50, + 299, + 239, + 263, + 351, + 368, + 256, + 299, + 272, + 326, + 163, + 145, + 346, + 307, + 75, + 390, + 132, + 249, + 139, + 275, + 378, + 226, + 290, + 306, + 141, + 61, + 372, + 205, + 152, + 372, + 225, + 127, + 63, + 307, + 98, + 142, + 131, + 260, + 199, + 97, + 152, + 268, + 21, + 340, + 326, + 238, + 235, + 198, + 45, + 147, + 294, + 2, + 378, + 323, + 337, + 200, + 134, + 391, + 167, + 59, + 129, + 194, + 359, + 276, + 65, + 195, + 245, + 376, + 385, + 277, + 170, + 330, + 12, + 372, + 259, + 374, + 13, + 169, + 27, + 206, + 186, + 85, + 77, + 134, + 343, + 325, + 134, + 385, + 334, + 234, + 329, + 381, + 178, + 211, + 218, + 261, + 245, + 195, + 244, + 389, + 281, + 298, + 132, + 180, + 391, + 237, + 138, + 352, + 99, + 17, + 261, + 368, + 81, + 172, + 143, + 238, + 138, + 88, + 200, + 275, + 168, + 313, + 352, + 26, + 2, + 73, + 348, + 173, + 275, + 327, + 289, + 34, + 90, + 38, + 299, + 212, + 69, + 95, + 186, + 288, + 345, + 138, + 387, + 168, + 32, + 53, + 257, + 181, + 153, + 288, + 24, + 307, + 339, + 165, + 104, + 305, + 279, + 84, + 341, + 259, + 342, + 227, + 359, + 109, + 117, + 28, + 128, + 172, + 228, + 321, + 178, + 161, + 284, + 227, + 241, + 355, + 225, + 154, + 328, + 167, + 184, + 345, + 238, + 156, + 342, + 372, + 378, + 20, + 134, + 192, + 378, + 176, + 277, + 81, + 26, + 120, + 70, + 80, + 192, + 354, + 225, + 8, + 378, + 45, + 342, + 92, + 162, + 113, + 239, + 164, + 125, + 113, + 386, + 69, + 69, + 297, + 170, + 317, + 42, + 162, + 309, + 134, + 301, + 82, + 44, + 153, + 183, + 29, + 350, + 73, + 90, + 53, + 351, + 261, + 69, + 144, + 291, + 199, + 96, + 60, + 230, + 176, + 157, + 180, + 148, + 54, + 131, + 123, + 388, + 64, + 326, + 13, + 263, + 60, + 300, + 68, + 287, + 160, + 41, + 292, + 176, + 291, + 11, + 143, + 334, + 353, + 377, + 283, + 243, + 1, + 247, + 136, + 103, + 124, + 216, + 65, + 349, + 369, + 395, + 310, + 184, + 399, + 85, + 341, + 47, + 361, + 7, + 115, + 88, + 5, + 226, + 102, + 219, + 348, + 259, + 245, + 2, + 351, + 281, + 116, + 380, + 153, + 31, + 187, + 39, + 266, + 107, + 317, + 351, + 27, + 289, + 158, + 275, + 191, + 197, + 326, + 214, + 305, + 275, + 41, + 187, + 266, + 17, + 377, + 338, + 267, + 395, + 2, + 55, + 249, + 374, + 265, + 163, + 339, + 42, + 384, + 185, + 365, + 99, + 156, + 176, + 149, + 291, + 87, + 177, + 40, + 86, + 317, + 24, + 221, + 74, + 25, + 305, + 383, + 285, + 224, + 289, + 72, + 341, + 334, + 36, + 39, + 253, + 20, + 390, + 304, + 194, + 150, + 309, + 29, + 252, + 21, + 101, + 194, + 101, + 358, + 68, + 356, + 1, + 195, + 220, + 63, + 293, + 127, + 205, + 131, + 206, + 69, + 13, + 201, + 373, + 43, + 235, + 387, + 384, + 49, + 356, + 312, + 242, + 68, + 9, + 316, + 85, + 363, + 272, + 216, + 338, + 229, + 283, + 49, + 18, + 69, + 224, + 47, + 127, + 54, + 379, + 15, + 263, + 5, + 75, + 123, + 258, + 218, + 205, + 5, + 202, + 112, + 102, + 268, + 202, + 364, + 104, + 101, + 346, + 357, + 332, + 161, + 354, + 275, + 34, + 237, + 361, + 72, + 137, + 121, + 85, + 74, + 78, + 113, + 397, + 208, + 84, + 10, + 158, + 254, + 172, + 189, + 7, + 69, + 23, + 388, + 283, + 239, + 113, + 185, + 4, + 149, + 313, + 78, + 331, + 193, + 76, + 342, + 326, + 324, + 249, + 249, + 12, + 13, + 192, + 63, + 296, + 230, + 71, + 74, + 391, + 389, + 92, + 247, + 53, + 267, + 311, + 383, + 112, + 33, + 352, + 194, + 379, + 150, + 55, + 344, + 219, + 391, + 232, + 346, + 395, + 322, + 300, + 282, + 317, + 300, + 121, + 370, + 325, + 43, + 22, + 374, + 24, + 121, + 16, + 34, + 234, + 127, + 237, + 369, + 157, + 167, + 277, + 295, + 247, + 382, + 217, + 319, + 227, + 349, + 296, + 369, + 325, + 80, + 72, + 340, + 355, + 88, + 111, + 131, + 128, + 11, + 383, + 167, + 126, + 286, + 303, + 89, + 308, + 83, + 333, + 113, + 312, + 193, + 114, + 15, + 374, + 386, + 269, + 391, + 113, + 43, + 177, + 70, + 142, + 13, + 84, + 204, + 305, + 141, + 167, + 27, + 349, + 333, + 250, + 92, + 193, + 332, + 224, + 328, + 87, + 29, + 73, + 331, + 80, + 194, + 75, + 49, + 312, + 283, + 233, + 152, + 215, + 361, + 170, + 45, + 70, + 92, + 185, + 381, + 120, + 76, + 19, + 79, + 170, + 14, + 48, + 358, + 153, + 354, + 200, + 173, + 250, + 180, + 72, + 202, + 330, + 312, + 37, + 235, + 48, + 17, + 337, + 144, + 301, + 376, + 197, + 179, + 380, + 30, + 61, + 150, + 146, + 170, + 393, + 109, + 374, + 141, + 15, + 77, + 332, + 153, + 400, + 334, + 195, + 87, + 108, + 360, + 321, + 11, + 144, + 17, + 146, + 342, + 301, + 247, + 69, + 239, + 263, + 327, + 1, + 109, + 62, + 82, + 315, + 9, + 192, + 57, + 91, + 98, + 197, + 237, + 398, + 217, + 324, + 76, + 366, + 215, + 111, + 161, + 213, + 228, + 332, + 182, + 278, + 289, + 279, + 138, + 351, + 255, + 356, + 301, + 180, + 378, + 67, + 245, + 204, + 337, + 337, + 397, + 39, + 212, + 387, + 378, + 38, + 213, + 76, + 81, + 33, + 202, + 149, + 68, + 398, + 243, + 375, + 303, + 163, + 150, + 366, + 20, + 156, + 108, + 150, + 41, + 119, + 22, + 67, + 394, + 120, + 90, + 195, + 321, + 361, + 74, + 310, + 372, + 282, + 34, + 394, + 316, + 131, + 143, + 119, + 278, + 86, + 306, + 365, + 238, + 196, + 222, + 330, + 393, + 190, + 35, + 318, + 83, + 67, + 67, + 3, + 43, + 219, + 197, + 264, + 250, + 319, + 131, + 47, + 220, + 255, + 334, + 372, + 358, + 2, + 392, + 32, + 217, + 207, + 271, + 204, + 39, + 338, + 348, + 109, + 246, + 16, + 367, + 198, + 93, + 141, + 248, + 197, + 163, + 264, + 66, + 54, + 293, + 253, + 377, + 233, + 290, + 53, + 351, + 240, + 399, + 74, + 249, + 185, + 137, + 53, + 247, + 334, + 18, + 112, + 162, + 387, + 227, + 7, + 326, + 132, + 22, + 26, + 314, + 359, + 72, + 194, + 148, + 393, + 160, + 49, + 275, + 120, + 346, + 164, + 97, + 317, + 267, + 212, + 297, + 201, + 350, + 332, + 350, + 329, + 223, + 385, + 24, + 167, + 279, + 374, + 128, + 392, + 117, + 41, + 143, + 38, + 312, + 226, + 313, + 78, + 209, + 351, + 320, + 194, + 192, + 333, + 242, + 254, + 340, + 290, + 72, + 359, + 370, + 220, + 241, + 48, + 197, + 31, + 297, + 282, + 375, + 181, + 97, + 70, + 87, + 363, + 63, + 286, + 166, + 114, + 344, + 332, + 31, + 167, + 278, + 75, + 340, + 138, + 83, + 189, + 263, + 221, + 243, + 366, + 190, + 336, + 79, + 235, + 338, + 290, + 128, + 100, + 80, + 347, + 341, + 351, + 160, + 328, + 183, + 351, + 361, + 157, + 91, + 95, + 217, + 365, + 124, + 325, + 293, + 212, + 170, + 376, + 296, + 178, + 140, + 127, + 86, + 200, + 216, + 23, + 239, + 385, + 134, + 316, + 187, + 391, + 71, + 19, + 9, + 286, + 46, + 42, + 172, + 292, + 58, + 67, + 84, + 4, + 159, + 110, + 66, + 213, + 3, + 320, + 40, + 23, + 97, + 86, + 102, + 83, + 119, + 237, + 242, + 171, + 320, + 268, + 377, + 53, + 65, + 133, + 144, + 389, + 275, + 215, + 100, + 134, + 185, + 94, + 213, + 307, + 297, + 250, + 321, + 252, + 106, + 400, + 265, + 266, + 176, + 141, + 14, + 201, + 250, + 295, + 202, + 287, + 301, + 179, + 133, + 68, + 347, + 113, + 181, + 148, + 346, + 356, + 258, + 69, + 130, + 84, + 244, + 85, + 109, + 139, + 268, + 83, + 367, + 129, + 52, + 287, + 217, + 164, + 123, + 202, + 122, + 163, + 79, + 321, + 202, + 302, + 93, + 256, + 29, + 16, + 209, + 348, + 315, + 282, + 391, + 51, + 247, + 184, + 351, + 40, + 96, + 60, + 39, + 278, + 108, + 81, + 389, + 344, + 149, + 176, + 64, + 344, + 165, + 262, + 40, + 75, + 263, + 46, + 392, + 266, + 47, + 8, + 278, + 262, + 192, + 260, + 329, + 332, + 25, + 314, + 15, + 22, + 146, + 101, + 343, + 245, + 238, + 354, + 222, + 69, + 259, + 139, + 352, + 73, + 46, + 223, + 294, + 122, + 292, + 312, + 382, + 338, + 260, + 334, + 165, + 341, + 62, + 108, + 227, + 232, + 208, + 40, + 342, + 281, + 120, + 62, + 185, + 165, + 348, + 114, + 26, + 65, + 146, + 33, + 34, + 340, + 156, + 275, + 68, + 187, + 396, + 205, + 366, + 26, + 298, + 64, + 220, + 73, + 192, + 303, + 57, + 382, + 273, + 313, + 385, + 134, + 261, + 327, + 307, + 325, + 108, + 386, + 251, + 305, + 114, + 392, + 114, + 147, + 72, + 312, + 108, + 264, + 378, + 316, + 398, + 169, + 217, + 39, + 58, + 46, + 12, + 265, + 7, + 187, + 105, + 53, + 133, + 44, + 244, + 115, + 129, + 282, + 22, + 340, + 200, + 121, + 90, + 209, + 97, + 388, + 133, + 345, + 113, + 289, + 298, + 312, + 284, + 72, + 98, + 259, + 201, + 111, + 357, + 337, + 369, + 286, + 346, + 206, + 159, + 20, + 266, + 177, + 386, + 114, + 16, + 334, + 132, + 277, + 214, + 375, + 229, + 29, + 124, + 19, + 95, + 169, + 65, + 318, + 120, + 245, + 31, + 301, + 306, + 197, + 261, + 102, + 290, + 156, + 69, + 330, + 346, + 139, + 159, + 287, + 284, + 126, + 301, + 57, + 274, + 386, + 106, + 147, + 19, + 344, + 11, + 276, + 31, + 252, + 87, + 133, + 73, + 259, + 20, + 85, + 334, + 311, + 352, + 197, + 282, + 348, + 359, + 120, + 18, + 250, + 389, + 233, + 6, + 75, + 395, + 191, + 51, + 156, + 387, + 377, + 155, + 355, + 343, + 49, + 270, + 308, + 95, + 41, + 66, + 380, + 335, + 224, + 162, + 198, + 366, + 44, + 259, + 232, + 170, + 177, + 251, + 256, + 10, + 337, + 175, + 82, + 230, + 54, + 275, + 34, + 113, + 228, + 288, + 151, + 199, + 361, + 244, + 221, + 336, + 336, + 30, + 105, + 228, + 317, + 356, + 227, + 251, + 58, + 6, + 165, + 150, + 400, + 271, + 48, + 343, + 383, + 48, + 144, + 289, + 270, + 147, + 18, + 131, + 302, + 191, + 249, + 143, + 32, + 279, + 245, + 350, + 176, + 154, + 103, + 355, + 359, + 167, + 239, + 121, + 361, + 10, + 217, + 78, + 207, + 391, + 309, + 16, + 65, + 309, + 185, + 299, + 299, + 372, + 86, + 146, + 316, + 207, + 96, + 196, + 97, + 28, + 28, + 128, + 234, + 123, + 108, + 88, + 359, + 124, + 27, + 76, + 377, + 318, + 155, + 251, + 231, + 148, + 352, + 378, + 3, + 93, + 400, + 34, + 235, + 299, + 360, + 118, + 211, + 22, + 282, + 57, + 270, + 295, + 150, + 283, + 204, + 12, + 357, + 231, + 119, + 20, + 173, + 55, + 129, + 61, + 286, + 382, + 303, + 135, + 89, + 249, + 384, + 77, + 379, + 142, + 333, + 178, + 295, + 198, + 293, + 338, + 150, + 10, + 17, + 354, + 177, + 157, + 76, + 38, + 293, + 236, + 205, + 98, + 169, + 265, + 109, + 91, + 172, + 218, + 125, + 298, + 50, + 339, + 115, + 168, + 165, + 26, + 53, + 84, + 236, + 13, + 97, + 400, + 387, + 37, + 243, + 172, + 180, + 285, + 94, + 209, + 125, + 353, + 67, + 257, + 34, + 168, + 360, + 78, + 251, + 320, + 278, + 376, + 317, + 148, + 263, + 32, + 356, + 160, + 208, + 289, + 235, + 249, + 357, + 318, + 55, + 155, + 283, + 134, + 60, + 156, + 21, + 295, + 20, + 65, + 46, + 215, + 321, + 39, + 12, + 346, + 108, + 321, + 270, + 156, + 136, + 334, + 364, + 318, + 168, + 365, + 79, + 90, + 123, + 325, + 330, + 189, + 52, + 123, + 310, + 267, + 231, + 289, + 133, + 293, + 32, + 346, + 288, + 313, + 108, + 398, + 62, + 321, + 25, + 362, + 268, + 313, + 123, + 280, + 353, + 129, + 100, + 170, + 54, + 13, + 348, + 167, + 82, + 167, + 176, + 41, + 235, + 45, + 400, + 216, + 211, + 233, + 297, + 310, + 240, + 193, + 248, + 242, + 375, + 371, + 170, + 342, + 197, + 190, + 367, + 43, + 71, + 249, + 251, + 299, + 317, + 291, + 345, + 69, + 60, + 333, + 21, + 312, + 194, + 6, + 285, + 320, + 201, + 8, + 218, + 286, + 127, + 388, + 183, + 27, + 181, + 263, + 102, + 246, + 134, + 37, + 236, + 262, + 196, + 186, + 157, + 281, + 266, + 263, + 219, + 345, + 120, + 22, + 210, + 246, + 72, + 29, + 121, + 299, + 240, + 167, + 270, + 47, + 229, + 84, + 226, + 26, + 70, + 85, + 197, + 218, + 198, + 278, + 232, + 36, + 1, + 298, + 144, + 130, + 2, + 240, + 86, + 216, + 288, + 135, + 98, + 68, + 41, + 142, + 192, + 301, + 169, + 114, + 261, + 11, + 322, + 148, + 66, + 196, + 358, + 280, + 347, + 15, + 9, + 212, + 383, + 394, + 127, + 194, + 277, + 135, + 231, + 223, + 84, + 284, + 98, + 286, + 367, + 28, + 299, + 74, + 187, + 260, + 273, + 300, + 206, + 23, + 244, + 291, + 364, + 21, + 12, + 52, + 362, + 20, + 353, + 38, + 370, + 188, + 64, + 320, + 226, + 103, + 206, + 25, + 197, + 35, + 348, + 213, + 182, + 364, + 249, + 118, + 352, + 286, + 166, + 101, + 375, + 292, + 258, + 62, + 372, + 102, + 149, + 250, + 223, + 97, + 180, + 129, + 394, + 184, + 132, + 29, + 88, + 104, + 180, + 50, + 97, + 192, + 339, + 166, + 234, + 374, + 219, + 233, + 141, + 337, + 317, + 274, + 44, + 165, + 189, + 112, + 363, + 156, + 291, + 44, + 288, + 142, + 391, + 289, + 17, + 341, + 335, + 6, + 177, + 219, + 285, + 224, + 62, + 20, + 258, + 270, + 91, + 254, + 334, + 124, + 185, + 120, + 8, + 13, + 339, + 306, + 333, + 255, + 41, + 7, + 316, + 236, + 80, + 145, + 247, + 368, + 312, + 124, + 346, + 116, + 1, + 108, + 9, + 126, + 303, + 357, + 5, + 223, + 83, + 172, + 205, + 242, + 77, + 61, + 159, + 121, + 268, + 256, + 331, + 203, + 70, + 217, + 122, + 310, + 142, + 156, + 108, + 379, + 321, + 289, + 379, + 63, + 264, + 372, + 395, + 261, + 190, + 11, + 291, + 148, + 72, + 215, + 259, + 304, + 381, + 38, + 216, + 134, + 62, + 211, + 279, + 213, + 125, + 27, + 254, + 81, + 43, + 150, + 256, + 371, + 295, + 219, + 335, + 230, + 79, + 177, + 159, + 241, + 304, + 63, + 247, + 107, + 143, + 400, + 262, + 369, + 242, + 90, + 82, + 105, + 229, + 162, + 222, + 383, + 363, + 223, + 211, + 114, + 134, + 162, + 245, + 371, + 95, + 329, + 124, + 216, + 201, + 195, + 157, + 85, + 309, + 271, + 384, + 143, + 51, + 366, + 183, + 326, + 170, + 49, + 326, + 351, + 107, + 141, + 334, + 102, + 323, + 286, + 12, + 215, + 4, + 228, + 322, + 255, + 256, + 323, + 69, + 168, + 274, + 148, + 237, + 194, + 331, + 203, + 132, + 151, + 238, + 215, + 46, + 106, + 35, + 225, + 360, + 124, + 386, + 37, + 111, + 331, + 340, + 12, + 181, + 143, + 249, + 348, + 165, + 10, + 282, + 18, + 359, + 346, + 371, + 267, + 355, + 15, + 212, + 68, + 382, + 222, + 110, + 54, + 270, + 53, + 245, + 213, + 152, + 80, + 323, + 6, + 264, + 149, + 360, + 388, + 323, + 284, + 315, + 125, + 119, + 95, + 243, + 218, + 360, + 394, + 383, + 221, + 289, + 113, + 294, + 359, + 140, + 113, + 292, + 48, + 266, + 386, + 30, + 186, + 65, + 384, + 351, + 228, + 31, + 144, + 359, + 352, + 50, + 362, + 362, + 202, + 27, + 294, + 9, + 68, + 164, + 105, + 37, + 137, + 251, + 394, + 20, + 306, + 145, + 176, + 74, + 229, + 235, + 211, + 174, + 14, + 221, + 165, + 116, + 374, + 198, + 136, + 148, + 198, + 271, + 222, + 48, + 143, + 19, + 399, + 386, + 125, + 378, + 40, + 140, + 183, + 78, + 100, + 26, + 66, + 233, + 114, + 122, + 23, + 183, + 115, + 338, + 357, + 255, + 71, + 230, + 65, + 115, + 75, + 86, + 110, + 100, + 90, + 389, + 159, + 318, + 397, + 40, + 70, + 41, + 106, + 55, + 49, + 181, + 344, + 381, + 132, + 26, + 52, + 306, + 172, + 323, + 197, + 116, + 126, + 39, + 154, + 77, + 256, + 48, + 39, + 317, + 384, + 347, + 66, + 178, + 266, + 1, + 110, + 162, + 153, + 2, + 86, + 192, + 145, + 245, + 193, + 396, + 366, + 205, + 369, + 88, + 158, + 160, + 217, + 58, + 287, + 384, + 110, + 345, + 369, + 36, + 366, + 71, + 233, + 246, + 213, + 300, + 68, + 291, + 245, + 208, + 356, + 303, + 212, + 152, + 181, + 292, + 67, + 379, + 354, + 388, + 372, + 30, + 304, + 135, + 123, + 118, + 281, + 380, + 344, + 20, + 53, + 107, + 3, + 216, + 381, + 22, + 363, + 271, + 269, + 196, + 97, + 40, + 399, + 115, + 361, + 219, + 128, + 340, + 15, + 308, + 186, + 8, + 292, + 183, + 63, + 42, + 8, + 273, + 45, + 195, + 108, + 140, + 324, + 230, + 306, + 159, + 324, + 172, + 72, + 109, + 203, + 188, + 329, + 186, + 61, + 174, + 362, + 143, + 10, + 388, + 66, + 211, + 227, + 13, + 239, + 201, + 198, + 96, + 208, + 26, + 345, + 336, + 21, + 145, + 1, + 206, + 393, + 81, + 251, + 303, + 195, + 11, + 68, + 205, + 341, + 144, + 178, + 256, + 348, + 70, + 12, + 6, + 385, + 201, + 108, + 92, + 284, + 140, + 43, + 51, + 106, + 172, + 148, + 195, + 218, + 370, + 73, + 335, + 189, + 138, + 13, + 227, + 227, + 208, + 338, + 137, + 379, + 68, + 308, + 236, + 258, + 293, + 287, + 13, + 129, + 132, + 60, + 174, + 126, + 319, + 185, + 189, + 318, + 232, + 359, + 275, + 364, + 46, + 256, + 179, + 172, + 368, + 45, + 68, + 132, + 201, + 21, + 285, + 99, + 338, + 340, + 140, + 300, + 270, + 208, + 380, + 187, + 188, + 22, + 112, + 304, + 55, + 39, + 198, + 20, + 355, + 257, + 298, + 91, + 235, + 18, + 235, + 58, + 77, + 397, + 232, + 51, + 277, + 284, + 292, + 360, + 369, + 188, + 350, + 158, + 125, + 158, + 49, + 160, + 111, + 64, + 21, + 368, + 390, + 287, + 279, + 104, + 291, + 246, + 294, + 196, + 400, + 161, + 133, + 319, + 310, + 62, + 118, + 205, + 320, + 164, + 44, + 81, + 10, + 270, + 51, + 23, + 265, + 121, + 184, + 389, + 120, + 355, + 221, + 167, + 105, + 289, + 147, + 174, + 133, + 185, + 225, + 228, + 309, + 218, + 320, + 233, + 115, + 126, + 22, + 383, + 356, + 254, + 36, + 19, + 95, + 80, + 327, + 107, + 42, + 327, + 70, + 107, + 45, + 119, + 323, + 83, + 81, + 68, + 261, + 195, + 76, + 45, + 172, + 6, + 154, + 305, + 108, + 263, + 249, + 146, + 120, + 112, + 298, + 207, + 382, + 231, + 371, + 102, + 87, + 155, + 168, + 387, + 309, + 70, + 166, + 95, + 12, + 343, + 302, + 266, + 113, + 41, + 173, + 268, + 350, + 224, + 42, + 70, + 353, + 6, + 319, + 39, + 144, + 223, + 240, + 68, + 11, + 36, + 326, + 364, + 31, + 7, + 329, + 295, + 392, + 147, + 250, + 192, + 24, + 334, + 27, + 272, + 21, + 49, + 398, + 222, + 150, + 255, + 326, + 100, + 149, + 33, + 357, + 143, + 15, + 246, + 30, + 72, + 101, + 398, + 120, + 398, + 87, + 210, + 355, + 354, + 364, + 244, + 360, + 81, + 293, + 140, + 384, + 197, + 371, + 357, + 157, + 139, + 73, + 198, + 151, + 253, + 79, + 155, + 184, + 24, + 99, + 121, + 66, + 330, + 351, + 279, + 280, + 284, + 362, + 384, + 294, + 262, + 80, + 232, + 62, + 15, + 395, + 102, + 287, + 147, + 20, + 380, + 37, + 211, + 292, + 53, + 265, + 159, + 17, + 141, + 22, + 348, + 311, + 224, + 372, + 116, + 138, + 360, + 170, + 210, + 118, + 208, + 367, + 248, + 267, + 194, + 273, + 162, + 124, + 128, + 45, + 30, + 353, + 258, + 204, + 329, + 49, + 101, + 232, + 133, + 95, + 371, + 186, + 128, + 214, + 318, + 233, + 20, + 37, + 253, + 291, + 152, + 223, + 254, + 321, + 277, + 224, + 68, + 346, + 395, + 89, + 23, + 5, + 136, + 52, + 369, + 158, + 2, + 48, + 34, + 102, + 187, + 101, + 117, + 344, + 301, + 294, + 302, + 349, + 272, + 148, + 169, + 82, + 108, + 10, + 302, + 9, + 81, + 124, + 209, + 327, + 371, + 247, + 270, + 26, + 337, + 109, + 128, + 13, + 53, + 148, + 73, + 162, + 390, + 89, + 173, + 86, + 156, + 114, + 394, + 90, + 105, + 61, + 388, + 24, + 318, + 366, + 260, + 34, + 340, + 159, + 293, + 205, + 266, + 87, + 142, + 370, + 355, + 57, + 69, + 369, + 385, + 136, + 379, + 59, + 298, + 141, + 199, + 274, + 137, + 241, + 109, + 253, + 159, + 384, + 180, + 174, + 263, + 302, + 350, + 371, + 273, + 292, + 298, + 184, + 215, + 279, + 60, + 103, + 137, + 50, + 317, + 154, + 380, + 360, + 284, + 68, + 178, + 4, + 125, + 165, + 196, + 36, + 151, + 392, + 99, + 59, + 236, + 197, + 107, + 98, + 207, + 231, + 369, + 240, + 213, + 313, + 36, + 259, + 151, + 189, + 387, + 348, + 392, + 69, + 350, + 214, + 17, + 228, + 29, + 215, + 243, + 216, + 17, + 55, + 113, + 200, + 347, + 217, + 132, + 52, + 57, + 109, + 253, + 288, + 377, + 258, + 281, + 251, + 230, + 298, + 98, + 252, + 347, + 232, + 50, + 157, + 213, + 288, + 381, + 142, + 192, + 142, + 156, + 161, + 24, + 257, + 344, + 160, + 242, + 294, + 214, + 151, + 290, + 274, + 142, + 383, + 219, + 309, + 227, + 110, + 137, + 256, + 127, + 299, + 319, + 34, + 153, + 164, + 168, + 341, + 143, + 200, + 205, + 324, + 225, + 216, + 149, + 237, + 89, + 280, + 244, + 256, + 159, + 394, + 135, + 394, + 99, + 267, + 309, + 159, + 176, + 110, + 393, + 268, + 291, + 55, + 102, + 68, + 85, + 158, + 11, + 224, + 84, + 150, + 272, + 342, + 152, + 7, + 67, + 237, + 202, + 286, + 361, + 179, + 52, + 118, + 182, + 121, + 319, + 92, + 216, + 312, + 163, + 100, + 162, + 53, + 244, + 369, + 307, + 64, + 282, + 354, + 135, + 255, + 5, + 97, + 147, + 384, + 290, + 115, + 83, + 17, + 249, + 308, + 129, + 279, + 199, + 162, + 304, + 392, + 331, + 185, + 305, + 333, + 298, + 243, + 124, + 120, + 231, + 378, + 74, + 311, + 85, + 40, + 43, + 14, + 266, + 169, + 175, + 342, + 133, + 151, + 329, + 186, + 295, + 35, + 324, + 291, + 124, + 187, + 11, + 135, + 195, + 341, + 255, + 281, + 255, + 362, + 329, + 274, + 338, + 182, + 52, + 172, + 219, + 141, + 14, + 64, + 87, + 105, + 132, + 156, + 69, + 106, + 6, + 117, + 249, + 297, + 113, + 123, + 388, + 17, + 164, + 348, + 278, + 93, + 86, + 199, + 385, + 283, + 237, + 80, + 30, + 352, + 51, + 58, + 133, + 127, + 100, + 128, + 234, + 380, + 234, + 42, + 310, + 304, + 32, + 18, + 300, + 215, + 391, + 169, + 107, + 324, + 49, + 157, + 207, + 317, + 282, + 90, + 48, + 145, + 339, + 349, + 120, + 226, + 174, + 64, + 397, + 274, + 295, + 261, + 341, + 157, + 165, + 263, + 186, + 194, + 56, + 128, + 3, + 284, + 57, + 88, + 304, + 151, + 43, + 65, + 86, + 350, + 9, + 203, + 31, + 126, + 249, + 387, + 377, + 298, + 43, + 236, + 310, + 247, + 102, + 143, + 14, + 114, + 262, + 156, + 182, + 108, + 398, + 372, + 100, + 393, + 329, + 359, + 285, + 388, + 59, + 184, + 221, + 303, + 327, + 145, + 124, + 144, + 9, + 107, + 142, + 18, + 56, + 36, + 313, + 329, + 98, + 54, + 367, + 201, + 102, + 325, + 37, + 205, + 123, + 299, + 241, + 84, + 112, + 235, + 46, + 357, + 214, + 361, + 392, + 220, + 171, + 3, + 240, + 388, + 167, + 7, + 293, + 4, + 194, + 269, + 197, + 125, + 78, + 162, + 301, + 222, + 157, + 248, + 74, + 278, + 110, + 156, + 273, + 239, + 161, + 290, + 117, + 27, + 356, + 377, + 328, + 80, + 152, + 302, + 193, + 180, + 256, + 365, + 237, + 194, + 354, + 178, + 199, + 248, + 154, + 336, + 249, + 267, + 315, + 356, + 200, + 379, + 224, + 215, + 104, + 51, + 146, + 28, + 77, + 232, + 346, + 22, + 43, + 16, + 12, + 212, + 120, + 209, + 268, + 213, + 159, + 193, + 260, + 232, + 298, + 153, + 278, + 129, + 109, + 375, + 121, + 151, + 34, + 256, + 7, + 260, + 139, + 255, + 384, + 376, + 130, + 108, + 215, + 103, + 179, + 181, + 24, + 328, + 385, + 213, + 20, + 41, + 74, + 8, + 365, + 195, + 56, + 23, + 310, + 325, + 235, + 307, + 322, + 320, + 218, + 26, + 363, + 220, + 181, + 353, + 369, + 315, + 366, + 78, + 125, + 138, + 177, + 333, + 164, + 54, + 128, + 315, + 1, + 173, + 254, + 259, + 33, + 302, + 219, + 248, + 235, + 72, + 279, + 97, + 389, + 79, + 313, + 198, + 301, + 324, + 338, + 293, + 378, + 124, + 270, + 325, + 170, + 375, + 118, + 224, + 254, + 78, + 117, + 103, + 180, + 303, + 94, + 259, + 54, + 375, + 147, + 399, + 299, + 128, + 122, + 364, + 23, + 330, + 288, + 314, + 71, + 162, + 398, + 96, + 176, + 371, + 30, + 12, + 21, + 130, + 190, + 205, + 52, + 20, + 102, + 262, + 268, + 122, + 23, + 354, + 104, + 221, + 191, + 129, + 33, + 51, + 339, + 198, + 111, + 159, + 395, + 295, + 93, + 272, + 124, + 114, + 254, + 116, + 127, + 272, + 41, + 210, + 384, + 83, + 34, + 393, + 84, + 359, + 137, + 355, + 228, + 316, + 175, + 75, + 280, + 221, + 98, + 43, + 68, + 197, + 194, + 40, + 242, + 50, + 123, + 149, + 206, + 331, + 158, + 224, + 142, + 88, + 201, + 250, + 251, + 186, + 42, + 191, + 317, + 282, + 3, + 250, + 137, + 139, + 305, + 110, + 165, + 269, + 333, + 378, + 360, + 292, + 183, + 370, + 78, + 100, + 344, + 186, + 137, + 120, + 220, + 14, + 302, + 303, + 55, + 381, + 234, + 382, + 93, + 342, + 168, + 213, + 155, + 180, + 201, + 191, + 386, + 296, + 303, + 82, + 131, + 218, + 299, + 360, + 282, + 253, + 49, + 215, + 225, + 67, + 378, + 23, + 109, + 398, + 48, + 15, + 235, + 138, + 373, + 270, + 366, + 7, + 150, + 92, + 372, + 110, + 123, + 57, + 66, + 98, + 210, + 164, + 338, + 341, + 171, + 92, + 277, + 20, + 33, + 280, + 214, + 28, + 363, + 79, + 291, + 256, + 161, + 252, + 322, + 372, + 134, + 203, + 108, + 54, + 127, + 392, + 128, + 180, + 185, + 99, + 7, + 75, + 141, + 188, + 37, + 309, + 1, + 316, + 377, + 345, + 177, + 229, + 133, + 160, + 312, + 294, + 198, + 130, + 363, + 118, + 72, + 52, + 198, + 375, + 52, + 306, + 336, + 300, + 140, + 130, + 395, + 386, + 205, + 263, + 30, + 155, + 301, + 389, + 59, + 47, + 162, + 120, + 360, + 311, + 281, + 102, + 41, + 197, + 46, + 271, + 36, + 179, + 303, + 106, + 316, + 253, + 283, + 292, + 103, + 218, + 199, + 158, + 144, + 54, + 127, + 53, + 293, + 36, + 215, + 168, + 110, + 233, + 192, + 377, + 1, + 170, + 245, + 225, + 363, + 172, + 56, + 110, + 165, + 134, + 139, + 248, + 325, + 84, + 340, + 53, + 78, + 395, + 9, + 288, + 223, + 105, + 165, + 230, + 317, + 189, + 72, + 252, + 296, + 169, + 214, + 75, + 179, + 256, + 60, + 178, + 30, + 138, + 376, + 327, + 98, + 191, + 48, + 14, + 320, + 39, + 172, + 183, + 229, + 291, + 88, + 110, + 400, + 12, + 238, + 159, + 309, + 256, + 170, + 26, + 348, + 191, + 296, + 236, + 275, + 314, + 280, + 126, + 231, + 185, + 263, + 306, + 35, + 35, + 378, + 198, + 162, + 49, + 212, + 224, + 66, 40, - 320, - 76, - 369, - 352, + 47, + 24, + 154, + 226, + 198, + 98, + 193, + 398, + 51, + 130, + 64, + 73, + 378, + 189, + 71, 158, - 247, - 82, + 314, + 47, + 209, + 339, + 197, + 372, + 201, + 116, + 33, + 215, + 169, + 211, + 155, + 378, + 11, + 226, + 125, + 188, + 182, + 341, + 102, + 318, + 81, + 359, + 388, + 11, + 174, + 241, + 179, + 367, 368, - 24, - 41, - 307, - 273, - 207, - 16, - 121, + 311, + 232, + 9, + 131, + 174, + 384, + 45, + 355, + 209, + 289, + 372, + 339, + 86, + 40, + 385, + 79, + 15, + 161, + 386, + 386, + 124, + 368, + 305, + 299, + 301, + 384, + 315, + 389, + 378, + 95, + 249, + 394, + 393, + 174, + 291, + 259, + 290, + 268, + 373, + 340, + 39, + 253, + 294, + 254, + 212, + 222, + 164, + 27, 379, - 304, + 39, + 50, + 70, + 153, + 191, + 292, + 21, + 9, + 254, + 100, + 115, + 80, + 117, + 387, + 389, + 236, + 257, + 226, + 292, + 169, + 238, + 92, + 36, + 190, + 73, + 177, + 301, + 24, + 173, + 168, + 242, + 208, + 91, + 366, + 87, + 206, + 247, + 161, + 340, + 105, + 151, + 108, + 26, + 124, + 228, + 268, + 371, 176, - 128, + 360, + 334, + 164, + 190, + 10, + 59, + 63, + 67, + 2, + 135, + 334, + 166, + 266, + 350, + 153, + 142, + 32, + 261, + 107, + 389, + 170, + 1, + 27, + 19, + 331, + 288, + 190, + 311, + 189, + 82, + 34, + 369, + 89, + 127, + 217, + 344, + 248, + 312, 233, - 333, 215, - 74, - 28, - 326, + 86, + 5, + 203, + 362, + 54, + 278, + 33, + 310, + 342, + 154, + 168, + 376, + 378, 16, - 252, + 140, + 285, + 336, + 237, + 185, + 303, + 222, + 10, + 120, + 341, + 110, + 125, + 16, + 180, + 211, + 362, + 344, + 244, + 199, + 168, + 146, + 114, + 55, + 347, + 242, + 318, + 392, + 298, + 316, + 230, + 109, + 23, + 271, + 289, + 169, + 26, + 96, + 47, + 114, + 159, + 119, + 320, + 367, + 10, + 36, 171, - 106, - 66, + 349, + 270, + 384, + 245, + 15, + 393, + 192, + 43, + 356, + 247, + 68, + 320, + 215, + 21, + 366, + 58, + 186, + 335, + 131, + 321, + 7, + 280, + 239, + 224, + 159, + 237, + 271, + 13, + 129, + 231, + 396, + 221, + 359, + 14, + 372, + 253, + 267, + 349, + 375, + 290, + 361, + 243, + 252, + 1, + 261, + 397, + 60, + 375, + 393, + 234, + 105, + 342, + 301, + 380, + 143, + 393, + 282, + 6, + 279, + 321, + 308, + 148, + 143, + 358, + 114, + 192, + 206, + 220, + 382, + 343, + 207, + 186, + 194, + 395, + 144, + 77, + 264, + 19, + 251, + 336, + 60, + 57, + 182, + 363, + 19, + 225, + 226, + 241, + 333, + 260, + 267, + 380, + 375, + 234, + 340, + 27, + 132, + 335, + 379, + 143, + 225, + 50, + 8, + 209, + 306, + 223, + 122, + 127, + 302, + 244, + 194, + 301, + 251, + 393, + 326, + 239, + 50, + 98, + 352, + 100, + 65, + 372, + 365, + 241, + 43, + 336, + 353, + 259, + 144, + 101, + 356, + 209, 374, - 288, - 67, - 322, + 340, + 336, + 91, + 339, + 370, + 193, + 232, + 254, + 313, + 76, + 198, + 290, + 14, + 378, + 353, + 209, + 233, + 376, + 326, + 391, + 286, + 309, + 10, + 263, + 45, + 83, + 92, + 181, + 239, + 87, + 82, + 171, + 217, + 52, + 127, + 323, + 157, + 270, + 21, + 114, + 172, + 51, + 290, + 276, + 308, + 47, + 296, + 84, + 122, + 365, + 373, + 324, + 104, + 100, + 6, + 382, 211, + 363, + 210, + 308, + 291, + 128, + 282, + 225, + 218, + 333, + 13, + 377, + 400, + 33, + 348, + 232, + 364, + 276, + 350, + 187, + 47, + 147, + 345, + 198, + 146, + 395, + 294, + 32, + 300, + 322, + 128, + 352, + 334, + 343, + 169, + 355, + 336, + 71, + 15, + 213, + 131, + 25, + 389, + 125, + 107, + 156, + 68, + 111, + 126, + 320, + 276, + 360, + 73, + 92, + 310, + 12, + 346, + 25, + 110, + 396, + 52, + 234, + 348, + 94, + 20, + 250, + 377, + 226, + 10, + 372, + 193, + 108, + 83, + 360, + 322, + 303, + 396, + 94, + 316, + 160, + 102, + 388, + 212, + 357, + 1, + 142, + 63, + 131, + 166, + 221, + 115, + 172, + 375, + 108, + 293, + 210, + 222, + 226, + 137, + 260, + 166, + 260, + 199, + 19, + 344, + 166, + 381, + 304, + 325, + 344, + 343, + 122, + 282, + 16, + 71, + 257, + 306, + 323, 54, - 86, + 366, + 47, + 264, + 262, + 8, + 213, + 64, + 186, + 6, 222, - 190, - 76, + 389, + 122, + 178, + 176, + 337, + 380, + 315, + 359, + 169, + 305, + 77, 30, - 215, - 150, - 72, - 232, + 113, + 291, + 341, 317, - 86, - 267, - 232, - 249, - 352, - 373, + 273, + 47, + 258, + 191, + 159, + 219, 162, + 73, + 23, + 60, + 344, + 198, + 318, + 138, + 4, + 184, + 16, + 379, + 37, + 306, + 338, + 189, + 193, + 173, + 323, + 164, + 305, + 33, + 157, + 330, + 27, + 16, + 335, + 339, + 352, + 191, + 10, + 36, + 222, + 77, + 307, + 103, + 358, + 196, + 333, + 169, + 386, + 308, + 152, + 34, + 75, + 348, + 219, + 343, + 48, + 11, + 2, + 23, + 367, + 365, + 294, + 275, + 39, + 338, + 154, + 335, 245, - 140, - 149, + 313, + 264, + 107, + 223, + 304, + 61, + 306, + 186, + 108, + 147, + 236, + 283, + 147, + 397, + 343, + 111, + 184, + 313, + 264, + 132, + 398, + 49, + 298, + 325, + 370, + 400, + 208, + 146, + 381, + 43, + 153, + 188, + 309, + 212, + 243, + 278, + 184, + 388, + 222, + 46, + 32, + 171, + 230, + 253, + 318, + 128, + 128, + 306, + 298, + 223, + 188, + 277, + 70, + 119, + 232, + 129, + 156, + 167, + 37, + 137, + 356, + 392, + 209, + 324, + 290, + 386, + 319, + 285, + 99, + 339, + 323, + 314, + 301, + 123, + 156, + 311, + 350, + 63, + 246, 240, - 206, - 75, - 57, - 193, - 272, - 91, + 78, + 110, + 342, + 332, + 374, + 286, + 20, + 253, + 332, + 340, + 37, + 210, + 174, + 324, + 236, + 243, + 395, + 375, + 134, + 288, + 177, + 279, + 33, + 286, + 204, + 134, + 319, + 391, + 181, + 211, + 355, + 32, + 312, + 62, + 69, + 124, + 297, + 38, + 388, + 37, + 350, + 53, + 2, + 129, + 24, + 234, + 372, + 394, + 231, + 168, + 367, + 139, + 345, + 46, + 279, + 180, + 147, + 89, + 364, + 168, + 153, + 94, + 63, + 62, + 127, + 110, + 245, + 229, + 4, + 298, + 352, + 262, + 41, + 269, + 121, + 129, + 40, + 228, + 254, + 114, + 128, + 118, + 73, + 261, + 375, + 65, + 14, + 175, + 128, + 367, + 110, + 50, + 366, + 65, + 59, + 170, + 260, + 58, + 12, + 224, + 246, + 87, + 210, + 12, + 130, + 354, + 123, + 122, + 299, + 143, + 311, + 187, + 298, + 372, + 201, + 159, + 395, + 356, + 15, + 142, + 352, + 212, + 302, + 212, + 213, + 58, + 265, + 209, + 156, + 392, + 261, + 313, + 323, + 293, + 302, + 299, + 171, + 258, + 353, + 382, + 54, 321, - 255, - 173, + 78, + 60, + 304, + 146, + 212, + 282, + 237, + 219, + 114, + 2, + 239, + 307, + 247, + 95, + 331, + 247, + 252, + 7, + 289, + 179, + 238, + 328, + 369, + 354, + 130, + 357, + 248, + 292, + 97, + 113, + 297, + 244, + 202, + 21, + 227, + 141, + 78, + 182, + 373, + 191, + 327, + 254, + 61, + 226, + 246, + 1, + 26, + 114, + 335, + 159, + 388, + 273, + 79, + 257, + 361, + 329, + 114, + 368, + 300, + 118, + 329, + 136, + 186, + 281, + 158, + 4, + 132, + 30, + 396, + 361, + 154, + 118, + 151, + 380, + 178, + 238, + 315, + 195, + 179, + 207, + 341, + 231, + 47, + 78, + 37, + 389, + 115, + 329, + 191, + 169, + 217, + 367, + 116, + 61, + 113, + 12, + 21, + 123, + 213, + 128, + 184, + 321, + 260, + 131, + 119, + 34, + 15, + 178, + 58, + 117, + 54, + 35, + 292, 92, - 45, - 251, + 271, + 181, + 62, + 168, + 82, + 72, + 310, + 215, + 309, + 334, + 281, + 72, + 351, + 333, + 171, + 207, + 85, + 221, + 232, + 349, + 59, + 258, + 43, + 216, + 54, + 211, + 345, + 131, + 314, + 391, + 39, + 300, + 41, + 35, + 9, + 313, + 269, + 86, + 239, + 189, + 240, + 279, + 331, + 333, + 359, + 128, + 229, + 107, + 87, + 163, + 49, + 151, + 167, + 221, + 327, + 324, + 305, + 281, + 309, + 269, + 141, + 295, + 56, + 66, + 356, + 49, + 289, + 136, 139, - 263, - 400, - 280, + 117, 257, - 184, + 361, + 297, + 329, + 31, + 142, + 389, + 164, 32, - 396, - 182, - 355, - 300, - 339, + 96, + 210, + 149, + 145, + 106, + 51, + 273, + 80, + 211, + 61, + 60, + 106, + 99, + 216, + 309, + 175, + 314, + 370, + 204, + 236, + 148, + 395, + 283, + 55, + 159, + 343, + 292, + 375, + 39, + 237, + 347, + 126, + 192, + 356, + 188, + 357, + 346, + 280, + 308, + 188, + 186, + 159, + 121, + 33, + 52, + 217, + 14, + 191, + 90, + 373, + 5, + 147, + 291, + 332, + 191, + 100, + 27, 17, - 388, + 300, + 63, + 277, + 308, + 235, + 301, + 63, + 208, + 269, + 70, + 134, + 101, + 74, + 393, + 309, + 50, + 69, + 92, + 276, + 89, + 329, + 158, + 346, + 309, + 274, + 274, + 67, + 46, + 45, + 49, + 65, + 254, + 211, + 71, + 206, + 254, + 354, + 301, + 80, + 293, + 229, 156, - 186, - 286, - 360, - 342, - 143, - 248, - 135, - 394, - 353, - 366, - 150, + 139, + 155, + 37, + 189, + 159, + 213, + 359, + 284, + 341, + 118, + 307, + 223, + 267, + 345, + 310, + 22, + 136, + 211, + 329, + 209, + 117, + 199, + 164, + 47, + 255, + 281, + 170, + 22, + 313, + 17, + 327, + 304, + 147, 174, - 332, - 91, - 297 + 229, + 83, + 289, + 92, + 335, + 316, + 143, + 179, + 325, + 121, + 128, + 38, + 61, + 64, + 321, + 69, + 321, + 136, + 101, + 108 ], "format": { "is_signed": false, @@ -219,6 +40019,19906 @@ }, "ans_mem": { "data": [ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, diff --git a/calyx-py/test/correctness/sdn.expect b/calyx-py/test/correctness/sdn.expect index 390add283..f84dae9ac 100644 --- a/calyx-py/test/correctness/sdn.expect +++ b/calyx-py/test/correctness/sdn.expect @@ -1,308 +1,60008 @@ { "ans_mem": [ + 87, + 327, + 190, + 248, + 14, + 289, + 110, + 293, + 61, + 331, + 120, + 378, + 17, + 235, + 172, + 373, + 64, + 265, + 115, + 325, + 31, + 373, + 180, + 300, + 85, + 359, + 176, + 297, + 2, + 217, + 120, + 85, + 145, + 3, + 5, + 41, + 372, + 29, + 396, + 70, + 216, + 51, + 369, + 200, + 354, + 94, + 292, + 359, + 361, + 363, + 279, + 224, + 95, + 383, + 350, + 216, + 157, + 384, + 129, + 293, + 25, + 213, + 157, + 284, 40, - 76, - 352, - 158, - 247, - 82, - 273, - 121, + 289, + 116, + 218, + 356, + 279, + 177, + 329, + 172, + 359, + 109, + 388, + 349, + 389, + 128, + 39, + 77, + 248, + 114, + 331, + 71, + 294, + 112, + 365, + 83, + 64, + 294, + 115, + 385, + 31, + 57, + 48, + 242, + 162, + 287, + 63, + 336, + 188, + 255, + 18, + 282, + 132, + 377, + 80, + 240, + 123, + 238, + 37, + 244, + 150, + 344, + 36, + 357, + 157, + 149, + 329, + 134, + 351, + 57, + 102, + 289, + 62, + 68, + 283, + 302, 207, + 289, + 381, + 132, + 372, + 13, + 208, + 252, + 139, + 227, + 69, + 229, + 227, + 227, + 26, + 217, + 287, + 253, + 212, + 205, + 315, + 240, + 279, + 218, + 53, + 270, + 338, + 295, + 201, + 232, + 218, + 278, + 254, + 216, + 290, + 242, + 140, + 289, + 137, + 238, + 163, + 373, + 126, + 351, + 72, + 267, + 187, + 376, + 44, + 223, + 164, + 269, 41, - 233, - 176, - 333, - 16, - 215, - 106, - 326, + 297, 28, + 254, + 143, + 399, + 62, + 211, + 134, + 219, + 21, + 346, + 140, + 306, + 98, + 341, + 175, + 339, + 93, + 289, + 39, + 278, + 47, + 396, + 14, + 340, + 75, + 249, + 68, + 281, + 100, + 366, + 63, + 306, + 211, + 342, + 206, + 94, + 347, + 102, + 237, + 13, + 375, + 148, + 329, + 96, + 198, + 55, + 129, + 273, + 29, + 209, + 190, + 361, + 37, + 267, + 121, + 222, + 224, + 55, + 368, + 170, + 330, + 372, + 130, + 203, + 172, + 385, + 26, + 370, + 156, + 399, + 130, + 289, + 158, + 219, + 101, + 232, + 162, + 278, + 6, + 341, + 296, + 266, + 321, + 265, + 112, + 398, + 1, + 399, + 188, 252, + 41, + 256, + 97, + 328, + 96, + 331, + 45, + 216, + 129, + 370, + 225, + 180, + 289, + 6, + 221, + 180, + 394, + 2, + 316, + 149, + 305, + 22, + 242, + 177, + 336, + 52, + 380, + 142, + 302, + 17, + 370, + 191, + 351, + 7, + 335, + 190, + 295, + 51, + 383, + 198, + 212, + 52, + 319, + 191, + 279, + 45, + 378, + 184, + 355, + 94, + 368, + 165, + 341, + 21, + 380, + 111, + 217, + 46, + 149, + 206, + 98, + 149, + 4, + 184, + 34, + 196, + 34, + 318, + 104, + 268, + 38, + 314, + 125, + 232, + 69, + 218, + 122, + 393, + 8, + 254, + 166, + 300, + 170, + 255, + 182, + 290, + 64, + 201, + 144, + 346, + 54, + 371, + 179, + 341, + 58, + 340, + 188, + 312, + 99, + 156, + 13, + 235, + 170, + 280, + 36, + 294, + 176, + 260, + 95, + 344, + 30, + 238, + 33, + 303, + 11, + 366, + 142, + 347, + 83, + 277, + 188, + 236, + 46, + 307, + 180, + 383, + 55, + 315, + 141, + 337, + 30, + 283, + 99, + 360, + 113, + 370, + 50, + 347, + 394, + 142, + 272, + 342, + 167, + 248, + 41, + 313, + 130, + 385, + 57, + 202, + 102, + 373, + 242, + 113, + 382, + 255, + 47, + 306, 150, - 374, - 16, - 322, - 86, + 299, + 205, + 221, + 2, + 215, + 167, + 230, + 15, + 338, + 171, + 286, + 66, + 391, + 61, + 209, + 45, + 378, + 56, + 249, + 181, + 312, + 6, + 383, + 175, + 389, + 31, + 249, + 102, + 394, + 30, + 235, + 183, + 389, + 46, + 287, + 127, + 357, + 96, + 367, + 113, + 394, + 75, + 260, + 146, + 261, + 67, + 377, + 180, + 334, + 98, + 209, + 192, + 293, + 80, + 306, + 74, + 321, + 41, + 257, + 101, + 238, + 83, + 383, + 93, + 332, + 38, + 296, + 183, + 244, + 101, + 357, + 148, + 274, + 264, + 19, + 219, + 121, + 218, + 353, + 245, + 266, + 214, + 382, + 54, 211, - 76, - 317, + 19, + 68, + 395, + 37, + 263, + 91, + 224, 72, - 232, - 193, 352, - 57, + 177, + 286, + 13, + 346, + 120, + 341, + 149, + 324, + 200, + 273, + 271, + 89, + 205, + 297, + 230, + 16, + 292, + 274, + 165, + 226, + 208, + 233, + 384, + 204, + 95, + 354, + 129, + 238, + 2, + 372, + 22, + 271, + 103, + 314, + 51, + 395, + 162, + 18, + 273, + 143, + 26, + 112, + 308, + 70, + 328, + 148, + 246, + 49, + 342, + 147, + 204, + 110, + 233, + 70, + 217, + 167, + 276, + 130, + 400, + 117, + 351, + 114, + 301, + 196, + 226, + 342, + 258, + 376, + 383, + 219, + 112, + 231, + 64, + 371, + 145, + 241, + 5, + 328, + 137, + 252, + 124, + 228, + 152, + 322, + 239, + 51, + 303, + 326, + 140, + 320, + 84, + 274, + 41, + 290, + 279, + 196, + 329, + 89, + 197, + 348, + 34, + 217, + 152, + 233, + 13, + 246, + 190, + 301, + 147, + 393, + 27, + 302, + 185, + 222, + 82, + 370, + 166, + 351, + 128, + 385, + 193, + 254, + 78, 240, + 131, + 307, + 26, + 375, + 90, + 253, + 200, + 238, + 56, + 317, + 119, + 232, + 81, + 394, + 93, + 216, + 351, + 290, + 123, + 309, + 104, + 362, + 171, + 261, + 147, + 323, + 200, + 291, + 83, + 386, + 196, + 271, + 12, + 224, + 124, + 270, + 371, + 236, + 14, + 228, + 94, + 206, + 125, + 252, + 17, + 273, + 191, + 388, + 84, + 367, + 153, + 263, + 6, + 244, + 191, + 245, + 62, + 303, + 158, + 364, + 10, + 221, + 305, + 32, + 159, + 335, + 71, + 353, + 397, + 16, + 144, + 66, + 306, + 143, + 301, + 175, + 330, + 1, + 303, + 172, + 361, + 7, + 373, + 146, + 253, + 161, + 360, + 351, + 203, + 183, + 335, + 111, + 300, + 332, + 29, + 147, + 81, + 295, + 146, + 264, + 148, + 263, + 134, + 227, + 292, + 29, + 146, + 42, + 138, + 280, + 52, + 163, + 344, + 72, + 253, + 14, + 209, + 52, + 381, + 134, + 260, + 84, + 393, + 151, + 338, + 181, + 388, + 279, + 11, + 350, + 228, + 179, + 268, + 87, + 257, + 187, + 333, + 32, + 247, + 151, + 206, + 77, + 371, + 195, + 379, + 83, + 251, 173, - 91, - 139, + 391, + 27, + 272, + 118, + 379, + 79, + 395, + 167, + 334, + 53, + 314, + 101, + 237, + 63, + 282, + 103, 400, - 32, + 52, + 203, + 169, + 243, + 83, + 392, + 162, + 286, + 4, + 300, + 146, + 381, + 48, + 212, + 142, + 358, + 24, + 208, + 161, + 282, + 27, + 237, + 21, + 373, + 133, + 219, + 58, + 197, + 228, + 139, + 339, + 220, + 231, + 157, + 223, + 93, + 227, + 192, + 354, + 117, + 203, + 106, + 264, + 11, + 273, + 99, + 374, + 1, + 205, + 334, + 248, + 283, + 262, + 305, + 49, + 350, + 53, + 215, + 336, + 364, + 226, + 217, + 313, + 200, + 303, + 56, + 380, + 93, + 328, + 77, + 290, + 44, + 274, + 137, + 393, + 83, + 208, 280, - 184, + 279, + 75, + 220, + 233, + 267, + 51, + 287, + 145, + 246, + 132, + 146, + 98, + 162, + 58, + 155, + 37, + 155, + 40, + 146, + 165, + 105, + 393, + 177, + 348, + 97, + 233, + 161, + 315, + 70, + 230, + 33, + 237, + 45, 257, - 17, - 156, - 360, + 64, + 382, + 164, + 9, + 381, + 31, + 56, + 51, + 37, + 365, + 64, + 383, + 152, + 55, + 190, + 27, + 240, + 169, + 66, + 138, + 48, + 316, + 166, + 388, + 62, + 150, + 106, + 382, + 34, + 249, + 151, + 136, + 121, + 21, + 155, + 244, + 39, + 239, 186, + 231, + 189, + 296, + 35, + 262, + 170, + 316, + 169, + 229, + 106, + 322, + 143, + 151, + 156, + 188, + 57, + 281, + 195, + 82, + 169, + 62, + 146, + 168, + 338, + 102, + 211, + 40, + 222, + 134, + 302, + 193, + 305, + 137, + 211, + 92, + 292, + 238, + 178, + 317, + 17, + 356, + 4, + 355, + 216, + 217, 342, - 135, - 366, - 174, - 91, - 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 - ], - "commands": [ - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, + 274, + 248, + 352, + 353, + 125, + 209, + 96, + 325, + 145, + 22, + 395, + 180, + 282, + 85, + 351, + 163, + 297, + 49, + 369, + 183, + 349, + 59, + 240, + 112, + 300, + 310, + 378, + 396, + 273, + 16, + 242, + 133, + 215, + 93, + 255, + 152, + 400, + 100, + 264, + 9, + 272, + 85, + 323, + 22, + 400, + 37, + 356, + 115, + 324, + 67, + 370, + 3, + 359, + 156, + 272, + 14, + 264, + 108, + 303, + 53, + 261, + 101, + 236, + 48, + 224, + 193, + 388, + 72, + 383, + 125, + 345, + 75, + 209, + 172, + 225, + 73, + 262, + 152, + 46, + 74, + 27, + 3, + 326, + 67, + 155, + 22, + 290, + 157, + 305, + 36, + 230, + 127, + 350, + 31, + 375, + 105, + 331, + 135, + 394, + 11, + 360, + 163, + 319, + 147, + 391, + 184, + 282, + 19, + 232, + 60, + 308, + 306, + 71, + 283, + 391, + 387, + 61, + 159, + 51, + 47, + 44, + 254, + 193, + 211, + 25, + 259, + 136, + 269, + 95, + 209, + 167, + 301, + 50, + 253, + 117, + 259, + 65, + 237, + 121, + 308, + 62, + 280, + 115, + 315, + 68, + 263, + 114, 2, - 0 - ], - "values": [ - 40, + 141, + 150, + 57, + 280, + 141, + 26, + 158, + 221, + 100, + 284, + 174, + 251, + 61, + 198, + 385, + 74, + 117, + 101, + 50, + 343, + 291, + 85, + 376, + 67, + 152, + 77, + 306, + 287, + 46, + 143, + 136, + 304, + 130, + 338, + 14, + 208, + 153, + 397, + 108, + 224, + 42, + 306, + 145, + 387, + 76, + 331, + 189, + 237, + 190, + 264, + 149, + 338, + 63, + 223, + 104, + 395, + 9, + 219, + 113, + 362, + 21, + 232, + 59, + 214, + 91, + 356, + 91, + 371, + 142, + 280, + 49, + 230, + 25, + 392, + 190, + 284, + 147, + 285, + 117, + 357, + 147, + 276, + 69, + 301, + 115, + 320, + 16, + 330, + 148, + 337, + 56, + 380, + 112, + 398, + 149, + 351, + 182, + 229, + 338, + 82, + 254, + 207, + 134, + 238, + 202, + 271, + 148, + 231, + 73, + 213, + 198, + 326, + 68, 320, + 123, + 201, + 25, + 288, + 149, + 342, + 163, + 210, + 170, + 263, + 152, + 234, + 210, + 314, + 204, + 347, + 60, + 163, + 366, + 134, + 204, + 185, + 74, + 68, + 309, + 276, + 89, + 207, + 7, + 336, + 151, + 381, + 50, + 304, + 157, + 268, + 148, + 243, + 166, + 256, + 177, + 341, + 25, + 165, + 394, + 106, + 335, + 122, + 243, + 37, + 252, + 135, + 389, + 105, + 316, + 166, + 252, + 30, + 262, + 130, + 378, 76, + 251, + 251, + 327, + 380, + 276, + 345, + 137, + 258, + 75, + 349, + 167, + 359, + 92, + 270, + 133, + 224, + 96, + 290, + 282, + 98, + 289, + 100, + 244, + 82, + 165, + 280, + 24, + 121, + 174, + 169, + 185, + 364, + 110, + 179, + 312, + 59, + 247, + 153, + 249, + 150, + 241, + 33, 369, + 169, + 391, + 48, + 284, + 181, + 208, + 62, + 268, + 121, + 228, + 41, + 299, + 141, + 207, + 143, + 217, + 61, + 356, + 122, + 358, + 36, + 327, + 120, + 285, + 83, + 339, + 117, + 331, + 9, + 210, + 135, + 397, + 55, + 297, + 129, + 288, + 69, + 333, + 157, + 383, + 91, + 239, + 200, + 276, + 3, + 200, + 324, + 98, + 105, + 25, + 183, + 385, + 67, + 356, + 56, + 391, + 143, + 299, + 88, + 233, + 150, + 299, + 96, + 247, + 103, + 340, + 50, + 307, + 187, + 212, + 46, + 292, + 161, + 322, + 52, + 236, + 163, + 72, + 132, + 48, + 384, + 159, + 97, + 102, + 58, + 270, + 132, + 258, + 96, + 318, + 111, + 302, + 82, + 393, + 131, + 373, + 17, + 281, + 164, + 272, + 83, + 321, + 15, + 319, + 30, + 240, + 264, + 143, + 239, + 12, + 251, + 146, + 217, + 155, + 248, + 177, + 230, + 117, + 264, + 179, + 255, + 137, + 219, + 131, + 398, + 131, + 337, + 94, + 384, + 112, + 258, + 104, + 201, + 174, + 274, + 74, + 337, + 144, + 314, + 96, + 220, + 110, + 374, + 180, + 344, + 180, + 331, + 138, + 364, + 28, + 305, + 101, + 235, + 141, + 392, + 107, + 189, + 248, + 150, + 199, + 344, + 171, + 293, + 152, + 384, + 291, + 254, + 322, + 351, + 239, + 64, + 398, + 8, + 118, + 329, + 47, + 335, + 123, + 335, + 58, + 375, + 104, + 328, + 20, + 268, + 170, + 245, + 23, + 355, + 68, + 390, + 73, + 352, + 200, + 336, + 11, + 205, + 59, + 248, + 53, + 256, + 188, + 248, + 79, + 240, + 176, + 349, + 13, + 277, + 162, + 262, + 93, + 253, + 181, + 261, + 79, + 214, + 107, + 395, + 73, + 393, + 175, + 227, + 63, + 231, + 155, + 295, + 18, + 336, + 16, + 218, + 56, + 368, + 42, + 209, + 268, + 16, + 210, + 205, + 7, + 359, + 195, + 298, + 137, + 242, + 36, + 399, + 382, + 5, + 241, + 329, + 297, + 396, + 29, + 272, + 75, + 240, + 186, + 247, + 18, + 271, + 71, + 203, + 74, + 351, + 143, + 347, + 58, + 379, + 151, + 384, + 18, + 258, + 124, + 252, + 16, + 215, + 106, + 218, + 32, + 257, + 133, + 237, + 51, + 284, + 139, + 257, + 25, + 244, + 142, + 208, + 35, + 391, + 147, + 303, + 188, + 292, + 40, + 272, + 110, + 220, + 3, + 351, + 157, + 362, + 53, + 398, + 170, + 385, + 2, + 213, + 168, + 394, + 17, + 302, + 189, + 8, + 333, + 200, + 358, + 10, + 323, + 200, + 355, + 63, + 360, + 185, + 205, + 27, + 351, + 188, + 228, + 29, + 238, + 187, + 303, + 6, + 348, + 175, + 266, + 96, + 331, + 181, + 270, + 51, + 340, + 172, + 239, + 43, + 296, + 159, + 337, + 29, + 317, + 115, + 332, + 12, + 271, + 138, + 65, + 218, + 148, + 380, + 49, + 184, + 96, + 200, + 306, + 23, + 398, + 120, + 218, + 85, + 343, + 131, + 211, + 15, + 316, + 143, + 288, + 32, + 113, + 29, + 228, + 143, + 372, + 34, + 356, + 166, + 274, + 100, + 350, + 111, + 62, + 101, + 361, + 42, + 195, + 23, + 52, + 206, + 17, + 331, + 53, + 240, + 67, + 340, + 183, + 260, + 35, + 266, + 193, + 280, + 67, + 389, + 156, + 241, + 91, + 298, + 168, + 396, + 2, + 303, + 134, + 282, + 40, + 291, + 183, + 362, + 52, + 283, + 157, + 317, + 188, + 364, + 69, + 381, + 133, + 318, + 44, + 278, + 193, + 264, + 30, + 257, + 127, + 252, + 77, + 322, + 173, + 216, + 44, + 354, + 155, + 280, + 189, + 288, + 139, + 367, + 373, + 140, + 343, + 297, + 334, + 92, + 388, + 193, + 13, + 236, + 197, + 169, + 25, + 345, + 30, + 87, + 102, + 39, + 288, + 158, + 256, + 87, + 272, + 197, + 264, + 20, + 399, + 129, + 283, + 53, + 131, + 393, + 99, + 124, + 58, + 152, + 251, + 42, + 237, + 35, + 362, + 66, + 213, + 297, + 288, + 292, + 325, + 142, + 358, + 44, + 360, + 140, + 213, + 117, + 303, + 71, + 249, + 38, + 366, + 72, + 253, + 89, + 353, + 163, + 392, + 16, + 353, + 78, + 282, + 126, + 355, + 47, + 273, + 129, + 342, + 2, + 301, + 91, + 235, + 70, + 304, + 345, + 346, + 121, + 216, + 83, + 204, + 120, + 389, + 130, + 305, + 32, + 252, + 134, + 216, + 16, + 296, + 31, + 255, + 11, + 202, + 167, + 396, + 90, + 389, + 120, + 245, + 75, + 262, + 185, + 307, + 89, + 374, + 134, + 331, + 51, + 342, + 145, + 205, + 27, + 282, + 145, + 57, + 398, + 165, + 212, + 33, + 290, + 160, + 384, + 53, + 218, + 132, + 381, + 41, + 298, + 40, + 260, + 348, + 300, + 218, + 6, + 381, + 65, + 220, + 41, + 255, + 174, + 289, + 77, + 400, + 110, + 316, + 66, + 248, + 69, + 254, + 10, + 398, + 28, + 261, + 98, + 314, + 76, + 396, + 39, + 322, + 160, + 395, + 206, + 13, + 300, + 169, + 304, + 92, + 287, + 150, + 240, + 293, + 80, + 399, + 167, + 354, + 196, + 211, + 168, + 251, + 356, + 18, + 343, + 194, + 350, + 132, + 318, + 222, + 323, + 151, + 218, + 126, + 342, + 103, + 285, + 147, + 352, + 250, + 317, + 167, + 213, + 387, + 195, + 274, + 103, + 331, + 337, + 289, + 369, + 399, + 333, + 286, + 385, + 366, + 400, + 25, + 341, + 141, + 221, + 73, + 246, + 184, + 338, + 92, + 332, + 101, + 204, + 181, + 321, + 132, + 360, + 4, + 331, + 112, + 210, + 53, + 243, + 189, + 399, + 52, + 378, + 119, + 260, + 85, + 341, + 193, + 263, + 74, + 295, + 127, + 311, + 154, + 315, + 37, + 371, + 152, + 251, + 25, + 249, + 320, + 41, + 316, + 37, + 225, + 368, + 68, + 367, + 389, + 361, + 250, + 338, + 355, + 186, + 347, + 325, + 202, + 88, + 377, + 175, + 303, + 79, + 317, + 138, + 346, + 80, + 317, + 186, + 364, + 88, + 248, + 68, + 362, + 69, + 92, + 211, + 55, + 231, + 92, + 337, + 87, + 277, + 17, + 358, + 15, + 327, + 196, + 264, + 92, + 211, + 140, + 203, + 17, + 393, + 185, + 385, + 316, + 54, + 293, + 252, + 386, + 359, + 54, + 351, + 148, + 351, + 207, + 37, + 257, + 188, + 386, + 81, + 321, + 132, + 310, + 44, + 296, + 188, + 228, + 39, + 338, + 156, + 229, + 52, + 385, + 142, + 97, + 139, + 258, + 77, + 316, + 189, + 114, + 136, + 278, + 128, + 328, + 84, + 309, + 112, + 232, + 194, + 344, + 119, + 281, + 105, + 295, + 105, + 251, + 39, + 317, + 179, + 360, + 100, + 260, + 76, + 386, + 37, + 334, + 238, + 299, + 90, + 330, + 311, + 126, + 385, + 61, + 385, + 200, + 356, + 64, + 167, + 56, + 108, + 305, + 26, + 214, + 82, + 284, + 19, + 324, + 54, + 246, + 133, + 247, + 57, + 258, + 157, + 302, + 74, + 330, + 103, + 365, + 87, + 121, + 226, + 88, + 348, + 57, + 305, + 37, + 315, + 97, + 312, + 266, + 307, + 33, + 311, + 393, + 315, + 311, + 166, + 390, + 138, + 313, + 34, + 358, + 200, + 280, + 15, + 386, + 168, + 266, + 4, + 249, + 192, + 365, + 99, + 365, + 59, + 400, + 25, + 381, + 104, + 357, + 16, + 359, + 126, + 394, + 54, + 86, + 322, + 343, + 313, + 260, + 222, + 165, + 243, + 230, + 355, + 73, + 204, + 279, + 324, + 149, + 223, + 352, + 80, + 264, + 114, + 319, + 73, + 318, + 145, + 255, + 99, + 289, + 187, + 281, + 8, + 381, + 178, + 261, + 29, + 142, + 46, + 109, + 121, + 300, + 113, + 308, + 57, + 313, + 138, + 221, + 37, + 380, + 89, + 310, + 38, + 357, + 38, + 332, + 117, + 345, + 29, + 319, + 123, + 320, + 61, + 239, + 109, + 224, + 5, + 228, + 168, + 228, + 100, + 156, + 52, + 50, + 356, + 50, + 161, + 283, + 149, + 215, + 65, + 267, + 142, + 216, + 20, + 334, + 160, + 373, + 77, + 203, + 170, + 362, + 73, + 219, + 156, + 249, + 52, + 386, + 105, + 360, + 84, + 385, + 111, + 229, + 197, + 308, + 111, + 385, + 191, + 267, + 153, + 302, + 32, + 302, + 130, + 361, + 143, + 260, + 183, + 313, + 168, + 386, + 53, + 355, + 190, + 305, + 42, + 255, + 112, + 317, + 116, + 271, + 80, + 202, + 154, + 214, + 50, + 296, + 25, + 377, + 28, + 255, + 96, + 297, + 181, + 342, + 78, + 365, + 253, + 374, + 243, + 345, + 254, + 297, + 354, + 373, + 276, + 313, + 88, + 43, + 246, + 76, + 201, + 179, + 385, + 60, + 367, + 111, + 373, + 85, + 373, + 171, + 268, + 42, + 292, + 159, + 285, + 58, + 267, + 192, + 223, + 19, + 110, + 246, + 47, + 330, + 168, + 201, + 22, + 282, + 199, + 236, + 61, + 307, + 115, + 310, + 29, + 331, + 115, + 378, + 26, + 241, + 171, + 260, + 83, + 262, + 101, + 335, + 74, + 293, + 178, + 355, + 49, + 218, + 167, + 283, + 2, + 293, + 9, + 269, + 30, + 284, + 47, + 274, + 16, + 336, + 371, + 378, + 343, + 379, + 235, + 316, + 62, + 292, + 207, + 213, + 335, + 393, + 136, + 357, + 67, + 345, + 63, + 310, + 105, + 242, + 84, + 202, + 163, + 326, + 64, + 344, + 80, + 256, + 267, + 374, + 200, + 367, + 50, + 320, + 340, + 172, + 241, + 100, + 378, + 191, + 223, + 322, + 132, + 385, + 43, + 305, + 24, + 239, + 157, + 252, + 47, + 255, + 178, + 261, + 99, + 302, + 170, + 378, + 28, + 292, + 142, + 277, + 154, + 282, + 189, + 307, + 43, + 280, + 102, + 299, + 159, + 273, + 186, + 321, + 181, + 257, + 125, + 222, + 158, + 238, + 141, + 265, + 18, + 285, + 134, + 345, + 24, + 258, + 160, + 301, + 32, + 182, + 175, + 55, + 46, + 335, + 178, + 360, + 116, + 300, + 46, + 321, + 107, + 317, + 95, + 237, + 101, + 40, + 182, + 16, + 46, + 34, + 78, + 372, + 37, + 234, + 314, + 182, + 346, + 20, + 391, + 114, + 397, + 3, + 344, + 144, + 243, + 168, + 267, + 34, + 273, + 121, + 273, + 68, + 298, + 141, + 399, + 96, + 358, + 177, + 248, + 84, + 364, + 176, + 224, + 18, + 383, + 154, + 291, + 25, + 323, + 123, + 392, + 52, + 311, + 185, + 330, + 41, + 320, + 168, + 368, + 83, + 343, + 129, + 294, + 5, + 279, + 102, + 299, + 235, + 262, + 25, + 234, + 221, + 203, + 185, + 399, + 37, + 362, + 390, + 369, + 58, + 310, + 30, + 302, + 355, + 253, + 380, + 205, + 182, + 220, + 62, + 288, + 108, + 295, + 96, + 343, + 125, + 257, + 25, + 279, + 62, + 300, + 6, + 221, + 196, + 202, + 4, + 319, + 170, + 363, + 73, + 271, + 195, + 240, + 86, + 144, + 26, + 6, + 128, + 353, + 95, + 379, + 116, + 238, + 85, + 149, + 77, + 188, + 336, + 74, + 283, + 254, + 81, + 202, + 332, + 358, + 237, + 213, + 335, + 313, + 112, + 55, + 146, + 50, + 228, + 190, + 286, + 96, + 238, + 131, + 328, + 56, + 302, + 151, + 332, + 112, + 312, + 131, + 236, + 138, + 335, + 325, + 60, + 343, + 337, + 47, + 316, + 222, + 91, + 208, + 50, + 278, + 375, + 260, + 254, + 149, + 390, + 275, + 157, + 347, + 176, + 361, + 116, + 344, + 165, + 337, + 103, + 239, + 359, + 89, + 149, + 65, + 160, + 113, + 287, + 95, + 159, + 351, + 50, + 96, + 382, + 161, + 323, + 293, + 263, + 293, + 262, + 266, + 41, + 261, + 190, + 228, + 119, + 222, + 22, + 272, + 184, + 353, + 36, + 368, + 133, + 254, + 9, + 249, + 136, + 257, + 125, + 285, + 143, + 280, + 289, + 164, + 210, + 195, + 248, + 63, + 393, + 172, + 378, + 81, + 333, + 47, + 297, + 36, + 369, + 52, + 373, + 25, + 271, + 164, + 219, + 69, + 258, + 158, + 294, + 2, + 396, + 160, + 203, + 70, + 260, + 182, + 319, + 24, + 317, + 190, + 329, + 4, + 271, + 146, + 386, + 49, + 334, + 113, + 254, + 25, + 313, + 107, + 252, + 45, + 250, + 138, + 208, + 87, + 388, + 121, + 310, + 39, + 360, + 27, + 357, + 42, + 278, + 135, + 294, + 84, + 324, + 343, + 172, + 354, + 180, + 374, + 22, + 259, + 117, + 263, + 4, + 327, + 109, + 182, + 188, + 356, + 76, + 379, + 377, + 173, + 234, + 38, + 298, + 175, + 218, + 91, + 239, + 81, + 313, + 102, + 377, + 91, + 215, + 151, + 257, + 77, + 388, + 122, + 343, + 10, + 323, + 141, + 377, + 40, + 364, + 190, + 202, + 65, + 326, + 36, + 254, + 53, + 395, + 128, + 220, + 63, + 326, + 55, + 334, + 128, + 284, + 19, + 216, + 138, + 205, + 8, + 290, + 34, + 222, + 24, + 303, + 200, + 255, + 99, + 239, + 55, + 289, + 71, + 237, + 199, + 231, + 32, + 309, + 45, + 223, + 109, + 318, + 34, + 310, + 118, + 311, + 8, + 333, + 103, + 214, + 55, + 229, + 154, + 209, + 53, + 271, + 108, + 390, + 57, + 135, + 36, + 371, + 162, + 25, + 115, + 40, + 13, + 240, + 80, + 108, + 275, + 59, + 32, + 399, + 52, + 317, + 98, + 337, + 120, + 252, + 59, + 209, + 18, + 259, + 2, + 248, + 35, + 375, + 31, + 233, + 190, + 242, + 251, + 243, + 80, + 218, + 192, + 263, + 148, + 223, + 368, + 163, + 230, + 48, + 262, + 134, + 331, + 68, + 272, + 390, + 298, + 323, + 262, + 272, + 187, + 336, + 66, + 373, + 166, + 217, + 82, + 257, + 259, + 297, + 213, + 225, + 320, + 288, + 154, + 227, + 99, + 210, + 164, + 289, + 165, + 226, + 189, + 250, + 313, + 105, + 386, + 399, + 191, + 310, + 338, + 314, + 155, + 228, + 232, + 386, + 165, + 256, + 331, + 80, + 320, + 131, + 334, + 327, + 286, + 22, + 253, + 108, + 289, + 77, + 208, + 118, + 310, + 45, + 398, + 164, + 341, + 50, + 362, + 109, + 353, + 36, + 205, + 181, + 326, + 91, + 304, + 188, + 395, + 131, + 328, + 337, + 392, + 145, + 263, + 258, + 245, + 130, + 284, + 372, + 233, + 286, + 348, + 38, + 335, + 214, + 241, + 277, + 85, + 264, + 172, + 55, + 355, + 118, + 376, + 47, + 228, + 182, + 291, + 35, + 229, + 126, + 384, + 5, + 234, + 109, + 296, + 4, + 272, + 134, + 84, + 286, + 188, + 22, + 192, + 89, + 187, + 339, + 77, + 180, + 77, + 239, + 110, + 349, + 172, + 225, + 74, + 348, + 125, + 357, + 79, + 225, + 101, + 387, + 4, + 398, + 123, + 226, + 166, + 347, + 55, + 165, + 96, + 299, + 144, + 209, + 75, + 385, + 153, + 348, + 68, + 324, + 135, + 217, + 75, + 367, + 146, + 261, + 12, + 399, + 126, + 220, + 62, + 300, + 120, + 286, + 40, + 270, + 86, + 24, + 388, + 189, + 252, + 137, + 279, + 148, + 145, + 219, + 107, + 305, + 272, + 58, + 370, + 156, + 302, + 17, + 292, + 37, + 398, + 72, + 261, + 130, + 319, + 26, + 346, + 35, + 69, + 188, + 300, + 31, + 306, + 120, + 225, + 86, + 267, + 105, + 344, + 19, + 314, + 148, + 365, + 46, + 376, + 148, + 265, + 20, + 267, + 181, + 235, + 27, + 208, + 124, + 238, + 64, + 339, + 156, + 284, + 29, + 327, + 161, + 285, + 31, + 377, + 5, + 267, + 238, + 305, + 389, + 10, + 380, + 104, + 204, + 92, + 354, + 154, + 239, + 33, + 273, + 155, + 366, + 71, + 373, + 186, + 319, + 46, + 247, + 120, + 217, + 78, + 343, + 122, + 205, + 190, + 2, + 368, + 183, + 67, + 292, + 198, + 368, + 40, + 245, + 113, + 359, + 33, + 244, + 187, + 240, + 34, + 286, + 178, + 292, + 71, + 384, + 166, + 288, + 81, + 317, + 190, + 32, + 261, + 111, + 242, + 14, + 248, + 157, + 212, + 84, + 218, + 66, + 261, + 143, + 253, + 83, + 358, + 139, + 382, + 7, + 235, + 160, + 271, + 100, + 286, + 114, + 318, + 76, + 354, + 101, + 292, + 78, + 285, + 182, + 291, + 55, + 350, + 195, + 325, + 6, + 301, + 195, + 210, + 35, + 215, + 12, + 308, + 97, + 273, + 156, + 278, + 80, + 246, + 184, + 268, + 67, + 294, + 172, + 374, + 98, + 228, + 171, + 307, + 81, + 392, + 33, + 231, + 21, + 294, + 308, + 348, + 203, + 333, + 351, + 219, + 272, + 267, + 225, + 152, + 307, + 47, + 221, + 128, + 339, + 313, + 66, + 369, + 60, + 368, + 52, + 103, + 125, + 269, + 78, + 147, + 157, + 96, + 384, + 124, + 385, + 132, + 299, + 103, + 277, + 166, + 276, + 208, + 325, + 91, + 353, + 184, + 369, + 8, + 290, + 169, + 202, + 23, + 293, + 78, + 388, + 178, + 229, + 37, + 278, + 169, + 391, + 60, + 206, + 174, + 377, + 70, + 400, + 196, + 257, + 31, + 384, + 1, + 312, + 39, + 219, + 199, + 376, + 85, + 345, + 178, + 88, + 31, + 11, + 80, + 53, + 119, + 204, + 15, + 329, + 197, + 213, + 50, + 379, + 149, + 221, + 76, + 226, + 143, + 85, + 57, + 3, + 392, + 160, + 69, + 135, + 339, + 83, + 347, + 197, + 180, + 69, + 48, + 237, + 73, + 58, + 294, + 138, + 364, + 39, + 282, + 100, + 244, + 161, + 293, + 37, + 315, + 160, + 377, + 76, + 262, + 34, + 327, + 99, + 329, + 27, + 284, + 52, + 374, + 155, + 325, + 99, + 242, + 111, + 383, + 29, + 322, + 120, + 225, + 50, + 376, + 130, + 299, + 46, + 362, + 21, + 326, + 332, + 305, + 227, + 325, + 129, + 262, + 11, + 332, + 229, + 365, + 374, + 25, + 310, + 172, + 391, + 100, + 286, + 357, + 315, + 283, + 338, + 136, + 233, + 23, + 356, + 166, + 283, + 302, + 271, + 209, + 340, + 74, + 377, + 108, + 345, + 83, + 328, + 181, + 287, + 86, + 382, + 144, + 359, + 50, + 336, + 185, + 321, + 3, + 313, + 166, + 363, + 1, + 231, + 165, + 384, + 23, + 385, + 194, + 381, + 79, + 354, + 182, + 266, + 26, + 216, + 135, + 313, + 130, + 370, + 105, + 396, + 131, + 205, + 42, + 207, + 9, + 271, + 367, + 257, + 322, + 137, + 278, + 99, + 258, + 22, + 221, + 321, + 105, + 168, + 349, + 196, + 360, + 133, + 323, + 35, + 310, + 106, + 292, + 87, + 309, + 127, + 202, + 187, + 355, + 398, + 281, + 157, + 241, + 259, + 247, + 279, + 256, + 131, + 400, + 105, + 400, + 169, + 307, + 158, + 204, + 131, + 303, + 162, + 397, + 190, + 204, + 105, + 341, + 163, + 244, + 179, + 331, + 62, + 270, + 232, + 304, + 378, + 145, + 317, + 318, + 374, + 254, + 212, + 331, + 367, + 306, + 91, + 230, + 119, + 387, + 139, + 249, + 361, + 91, + 256, + 179, + 393, + 115, + 245, + 195, + 374, + 255, + 128, + 266, + 121, + 324, + 4, + 274, + 320, + 398, + 327, + 330, + 231, + 39, + 297, + 139, + 230, + 61, + 293, + 198, + 282, + 51, + 366, + 188, + 276, + 78, + 380, + 140, + 361, + 64, + 279, + 200, + 347, + 66, + 395, + 153, + 7, + 103, + 52, + 227, + 181, + 353, + 21, + 326, + 195, + 327, + 37, + 287, + 118, + 317, + 28, + 379, + 186, + 382, + 40, + 352, + 173, + 383, + 94, + 213, + 178, + 313, + 200, + 400, + 7, + 252, + 114, + 296, + 48, + 377, + 103, + 201, + 215, + 372, + 368, + 257, + 61, + 349, + 115, + 274, + 89, + 212, + 47, + 231, + 200, + 260, + 69, + 303, + 146, + 303, + 49, + 360, + 157, + 235, + 97, + 193, + 156, + 348, + 64, + 257, + 115, + 362, + 73, + 243, + 178, + 330, + 102, + 36, + 166, + 153, + 64, + 175, + 7, + 198, + 70, + 296, + 195, + 51, + 176, + 274, + 138, + 253, + 144, + 263, + 127, + 246, + 6, + 278, + 167, + 361, + 7, + 124, + 86, + 103, + 216, + 85, + 376, + 176, + 72, + 88, + 69, + 82, + 394, + 151, + 258, + 43, + 371, + 109, + 329, + 1, + 203, + 110, + 361, + 78, + 250, + 177, + 325, + 50, + 398, + 8, + 322, + 90, + 391, + 31, + 358, + 30, + 260, + 81, + 224, + 132, + 219, + 52, + 337, + 193, + 229, + 90, + 274, + 162, + 109, + 246, + 159, + 260, + 70, + 352, + 110, + 328, + 83, + 375, + 171, + 298, + 10, + 314, + 126, + 246, + 42, + 250, + 160, + 201, + 6, + 205, + 57, + 44, + 143, + 65, + 106, + 65, + 192, + 71, + 307, + 106, + 294, + 48, + 257, + 174, + 203, + 66, + 372, + 179, + 251, + 21, + 356, + 134, + 301, + 6, + 245, + 190, + 362, + 79, + 305, + 138, + 210, + 1, + 239, + 39, + 203, + 75, + 311, + 80, + 330, + 9, + 332, + 196, + 247, + 2, + 369, + 174, + 292, + 311, + 154, + 272, + 78, + 212, + 355, + 257, + 249, + 197, + 357, + 79, + 241, + 106, + 363, + 82, + 243, + 103, + 257, + 79, + 330, + 132, + 205, + 18, + 293, + 322, + 299, + 198, + 231, + 22, + 357, + 114, + 240, + 23, + 351, + 105, + 323, + 74, + 233, + 121, + 127, + 186, + 326, + 168, + 221, + 357, + 347, + 149, + 370, + 82, + 324, + 108, + 325, + 38, + 233, + 162, + 244, + 194, + 394, + 3, + 223, + 191, + 204, + 32, + 379, + 114, + 264, + 212, + 385, + 1, + 278, + 175, + 267, + 25, + 344, + 110, + 238, + 21, + 288, + 148, + 236, + 98, + 126, + 28, + 138, + 53, + 180, + 209, + 68, + 142, + 23, + 169, + 14, + 162, + 248, + 42, + 107, + 377, + 58, + 399, + 181, + 276, + 6, + 284, + 117, + 293, + 264, + 197, + 334, + 30, + 380, + 39, + 216, + 126, + 222, + 12, + 328, + 126, + 217, + 17, + 226, + 168, + 257, + 148, + 275, + 157, + 276, + 114, + 342, + 40, + 379, + 125, + 228, + 28, + 280, + 84, + 149, + 19, + 59, + 385, + 107, + 243, + 2, + 324, + 191, + 213, + 186, + 255, + 92, + 300, + 150, + 254, + 8, + 242, + 193, + 253, + 82, + 361, + 165, + 330, + 21, + 374, + 153, + 240, + 77, + 261, + 159, + 257, + 27, + 293, + 161, + 228, + 31, + 369, + 139, + 324, + 20, + 330, + 155, + 226, + 79, + 394, + 187, + 298, + 92, + 253, + 160, + 287, + 152, + 217, + 157, + 202, + 124, + 359, + 138, + 230, + 1, + 330, + 156, + 319, + 82, + 283, + 182, + 342, + 184, + 229, + 141, + 314, + 135, + 383, + 344, + 296, + 162, + 353, + 37, + 218, + 156, + 209, + 17, + 262, + 136, + 239, + 309, + 132, + 221, + 201, + 81, + 391, + 395, + 390, + 206, + 227, + 395, + 35, + 208, + 357, + 151, + 240, + 89, + 220, + 155, + 279, + 383, + 70, + 221, + 34, + 282, + 99, + 268, + 186, + 376, + 61, + 290, + 189, + 382, + 88, + 173, + 248, + 9, + 175, + 17, + 330, + 67, + 254, + 25, + 245, + 54, + 125, + 76, + 78, + 212, + 138, + 361, + 40, + 209, + 160, + 232, + 184, + 343, + 78, + 354, + 105, + 221, + 15, + 319, + 146, + 100, + 232, + 142, + 180, + 120, + 339, + 132, + 335, + 84, + 396, + 146, + 296, + 126, + 279, + 163, + 241, + 187, + 373, + 143, + 226, + 22, + 382, + 110, + 329, + 13, + 333, + 182, + 274, + 161, + 181, + 266, + 84, + 394, + 174, + 294, + 87, + 219, + 166, + 201, + 90, + 235, + 181, + 346, + 93, + 385, + 152, + 385, + 91, + 283, + 110, + 298, + 74, + 245, + 199, + 374, + 107, + 312, + 10, + 251, + 136, + 252, + 170, + 382, + 140, + 280, + 183, + 395, + 374, + 330, + 234, + 381, + 344, + 369, + 263, + 244, + 141, + 398, + 247, + 235, + 16, + 238, + 158, + 284, + 52, + 288, + 197, + 392, + 75, + 204, + 166, + 260, + 35, + 258, + 23, + 319, + 277, + 162, + 273, + 33, + 144, + 92, + 358, + 72, + 235, + 79, + 91, + 47, + 380, + 120, + 201, + 47, + 193, + 302, + 181, + 250, + 49, + 115, + 121, + 278, + 69, + 348, + 178, + 395, + 145, + 218, + 44, + 349, + 168, + 248, + 109, + 345, + 167, + 271, + 115, + 334, + 157, + 272, + 100, + 274, + 103, + 214, + 61, + 272, + 163, + 277, + 24, + 264, + 199, + 369, + 37, + 336, + 186, + 260, + 61, + 378, + 146, + 324, + 83, + 288, + 180, + 283, + 50, + 369, + 148, + 382, + 92, + 316, + 127, + 251, + 89, + 321, + 67, + 359, + 31, + 318, + 23, + 327, + 376, + 245, + 369, + 311, + 283, + 43, + 361, + 243, + 396, + 38, + 204, + 201, + 200, + 365, + 330, + 147, + 243, + 120, + 66, + 377, + 183, + 222, + 58, + 344, + 39, + 385, + 194, + 236, + 5, + 250, + 103, + 247, + 68, + 258, + 21, + 337, + 341, + 273, + 389, + 199, + 300, + 74, + 253, + 13, + 358, + 58, + 354, + 224, + 87, + 355, + 44, + 217, + 85, + 214, + 24, + 341, + 103, + 303, + 31, + 203, + 47, + 311, + 199, + 367, + 59, + 262, + 192, + 242, + 59, + 253, + 198, + 359, + 25, + 226, + 70, + 366, + 67, + 357, + 24, + 329, + 180, + 290, + 41, + 222, + 148, + 244, + 89, + 306, + 105, + 305, + 147, + 213, + 37, + 309, + 173, + 279, + 11, + 394, + 193, + 308, + 74, + 257, + 198, + 322, + 46, + 246, + 3, + 315, + 113, + 381, + 332, + 383, + 18, + 267, + 21, + 236, + 258, + 386, + 15, + 279, + 61, + 269, + 151, + 205, + 16, + 318, + 188, + 359, + 52, + 212, + 97, + 242, + 240, + 289, + 328, + 266, + 135, + 143, + 210, + 199, + 307, + 214, + 10, + 47, + 148, + 254, + 389, + 185, + 379, + 124, + 291, + 136, + 370, + 14, + 263, + 130, + 348, + 27, + 338, + 171, + 229, + 1, + 298, + 184, + 43, + 293, + 126, + 224, + 6, + 276, + 150, + 397, + 61, + 396, + 189, + 330, + 27, + 323, + 180, + 66, + 270, + 156, + 18, + 166, + 3, + 108, + 28, + 159, + 364, + 37, + 380, + 146, + 64, + 141, + 290, + 39, + 130, + 63, + 374, + 155, + 328, + 24, + 274, + 138, + 280, + 29, + 303, + 99, + 296, + 89, + 223, + 75, + 229, + 13, + 309, + 7, + 219, + 87, + 273, + 111, + 317, + 25, + 328, + 109, + 345, + 17, + 291, + 168, + 267, + 29, + 383, + 189, + 263, + 37, + 251, + 90, + 351, + 385, + 7, + 228, + 20, + 278, + 199, + 273, + 18, + 377, + 171, + 221, + 11, + 228, + 138, + 335, + 179, + 201, + 192, + 277, + 170, + 316, + 112, + 387, + 100, + 350, + 161, + 312, + 112, + 385, + 69, + 303, + 126, + 217, + 16, + 374, + 156, + 227, + 181, + 396, + 114, + 226, + 353, + 220, + 294, + 331, + 257, + 126, + 248, + 85, + 328, + 200, + 331, + 81, + 339, + 124, + 381, + 87, + 343, + 144, + 396, + 197, + 338, + 155, + 283, + 159, + 273, + 59, + 229, + 118, + 367, + 38, + 345, + 146, + 329, + 94, + 260, + 114, + 313, + 4, + 248, + 117, + 328, + 94, + 210, + 46, + 351, + 130, + 379, + 30, + 275, + 149, + 298, + 93, + 337, + 49, + 344, + 353, + 171, + 397, + 54, + 205, + 47, + 216, + 278, + 331, + 265, + 48, + 363, + 3, + 78, + 260, + 179, + 247, + 67, + 243, + 9, + 320, + 166, + 257, + 36, + 317, + 130, + 208, + 38, + 102, + 33, + 192, + 161, + 351, + 60, + 318, + 326, + 198, + 170, + 12, + 122, + 386, + 398, + 25, + 314, + 143, + 291, + 63, + 398, + 157, + 367, + 35, + 375, + 314, + 123, + 303, + 82, + 370, + 180, + 247, + 72, + 267, + 129, + 338, + 180, + 259, + 62, + 329, + 158, + 281, + 87, + 283, + 181, + 223, + 60, + 304, + 155, + 383, + 77, + 400, + 184, + 282, + 69, + 255, + 102, + 333, + 63, + 315, + 126, + 394, + 32, + 201, + 164, + 229, + 96, + 347, + 118, + 305, + 16, + 204, + 199, + 377, + 155, + 392, + 181, + 322, + 7, + 385, + 121, + 205, + 37, + 193, + 8, + 112, + 189, + 315, + 136, + 375, + 112, + 376, + 213, + 140, + 385, + 25, + 271, + 163, + 352, + 14, + 257, + 101, + 213, + 83, + 248, + 91, + 313, + 352, + 180, + 6, + 51, + 290, + 144, + 316, + 13, + 340, + 356, + 379, + 97, + 378, + 14, + 340, + 157, + 126, + 254, + 288, + 46, + 234, + 7, + 222, + 270, + 323, + 320, + 346, + 271, + 201, + 269, + 246, + 34, + 298, + 127, + 272, + 70, + 232, + 113, + 218, + 86, + 242, + 115, + 278, + 93, + 266, + 156, + 314, + 26, + 222, + 110, + 361, + 361, + 76, + 112, + 82, + 10, + 344, + 85, + 309, + 122, + 392, + 68, + 374, + 112, + 303, + 38, + 201, + 120, + 282, + 40, + 277, + 119, + 393, + 90, + 396, + 196, + 21, + 155, + 342, + 36, + 325, + 59, + 399, + 28, + 78, + 47, + 42, + 209, + 228, + 330, + 159, + 285, + 87, + 389, + 148, + 204, + 70, + 289, + 166, + 344, + 20, + 320, + 122, + 223, + 64, + 205, + 154, + 245, + 393, + 279, + 80, + 319, + 370, + 121, + 316, + 11, + 396, + 317, + 104, + 329, + 85, + 353, + 135, + 245, + 168, + 322, + 382, + 325, + 241, + 214, + 327, + 389, + 140, + 335, + 126, + 271, + 187, + 236, + 309, + 220, + 263, + 51, + 228, + 109, + 400, + 89, + 233, + 66, + 243, + 359, + 213, + 335, + 220, + 209, + 280, + 24, + 282, + 5, + 352, + 2, + 208, + 137, + 247, + 36, + 344, + 188, + 271, + 26, + 129, + 45, + 326, + 193, + 291, + 168, + 364, + 345, + 17, + 208, + 154, + 202, + 19, + 225, + 171, + 244, + 98, + 341, + 120, + 302, + 42, + 275, + 152, + 251, + 15, + 340, + 188, + 393, + 87, + 359, + 111, + 333, + 46, + 388, + 114, + 376, + 89, + 277, + 134, + 259, + 42, + 346, + 184, + 298, + 93, + 275, + 107, + 268, + 81, + 282, + 129, + 213, + 4, + 246, + 188, + 234, + 81, + 395, + 166, + 303, + 110, + 306, + 112, + 345, + 83, + 316, + 29, + 334, + 65, + 386, + 73, + 242, + 333, + 203, + 196, + 381, + 169, + 222, + 106, + 391, + 156, + 251, + 126, + 391, + 195, + 246, + 197, + 330, + 263, + 53, + 242, + 134, + 312, + 219, + 184, + 368, + 11, + 388, + 86, + 279, + 182, + 258, + 58, + 321, + 172, + 28, + 242, + 112, + 362, + 50, + 295, + 116, + 332, + 23, + 228, + 183, + 289, + 65, + 274, + 161, + 214, + 56, + 379, + 107, + 211, + 36, + 374, + 174, + 330, + 80, + 371, + 104, + 218, + 80, + 154, + 46, + 266, + 118, + 82, + 379, + 118, + 327, + 61, + 359, + 180, + 286, + 36, + 354, + 102, + 394, + 1, + 151, + 207, + 73, + 379, + 155, + 374, + 17, + 331, + 15, + 246, + 75, + 327, + 9, + 234, + 339, + 88, + 349, + 277, + 16, + 268, + 202, + 105, + 323, + 22, + 241, + 172, + 284, + 30, + 374, + 188, + 392, + 86, + 319, + 136, + 234, + 20, + 253, + 127, + 265, + 86, + 382, + 161, + 283, + 19, + 385, + 195, + 394, + 37, + 327, + 111, + 239, + 13, + 340, + 140, + 296, + 80, + 332, + 132, + 256, + 63, + 398, + 170, + 359, + 27, + 356, + 123, + 295, + 85, + 260, + 144, + 354, + 43, + 398, + 126, + 274, + 66, + 342, + 147, + 268, + 65, + 272, + 142, + 224, + 46, + 292, + 112, + 341, + 73, + 390, + 122, + 202, + 43, + 311, + 154, + 17, + 192, + 325, + 89, + 202, + 42, + 214, + 121, + 225, + 6, + 54, + 41, + 288, + 78, + 351, + 52, + 391, + 138, + 339, + 73, + 378, + 109, + 293, + 366, + 355, + 188, + 219, + 22, + 377, + 115, + 219, + 353, + 226, + 241, + 234, + 352, + 57, + 306, + 149, + 221, + 28, + 219, + 158, + 343, + 16, + 313, + 163, + 326, + 66, + 350, + 122, + 292, + 25, + 395, + 149, + 256, + 15, + 335, + 170, + 233, + 4, + 218, + 121, + 271, + 16, + 366, + 188, + 265, + 72, + 202, + 182, + 206, + 100, + 301, + 112, + 374, + 26, + 312, + 262, + 35, + 227, + 67, + 358, + 25, + 289, + 50, + 276, + 398, + 123, + 334, + 23, + 293, + 380, + 146, + 349, + 31, + 283, + 177, + 307, + 46, + 273, + 173, + 132, + 110, + 122, + 312, + 58, + 347, + 195, + 303, + 2, + 278, + 151, + 216, + 49, + 204, + 69, + 380, + 97, + 224, + 132, + 287, + 84, + 370, + 56, + 214, + 105, + 383, + 37, + 218, + 163, + 345, + 33, + 318, + 4, + 395, + 83, + 384, + 16, + 237, + 226, + 260, + 295, + 315, + 326, + 202, + 181, + 267, + 195, + 318, + 178, + 212, + 96, + 229, + 138, + 261, + 49, + 227, + 190, + 228, + 24, + 393, + 164, + 385, + 10, + 281, + 130, + 231, + 87, + 116, + 347, + 37, + 271, + 195, + 223, + 41, + 247, + 294, + 238, + 313, + 323, + 290, + 141, + 391, + 54, + 163, + 48, + 347, + 184, + 62, + 198, + 344, + 66, + 154, + 32, + 233, + 52, + 362, + 172, + 275, + 68, + 283, + 78, + 203, + 101, + 240, + 84, + 336, + 154, + 354, + 59, + 239, + 145, + 345, + 13, + 292, + 135, + 320, + 100, + 349, + 189, + 233, + 82, + 390, + 196, + 289, + 1, + 310, + 46, + 315, + 19, + 326, + 130, + 286, + 67, + 394, + 32, + 281, + 98, + 201, + 162, + 345, + 24, + 375, + 179, + 347, + 85, + 344, + 155, + 241, + 50, + 273, + 175, + 234, + 35, + 356, + 155, + 243, + 57, + 332, + 8, + 250, + 28, + 337, + 12, + 15, + 35, + 22, + 348, + 133, + 212, + 84, + 328, + 152, + 223, + 66, + 320, + 121, + 228, + 79, + 236, + 126, + 218, + 14, + 346, + 117, + 370, + 72, + 266, + 132, + 391, + 69, + 207, + 165, + 251, + 182, + 376, + 21, + 336, + 121, + 262, + 43, + 330, + 116, + 246, + 46, + 383, + 40, + 266, + 2, + 389, + 195, + 344, + 19, + 378, + 113, + 208, + 83, + 250, + 159, + 201, + 29, + 372, + 108, + 303, + 55, + 225, + 143, + 369, + 37, + 139, + 222, + 81, + 110, + 294, + 95, + 339, + 171, + 277, + 78, + 320, + 119, + 374, + 95, + 296, + 180, + 367, + 19, + 327, + 112, + 321, + 62, + 297, + 240, + 377, + 22, + 296, + 43, + 232, + 68, + 314, + 112, + 252, + 72, + 388, + 153, + 304, + 7, + 211, + 200, + 326, + 73, + 197, + 22, + 246, + 13, + 305, + 304, + 56, + 221, + 397, + 245, + 144, + 246, + 93, + 266, + 140, + 256, + 97, + 273, + 165, + 347, + 186, + 212, + 11, + 228, + 177, + 305, + 68, + 334, + 126, + 244, + 33, + 326, + 193, + 396, + 30, + 284, + 122, + 298, + 31, + 366, + 113, + 293, + 53, + 173, + 26, + 56, + 97, + 50, + 35, + 344, + 144, + 13, + 383, + 141, + 337, + 101, + 341, + 376, + 360, + 104, + 263, + 3, + 314, + 124, + 346, + 23, + 318, + 46, + 338, + 50, + 249, + 270, + 205, + 232, + 175, + 263, + 63, + 340, + 163, + 354, + 25, + 387, + 186, + 242, + 16, + 355, + 128, + 309, + 87, + 195, + 99, + 332, + 184, + 131, + 125, + 305, + 60, + 303, + 154, + 348, + 58, + 374, + 257, + 372, + 315, + 312, + 125, + 195, + 322, + 113, + 389, + 162, + 350, + 14, + 217, + 48, + 224, + 33, + 239, + 191, + 206, + 35, + 330, + 178, + 287, + 86, + 228, + 101, + 372, + 61, + 313, + 67, + 237, + 32, + 211, + 141, + 396, + 49, + 385, + 128, + 331, + 66, + 286, + 148, + 324, + 11, + 282, + 200, + 313, + 2, + 299, + 174, + 269, + 75, + 399, + 102, + 395, + 80, + 329, + 194, + 328, + 147, + 364, + 67, + 357, + 125, + 345, + 57, + 307, + 132, + 312, + 6, + 400, + 126, + 327, + 90, + 352, + 155, + 288, + 146, + 220, + 144, + 289, + 200, + 354, + 77, + 241, + 118, + 312, + 13, + 223, + 131, + 388, + 1, + 318, + 134, + 280, + 63, + 206, + 55, + 377, + 338, + 27, + 373, + 357, + 133, + 324, + 2, + 288, + 151, + 371, + 77, + 245, + 151, + 203, + 98, + 328, + 142, + 377, + 33, + 304, + 174, + 327, + 40, + 124, + 25, + 133, + 80, + 151, + 151, + 212, + 31, + 141, + 60, + 75, + 179, + 106, + 103, + 300, + 164, + 239, + 121, + 221, + 305, + 351, + 296, + 375, + 231, + 222, + 299, + 20, + 348, + 80, + 332, + 286, + 147, + 259, + 1, + 371, + 178, + 327, + 319, + 272, + 245, + 247, + 300, + 344, + 138, + 207, + 3, + 235, + 159, + 300, + 52, + 276, + 115, + 370, + 166, + 345, + 62, + 290, + 110, + 355, + 198, + 239, + 77, + 238, + 158, + 332, + 63, + 238, + 158, + 258, + 64, + 374, + 107, + 309, + 127, + 222, + 172, + 212, + 132, + 292, + 187, + 307, + 154, + 306, + 75, + 208, + 136, + 388, + 86, + 379, + 197, + 255, + 79, + 150, + 24, + 193, + 72, + 126, + 128, + 145, + 211, + 173, + 258, + 286, + 25, + 125, + 370, + 176, + 235, + 129, + 390, + 155, + 223, + 3, + 337, + 178, + 292, + 3, + 201, + 151, + 263, + 92, + 251, + 155, + 267, + 29, + 360, + 81, + 382, + 7, + 384, + 148, + 43, + 152, + 212, + 87, + 246, + 181, + 227, + 92, + 304, + 180, + 201, + 185, + 260, + 72, + 331, + 41, + 344, + 98, + 326, + 86, + 282, + 191, + 354, + 88, + 251, + 147, + 364, + 34, + 230, + 120, + 249, + 51, + 368, + 194, + 374, + 95, + 380, + 108, + 393, + 64, + 222, + 147, + 300, + 134, + 391, + 274, + 293, + 390, + 232, + 354, + 311, + 329, + 208, + 204, + 364, + 339, + 247, + 342, + 233, + 55, + 330, + 143, + 264, + 383, + 9, + 341, + 96, + 246, + 237, + 120, + 312, + 68, + 326, + 134, + 323, + 314, + 393, + 288, + 48, + 322, + 189, + 326, + 322, + 69, + 258, + 37, + 300, + 165, + 322, + 299, + 376, + 156, + 224, + 51, + 126, + 289, + 48, + 395, + 173, + 312, + 48, + 346, + 227, + 270, + 200, + 387, + 295, + 278, + 185, + 225, + 20, + 350, + 135, + 380, + 4, + 353, + 180, + 332, + 194, + 224, + 106, + 285, + 90, + 215, + 161, + 369, + 50, + 325, + 168, + 273, + 65, + 349, + 137, + 306, + 5, + 227, + 129, + 36, + 165, + 280, + 173, + 325, + 170, + 288, + 218, + 86, + 393, + 190, + 378, + 95, + 223, + 136, + 314, + 76, + 398, + 137, + 384, + 90, + 317, + 76, + 324, + 100, + 324, + 105, + 215, + 35, + 331, + 130, + 395, + 330, + 336, + 332, + 322, + 85, + 126, + 393, + 80, + 394, + 140, + 345, + 50, + 180, + 239, + 9, + 175, + 14, + 95, + 317, + 52, + 330, + 150, + 134, + 221, + 46, + 266, + 143, + 297, + 39, + 276, + 105, + 344, + 94, + 299, + 112, + 258, + 83, + 335, + 190, + 390, + 69, + 285, + 112, + 364, + 43, + 376, + 173, + 214, + 8, + 217, + 106, + 137, + 127, + 5, + 121, + 60, + 214, + 190, + 94, + 277, + 188, + 149, + 183, + 128, + 224, + 119, + 272, + 40, + 240, + 113, + 394, + 27, + 144, + 22, + 226, + 132, + 33, + 31, + 35, + 309, + 112, + 385, + 79, + 393, + 159, + 246, + 80, + 359, + 144, + 316, + 38, + 234, + 168, + 223, + 8, + 387, + 134, + 204, + 55, + 217, + 199, + 81, + 257, + 119, + 205, + 97, + 236, + 186, + 358, + 18, + 288, + 50, + 244, + 189, + 248, + 2, + 348, + 5, + 215, + 65, + 222, + 24, + 239, + 45, + 252, + 376, + 158, + 379, + 27, + 361, + 181, + 394, + 35, + 234, + 116, + 201, + 97, + 282, + 177, + 317, + 37, + 246, + 36, + 272, + 45, + 291, + 308, + 176, + 248, + 57, + 353, + 8, + 322, + 81, + 235, + 15, + 240, + 97, + 247, + 37, + 253, + 86, + 379, + 3, + 398, + 35, + 365, + 47, + 313, + 5, + 268, + 181, + 291, + 135, + 208, + 113, + 348, + 119, + 355, + 38, + 290, + 136, + 14, + 119, + 70, + 137, + 100, + 320, + 168, + 73, + 125, + 82, + 46, + 22, + 354, + 28, + 257, + 156, + 305, + 30, + 237, + 184, + 265, + 88, + 197, + 216, + 32, + 324, + 135, + 388, + 97, + 357, + 40, + 371, + 173, + 290, + 155, + 357, + 100, + 336, + 147, + 334, + 105, + 332, + 114, + 351, + 108, + 331, + 375, + 278, + 352, + 250, + 43, + 278, + 169, + 329, + 32, + 368, + 149, + 240, + 7, + 374, + 102, + 268, + 46, + 386, + 80, + 277, + 71, + 294, + 392, + 157, + 379, + 141, + 207, + 130, + 51, + 172, + 61, + 102, + 364, + 74, + 288, + 134, + 274, + 58, + 126, + 123, + 366, + 277, + 348, + 315, + 50, + 213, + 20, + 34, + 369, + 3, + 393, + 68, + 129, + 97, + 282, + 195, + 257, + 151, + 277, + 237, + 106, + 327, + 265, + 236, + 64, + 252, + 144, + 298, + 20, + 389, + 179, + 217, + 189, + 128, + 347, + 93, + 305, + 129, + 363, + 166, + 377, + 59, + 350, + 147, + 357, + 76, + 302, + 177, + 222, + 25, + 392, + 178, + 300, + 56, + 331, + 157, + 291, + 80, + 106, + 33, + 57, + 213, + 195, + 231, + 123, + 308, + 21, + 256, + 196, + 372, + 388, + 39, + 240, + 251, + 94, + 360, + 61, + 396, + 327, + 269, + 358, + 322, + 179, + 301, + 81, + 319, + 62, + 301, + 86, + 234, + 15, + 311, + 183, + 333, + 10, + 288, + 116, + 273, + 5, + 285, + 146, + 345, + 6, + 362, + 185, + 48, + 371, + 80, + 343, + 343, + 137, + 284, + 373, + 255, + 48, + 233, + 153, + 327, + 273, + 261, + 215, + 49, + 292, + 117, + 315, + 78, + 383, + 70, + 328, + 180, + 203, + 68, + 230, + 10, + 296, + 264, + 202, + 255, + 334, + 397, + 45, + 356, + 186, + 356, + 60, + 317, + 151, + 386, + 149, + 345, + 240, + 221, + 83, + 204, + 22, + 304, + 174, + 337, + 93, + 311, + 120, + 274, + 74, + 276, + 291, + 202, + 212, + 388, + 206, + 270, + 263, + 358, + 374, + 306, + 6, + 355, + 80, + 285, + 118, + 380, + 94, + 152, + 19, + 185, + 115, + 253, + 184, + 382, + 24, + 327, + 169, + 349, + 352, + 2, + 202, + 249, + 318, + 349, + 103, + 385, + 370, + 161, + 348, + 166, + 284, + 307, + 219, + 369, + 138, + 232, + 11, + 236, + 151, + 14, + 28, + 49, + 163, + 51, + 318, + 149, + 362, + 96, + 364, + 133, + 47, + 113, + 371, + 100, + 310, + 181, + 317, + 34, + 204, + 199, + 326, + 14, + 399, + 106, + 8, + 346, + 185, + 126, + 342, + 17, + 321, + 395, + 129, + 381, + 34, + 301, + 127, + 380, + 136, + 260, + 258, + 387, + 281, + 83, + 208, + 393, + 392, + 212, + 144, + 193, + 263, + 195, + 208, + 53, + 381, + 116, + 241, + 51, + 353, + 143, + 273, + 14, + 396, + 109, + 353, + 69, + 333, + 199, + 373, + 56, + 222, + 186, + 247, + 10, + 342, + 149, + 253, + 1, + 358, + 108, + 362, + 43, + 217, + 164, + 283, + 20, + 201, + 118, + 374, + 53, + 329, + 194, + 346, + 17, + 285, + 115, + 309, + 45, + 312, + 175, + 306, + 35, + 307, + 147, + 244, + 99, + 118, + 81, + 142, + 85, + 176, + 353, + 32, + 310, + 164, + 282, + 169, + 204, + 59, + 225, + 19, + 229, + 31, + 209, + 108, + 332, + 243, + 207, + 363, + 388, + 392, + 377, + 267, + 249, + 286, + 153, + 351, + 91, + 283, + 129, + 18, + 124, + 8, + 207, + 177, + 334, + 137, + 116, + 160, + 349, + 53, + 126, + 233, + 315, + 363, + 75, + 368, + 101, + 186, + 127, + 31, + 122, + 157, + 241, + 88, + 225, + 132, + 65, + 397, + 114, + 261, + 129, + 314, + 1, + 203, + 142, + 346, + 120, + 263, + 274, + 285, + 257, + 206, + 338, + 19, + 293, + 102, + 267, + 181, + 254, + 134, + 308, + 68, + 241, + 167, + 235, + 21, + 312, + 159, + 394, + 66, + 276, + 149, + 372, + 22, + 308, + 132, + 236, + 50, + 219, + 148, + 387, + 70, + 330, + 159, + 292, + 96, + 297, + 199, + 355, + 24, + 277, + 112, + 264, + 162, + 256, + 101, + 156, + 241, + 56, + 306, + 176, + 228, + 158, + 263, + 76, + 273, + 160, + 374, + 61, + 326, + 128, + 335, + 31, + 314, + 30, + 280, + 105, + 267, + 59, + 230, + 174, + 385, + 197, + 298, + 128, + 340, + 175, + 393, + 150, + 327, + 196, + 395, + 314, + 11, + 310, + 341, + 55, + 278, + 11, + 277, + 88, + 268, + 44, + 359, + 71, + 333, + 284, + 175, + 217, + 20, + 241, + 105, + 203, + 70, + 269, + 192, + 400, + 22, + 361, + 75, + 275, + 399, + 144, + 390, + 179, + 400, + 223, + 136, + 396, + 304, + 295, + 137, + 390, + 27, + 228, + 129, + 343, + 9, + 315, + 133, + 330, + 14, + 342, + 180, + 229, + 86, + 317, + 172, + 219, + 85, + 203, + 127, + 224, + 70, + 243, + 199, + 314, + 138, + 248, + 195, + 273, + 206, + 244, + 230, + 259, + 46, + 352, + 119, + 335, + 93, + 208, + 171, + 361, + 91, + 222, + 391, + 268, + 304, + 108, + 284, + 288, + 249, + 235, + 133, + 274, + 39, + 259, + 106, + 223, + 12, + 273, + 186, + 369, + 44, + 336, + 110, + 30, + 182, + 64, + 110, + 57, + 21, + 60, + 114, + 98, + 125, + 144, + 213, + 53, + 312, + 170, + 348, + 72, + 235, + 170, + 385, + 62, + 263, + 128, + 257, + 79, + 365, + 173, + 388, + 45, + 385, + 163, + 349, + 92, + 208, + 149, + 42, + 326, + 129, + 344, + 58, + 194, + 18, + 123, + 209, + 90, + 114, + 73, + 197, + 26, + 88, + 99, + 316, + 169, + 243, + 27, + 377, + 165, + 245, + 339, + 55, + 350, + 213, + 350, + 214, + 154, + 288, + 79, + 226, + 262, + 137, + 211, + 91, + 278, + 169, + 336, + 373, + 383, + 65, + 94, + 318, + 73, + 274, + 389, + 197, + 19, + 336, + 98, + 205, + 158, + 201, + 74, + 53, + 380, + 74, + 344, + 103, + 269, + 346, + 196, + 225, + 2, + 371, + 159, + 355, + 110, + 362, + 196, + 380, + 196, + 371, + 128, + 220, + 326, + 330, + 304, + 340, + 138, + 309, + 258, + 88, + 238, + 101, + 224, + 376, + 243, + 399, + 177, + 163, + 150, + 243, + 45, + 344, + 248, + 122, + 371, + 178, + 209, + 183, + 379, + 180, + 284, + 151, + 277, + 162, + 97, + 135, + 181, + 347, + 88, + 311, + 120, + 320, + 21, + 387, + 184, + 381, + 43, + 377, + 195, + 321, + 59, + 276, + 188, + 232, + 84, + 284, + 124, + 201, + 5, + 289, + 101, + 301, + 122, + 300, + 343, + 44, + 294, + 387, + 12, + 245, + 210, + 275, + 96, + 386, + 72, + 355, + 29, + 277, + 8, + 260, + 35, + 304, + 378, + 138, + 357, + 209, + 363, + 203, + 98, + 392, + 297, + 134, + 304, + 123, + 257, + 134, + 214, + 179, + 330, + 67, + 395, + 89, + 305, + 115, + 69, + 83, + 10, + 56, + 233, + 179, + 216, + 59, + 101, + 49, + 117, + 15, + 268, + 69, + 289, + 171, + 392, + 81, + 204, + 124, + 310, + 100, + 264, + 166, + 277, + 74, + 218, + 106, + 354, + 62, + 274, + 41, + 259, + 86, + 316, + 179, + 247, + 94, + 280, + 131, + 394, + 12, + 325, + 104, + 295, + 95, + 327, + 84, + 263, + 35, + 357, + 33, + 250, + 67, + 147, + 327, + 66, + 212, + 189, + 244, + 44, + 206, + 172, + 349, + 79, + 261, + 104, + 265, + 182, + 305, + 11, + 225, + 127, + 266, + 66, + 365, + 156, + 233, + 57, + 300, + 56, + 359, + 22, + 229, + 146, + 4, + 230, + 105, + 382, + 92, + 233, + 196, + 229, + 75, + 326, + 104, + 335, + 112, + 301, + 69, + 249, + 143, + 301, + 78, + 309, + 179, + 244, + 275, + 317, + 84, + 160, + 87, + 37, + 85, + 265, + 195, + 246, + 56, + 226, + 102, + 310, + 16, + 300, + 136, + 386, + 63, + 223, + 114, + 354, + 80, + 249, + 186, + 218, + 61, + 130, + 132, + 119, + 137, + 32, + 132, + 260, + 92, + 238, + 132, + 203, + 116, + 317, + 54, + 306, + 193, + 48, + 199, + 154, + 209, + 186, + 191, + 187, + 300, + 170, + 143, + 91, + 128, + 48, + 186, + 301, + 33, + 245, + 179, + 395, + 83, + 333, + 128, + 268, + 79, + 306, + 185, + 252, + 2, + 398, + 159, + 267, + 95, + 345, + 95, + 287, + 75, + 393, + 111, + 376, + 40, + 244, + 67, + 270, + 101, + 366, + 24, + 267, + 50, + 306, + 130, + 331, + 44, + 244, + 21, + 323, + 11, + 214, + 60, + 334, + 13, + 316, + 103, + 232, + 90, + 272, + 148, + 232, + 76, + 333, + 109, + 256, + 191, + 222, + 184, + 359, + 91, + 351, + 18, + 254, + 113, + 221, + 304, + 327, + 310, + 345, + 355, + 206, + 356, + 375, + 350, + 6, + 326, + 146, + 343, + 46, + 383, + 340, + 85, + 215, + 191, + 354, + 6, + 235, + 113, + 310, + 63, + 323, + 137, + 241, + 98, + 215, + 135, + 234, + 93, + 280, + 139, + 60, + 323, + 143, + 342, + 11, + 141, + 66, + 252, + 133, + 202, + 73, + 239, + 153, + 263, + 58, + 351, + 186, + 256, + 85, + 346, + 163, + 275, + 3, + 378, + 145, + 372, + 9, + 225, + 139, + 307, + 50, + 260, + 152, + 75, + 127, + 294, + 63, + 378, + 152, + 323, + 98, + 337, + 198, + 359, + 97, + 276, + 147, + 376, + 45, + 385, + 194, + 372, + 195, + 206, + 77, + 343, + 186, + 325, + 178, + 334, + 195, + 234, + 132, + 381, + 99, + 218, + 138, + 261, + 17, + 245, + 172, + 244, + 81, + 281, + 143, + 237, + 26, + 275, + 138, + 348, + 73, + 327, + 168, + 289, + 38, + 299, + 186, + 345, + 69, + 257, + 168, + 288, + 24, + 279, + 104, + 259, + 84, + 342, + 117, + 227, + 128, + 359, + 178, + 284, + 20, + 355, + 161, + 342, + 70, + 372, + 167, + 378, + 92, + 378, + 134, + 277, + 69, + 225, + 192, + 378, + 42, + 239, + 120, + 386, + 82, + 317, + 192, + 301, + 44, + 261, + 125, + 291, + 29, + 113, + 96, + 326, + 144, + 60, + 300, + 199, + 292, + 54, + 291, + 176, + 334, + 64, + 353, + 131, + 377, + 41, + 160, + 11, + 310, + 136, + 399, + 47, + 103, + 7, + 226, + 184, + 219, + 348, + 259, + 31, + 245, + 187, + 281, + 380, + 27, + 275, + 158, + 326, + 305, + 41, + 266, + 377, + 338, + 55, + 267, + 163, + 374, + 185, + 384, + 99, + 291, + 176, + 87, + 177, + 40, + 383, + 24, + 285, + 25, + 224, + 194, + 390, + 72, + 304, + 150, + 252, + 36, + 358, + 101, + 220, + 20, + 293, + 194, + 205, + 68, + 206, + 101, + 235, + 13, + 384, + 195, + 312, + 43, + 316, + 49, + 216, + 18, + 229, + 15, + 283, + 224, + 379, + 112, + 205, + 102, + 202, + 268, + 161, + 364, + 346, + 237, + 85, + 361, + 137, + 208, + 74, + 254, + 121, + 78, + 113, + 239, + 158, + 172, + 149, + 331, + 78, + 342, + 193, + 326, + 63, + 324, + 71, + 249, + 74, + 391, + 53, + 247, + 112, + 352, + 33, + 219, + 194, + 391, + 322, + 121, + 300, + 22, + 282, + 121, + 317, + 370, + 325, + 157, + 237, + 167, + 295, + 382, + 217, + 227, + 349, + 340, + 88, + 131, + 383, + 11, + 286, + 303, + 83, + 333, + 193, + 15, + 269, + 114, + 391, + 113, + 142, + 204, + 27, + 349, + 141, + 333, + 29, + 250, + 167, + 224, + 80, + 328, + 193, + 283, + 75, + 233, + 152, + 361, + 45, + 354, + 120, + 76, + 202, + 170, + 330, + 19, + 337, + 153, + 301, + 79, + 380, + 200, + 374, + 72, + 144, + 17, + 197, + 146, + 334, + 170, + 109, + 195, + 11, + 144, + 17, + 146, + 239, + 1, + 263, + 192, + 315, + 62, + 82, + 9, + 324, + 111, + 366, + 98, + 332, + 182, + 76, + 138, + 255, + 180, + 301, + 67, + 204, + 337, + 337, + 397, + 212, + 81, + 202, + 149, + 243, + 375, + 20, + 303, + 150, + 366, + 41, + 394, + 22, + 321, + 67, + 372, + 34, + 316, + 131, + 119, + 306, + 196, + 365, + 190, + 393, + 318, + 67, + 219, + 43, + 264, + 131, + 220, + 334, + 358, + 32, + 392, + 217, + 16, + 207, + 198, + 271, + 93, + 204, + 163, + 338, + 348, + 293, + 253, + 351, + 399, + 249, + 53, + 247, + 137, + 18, + 326, + 112, + 26, + 162, + 72, + 194, + 275, + 49, + 346, + 148, + 317, + 120, + 212, + 164, + 201, + 350, + 350, + 385, + 41, + 279, + 312, + 226, + 194, + 209, + 351, + 320, + 72, + 254, + 197, + 290, + 48, + 359, + 220, + 70, + 282, + 363, + 166, + 114, + 31, + 167, + 340, + 83, + 263, + 243, + 190, + 336, + 235, + 100, + 347, + 128, + 341, + 91, + 328, + 183, + 351, + 95, + 365, + 157, + 325, + 86, + 212, + 124, + 296, + 23, + 140, + 286, + 71, + 292, + 200, + 213, + 19, + 172, + 46, + 110, + 58, + 84, + 320, + 4, + 3, + 389, + 144, + 215, + 23, + 134, + 97, + 250, + 185, + 321, + 86, + 252, + 106, + 265, + 83, + 266, + 179, + 250, + 53, + 295, + 113, + 301, + 65, + 244, + 130, + 14, + 139, + 68, + 321, + 129, + 302, + 69, + 256, + 123, + 315, + 84, + 282, + 122, + 351, + 85, + 163, + 83, + 108, + 344, + 79, + 149, + 51, + 165, + 263, + 60, + 75, + 278, + 192, + 46, + 332, + 47, + 146, + 245, + 15, + 354, + 101, + 222, + 22, + 223, + 139, + 294, + 73, + 260, + 122, + 232, + 46, + 342, + 108, + 62, + 120, + 348, + 26, + 146, + 275, + 33, + 156, + 34, + 366, + 26, + 298, + 64, + 220, + 57, + 273, + 261, + 108, + 307, + 325, + 114, + 72, + 114, + 147, + 378, + 39, + 398, + 169, + 217, + 58, + 244, + 105, + 46, + 133, + 44, + 200, + 209, + 90, + 345, + 133, + 289, + 97, + 259, + 98, + 357, + 369, + 20, + 286, + 346, + 206, + 266, + 386, + 29, + 277, + 214, + 169, + 375, + 120, + 31, + 306, + 197, + 290, + 156, + 330, + 139, + 346, + 159, + 284, + 19, + 301, + 106, + 344, + 31, + 252, + 73, + 20, + 85, + 282, + 359, + 18, + 250, + 233, + 395, + 156, + 51, + 355, + 155, + 308, + 49, + 95, + 66, + 162, + 366, + 44, + 170, + 251, + 256, + 337, + 230, + 275, + 113, + 228, + 151, + 288, + 199, + 244, + 58, + 221, + 105, + 336, + 6, + 228, + 165, + 227, + 48, + 400, + 144, + 383, + 18, + 289, + 176, + 270, + 154, + 279, + 10, + 245, + 103, + 361, + 78, + 217, + 196, + 207, + 16, + 309, + 123, + 299, + 86, + 299, + 108, + 207, + 96, + 234, + 148, + 377, + 88, + 231, + 76, + 378, + 3, + 299, + 22, + 211, + 270, + 12, + 231, + 20, + 55, + 286, + 61, + 382, + 142, + 249, + 77, + 384, + 150, + 379, + 17, + 333, + 177, + 293, + 98, + 338, + 157, + 91, + 109, + 172, + 125, + 26, + 115, + 400, + 53, + 285, + 165, + 209, + 84, + 353, + 172, + 360, + 13, + 320, + 180, + 278, + 37, + 263, + 168, + 356, + 67, + 318, + 155, + 134, + 156, + 295, + 20, + 65, + 46, + 346, + 108, + 321, + 79, + 334, + 168, + 364, + 52, + 318, + 123, + 365, + 189, + 325, + 123, + 293, + 62, + 398, + 108, + 321, + 25, + 268, + 123, + 313, + 100, + 235, + 129, + 400, + 54, + 211, + 167, + 297, + 193, + 240, + 43, + 248, + 170, + 371, + 71, + 342, + 194, + 251, + 60, + 299, + 183, + 317, + 21, + 291, + 181, + 345, + 37, + 320, + 102, + 201, + 22, + 286, + 134, + 281, + 72, + 263, + 196, + 345, + 29, + 270, + 186, + 226, + 36, + 218, + 121, + 232, + 167, + 240, + 68, + 216, + 198, + 301, + 41, + 322, + 130, + 358, + 11, + 280, + 135, + 66, + 192, + 169, + 194, + 223, + 284, + 286, + 28, + 260, + 187, + 273, + 74, + 300, + 23, + 206, + 12, + 52, + 38, + 320, + 103, + 206, + 197, + 348, + 182, + 249, + 286, + 101, + 375, + 258, + 102, + 250, + 97, + 394, + 129, + 29, + 184, + 50, + 339, + 97, + 234, + 141, + 374, + 44, + 337, + 165, + 317, + 189, + 291, + 142, + 391, + 341, + 335, + 224, + 20, + 258, + 124, + 270, + 8, + 254, + 185, + 306, + 13, + 316, + 120, + 236, + 7, + 247, + 116, + 368, + 9, + 312, + 5, + 357, + 223, + 121, + 256, + 203, + 217, + 142, + 310, + 379, + 321, + 289, + 264, + 261, + 11, + 148, + 259, + 72, + 304, + 38, + 381, + 62, + 213, + 27, + 254, + 43, + 256, + 230, + 177, + 241, + 63, + 107, + 143, + 369, + 90, + 242, + 162, + 383, + 363, + 162, + 223, + 95, + 211, + 124, + 329, + 85, + 216, + 195, + 201, + 51, + 309, + 157, + 366, + 12, + 183, + 107, + 102, + 255, + 69, + 323, + 168, + 274, + 194, + 203, + 238, + 106, + 225, + 124, + 360, + 386, + 181, + 331, + 10, + 249, + 348, + 359, + 267, + 15, + 382, + 68, + 270, + 54, + 213, + 152, + 264, + 80, + 149, + 284, + 95, + 315, + 119, + 394, + 221, + 289, + 140, + 294, + 48, + 266, + 186, + 384, + 30, + 228, + 65, + 352, + 50, + 362, + 27, + 137, + 394, + 9, + 306, + 145, + 229, + 68, + 211, + 174, + 221, + 20, + 374, + 136, + 386, + 14, + 378, + 148, + 40, + 233, + 198, + 78, + 122, + 338, + 100, + 357, + 115, + 230, + 71, + 110, + 65, + 397, + 70, + 41, + 55, + 344, + 381, + 52, + 172, + 197, + 39, + 126, + 77, + 39, + 384, + 66, + 266, + 162, + 1, + 153, + 245, + 145, + 396, + 88, + 366, + 158, + 205, + 58, + 384, + 71, + 366, + 233, + 246, + 213, + 208, + 152, + 356, + 30, + 292, + 181, + 379, + 123, + 354, + 53, + 388, + 3, + 372, + 344, + 196, + 269, + 399, + 15, + 361, + 128, + 219, + 63, + 340, + 183, + 308, + 42, + 292, + 195, + 324, + 159, + 230, + 172, + 329, + 10, + 211, + 109, + 13, + 208, + 186, + 96, + 143, + 198, + 206, + 145, + 251, + 195, + 303, + 341, + 178, + 256, + 12, + 385, + 92, + 201, + 43, + 284, + 148, + 218, + 370, + 189, + 13, + 227, + 68, + 208, + 338, + 379, + 13, + 287, + 132, + 319, + 60, + 318, + 126, + 364, + 46, + 189, + 45, + 132, + 21, + 338, + 140, + 340, + 99, + 187, + 22, + 304, + 55, + 39, + 257, + 298, + 18, + 58, + 397, + 51, + 277, + 188, + 292, + 49, + 360, + 125, + 368, + 64, + 390, + 158, + 279, + 62, + 291, + 160, + 294, + 44, + 400, + 196, + 310, + 10, + 320, + 133, + 355, + 23, + 228, + 118, + 309, + 22, + 320, + 120, + 383, + 167, + 356, + 105, + 147, + 327, + 70, + 133, + 323, + 83, + 185, + 68, + 195, + 172, + 305, + 108, + 263, + 120, + 249, + 87, + 382, + 168, + 231, + 95, + 371, + 12, + 387, + 173, + 268, + 41, + 224, + 42, + 353, + 6, + 319, + 147, + 223, + 39, + 326, + 68, + 364, + 150, + 295, + 36, + 250, + 143, + 398, + 7, + 357, + 101, + 398, + 24, + 354, + 27, + 293, + 140, + 21, + 197, + 100, + 157, + 253, + 15, + 198, + 72, + 121, + 351, + 87, + 79, + 24, + 384, + 80, + 294, + 62, + 287, + 102, + 380, + 211, + 53, + 265, + 141, + 348, + 17, + 224, + 116, + 360, + 170, + 210, + 45, + 248, + 118, + 273, + 30, + 329, + 194, + 371, + 49, + 214, + 162, + 233, + 95, + 291, + 124, + 223, + 37, + 277, + 133, + 346, + 68, + 369, + 186, + 301, + 23, + 302, + 102, + 349, + 52, + 371, + 101, + 247, + 2, + 148, + 48, + 108, + 10, + 124, + 394, + 9, + 148, + 13, + 162, + 260, + 73, + 340, + 156, + 205, + 89, + 370, + 114, + 355, + 90, + 369, + 159, + 274, + 61, + 241, + 142, + 253, + 69, + 384, + 136, + 302, + 59, + 350, + 137, + 273, + 50, + 292, + 137, + 215, + 4, + 279, + 178, + 284, + 36, + 236, + 197, + 369, + 99, + 213, + 107, + 313, + 59, + 387, + 36, + 348, + 113, + 214, + 69, + 243, + 200, + 17, + 258, + 132, + 281, + 17, + 251, + 157, + 230, + 52, + 347, + 156, + 213, + 98, + 381, + 160, + 257, + 50, + 344, + 151, + 274, + 34, + 219, + 110, + 309, + 164, + 227, + 89, + 299, + 143, + 319, + 159, + 205, + 324, + 225, + 394, + 394, + 393, + 55, + 291, + 158, + 224, + 68, + 272, + 152, + 342, + 85, + 202, + 179, + 361, + 7, + 319, + 182, + 244, + 53, + 369, + 162, + 307, + 64, + 255, + 147, + 290, + 83, + 279, + 115, + 304, + 129, + 331, + 298, + 124, + 231, + 120, + 266, + 85, + 342, + 175, + 40, + 186, + 324, + 43, + 14, + 11, + 195, + 255, + 281, + 255, + 182, + 362, + 219, + 14, + 105, + 87, + 156, + 249, + 6, + 117, + 17, + 123, + 278, + 93, + 385, + 199, + 86, + 30, + 133, + 234, + 127, + 380, + 32, + 310, + 128, + 215, + 18, + 391, + 107, + 324, + 90, + 317, + 145, + 349, + 48, + 274, + 64, + 295, + 186, + 3, + 194, + 88, + 128, + 65, + 350, + 151, + 249, + 31, + 387, + 126, + 298, + 43, + 247, + 143, + 398, + 14, + 372, + 108, + 329, + 100, + 359, + 145, + 303, + 9, + 327, + 142, + 313, + 18, + 201, + 102, + 98, + 299, + 123, + 241, + 84, + 235, + 46, + 214, + 3, + 240, + 194, + 388, + 7, + 293, + 197, + 222, + 74, + 248, + 278, + 161, + 290, + 356, + 152, + 377, + 328, + 302, + 365, + 237, + 199, + 248, + 154, + 336, + 200, + 249, + 51, + 356, + 104, + 346, + 77, + 146, + 268, + 16, + 260, + 120, + 232, + 159, + 193, + 129, + 7, + 121, + 151, + 376, + 139, + 215, + 24, + 108, + 103, + 20, + 74, + 195, + 8, + 310, + 235, + 307, + 320, + 363, + 181, + 369, + 78, + 366, + 138, + 333, + 54, + 254, + 177, + 219, + 1, + 279, + 128, + 389, + 173, + 301, + 124, + 338, + 293, + 378, + 270, + 224, + 117, + 180, + 259, + 94, + 147, + 299, + 122, + 364, + 288, + 71, + 162, + 96, + 130, + 30, + 190, + 262, + 12, + 21, + 52, + 221, + 23, + 33, + 339, + 198, + 295, + 159, + 124, + 114, + 272, + 127, + 210, + 34, + 384, + 137, + 359, + 75, + 355, + 197, + 280, + 43, + 221, + 123, + 331, + 40, + 224, + 158, + 201, + 88, + 251, + 142, + 317, + 186, + 250, + 137, + 305, + 78, + 333, + 137, + 370, + 100, + 344, + 120, + 302, + 14, + 382, + 155, + 55, + 296, + 180, + 218, + 131, + 282, + 49, + 253, + 225, + 378, + 15, + 398, + 138, + 270, + 150, + 372, + 57, + 210, + 123, + 338, + 98, + 171, + 214, + 92, + 291, + 33, + 256, + 79, + 203, + 134, + 392, + 99, + 127, + 75, + 309, + 128, + 316, + 185, + 377, + 141, + 177, + 160, + 363, + 72, + 198, + 52, + 336, + 140, + 386, + 130, + 30, + 155, + 59, + 47, + 360, + 281, + 41, + 46, + 36, + 303, + 106, + 316, + 199, + 253, + 127, + 283, + 36, + 292, + 192, + 293, + 215, + 172, + 377, + 245, + 134, + 363, + 84, + 248, + 165, + 340, + 53, + 395, + 189, + 288, + 78, + 230, + 178, + 317, + 9, + 252, + 172, + 214, + 98, + 256, + 183, + 376, + 48, + 327, + 110, + 291, + 14, + 296, + 159, + 236, + 26, + 275, + 170, + 280, + 35, + 263, + 126, + 212, + 24, + 398, + 198, + 98, + 162, + 314, + 71, + 209, + 198, + 47, + 193, + 211, + 11, + 378, + 189, + 116, + 359, + 81, + 388, + 169, + 155, + 125, + 232, + 9, + 384, + 182, + 355, + 174, + 209, + 79, + 372, + 174, + 386, + 161, + 299, + 384, + 315, + 378, + 394, + 174, + 291, + 39, + 259, + 290, + 373, + 294, + 50, + 254, + 70, + 212, + 379, + 292, + 115, + 389, + 80, + 226, + 117, + 292, + 169, + 73, + 301, + 168, + 24, + 366, + 91, + 206, + 105, + 247, + 26, + 268, + 151, + 360, + 176, + 59, + 164, + 334, + 67, + 350, + 135, + 261, + 32, + 153, + 27, + 331, + 190, + 82, + 189, + 89, + 127, + 248, + 233, + 215, + 54, + 203, + 168, + 362, + 16, + 278, + 140, + 310, + 10, + 342, + 185, + 376, + 125, + 336, + 180, + 303, + 55, + 222, + 168, + 341, + 23, + 347, + 169, + 316, + 47, + 230, + 159, + 271, + 119, + 289, + 349, + 43, + 384, + 192, + 245, + 68, + 247, + 186, + 320, + 7, + 366, + 131, + 335, + 14, + 321, + 159, + 224, + 129, + 237, + 359, + 267, + 375, + 290, + 143, + 261, + 6, + 397, + 143, + 375, + 192, + 393, + 234, + 380, + 77, + 393, + 144, + 321, + 308, + 358, + 182, + 343, + 207, + 363, + 226, + 241, + 333, + 132, + 267, + 340, + 225, + 8, + 306, + 122, + 302, + 194, + 251, + 50, + 393, + 100, + 326, + 372, + 241, + 353, + 259, + 356, + 374, + 193, + 336, + 91, + 339, + 76, + 370, + 313, + 290, + 376, + 391, + 10, + 286, + 45, + 239, + 181, + 171, + 52, + 323, + 270, + 114, + 51, + 276, + 122, + 296, + 47, + 324, + 104, + 382, + 84, + 210, + 6, + 308, + 13, + 218, + 333, + 232, + 187, + 364, + 147, + 276, + 32, + 294, + 198, + 352, + 343, + 71, + 355, + 15, + 336, + 389, + 156, + 68, + 276, + 126, + 73, + 346, + 12, + 396, + 94, + 234, + 20, + 348, + 193, + 250, + 83, + 226, + 102, + 360, + 94, + 322, + 142, + 303, + 63, + 396, + 166, + 316, + 19, + 212, + 172, + 375, + 166, + 210, + 71, + 260, + 166, + 381, + 54, + 304, + 186, + 325, + 47, + 282, + 122, + 257, + 8, + 323, + 113, + 222, + 77, + 389, + 191, + 380, + 159, + 291, + 162, + 273, + 4, + 258, + 138, + 318, + 16, + 306, + 173, + 338, + 33, + 323, + 164, + 352, + 36, + 191, + 77, + 358, + 196, + 386, + 169, + 75, + 219, + 48, + 343, + 2, + 294, + 39, + 338, + 335, + 245, + 223, + 61, + 306, + 147, + 283, + 111, + 397, + 184, + 343, + 132, + 398, + 298, + 188, + 325, + 184, + 400, + 208, + 381, + 171, + 309, + 128, + 212, + 230, + 188, + 306, + 70, + 119, + 129, + 167, + 392, + 324, + 99, + 290, + 319, + 156, + 285, + 63, + 339, + 110, + 301, + 246, + 332, + 37, + 286, + 253, + 332, + 243, + 134, + 395, + 33, + 288, + 177, + 319, + 181, + 312, + 32, + 388, + 129, + 350, + 62, + 372, + 69, + 394, + 180, + 231, + 38, + 367, + 147, + 279, + 53, + 364, + 153, + 245, + 2, + 229, + 129, + 352, + 24, + 41, + 118, + 261, + 375, + 175, + 367, + 50, + 366, + 110, + 260, + 65, + 246, + 170, + 210, + 12, + 123, + 372, + 122, + 201, + 15, + 356, + 143, + 302, + 142, + 212, + 265, + 209, + 171, + 261, + 302, + 54, + 299, + 146, + 321, + 78, + 282, + 114, + 247, + 60, + 331, + 130, + 252, + 2, + 289, + 97, + 238, + 141, + 328, + 78, + 369, + 1, + 354, + 114, + 292, + 297, + 114, + 244, + 373, + 327, + 158, + 254, + 30, + 226, + 118, + 335, + 388, + 257, + 329, + 300, + 179, + 329, + 47, + 281, + 78, + 396, + 191, + 341, + 21, + 231, + 169, + 217, + 113, + 367, + 34, + 213, + 184, + 271, + 15, + 178, + 58, + 117, + 334, + 54, + 281, + 168, + 351, + 62, + 333, + 82, + 207, + 72, + 232, + 85, + 345, + 59, + 300, + 54, + 313, + 189, + 240, + 41, + 279, + 128, + 333, + 87, + 359, + 107, + 324, + 49, + 305, + 163, + 269, + 56, + 356, + 167, + 289, + 66, + 297, + 139, + 210, + 32, + 164, + 80, + 309, + 149, + 314, + 99, + 370, + 145, + 395, + 39, + 283, + 106, + 343, + 126, + 292, + 192, + 237, + 33, + 347, + 188, + 308, + 14, + 217, + 188, + 373, + 100, + 300, + 191, + 277, + 63, + 308, + 191, + 301, + 63, + 208, + 70, + 309, + 50, + 276, + 92, + 309, + 46, + 254, + 45, + 211, + 139, + 254, + 49, + 301, + 229, + 359, + 284, + 22, + 341, + 199, + 223, + 47, + 267, + 22, + 345, + 174, + 310, + 211, + 329, + 209, + 143, + 255, + 313, + 327, + 61, + 316, + 325, + 321, + 101, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "commands": [ + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0 + ], + "values": [ + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, + 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, + 273, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, + 267, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, + 249, + 238, + 161, + 146, + 341, + 351, + 152, + 60, + 318, + 340, + 240, + 326, + 163, + 198, + 230, + 170, + 331, + 12, + 194, + 122, + 125, + 386, + 398, + 314, + 291, + 337, + 398, + 4, + 25, + 143, + 367, + 208, + 383, + 171, + 375, + 147, + 63, + 292, + 157, + 314, + 303, + 2, + 370, + 117, + 144, + 247, + 35, + 38, + 267, + 7, + 81, + 82, + 338, + 123, + 180, + 207, + 319, + 259, + 129, + 329, + 281, + 384, + 283, + 217, + 223, + 394, + 72, + 215, + 304, + 325, + 383, + 364, + 180, + 3, + 158, + 105, + 181, + 209, + 400, + 344, + 62, + 233, + 155, + 225, + 174, + 282, + 225, + 87, + 168, + 184, + 60, + 104, + 231, + 344, + 77, + 69, + 63, + 106, + 63, + 102, + 255, + 363, + 126, + 134, + 212, + 319, + 336, + 32, + 164, + 96, + 87, + 118, + 196, + 36, + 206, + 333, + 315, + 394, + 201, + 99, + 199, + 126, + 113, + 229, + 155, + 375, + 114, + 16, + 74, + 181, + 347, + 265, + 105, + 54, + 121, + 305, + 297, + 179, + 204, + 373, + 377, + 392, + 242, + 322, + 193, + 228, + 385, + 119, + 79, + 305, + 90, + 243, + 332, + 285, + 7, + 37, + 8, + 30, + 294, + 267, + 112, + 205, + 149, + 165, + 196, + 189, + 78, + 346, + 385, + 136, + 112, + 315, + 375, + 376, + 284, + 213, + 202, + 319, + 18, + 121, + 62, + 140, + 232, + 25, + 385, + 369, + 271, + 345, + 321, + 14, + 352, + 83, + 163, + 43, + 257, + 213, + 8, + 176, + 339, + 91, + 101, + 332, + 334, + 248, + 360, + 49, + 16, + 313, + 352, + 88, + 328, + 180, + 294, + 6, + 51, + 334, + 40, + 290, + 69, + 144, + 316, + 340, + 380, + 13, + 167, + 356, + 317, + 379, + 285, + 321, + 370, + 378, + 97, + 187, + 14, + 340, + 236, + 14, + 157, + 202, + 197, + 126, + 349, + 254, + 392, + 288, + 171, + 46, + 7, + 234, + 222, + 41, + 199, + 153, + 82, + 270, + 317, + 323, + 378, + 320, + 392, + 346, + 299, + 271, + 124, + 201, + 375, + 269, + 52, + 246, + 392, + 34, + 298, + 70, + 272, + 78, + 232, + 86, + 338, + 93, + 127, + 218, + 227, + 113, + 39, + 203, + 66, + 51, + 306, + 89, + 242, + 115, + 133, + 226, + 278, + 266, + 135, + 202, + 127, + 314, + 156, + 32, + 26, + 265, + 222, + 110, + 361, + 275, + 361, + 343, + 63, + 225, + 55, + 76, + 386, + 82, + 112, + 10, + 85, + 174, + 310, + 68, + 201, + 344, + 353, + 94, + 122, + 309, + 392, + 396, + 67, + 112, + 225, + 120, + 374, + 119, + 38, + 40, + 17, + 303, + 201, + 1, + 282, + 328, + 277, + 330, + 393, + 90, + 298, + 199, + 21, + 196, + 363, + 244, + 396, + 36, + 336, + 245, + 313, + 158, + 59, + 376, + 155, + 157, + 28, + 205, + 314, + 192, + 342, + 181, + 325, + 388, + 78, + 399, + 343, + 11, + 52, + 400, + 70, + 47, + 162, + 42, + 15, + 209, + 228, + 330, + 305, + 190, + 285, + 389, + 204, + 221, + 289, + 159, + 377, + 148, + 186, + 87, + 188, + 344, + 116, + 320, + 400, + 223, + 70, + 311, + 20, + 166, + 145, + 189, + 45, + 205, + 122, + 245, + 393, + 340, + 230, + 64, + 279, + 170, + 350, + 154, + 206, + 319, + 370, + 316, + 262, + 326, + 396, + 317, + 329, + 262, + 327, + 282, + 197, + 80, + 299, + 353, + 321, + 124, + 121, + 11, + 245, + 317, + 368, + 189, + 221, + 322, + 382, + 159, + 104, + 135, + 155, + 325, + 241, + 183, + 214, + 85, + 211, + 170, + 168, + 327, + 389, + 94, + 157, + 235, + 385, + 335, + 271, + 236, + 22, + 290, + 220, + 163, + 391, + 224, + 140, + 116, + 268, + 309, + 126, + 89, + 220, + 187, + 252, + 277, + 111, + 263, + 297, + 262, + 92, + 51, + 89, + 228, + 400, + 109, + 156, + 233, + 131, + 115, + 394, + 210, + 161, + 243, + 66, + 150, + 359, + 213, + 368, + 98, + 214, + 335, + 332, + 220, + 26, + 209, + 44, + 280, + 282, + 386, + 24, + 213, + 197, + 352, + 5, + 10, + 42, + 2, + 101, + 36, + 208, + 137, + 247, + 397, + 162, + 344, + 26, + 366, + 25, + 271, + 218, + 188, + 75, + 11, + 24, + 45, + 129, + 384, + 134, + 326, + 23, + 193, + 291, + 15, + 62, + 168, + 364, + 345, + 208, + 291, + 112, + 141, + 202, + 17, + 270, + 154, + 61, + 104, + 19, + 98, + 95, + 202, + 225, + 42, + 244, + 15, + 149, + 171, + 270, + 120, + 341, + 302, + 393, + 275, + 34, + 226, + 152, + 94, + 199, + 392, + 251, + 188, + 340, + 389, + 393, + 216, + 87, + 111, + 359, + 114, + 46, + 165, + 333, + 266, + 358, + 74, + 363, + 134, + 168, + 388, + 145, + 184, + 366, + 376, + 89, + 277, + 259, + 374, + 25, + 346, + 107, + 139, + 42, + 212, + 208, + 129, + 319, + 298, + 275, + 58, + 376, + 93, + 207, + 351, + 268, + 282, + 213, + 125, + 81, + 243, + 238, + 246, + 347, + 188, + 166, + 126, + 110, + 214, + 265, + 234, + 395, + 343, + 119, + 108, + 303, + 4, + 306, + 307, + 196, + 86, + 345, + 112, + 81, + 390, + 297, + 80, + 104, + 212, + 234, + 132, + 316, + 136, + 102, + 83, + 276, + 393, + 29, + 164, + 334, + 386, + 171, + 242, + 246, + 65, + 175, + 333, + 73, + 54, + 173, + 138, + 203, + 260, + 381, + 163, + 196, + 283, + 123, + 169, + 106, + 316, + 156, + 222, + 126, + 115, + 299, + 391, + 251, + 391, + 246, + 330, + 195, + 263, + 238, + 242, + 197, + 62, + 71, + 140, + 312, + 282, + 76, + 105, + 219, + 368, + 240, + 15, + 41, + 53, + 135, + 134, + 207, + 371, + 388, + 82, + 311, + 184, + 147, + 11, + 86, + 293, + 279, + 58, + 258, + 400, + 321, + 330, + 100, + 182, + 28, + 50, + 31, + 166, + 163, + 94, + 172, + 206, + 47, + 191, + 242, + 112, + 313, + 75, + 362, + 187, + 116, + 295, + 332, + 387, + 23, + 183, + 296, + 65, + 228, + 251, + 289, + 161, + 340, + 274, + 214, + 56, + 75, + 36, + 379, + 23, + 211, + 329, + 71, + 80, + 350, + 86, + 107, + 174, + 104, + 367, + 80, + 269, + 273, + 273, + 46, + 331, + 374, + 154, + 135, + 330, + 41, + 82, + 206, + 348, + 118, + 61, + 36, + 315, + 189, + 371, + 218, + 223, + 130, + 1, + 18, + 113, + 73, + 134, + 118, + 17, + 33, + 15, + 266, + 379, + 145, + 185, + 379, + 180, + 75, + 208, + 21, + 327, + 163, + 359, + 193, + 286, + 354, + 205, + 102, + 336, + 394, + 133, + 89, + 178, + 84, + 9, + 151, + 71, + 261, + 283, + 207, + 379, + 99, + 155, + 108, + 374, + 96, + 331, + 363, + 146, + 115, + 246, + 342, + 327, + 176, + 358, + 234, + 104, + 158, + 351, + 350, + 339, + 114, + 88, + 202, + 349, + 217, + 277, + 196, + 16, + 268, + 168, + 202, + 129, + 175, + 22, + 323, + 105, + 143, + 241, + 30, + 215, + 172, + 45, + 22, + 284, + 86, + 20, + 374, + 160, + 244, + 392, + 265, + 319, + 86, + 347, + 188, + 130, + 179, + 136, + 27, + 189, + 288, + 234, + 253, + 19, + 217, + 265, + 127, + 316, + 161, + 37, + 84, + 376, + 382, + 181, + 195, + 85, + 13, + 283, + 111, + 238, + 385, + 291, + 394, + 154, + 80, + 140, + 292, + 132, + 56, + 170, + 209, + 327, + 159, + 216, + 87, + 63, + 123, + 239, + 27, + 184, + 340, + 164, + 177, + 296, + 332, + 340, + 164, + 21, + 87, + 256, + 398, + 143, + 236, + 85, + 359, + 114, + 144, + 356, + 295, + 148, + 43, + 204, + 212, + 48, + 156, + 260, + 287, + 173, + 126, + 147, + 354, + 142, + 274, + 66, + 398, + 150, + 274, + 30, + 342, + 28, + 65, + 177, + 363, + 283, + 268, + 199, + 372, + 272, + 176, + 250, + 46, + 344, + 224, + 292, + 346, + 112, + 73, + 341, + 390, + 344, + 43, + 276, + 17, + 327, + 89, + 39, + 42, + 299, + 202, + 289, + 357, + 288, + 122, + 64, + 6, + 54, + 154, + 235, + 336, + 19, + 311, + 41, + 192, + 303, + 347, + 387, + 201, + 132, + 325, + 273, + 202, + 162, + 214, + 90, + 78, + 118, + 273, + 121, + 225, + 36, + 126, + 370, + 258, + 315, + 288, + 323, + 229, + 52, + 351, + 379, + 128, + 391, + 339, + 138, + 73, + 266, + 393, + 99, + 74, + 378, + 109, + 229, + 293, + 366, + 355, + 219, + 377, + 219, + 246, + 353, + 226, + 241, + 375, + 39, + 229, + 188, + 275, + 240, + 115, + 234, + 352, + 22, + 306, + 302, + 317, + 221, + 224, + 140, + 219, + 155, + 166, + 343, + 313, + 326, + 99, + 168, + 79, + 149, + 57, + 144, + 228, + 28, + 38, + 352, + 112, + 16, + 350, + 66, + 158, + 25, + 292, + 376, + 285, + 163, + 43, + 214, + 395, + 15, + 122, + 365, + 4, + 308, + 16, + 13, + 205, + 256, + 335, + 252, + 301, + 149, + 170, + 206, + 121, + 397, + 387, + 174, + 348, + 72, + 233, + 218, + 254, + 139, + 271, + 101, + 321, + 188, + 366, + 86, + 265, + 182, + 350, + 202, + 393, + 160, + 134, + 312, + 206, + 112, + 28, + 301, + 374, + 312, + 104, + 262, + 100, + 104, + 276, + 199, + 90, + 232, + 124, + 363, + 26, + 269, + 188, + 227, + 344, + 380, + 35, + 67, + 161, + 125, + 386, + 358, + 289, + 276, + 25, + 398, + 105, + 334, + 360, + 273, + 293, + 50, + 350, + 94, + 326, + 23, + 380, + 349, + 123, + 132, + 283, + 121, + 211, + 327, + 186, + 146, + 362, + 307, + 31, + 74, + 338, + 177, + 173, + 132, + 336, + 35, + 273, + 46, + 265, + 110, + 262, + 229, + 197, + 166, + 122, + 13, + 289, + 312, + 229, + 58, + 347, + 2, + 49, + 303, + 195, + 69, + 312, + 223, + 319, + 278, + 151, + 97, + 216, + 197, + 295, + 84, + 204, + 179, + 157, + 380, + 224, + 93, + 58, + 287, + 378, + 56, + 37, + 168, + 370, + 33, + 4, + 362, + 347, + 132, + 351, + 163, + 207, + 109, + 214, + 170, + 327, + 383, + 218, + 64, + 105, + 345, + 212, + 318, + 395, + 384, + 237, + 387, + 83, + 203, + 55, + 163, + 226, + 131, + 203, + 260, + 132, + 214, + 16, + 210, + 239, + 25, + 280, + 295, + 363, + 315, + 326, + 274, + 211, + 272, + 202, + 239, + 63, + 357, + 366, + 181, + 267, + 170, + 378, + 318, + 195, + 178, + 97, + 56, + 354, + 96, + 212, + 376, + 138, + 229, + 261, + 32, + 49, + 256, + 52, + 190, + 227, + 164, + 342, + 228, + 393, + 290, + 24, + 95, + 385, + 281, + 304, + 130, + 235, + 150, + 10, + 297, + 396, + 61, + 235, + 87, + 116, + 189, + 5, + 231, + 45, + 303, + 297, + 347, + 271, + 37, + 195, + 223, + 270, + 309, + 247, + 247, + 203, + 294, + 307, + 238, + 313, + 41, + 323, + 290, + 84, + 391, + 368, + 160, + 236, + 337, + 61, + 85, + 141, + 54, + 48, + 62, + 168, + 245, + 163, + 66, + 323, + 173, + 145, + 184, + 198, + 154, + 347, + 366, + 284, + 257, + 32, + 281, + 344, + 387, + 18, + 196, + 65, + 52, + 233, + 388, + 35, + 68, + 362, + 78, + 275, + 84, + 59, + 172, + 13, + 283, + 218, + 14, + 206, + 203, + 100, + 234, + 376, + 364, + 240, + 82, + 101, + 336, + 1, + 182, + 354, + 385, + 365, + 154, + 390, + 302, + 239, + 46, + 345, + 353, + 107, + 329, + 292, + 145, + 300, + 135, + 320, + 342, + 107, + 349, + 120, + 233, + 55, + 189, + 390, + 201, + 315, + 289, + 310, + 291, + 315, + 196, + 15, + 92, + 326, + 89, + 196, + 286, + 19, + 265, + 370, + 394, + 67, + 138, + 281, + 98, + 201, + 309, + 154, + 37, + 266, + 32, + 345, + 130, + 98, + 250, + 263, + 24, + 315, + 326, + 375, + 362, + 347, + 85, + 50, + 241, + 344, + 67, + 241, + 302, + 162, + 377, + 179, + 80, + 73, + 155, + 75, + 55, + 35, + 273, + 175, + 370, + 234, + 273, + 57, + 91, + 74, + 8, + 44, + 28, + 118, + 356, + 190, + 359, + 243, + 388, + 273, + 381, + 332, + 12, + 106, + 250, + 155, + 70, + 361, + 15, + 124, + 321, + 337, + 44, + 353, + 35, + 247, + 22, + 84, + 301, + 297, + 132, + 225, + 66, + 105, + 348, + 133, + 212, + 152, + 328, + 79, + 49, + 223, + 121, + 74, + 126, + 320, + 67, + 374, + 228, + 173, + 17, + 236, + 12, + 117, + 218, + 192, + 346, + 370, + 138, + 266, + 270, + 391, + 167, + 132, + 233, + 207, + 162, + 65, + 251, + 14, + 173, + 72, + 191, + 165, + 38, + 8, + 204, + 204, + 376, + 203, + 105, + 182, + 336, + 121, + 20, + 69, + 275, + 254, + 40, + 149, + 343, + 197, + 262, + 21, + 259, + 330, + 246, + 383, + 43, + 325, + 46, + 40, + 338, + 262, + 116, + 75, + 266, + 2, + 389, + 90, + 29, + 101, + 244, + 363, + 58, + 3, + 68, + 137, + 195, + 344, + 105, + 113, + 378, + 19, + 107, + 208, + 83, + 250, + 201, + 238, + 283, + 135, + 372, + 74, + 200, + 159, + 216, + 334, + 29, + 108, + 156, + 303, + 300, + 55, + 37, + 366, + 225, + 323, + 181, + 217, + 388, + 143, + 313, + 369, + 81, + 389, + 128, + 139, + 179, + 222, + 110, + 154, + 166, + 5, + 95, + 294, + 339, + 277, + 171, + 320, + 105, + 216, + 374, + 266, + 8, + 78, + 296, + 119, + 367, + 95, + 357, + 180, + 175, + 43, + 7, + 15, + 348, + 26, + 116, + 327, + 321, + 19, + 297, + 62, + 377, + 112, + 175, + 240, + 1, + 178, + 3, + 90, + 149, + 377, + 103, + 296, + 40, + 22, + 43, + 232, + 212, + 343, + 228, + 276, + 68, + 140, + 112, + 314, + 72, + 7, + 274, + 163, + 252, + 153, + 388, + 304, + 218, + 73, + 107, + 246, + 145, + 200, + 211, + 22, + 85, + 197, + 326, + 200, + 373, + 310, + 263, + 86, + 13, + 388, + 309, + 246, + 248, + 305, + 388, + 304, + 165, + 221, + 303, + 397, + 56, + 245, + 246, + 48, + 87, + 266, + 108, + 56, + 144, + 140, + 93, + 245, + 256, + 97, + 226, + 273, + 347, + 165, + 212, + 228, + 207, + 169, + 305, + 371, + 186, + 334, + 396, + 244, + 100, + 352, + 358, + 326, + 339, + 270, + 396, + 301, + 284, + 11, + 177, + 191, + 126, + 68, + 227, + 33, + 366, + 298, + 359, + 193, + 122, + 393, + 122, + 203, + 30, + 303, + 194, + 392, + 151, + 366, + 31, + 293, + 174, + 53, + 26, + 218, + 85, + 136, + 306, + 113, + 10, + 61, + 173, + 48, + 56, + 97, + 70, + 146, + 399, + 283, + 50, + 278, + 366, + 185, + 35, + 323, + 13, + 344, + 144, + 141, + 33, + 279, + 89, + 383, + 267, + 101, + 396, + 337, + 247, + 341, + 224, + 376, + 360, + 9, + 196, + 136, + 104, + 376, + 263, + 383, + 3, + 124, + 314, + 136, + 23, + 46, + 346, + 318, + 338, + 249, + 270, + 205, + 145, + 179, + 232, + 245, + 228, + 230, + 50, + 263, + 119, + 7, + 240, + 2, + 149, + 158, + 120, + 175, + 163, + 63, + 25, + 16, + 263, + 219, + 340, + 339, + 186, + 128, + 29, + 354, + 195, + 387, + 145, + 121, + 184, + 268, + 344, + 9, + 87, + 242, + 355, + 309, + 99, + 220, + 131, + 247, + 82, + 101, + 373, + 220, + 119, + 373, + 332, + 125, + 264, + 247, + 118, + 307, + 305, + 303, + 348, + 275, + 60, + 325, + 154, + 189, + 374, + 374, + 58, + 365, + 353, + 257, + 372, + 315, + 352, + 259, + 312, + 395, + 320, + 181, + 125, + 206, + 195, + 161, + 322, + 389, + 398, + 113, + 77, + 376, + 162, + 8, + 350, + 14, + 298, + 48, + 217, + 217, + 33, + 86, + 224, + 239, + 206, + 35, + 321, + 330, + 287, + 89, + 7, + 134, + 191, + 149, + 274, + 228, + 229, + 108, + 372, + 313, + 237, + 211, + 178, + 101, + 396, + 55, + 86, + 137, + 61, + 118, + 67, + 336, + 327, + 88, + 317, + 32, + 385, + 275, + 164, + 331, + 286, + 49, + 66, + 242, + 20, + 141, + 11, + 313, + 313, + 2, + 324, + 128, + 172, + 282, + 199, + 384, + 313, + 148, + 73, + 200, + 366, + 75, + 260, + 133, + 299, + 269, + 29, + 399, + 355, + 358, + 174, + 102, + 169, + 194, + 343, + 174, + 170, + 171, + 80, + 395, + 329, + 147, + 64, + 328, + 372, + 364, + 228, + 357, + 151, + 85, + 95, + 185, + 345, + 307, + 300, + 312, + 237, + 125, + 132, + 164, + 392, + 70, + 400, + 67, + 126, + 155, + 317, + 57, + 54, + 276, + 146, + 184, + 137, + 107, + 376, + 362, + 6, + 95, + 273, + 327, + 100, + 110, + 352, + 90, + 144, + 288, + 323, + 126, + 200, + 400, + 220, + 59, + 34, + 289, + 354, + 118, + 241, + 148, + 199, + 322, + 40, + 312, + 140, + 77, + 112, + 223, + 140, + 13, + 1, + 185, + 388, + 24, + 131, + 398, + 318, + 280, + 63, + 175, + 47, + 134, + 327, + 206, + 52, + 48, + 64, + 194, + 178, + 377, + 55, + 55, + 107, + 265, + 338, + 263, + 27, + 92, + 373, + 357, + 295, + 207, + 324, + 133, + 119, + 151, + 175, + 2, + 77, + 288, + 151, + 116, + 168, + 371, + 245, + 20, + 142, + 174, + 112, + 203, + 98, + 209, + 73, + 328, + 15, + 33, + 40, + 377, + 124, + 370, + 396, + 25, + 215, + 368, + 135, + 133, + 151, + 282, + 80, + 304, + 280, + 67, + 327, + 177, + 333, + 178, + 151, + 146, + 56, + 76, + 312, + 186, + 212, + 132, + 31, + 296, + 141, + 60, + 75, + 209, + 382, + 49, + 179, + 389, + 106, + 146, + 103, + 158, + 300, + 91, + 239, + 221, + 305, + 164, + 148, + 351, + 270, + 121, + 129, + 383, + 296, + 375, + 49, + 259, + 231, + 272, + 275, + 352, + 222, + 339, + 299, + 54, + 20, + 348, + 80, + 332, + 342, + 227, + 27, + 286, + 243, + 162, + 147, + 164, + 1, + 259, + 222, + 398, + 371, + 322, + 178, + 327, + 33, + 319, + 175, + 272, + 351, + 245, + 247, + 55, + 154, + 325, + 300, + 344, + 8, + 207, + 79, + 138, + 76, + 159, + 115, + 3, + 166, + 336, + 235, + 300, + 344, + 89, + 276, + 110, + 117, + 37, + 52, + 370, + 20, + 345, + 290, + 198, + 158, + 127, + 226, + 355, + 239, + 381, + 158, + 51, + 62, + 152, + 355, + 148, + 97, + 108, + 238, + 107, + 127, + 103, + 332, + 77, + 238, + 258, + 211, + 86, + 374, + 172, + 60, + 339, + 309, + 220, + 63, + 387, + 132, + 222, + 369, + 243, + 388, + 64, + 375, + 264, + 212, + 33, + 121, + 187, + 326, + 35, + 154, + 292, + 303, + 337, + 25, + 18, + 307, + 136, + 197, + 241, + 150, + 181, + 335, + 306, + 208, + 388, + 379, + 75, + 133, + 295, + 343, + 86, + 255, + 193, + 126, + 128, + 200, + 307, + 76, + 79, + 145, + 213, + 249, + 24, + 240, + 384, + 245, + 333, + 72, + 145, + 21, + 306, + 86, + 173, + 172, + 211, + 258, + 226, + 235, + 109, + 286, + 169, + 25, + 331, + 125, + 369, + 176, + 370, + 310, + 235, + 390, + 179, + 136, + 223, + 129, + 155, + 337, + 82, + 292, + 111, + 332, + 252, + 3, + 178, + 201, + 31, + 143, + 154, + 3, + 92, + 263, + 171, + 6, + 151, + 251, + 267, + 29, + 157, + 153, + 29, + 155, + 360, + 338, + 81, + 96, + 166, + 93, + 382, + 7, + 176, + 53, + 43, + 393, + 210, + 87, + 3, + 92, + 384, + 148, + 152, + 181, + 378, + 353, + 202, + 196, + 212, + 235, + 246, + 227, + 236, + 304, + 180, + 201, + 336, + 19, + 17, + 185, + 255, + 99, + 133, + 98, + 227, + 72, + 260, + 260, + 1, + 331, + 219, + 41, + 32, + 344, + 335, + 326, + 98, + 42, + 86, + 90, + 282, + 381, + 88, + 34, + 191, + 96, + 147, + 378, + 354, + 218, + 251, + 384, + 240, + 337, + 120, + 364, + 51, + 95, + 159, + 230, + 373, + 52, + 81, + 249, + 194, + 368, + 374, + 108, + 380, + 57, + 66, + 393, + 222, + 300, + 147, + 158, + 391, + 226, + 64, + 347, + 241, + 134, + 274, + 162, + 293, + 167, + 372, + 176, + 390, + 232, + 354, + 250, + 311, + 191, + 329, + 177, + 208, + 88, + 204, + 342, + 364, + 296, + 222, + 339, + 247, + 144, + 372, + 342, + 233, + 83, + 223, + 210, + 330, + 68, + 282, + 171, + 177, + 203, + 264, + 383, + 308, + 341, + 246, + 352, + 55, + 143, + 193, + 319, + 54, + 311, + 237, + 52, + 9, + 391, + 294, + 96, + 47, + 46, + 132, + 312, + 120, + 231, + 68, + 134, + 61, + 326, + 323, + 314, + 393, + 288, + 322, + 177, + 326, + 322, + 244, + 117, + 322, + 253, + 385, + 258, + 296, + 48, + 189, + 2, + 329, + 351, + 237, + 92, + 69, + 105, + 388, + 37, + 399, + 165, + 300, + 268, + 143, + 322, + 299, + 376, + 221, + 363, + 158, + 156, + 224, + 336, + 126, + 51, + 205, + 107, + 56, + 289, + 395, + 312, + 48, + 310, + 384, + 190, + 173, + 332, + 346, + 227, + 362, + 48, + 270, + 387, + 232, + 303, + 113, + 368, + 295, + 278, + 200, + 20, + 181, + 111, + 16, + 185, + 225, + 282, + 350, + 380, + 156, + 20, + 135, + 302, + 199, + 180, + 194, + 15, + 4, + 341, + 106, + 353, + 294, + 300, + 208, + 161, + 332, + 224, + 387, + 285, + 236, + 262, + 294, + 90, + 50, + 65, + 215, + 111, + 5, + 191, + 138, + 168, + 139, + 369, + 325, + 137, + 273, + 399, + 54, + 314, + 75, + 286, + 349, + 36, + 276, + 306, + 129, + 7, + 165, + 103, + 373, + 227, + 376, + 173, + 326, + 378, + 347, + 63, + 280, + 319, + 46, + 325, + 232, + 170, + 322, + 288, + 364, + 218, + 260, + 86, + 95, + 393, + 190, + 76, + 48, + 378, + 136, + 316, + 223, + 83, + 314, + 42, + 398, + 252, + 384, + 90, + 76, + 310, + 100, + 209, + 301, + 317, + 120, + 324, + 137, + 324, + 35, + 167, + 215, + 235, + 331, + 316, + 310, + 192, + 395, + 180, + 375, + 142, + 105, + 213, + 183, + 82, + 330, + 336, + 130, + 162, + 166, + 124, + 28, + 222, + 332, + 322, + 246, + 31, + 184, + 85, + 111, + 126, + 373, + 393, + 343, + 80, + 50, + 140, + 394, + 9, + 14, + 345, + 10, + 180, + 375, + 313, + 266, + 95, + 287, + 52, + 93, + 239, + 57, + 397, + 175, + 250, + 52, + 64, + 317, + 112, + 330, + 370, + 150, + 224, + 248, + 134, + 143, + 11, + 221, + 203, + 266, + 46, + 297, + 105, + 276, + 255, + 39, + 112, + 9, + 344, + 94, + 61, + 299, + 16, + 190, + 112, + 83, + 208, + 173, + 19, + 258, + 392, + 106, + 208, + 103, + 280, + 137, + 127, + 193, + 335, + 287, + 314, + 390, + 69, + 121, + 162, + 285, + 55, + 364, + 96, + 376, + 314, + 90, + 43, + 214, + 208, + 190, + 125, + 188, + 233, + 297, + 320, + 210, + 217, + 8, + 149, + 70, + 183, + 365, + 90, + 147, + 244, + 5, + 168, + 235, + 60, + 153, + 128, + 214, + 94, + 227, + 159, + 218, + 277, + 134, + 119, + 383, + 113, + 190, + 144, + 77, + 75, + 224, + 272, + 84, + 240, + 98, + 394, + 394, + 40, + 69, + 24, + 27, + 266, + 26, + 22, + 33, + 196, + 210, + 63, + 226, + 31, + 132, + 199, + 28, + 35, + 22, + 79, + 80, + 59, + 365, + 309, + 112, + 133, + 38, + 396, + 159, + 385, + 375, + 8, + 393, + 144, + 55, + 254, + 246, + 359, + 316, + 126, + 362, + 213, + 81, + 357, + 385, + 104, + 97, + 168, + 273, + 234, + 42, + 223, + 18, + 387, + 139, + 50, + 399, + 387, + 227, + 134, + 199, + 204, + 151, + 318, + 217, + 2, + 141, + 167, + 110, + 247, + 380, + 257, + 205, + 119, + 5, + 186, + 236, + 249, + 358, + 65, + 203, + 379, + 372, + 288, + 359, + 342, + 50, + 350, + 244, + 248, + 348, + 294, + 189, + 369, + 188, + 64, + 65, + 24, + 43, + 45, + 215, + 386, + 108, + 1, + 222, + 137, + 239, + 295, + 74, + 183, + 134, + 252, + 376, + 379, + 361, + 394, + 165, + 234, + 285, + 158, + 181, + 201, + 282, + 116, + 260, + 246, + 317, + 27, + 15, + 144, + 119, + 246, + 94, + 272, + 35, + 250, + 291, + 97, + 350, + 37, + 308, + 267, + 166, + 248, + 36, + 242, + 91, + 177, + 111, + 278, + 15, + 353, + 268, + 45, + 189, + 151, + 23, + 322, + 235, + 328, + 240, + 156, + 176, + 57, + 247, + 8, + 81, + 186, + 15, + 254, + 97, + 66, + 253, + 143, + 18, + 345, + 37, + 86, + 255, + 3, + 45, + 373, + 306, + 102, + 379, + 44, + 398, + 365, + 224, + 312, + 14, + 1, + 313, + 268, + 35, + 227, + 47, + 291, + 154, + 208, + 230, + 348, + 394, + 5, + 338, + 318, + 355, + 87, + 181, + 248, + 97, + 321, + 290, + 135, + 352, + 113, + 119, + 390, + 136, + 51, + 119, + 43, + 141, + 38, + 75, + 137, + 14, + 356, + 70, + 100, + 73, + 168, + 44, + 290, + 342, + 113, + 82, + 333, + 187, + 70, + 46, + 125, + 320, + 96, + 228, + 252, + 151, + 343, + 21, + 22, + 196, + 28, + 354, + 331, + 257, + 305, + 289, + 30, + 237, + 156, + 250, + 88, + 184, + 32, + 272, + 171, + 27, + 97, + 265, + 337, + 197, + 67, + 339, + 133, + 16, + 216, + 324, + 388, + 248, + 131, + 357, + 135, + 371, + 392, + 290, + 230, + 90, + 254, + 40, + 359, + 309, + 357, + 336, + 334, + 173, + 155, + 282, + 1, + 263, + 155, + 369, + 332, + 100, + 147, + 383, + 65, + 351, + 209, + 105, + 331, + 100, + 270, + 114, + 108, + 128, + 220, + 375, + 141, + 69, + 19, + 278, + 352, + 365, + 250, + 278, + 234, + 141, + 380, + 43, + 169, + 2, + 256, + 329, + 97, + 368, + 32, + 240, + 374, + 373, + 48, + 268, + 386, + 149, + 7, + 46, + 277, + 127, + 243, + 102, + 294, + 80, + 28, + 71, + 328, + 193, + 87, + 346, + 122, + 276, + 392, + 175, + 227, + 163, + 29, + 91, + 157, + 379, + 114, + 220, + 141, + 29, + 207, + 248, + 130, + 22, + 51, + 383, + 172, + 61, + 25, + 28, + 102, + 103, + 134, + 364, + 74, + 126, + 261, + 288, + 87, + 311, + 274, + 388, + 58, + 400, + 184, + 53, + 123, + 170, + 366, + 175, + 277, + 348, + 243, + 322, + 315, + 35, + 50, + 20, + 388, + 213, + 82, + 34, + 53, + 297, + 369, + 3, + 68, + 152, + 119, + 393, + 57, + 220, + 129, + 97, + 171, + 338, + 282, + 195, + 176, + 257, + 277, + 47, + 237, + 332, + 151, + 383, + 185, + 185, + 106, + 161, + 327, + 45, + 265, + 236, + 170, + 252, + 172, + 64, + 298, + 144, + 262, + 389, + 179, + 308, + 126, + 189, + 128, + 20, + 272, + 129, + 60, + 166, + 217, + 147, + 250, + 248, + 325, + 177, + 84, + 347, + 305, + 363, + 177, + 93, + 29, + 377, + 350, + 284, + 109, + 363, + 178, + 237, + 145, + 115, + 59, + 166, + 168, + 76, + 35, + 25, + 357, + 56, + 157, + 157, + 302, + 222, + 80, + 265, + 392, + 110, + 163, + 300, + 33, + 57, + 88, + 29, + 66, + 106, + 75, + 210, + 331, + 23, + 291, + 377, + 385, + 369, + 327, + 106, + 193, + 36, + 213, + 231, + 195, + 22, + 123, + 308, + 50, + 256, + 372, + 388, + 240, + 399, + 251, + 360, + 41, + 21, + 304, + 298, + 390, + 196, + 105, + 56, + 396, + 102, + 327, + 39, + 91, + 269, + 317, + 127, + 358, + 322, + 301, + 319, + 94, + 268, + 61, + 301, + 259, + 293, + 234, + 311, + 135, + 233, + 143, + 3, + 380, + 179, + 81, + 102, + 314, + 3, + 43, + 62, + 160, + 86, + 39, + 15, + 333, + 288, + 377, + 10, + 253, + 163, + 5, + 273, + 285, + 183, + 116, + 6, + 259, + 374, + 38, + 365, + 345, + 336, + 103, + 51, + 48, + 92, + 146, + 80, + 205, + 185, + 362, + 228, + 257, + 225, + 176, + 49, + 366, + 371, + 308, + 343, + 386, + 9, + 343, + 265, + 284, + 137, + 373, + 372, + 255, + 233, + 154, + 64, + 136, + 48, + 377, + 179, + 153, + 327, + 385, + 349, + 273, + 130, + 261, + 207, + 215, + 311, + 49, + 117, + 78, + 292, + 315, + 70, + 383, + 160, + 21, + 56, + 201, + 328, + 99, + 181, + 68, + 203, + 114, + 180, + 262, + 378, + 397, + 230, + 165, + 355, + 10, + 296, + 109, + 264, + 80, + 202, + 255, + 381, + 55, + 193, + 334, + 397, + 386, + 216, + 356, + 356, + 45, + 9, + 304, + 186, + 334, + 60, + 128, + 317, + 163, + 151, + 234, + 115, + 386, + 77, + 345, + 149, + 240, + 221, + 84, + 143, + 332, + 344, + 204, + 83, + 22, + 304, + 183, + 337, + 311, + 274, + 93, + 276, + 341, + 94, + 174, + 346, + 74, + 90, + 348, + 120, + 291, + 202, + 220, + 3, + 316, + 19, + 212, + 276, + 388, + 228, + 302, + 120, + 150, + 206, + 30, + 130, + 270, + 263, + 358, + 374, + 84, + 208, + 306, + 187, + 258, + 90, + 6, + 355, + 101, + 239, + 80, + 241, + 285, + 368, + 94, + 118, + 380, + 152, + 164, + 400, + 185, + 115, + 270, + 19, + 271, + 298, + 56, + 118, + 253, + 270, + 184, + 372, + 169, + 382, + 327, + 349, + 352, + 177, + 202, + 24, + 129, + 129, + 93, + 42, + 377, + 2, + 249, + 249, + 188, + 82, + 318, + 72, + 349, + 180, + 103, + 308, + 385, + 189, + 370, + 334, + 348, + 161, + 284, + 17, + 166, + 198, + 307, + 323, + 225, + 170, + 219, + 369, + 81, + 247, + 232, + 138, + 57, + 11, + 142, + 236, + 151, + 308, + 14, + 329, + 184, + 170, + 28, + 13, + 49, + 11, + 163, + 10, + 51, + 140, + 96, + 318, + 258, + 149, + 362, + 133, + 39, + 113, + 47, + 100, + 52, + 364, + 34, + 14, + 181, + 354, + 13, + 226, + 258, + 178, + 371, + 321, + 303, + 310, + 131, + 317, + 199, + 52, + 178, + 204, + 8, + 326, + 63, + 53, + 399, + 64, + 5, + 106, + 177, + 258, + 133, + 283, + 346, + 114, + 185, + 313, + 126, + 101, + 342, + 17, + 99, + 321, + 35, + 102, + 395, + 212, + 129, + 147, + 381, + 301, + 206, + 34, + 380, + 127, + 260, + 136, + 258, + 97, + 387, + 150, + 103, + 281, + 302, + 208, + 18, + 198, + 304, + 337, + 311, + 83, + 393, + 112, + 231, + 378, + 392, + 212, + 267, + 32, + 144, + 78, + 193, + 355, + 263, + 84, + 195, + 116, + 143, + 5, + 109, + 199, + 208, + 381, + 53, + 241, + 353, + 90, + 325, + 51, + 186, + 323, + 273, + 208, + 14, + 69, + 88, + 396, + 380, + 353, + 15, + 170, + 333, + 116, + 373, + 262, + 149, + 222, + 312, + 56, + 190, + 247, + 292, + 10, + 53, + 342, + 87, + 65, + 1, + 394, + 43, + 253, + 107, + 112, + 172, + 108, + 164, + 286, + 358, + 259, + 269, + 362, + 217, + 283, + 284, + 200, + 118, + 55, + 201, + 194, + 324, + 374, + 126, + 329, + 177, + 20, + 187, + 53, + 349, + 115, + 189, + 394, + 183, + 55, + 346, + 175, + 1, + 285, + 351, + 309, + 171, + 17, + 268, + 312, + 50, + 45, + 35, + 43, + 70, + 328, + 55, + 200, + 99, + 306, + 147, + 81, + 74, + 247, + 196, + 307, + 91, + 85, + 186, + 398, + 242, + 118, + 244, + 142, + 309, + 32, + 351, + 221, + 176, + 12, + 83, + 102, + 188, + 353, + 127, + 345, + 164, + 169, + 310, + 93, + 240, + 282, + 80, + 204, + 345, + 127, + 59, + 19, + 31, + 225, + 229, + 209, + 154, + 332, + 243, + 186, + 77, + 7, + 207, + 328, + 363, + 81, + 108, + 194, + 388, + 165, + 300, + 184, + 43, + 102, + 392, + 393, + 377, + 267, + 303, + 249, + 178, + 286, + 351, + 297, + 263, + 153, + 347, + 91, + 18, + 341, + 283, + 129, + 124, + 8, + 263, + 204, + 4, + 156, + 177, + 148, + 228, + 207, + 334, + 338, + 382, + 343, + 137, + 116, + 160, + 270, + 223, + 91, + 53, + 349, + 386, + 346, + 126, + 47, + 233, + 320, + 315, + 309, + 363, + 169, + 75, + 368, + 153, + 118, + 101, + 309, + 186, + 89, + 127, + 293, + 31, + 122, + 340, + 125, + 157, + 142, + 88, + 241, + 180, + 225, + 225, + 132, + 236, + 114, + 223, + 129, + 65, + 40, + 397, + 111, + 261, + 314, + 160, + 203, + 346, + 263, + 142, + 398, + 215, + 1, + 120, + 274, + 285, + 341, + 151, + 38, + 119, + 257, + 314, + 332, + 378, + 64, + 206, + 151, + 311, + 283, + 338, + 362, + 19, + 90, + 293, + 21, + 267, + 102, + 181, + 253, + 80, + 251, + 134, + 254, + 276, + 70, + 308, + 228, + 241, + 235, + 68, + 312, + 394, + 276, + 221, + 372, + 31, + 167, + 262, + 358, + 21, + 159, + 70, + 371, + 149, + 132, + 136, + 66, + 171, + 308, + 148, + 301, + 22, + 368, + 50, + 236, + 219, + 159, + 317, + 387, + 357, + 94, + 199, + 263, + 383, + 330, + 112, + 162, + 323, + 263, + 20, + 70, + 96, + 292, + 17, + 309, + 45, + 297, + 355, + 75, + 260, + 232, + 147, + 277, + 368, + 264, + 101, + 23, + 156, + 24, + 318, + 322, + 153, + 256, + 6, + 188, + 176, + 158, + 160, + 200, + 112, + 384, + 52, + 241, + 128, + 56, + 135, + 306, + 239, + 228, + 263, + 152, + 14, + 274, + 273, + 307, + 374, + 76, + 355, + 91, + 326, + 335, + 314, + 400, + 280, + 267, + 44, + 230, + 61, + 385, + 109, + 31, + 6, + 291, + 298, + 65, + 229, + 30, + 188, + 241, + 151, + 59, + 168, + 105, + 308, + 174, + 340, + 393, + 250, + 180, + 327, + 389, + 395, + 314, + 17, + 310, + 197, + 341, + 90, + 128, + 379, + 175, + 7, + 398, + 150, + 261, + 283, + 196, + 168, + 278, + 277, + 120, + 268, + 138, + 340, + 359, + 333, + 100, + 284, + 50, + 11, + 243, + 6, + 149, + 55, + 11, + 104, + 217, + 88, + 254, + 44, + 306, + 48, + 227, + 30, + 205, + 71, + 175, + 241, + 300, + 203, + 73, + 343, + 269, + 20, + 175, + 122, + 70, + 104, + 105, + 66, + 28, + 22, + 196, + 192, + 150, + 328, + 394, + 400, + 9, + 88, + 75, + 361, + 9, + 199, + 228, + 275, + 45, + 399, + 390, + 59, + 144, + 341, + 179, + 11, + 323, + 400, + 392, + 223, + 396, + 304, + 131, + 295, + 136, + 391, + 298, + 390, + 228, + 343, + 390, + 183, + 137, + 129, + 8, + 315, + 27, + 9, + 330, + 9, + 342, + 14, + 86, + 243, + 303, + 133, + 229, + 46, + 144, + 317, + 243, + 219, + 196, + 203, + 244, + 92, + 364, + 85, + 180, + 172, + 346, + 127, + 133, + 224, + 151, + 199, + 243, + 53, + 138, + 165, + 314, + 248, + 248, + 12, + 173, + 273, + 345, + 168, + 70, + 346, + 94, + 364, + 206, + 170, + 244, + 230, + 300, + 387, + 195, + 206, + 185, + 165, + 100, + 133, + 400, + 259, + 373, + 46, + 104, + 352, + 335, + 208, + 297, + 93, + 361, + 119, + 99, + 54, + 63, + 222, + 106, + 91, + 391, + 171, + 268, + 36, + 304, + 284, + 288, + 249, + 233, + 235, + 371, + 226, + 235, + 112, + 42, + 274, + 108, + 101, + 123, + 123, + 167, + 259, + 149, + 133, + 98, + 223, + 78, + 106, + 39, + 220, + 254, + 186, + 12, + 270, + 291, + 273, + 369, + 336, + 44, + 184, + 281, + 30, + 15, + 64, + 231, + 280, + 57, + 110, + 182, + 250, + 326, + 75, + 140, + 110, + 21, + 130, + 278, + 127, + 389, + 60, + 61, + 114, + 259, + 125, + 98, + 327, + 128, + 144, + 317, + 213, + 53, + 231, + 299, + 170, + 312, + 170, + 348, + 72, + 128, + 60, + 173, + 163, + 235, + 149, + 25, + 62, + 385, + 328, + 79, + 155, + 218, + 45, + 171, + 92, + 254, + 42, + 152, + 263, + 22, + 129, + 257, + 253, + 365, + 296, + 388, + 1, + 385, + 366, + 58, + 228, + 172, + 73, + 349, + 207, + 292, + 1, + 208, + 392, + 315, + 18, + 73, + 119, + 326, + 344, + 194, + 90, + 73, + 88, + 26, + 230, + 288, + 342, + 123, + 97, + 286, + 302, + 114, + 88, + 197, + 209, + 360, + 219, + 37, + 143, + 99, + 14, + 27, + 57, + 272, + 26, + 169, + 316, + 209, + 165, + 243, + 377, + 245, + 339, + 100, + 238, + 330, + 110, + 350, + 67, + 213, + 122, + 355, + 55, + 137, + 350, + 172, + 300, + 142, + 214, + 288, + 296, + 154, + 107, + 47, + 226, + 262, + 79, + 305, + 355, + 155, + 137, + 211, + 169, + 91, + 278, + 69, + 314, + 336, + 373, + 383, + 373, + 68, + 166, + 362, + 346, + 6, + 65, + 395, + 94, + 337, + 318, + 87, + 274, + 73, + 389, + 137, + 71, + 369, + 197, + 36, + 19, + 286, + 336, + 98, + 74, + 95, + 205, + 53, + 255, + 256, + 158, + 201, + 54, + 343, + 344, + 30, + 380, + 124, + 344, + 74, + 269, + 346, + 225, + 49, + 172, + 371, + 355, + 103, + 275, + 118, + 365, + 196, + 186, + 180, + 159, + 2, + 110, + 189, + 183, + 362, + 314, + 196, + 304, + 171, + 380, + 63, + 196, + 364, + 118, + 371, + 220, + 163, + 128, + 177, + 326, + 77, + 77, + 296, + 330, + 380, + 304, + 36, + 340, + 314, + 309, + 258, + 238, + 138, + 26, + 15, + 351, + 88, + 84, + 101, + 98, + 224, + 376, + 376, + 243, + 249, + 399, + 221, + 224, + 18, + 177, + 163, + 150, + 378, + 353, + 285, + 45, + 243, + 24, + 344, + 202, + 335, + 248, + 241, + 122, + 371, + 209, + 178, + 232, + 218, + 183, + 72, + 400, + 212, + 379, + 180, + 178, + 284, + 107, + 393, + 151, + 277, + 262, + 162, + 293, + 135, + 357, + 97, + 343, + 9, + 181, + 95, + 347, + 120, + 363, + 88, + 311, + 320, + 64, + 21, + 43, + 354, + 184, + 343, + 387, + 195, + 381, + 262, + 320, + 377, + 188, + 284, + 225, + 316, + 327, + 321, + 368, + 276, + 232, + 119, + 124, + 59, + 284, + 84, + 201, + 289, + 253, + 301, + 233, + 5, + 316, + 300, + 242, + 343, + 30, + 50, + 101, + 51, + 294, + 387, + 292, + 245, + 27, + 210, + 226, + 273, + 232, + 24, + 275, + 122, + 154, + 138, + 221, + 386, + 355, + 44, + 95, + 32, + 136, + 12, + 277, + 260, + 301, + 292, + 172, + 112, + 96, + 217, + 72, + 304, + 89, + 29, + 33, + 35, + 8, + 378, + 94, + 327, + 35, + 279, + 396, + 368, + 251, + 85, + 138, + 357, + 60, + 1, + 209, + 171, + 363, + 324, + 203, + 355, + 98, + 120, + 392, + 285, + 297, + 105, + 134, + 123, + 167, + 134, + 304, + 61, + 257, + 166, + 40, + 214, + 328, + 179, + 330, + 261, + 325, + 78, + 67, + 167, + 395, + 306, + 89, + 305, + 386, + 115, + 4, + 121, + 69, + 41, + 83, + 3, + 10, + 56, + 94, + 338, + 233, + 179, + 378, + 8, + 101, + 216, + 59, + 49, + 95, + 366, + 117, + 355, + 356, + 15, + 287, + 266, + 268, + 189, + 289, + 392, + 204, + 69, + 310, + 264, + 240, + 171, + 277, + 397, + 173, + 397, + 218, + 81, + 124, + 354, + 240, + 166, + 100, + 73, + 274, + 302, + 110, + 268, + 17, + 74, + 62, + 41, + 86, + 106, + 363, + 200, + 67, + 94, + 56, + 161, + 12, + 127, + 184, + 355, + 259, + 95, + 299, + 316, + 247, + 84, + 35, + 33, + 235, + 280, + 376, + 295, + 394, + 179, + 299, + 174, + 325, + 131, + 54, + 295, + 13, + 327, + 231, + 367, + 67, + 353, + 104, + 66, + 381, + 87, + 63, + 45, + 89, + 21, + 263, + 357, + 331, + 183, + 264, + 367, + 250, + 44, + 149, + 94, + 147, + 131, + 327, + 189, + 212, + 172, + 360, + 244, + 206, + 177, + 115, + 79, + 38, + 349, + 152, + 104, + 261, + 265, + 299, + 328, + 242, + 1, + 305, + 216, + 182, + 127, + 332, + 192, + 162, + 225, + 35, + 11, + 390, + 66, + 41, + 266, + 175, + 397, + 156, + 365, + 57, + 363, + 50, + 56, + 301, + 233, + 22, + 136, + 381, + 300, + 4, + 7, + 18, + 359, + 341, + 229, + 29, + 1, + 399, + 146, + 242, + 289, + 230, + 352, + 92, + 105, + 382, + 334, + 233, + 229, + 326, + 50, + 335, + 276, + 196, + 354, + 6, + 104, + 156, + 75, + 301, + 265, + 179, + 383, + 34, + 112, + 29, + 294, + 69, + 249, + 246, + 143, + 191, + 301, + 163, + 309, + 244, + 321, + 78, + 13, + 179, + 236, + 275, + 240, + 283, + 186, + 317, + 105, + 84, + 160, + 308, + 138, + 87, + 37, + 211, + 7, + 85, + 333, + 195, + 265, + 246, + 56, + 16, + 226, + 102, + 171, + 310, + 328, + 63, + 300, + 160, + 136, + 114, + 386, + 247, + 43, + 95, + 217, + 223, + 186, + 130, + 354, + 398, + 132, + 341, + 34, + 249, + 218, + 51, + 197, + 97, + 80, + 25, + 61, + 119, + 28, + 137, + 160, + 222, + 119, + 132, + 44, + 273, + 61, + 110, + 217, + 12, + 32, + 15, + 47, + 260, + 149, + 132, + 92, + 238, + 330, + 116, + 203, + 317, + 306, + 227, + 79, + 193, + 245, + 309, + 54, + 282, + 199, + 108, + 185, + 48, + 73, + 18, + 154, + 379, + 186, + 244, + 209, + 191, + 69, + 187, + 13, + 192, + 45, + 170, + 300, + 23, + 274, + 143, + 128, + 341, + 91, + 65, + 186, + 48, + 154, + 291, + 350, + 301, + 179, + 245, + 33, + 395, + 333, + 155, + 364, + 83, + 79, + 268, + 306, + 252, + 335, + 398, + 90, + 128, + 267, + 146, + 185, + 127, + 300, + 2, + 376, + 345, + 368, + 95, + 287, + 143, + 159, + 216, + 150, + 95, + 272, + 393, + 376, + 355, + 244, + 191, + 270, + 20, + 366, + 235, + 121, + 75, + 40, + 398, + 67, + 354, + 267, + 87, + 336, + 231, + 24, + 111, + 247, + 306, + 400, + 225, + 50, + 329, + 330, + 101, + 97, + 331, + 244, + 323, + 146, + 214, + 63, + 253, + 44, + 6, + 21, + 334, + 60, + 286, + 130, + 11, + 316, + 346, + 232, + 301, + 63, + 24, + 272, + 289, + 60, + 232, + 292, + 333, + 256, + 302, + 305, + 80, + 330, + 13, + 310, + 222, + 358, + 103, + 148, + 277, + 292, + 109, + 90, + 191, + 76, + 277, + 52, + 200, + 184, + 163, + 359, + 323, + 326, + 219, + 295, + 173, + 57, + 351, + 236, + 346, + 254, + 221, + 304, + 91, + 327, + 310, + 345, + 355, + 18, + 19, + 206, + 267, + 356, + 108, + 113, + 173, + 8, + 180, + 374, + 30, + 270, + 249, + 335, + 375, + 350, + 326, + 169, + 343, + 383, + 340, + 54, + 104, + 160, + 6, + 37, + 46, + 36, + 215, + 146, + 324, + 354, + 130, + 156, + 331, + 204, + 235, + 310, + 85, + 102, + 6, + 63, + 98, + 323, + 241, + 191, + 400, + 32, + 399, + 290, + 93, + 70, + 215, + 113, + 349, + 321, + 71, + 60, + 137, + 209, + 135, + 234, + 11, + 94, + 108, + 139, + 66, + 43, + 73, + 280, + 336, + 58, + 329, + 143, + 269, + 39, + 141, + 23, + 133, + 225, + 43, + 323, + 19, + 317, + 342, + 23, + 63, + 177, + 85, + 180, + 153, + 252, + 3, + 186, + 202, + 303, + 338, + 317, + 9, + 50, + 299, + 239, + 263, + 351, + 368, + 256, + 299, + 272, + 326, + 163, + 145, + 346, + 307, + 75, + 390, + 132, + 249, + 139, + 275, + 378, + 226, + 290, + 306, + 141, + 61, + 372, + 205, + 152, + 372, + 225, + 127, + 63, + 307, + 98, + 142, + 131, + 260, + 199, + 97, + 152, + 268, + 21, + 340, + 326, + 238, + 235, + 198, + 45, + 147, + 294, + 2, + 378, + 323, + 337, + 200, + 134, + 391, + 167, + 59, + 129, + 194, + 359, + 276, + 65, + 195, + 245, + 376, + 385, + 277, + 170, + 330, + 12, + 372, + 259, + 374, + 13, + 169, + 27, + 206, + 186, + 85, + 77, + 134, + 343, + 325, + 134, + 385, + 334, + 234, + 329, + 381, + 178, + 211, + 218, + 261, + 245, + 195, + 244, + 389, + 281, + 298, + 132, + 180, + 391, + 237, + 138, + 352, + 99, + 17, + 261, + 368, + 81, + 172, + 143, + 238, + 138, + 88, + 200, + 275, + 168, + 313, + 352, + 26, + 2, + 73, + 348, + 173, + 275, + 327, + 289, + 34, + 90, + 38, + 299, + 212, + 69, + 95, + 186, + 288, + 345, + 138, + 387, + 168, + 32, + 53, + 257, + 181, + 153, + 288, + 24, + 307, + 339, + 165, + 104, + 305, + 279, + 84, + 341, + 259, + 342, + 227, + 359, + 109, + 117, + 28, + 128, + 172, + 228, + 321, + 178, + 161, + 284, + 227, + 241, + 355, + 225, + 154, + 328, + 167, + 184, + 345, + 238, + 156, + 342, + 372, + 378, + 20, + 134, + 192, + 378, + 176, + 277, + 81, + 26, + 120, + 70, + 80, + 192, + 354, + 225, + 8, + 378, + 45, + 342, + 92, + 162, + 113, + 239, + 164, + 125, + 113, + 386, + 69, + 69, + 297, + 170, + 317, + 42, + 162, + 309, + 134, + 301, + 82, + 44, + 153, + 183, + 29, + 350, + 73, + 90, + 53, + 351, + 261, + 69, + 144, + 291, + 199, + 96, + 60, + 230, + 176, + 157, + 180, + 148, + 54, + 131, + 123, + 388, + 64, + 326, + 13, + 263, + 60, + 300, + 68, + 287, + 160, + 41, + 292, + 176, + 291, + 11, + 143, + 334, + 353, + 377, + 283, + 243, + 1, + 247, + 136, + 103, + 124, + 216, + 65, + 349, + 369, + 395, + 310, + 184, + 399, + 85, + 341, + 47, + 361, + 7, + 115, + 88, + 5, + 226, + 102, + 219, + 348, + 259, + 245, + 2, + 351, + 281, + 116, + 380, + 153, + 31, + 187, + 39, + 266, + 107, + 317, + 351, + 27, + 289, + 158, + 275, + 191, + 197, + 326, + 214, + 305, + 275, + 41, + 187, + 266, + 17, + 377, + 338, + 267, + 395, + 2, + 55, + 249, + 374, + 265, + 163, + 339, + 42, + 384, + 185, + 365, + 99, + 156, + 176, + 149, + 291, + 87, + 177, + 40, + 86, + 317, + 24, + 221, + 74, + 25, + 305, + 383, + 285, + 224, + 289, + 72, + 341, + 334, + 36, + 39, + 253, + 20, + 390, + 304, + 194, + 150, + 309, + 29, + 252, + 21, + 101, + 194, + 101, + 358, + 68, + 356, + 1, + 195, + 220, + 63, + 293, + 127, + 205, + 131, + 206, + 69, + 13, + 201, + 373, + 43, + 235, + 387, + 384, + 49, + 356, + 312, + 242, + 68, + 9, + 316, + 85, + 363, + 272, + 216, + 338, + 229, + 283, + 49, + 18, + 69, + 224, + 47, + 127, + 54, + 379, + 15, + 263, + 5, + 75, + 123, + 258, + 218, + 205, + 5, + 202, + 112, + 102, + 268, + 202, + 364, + 104, + 101, + 346, + 357, + 332, + 161, + 354, + 275, + 34, + 237, + 361, + 72, + 137, + 121, + 85, + 74, + 78, + 113, + 397, + 208, + 84, + 10, + 158, + 254, + 172, + 189, + 7, + 69, + 23, + 388, + 283, + 239, + 113, + 185, + 4, + 149, + 313, + 78, + 331, + 193, + 76, + 342, + 326, + 324, + 249, + 249, + 12, + 13, + 192, + 63, + 296, + 230, + 71, + 74, + 391, + 389, + 92, + 247, + 53, + 267, + 311, + 383, + 112, + 33, + 352, + 194, + 379, + 150, + 55, + 344, + 219, + 391, + 232, + 346, + 395, + 322, + 300, + 282, + 317, + 300, + 121, + 370, + 325, + 43, + 22, + 374, + 24, + 121, + 16, + 34, + 234, + 127, + 237, + 369, + 157, + 167, + 277, + 295, + 247, + 382, + 217, + 319, + 227, + 349, + 296, + 369, + 325, + 80, + 72, + 340, + 355, + 88, + 111, + 131, + 128, + 11, + 383, + 167, + 126, + 286, + 303, + 89, + 308, + 83, + 333, + 113, + 312, + 193, + 114, + 15, + 374, + 386, + 269, + 391, + 113, + 43, + 177, + 70, + 142, + 13, + 84, + 204, + 305, + 141, + 167, + 27, + 349, + 333, + 250, + 92, + 193, + 332, + 224, + 328, + 87, + 29, + 73, + 331, + 80, + 194, + 75, + 49, + 312, + 283, + 233, + 152, + 215, + 361, + 170, + 45, + 70, + 92, + 185, + 381, + 120, + 76, + 19, + 79, + 170, + 14, + 48, + 358, + 153, + 354, + 200, + 173, + 250, + 180, + 72, + 202, + 330, + 312, + 37, + 235, + 48, + 17, + 337, + 144, + 301, + 376, + 197, + 179, + 380, + 30, + 61, + 150, + 146, + 170, + 393, + 109, + 374, + 141, + 15, + 77, + 332, + 153, + 400, + 334, + 195, + 87, + 108, + 360, + 321, + 11, + 144, + 17, + 146, + 342, + 301, + 247, + 69, + 239, + 263, + 327, + 1, + 109, + 62, + 82, + 315, + 9, + 192, + 57, + 91, + 98, + 197, + 237, + 398, + 217, + 324, + 76, + 366, + 215, + 111, + 161, + 213, + 228, + 332, + 182, + 278, + 289, + 279, + 138, + 351, + 255, + 356, + 301, + 180, + 378, + 67, + 245, + 204, + 337, + 337, + 397, + 39, + 212, + 387, + 378, + 38, + 213, + 76, + 81, + 33, + 202, + 149, + 68, + 398, + 243, + 375, + 303, + 163, + 150, + 366, + 20, + 156, + 108, + 150, + 41, + 119, + 22, + 67, + 394, + 120, + 90, + 195, + 321, + 361, + 74, + 310, + 372, + 282, + 34, + 394, + 316, + 131, + 143, + 119, + 278, + 86, + 306, + 365, + 238, + 196, + 222, + 330, + 393, + 190, + 35, + 318, + 83, + 67, + 67, + 3, + 43, + 219, + 197, + 264, + 250, + 319, + 131, + 47, + 220, + 255, + 334, + 372, + 358, + 2, + 392, + 32, + 217, + 207, + 271, + 204, + 39, + 338, + 348, + 109, + 246, + 16, + 367, + 198, + 93, + 141, + 248, + 197, + 163, + 264, + 66, + 54, + 293, + 253, + 377, + 233, + 290, + 53, + 351, + 240, + 399, + 74, + 249, + 185, + 137, + 53, + 247, + 334, + 18, + 112, + 162, + 387, + 227, + 7, + 326, + 132, + 22, + 26, + 314, + 359, + 72, + 194, + 148, + 393, + 160, + 49, + 275, + 120, + 346, + 164, + 97, + 317, + 267, + 212, + 297, + 201, + 350, + 332, + 350, + 329, + 223, + 385, + 24, + 167, + 279, + 374, + 128, + 392, + 117, + 41, + 143, + 38, + 312, + 226, + 313, + 78, + 209, + 351, + 320, + 194, + 192, + 333, + 242, + 254, + 340, + 290, + 72, + 359, + 370, + 220, + 241, + 48, + 197, + 31, + 297, + 282, + 375, + 181, + 97, + 70, + 87, + 363, + 63, + 286, + 166, + 114, + 344, + 332, + 31, + 167, + 278, + 75, + 340, + 138, + 83, + 189, + 263, + 221, + 243, + 366, + 190, + 336, + 79, + 235, + 338, + 290, + 128, + 100, + 80, + 347, + 341, + 351, + 160, + 328, + 183, + 351, + 361, + 157, + 91, + 95, + 217, + 365, + 124, + 325, + 293, + 212, + 170, + 376, + 296, + 178, + 140, + 127, + 86, + 200, + 216, + 23, + 239, + 385, + 134, + 316, + 187, + 391, + 71, + 19, + 9, + 286, + 46, + 42, + 172, + 292, + 58, + 67, + 84, + 4, + 159, + 110, + 66, + 213, + 3, + 320, + 40, + 23, + 97, + 86, + 102, + 83, + 119, + 237, + 242, + 171, + 320, + 268, + 377, + 53, + 65, + 133, + 144, + 389, + 275, + 215, + 100, + 134, + 185, + 94, + 213, + 307, + 297, + 250, + 321, + 252, + 106, + 400, + 265, + 266, + 176, + 141, + 14, + 201, + 250, + 295, + 202, + 287, + 301, + 179, + 133, + 68, + 347, + 113, + 181, + 148, + 346, + 356, + 258, + 69, + 130, + 84, + 244, + 85, + 109, + 139, + 268, + 83, + 367, + 129, + 52, + 287, + 217, + 164, + 123, + 202, + 122, + 163, + 79, + 321, + 202, + 302, + 93, + 256, + 29, + 16, + 209, + 348, + 315, + 282, + 391, + 51, + 247, + 184, + 351, + 40, + 96, + 60, + 39, + 278, + 108, + 81, + 389, + 344, + 149, + 176, + 64, + 344, + 165, + 262, + 40, + 75, + 263, + 46, + 392, + 266, + 47, + 8, + 278, + 262, + 192, + 260, + 329, + 332, + 25, + 314, + 15, + 22, + 146, + 101, + 343, + 245, + 238, + 354, + 222, + 69, + 259, + 139, + 352, + 73, + 46, + 223, + 294, + 122, + 292, + 312, + 382, + 338, + 260, + 334, + 165, + 341, + 62, + 108, + 227, + 232, + 208, + 40, + 342, + 281, + 120, + 62, + 185, + 165, + 348, + 114, + 26, + 65, + 146, + 33, + 34, + 340, + 156, + 275, + 68, + 187, + 396, + 205, + 366, + 26, + 298, + 64, + 220, + 73, + 192, + 303, + 57, + 382, + 273, + 313, + 385, + 134, + 261, + 327, + 307, + 325, + 108, + 386, + 251, + 305, + 114, + 392, + 114, + 147, + 72, + 312, + 108, + 264, + 378, + 316, + 398, + 169, + 217, + 39, + 58, + 46, + 12, + 265, + 7, + 187, + 105, + 53, + 133, + 44, + 244, + 115, + 129, + 282, + 22, + 340, + 200, + 121, + 90, + 209, + 97, + 388, + 133, + 345, + 113, + 289, + 298, + 312, + 284, + 72, + 98, + 259, + 201, + 111, + 357, + 337, + 369, + 286, + 346, + 206, + 159, + 20, + 266, + 177, + 386, + 114, + 16, + 334, + 132, + 277, + 214, + 375, + 229, + 29, + 124, + 19, + 95, + 169, + 65, + 318, + 120, + 245, + 31, + 301, + 306, + 197, + 261, + 102, + 290, + 156, + 69, + 330, + 346, + 139, + 159, + 287, + 284, + 126, + 301, + 57, + 274, + 386, + 106, + 147, + 19, + 344, + 11, + 276, + 31, + 252, + 87, + 133, + 73, + 259, + 20, + 85, + 334, + 311, + 352, + 197, + 282, + 348, + 359, + 120, + 18, + 250, + 389, + 233, + 6, + 75, + 395, + 191, + 51, + 156, + 387, + 377, + 155, + 355, + 343, + 49, + 270, + 308, + 95, + 41, + 66, + 380, + 335, + 224, + 162, + 198, + 366, + 44, + 259, + 232, + 170, + 177, + 251, + 256, + 10, + 337, + 175, + 82, + 230, + 54, + 275, + 34, + 113, + 228, + 288, + 151, + 199, + 361, + 244, + 221, + 336, + 336, + 30, + 105, + 228, + 317, + 356, + 227, + 251, + 58, + 6, + 165, + 150, + 400, + 271, + 48, + 343, + 383, + 48, + 144, + 289, + 270, + 147, + 18, + 131, + 302, + 191, + 249, + 143, + 32, + 279, + 245, + 350, + 176, + 154, + 103, + 355, + 359, + 167, + 239, + 121, + 361, + 10, + 217, + 78, + 207, + 391, + 309, + 16, + 65, + 309, + 185, + 299, + 299, + 372, + 86, + 146, + 316, + 207, + 96, + 196, + 97, + 28, + 28, + 128, + 234, + 123, + 108, + 88, + 359, + 124, + 27, + 76, + 377, + 318, + 155, + 251, + 231, + 148, + 352, + 378, + 3, + 93, + 400, + 34, + 235, + 299, + 360, + 118, + 211, + 22, + 282, + 57, + 270, + 295, + 150, + 283, + 204, + 12, + 357, + 231, + 119, + 20, + 173, + 55, + 129, + 61, + 286, + 382, + 303, + 135, + 89, + 249, + 384, + 77, + 379, + 142, + 333, + 178, + 295, + 198, + 293, + 338, + 150, + 10, + 17, + 354, + 177, + 157, + 76, + 38, + 293, + 236, + 205, + 98, + 169, + 265, + 109, + 91, + 172, + 218, + 125, + 298, + 50, + 339, + 115, + 168, + 165, + 26, + 53, + 84, + 236, + 13, + 97, + 400, + 387, + 37, + 243, + 172, + 180, + 285, + 94, + 209, + 125, + 353, + 67, + 257, + 34, + 168, + 360, + 78, + 251, + 320, + 278, + 376, + 317, + 148, + 263, + 32, + 356, + 160, + 208, + 289, + 235, + 249, + 357, + 318, + 55, + 155, + 283, + 134, + 60, + 156, + 21, + 295, + 20, + 65, + 46, + 215, + 321, + 39, + 12, + 346, + 108, + 321, + 270, + 156, + 136, + 334, + 364, + 318, + 168, + 365, + 79, + 90, + 123, + 325, + 330, + 189, + 52, + 123, + 310, + 267, + 231, + 289, + 133, + 293, + 32, + 346, + 288, + 313, + 108, + 398, + 62, + 321, + 25, + 362, + 268, + 313, + 123, + 280, + 353, + 129, + 100, + 170, + 54, + 13, + 348, + 167, + 82, + 167, + 176, + 41, + 235, + 45, + 400, + 216, + 211, + 233, + 297, + 310, + 240, + 193, + 248, + 242, + 375, + 371, + 170, + 342, + 197, + 190, + 367, + 43, + 71, + 249, + 251, + 299, + 317, + 291, + 345, + 69, + 60, + 333, + 21, + 312, + 194, + 6, + 285, + 320, + 201, + 8, + 218, + 286, + 127, + 388, + 183, + 27, + 181, + 263, + 102, + 246, + 134, + 37, + 236, + 262, + 196, + 186, + 157, + 281, + 266, + 263, + 219, + 345, + 120, + 22, + 210, + 246, + 72, + 29, + 121, + 299, + 240, + 167, + 270, + 47, + 229, + 84, + 226, + 26, + 70, + 85, + 197, + 218, + 198, + 278, + 232, + 36, + 1, + 298, + 144, + 130, + 2, + 240, + 86, + 216, + 288, + 135, + 98, + 68, + 41, + 142, + 192, + 301, + 169, + 114, + 261, + 11, + 322, + 148, + 66, + 196, + 358, + 280, + 347, + 15, + 9, + 212, + 383, + 394, + 127, + 194, + 277, + 135, + 231, + 223, + 84, + 284, + 98, + 286, + 367, + 28, + 299, + 74, + 187, + 260, + 273, + 300, + 206, + 23, + 244, + 291, + 364, + 21, + 12, + 52, + 362, + 20, + 353, + 38, + 370, + 188, + 64, + 320, + 226, + 103, + 206, + 25, + 197, + 35, + 348, + 213, + 182, + 364, + 249, + 118, + 352, + 286, + 166, + 101, + 375, + 292, + 258, + 62, + 372, + 102, + 149, + 250, + 223, + 97, + 180, + 129, + 394, + 184, + 132, + 29, + 88, + 104, + 180, + 50, + 97, + 192, + 339, + 166, + 234, + 374, + 219, + 233, + 141, + 337, + 317, + 274, + 44, + 165, + 189, + 112, + 363, + 156, + 291, + 44, + 288, + 142, + 391, + 289, + 17, + 341, + 335, + 6, + 177, + 219, + 285, + 224, + 62, + 20, + 258, + 270, + 91, + 254, + 334, + 124, + 185, + 120, + 8, + 13, + 339, + 306, + 333, + 255, + 41, + 7, + 316, + 236, + 80, + 145, + 247, + 368, + 312, + 124, + 346, + 116, + 1, + 108, + 9, + 126, + 303, + 357, + 5, + 223, + 83, + 172, + 205, + 242, + 77, + 61, + 159, + 121, + 268, + 256, + 331, + 203, + 70, + 217, + 122, + 310, + 142, + 156, + 108, + 379, + 321, + 289, + 379, + 63, + 264, + 372, + 395, + 261, + 190, + 11, + 291, + 148, + 72, + 215, + 259, + 304, + 381, + 38, + 216, + 134, + 62, + 211, + 279, + 213, + 125, + 27, + 254, + 81, + 43, + 150, + 256, + 371, + 295, + 219, + 335, + 230, + 79, + 177, + 159, + 241, + 304, + 63, + 247, + 107, + 143, + 400, + 262, + 369, + 242, + 90, + 82, + 105, + 229, + 162, + 222, + 383, + 363, + 223, + 211, + 114, + 134, + 162, + 245, + 371, + 95, + 329, + 124, + 216, + 201, + 195, + 157, + 85, + 309, + 271, + 384, + 143, + 51, + 366, + 183, + 326, + 170, + 49, + 326, + 351, + 107, + 141, + 334, + 102, + 323, + 286, + 12, + 215, + 4, + 228, + 322, + 255, + 256, + 323, + 69, + 168, + 274, + 148, + 237, + 194, + 331, + 203, + 132, + 151, + 238, + 215, + 46, + 106, + 35, + 225, + 360, + 124, + 386, + 37, + 111, + 331, + 340, + 12, + 181, + 143, + 249, + 348, + 165, + 10, + 282, + 18, + 359, + 346, + 371, + 267, + 355, + 15, + 212, + 68, + 382, + 222, + 110, + 54, + 270, + 53, + 245, + 213, + 152, + 80, + 323, + 6, + 264, + 149, + 360, + 388, + 323, + 284, + 315, + 125, + 119, + 95, + 243, + 218, + 360, + 394, + 383, + 221, + 289, + 113, + 294, + 359, + 140, + 113, + 292, + 48, + 266, + 386, + 30, + 186, + 65, + 384, + 351, + 228, + 31, + 144, + 359, + 352, + 50, + 362, + 362, + 202, + 27, + 294, + 9, + 68, + 164, + 105, + 37, + 137, + 251, + 394, + 20, + 306, + 145, + 176, + 74, + 229, + 235, + 211, + 174, + 14, + 221, + 165, + 116, + 374, + 198, + 136, + 148, + 198, + 271, + 222, + 48, + 143, + 19, + 399, + 386, + 125, + 378, + 40, + 140, + 183, + 78, + 100, + 26, + 66, + 233, + 114, + 122, + 23, + 183, + 115, + 338, + 357, + 255, + 71, + 230, + 65, + 115, + 75, + 86, + 110, + 100, + 90, + 389, + 159, + 318, + 397, + 40, + 70, + 41, + 106, + 55, + 49, + 181, + 344, + 381, + 132, + 26, + 52, + 306, + 172, + 323, + 197, + 116, + 126, + 39, + 154, + 77, + 256, + 48, + 39, + 317, + 384, + 347, + 66, + 178, + 266, + 1, + 110, + 162, + 153, + 2, + 86, + 192, + 145, + 245, + 193, + 396, + 366, + 205, + 369, + 88, + 158, + 160, + 217, + 58, + 287, + 384, + 110, + 345, + 369, + 36, + 366, + 71, + 233, + 246, + 213, + 300, + 68, + 291, + 245, + 208, + 356, + 303, + 212, + 152, + 181, + 292, + 67, + 379, + 354, + 388, + 372, + 30, + 304, + 135, + 123, + 118, + 281, + 380, + 344, + 20, + 53, + 107, + 3, + 216, + 381, + 22, + 363, + 271, + 269, + 196, + 97, + 40, + 399, + 115, + 361, + 219, + 128, + 340, + 15, + 308, + 186, + 8, + 292, + 183, + 63, + 42, + 8, + 273, + 45, + 195, + 108, + 140, + 324, + 230, + 306, + 159, + 324, + 172, + 72, + 109, + 203, + 188, + 329, + 186, + 61, + 174, + 362, + 143, + 10, + 388, + 66, + 211, + 227, + 13, + 239, + 201, + 198, + 96, + 208, + 26, + 345, + 336, + 21, + 145, + 1, + 206, + 393, + 81, + 251, + 303, + 195, + 11, + 68, + 205, + 341, + 144, + 178, + 256, + 348, + 70, + 12, + 6, + 385, + 201, + 108, + 92, + 284, + 140, + 43, + 51, + 106, + 172, + 148, + 195, + 218, + 370, + 73, + 335, + 189, + 138, + 13, + 227, + 227, + 208, + 338, + 137, + 379, + 68, + 308, + 236, + 258, + 293, + 287, + 13, + 129, + 132, + 60, + 174, + 126, + 319, + 185, + 189, + 318, + 232, + 359, + 275, + 364, + 46, + 256, + 179, + 172, + 368, + 45, + 68, + 132, + 201, + 21, + 285, + 99, + 338, + 340, + 140, + 300, + 270, + 208, + 380, + 187, + 188, + 22, + 112, + 304, + 55, + 39, + 198, + 20, + 355, + 257, + 298, + 91, + 235, + 18, + 235, + 58, + 77, + 397, + 232, + 51, + 277, + 284, + 292, + 360, + 369, + 188, + 350, + 158, + 125, + 158, + 49, + 160, + 111, + 64, + 21, + 368, + 390, + 287, + 279, + 104, + 291, + 246, + 294, + 196, + 400, + 161, + 133, + 319, + 310, + 62, + 118, + 205, + 320, + 164, + 44, + 81, + 10, + 270, + 51, + 23, + 265, + 121, + 184, + 389, + 120, + 355, + 221, + 167, + 105, + 289, + 147, + 174, + 133, + 185, + 225, + 228, + 309, + 218, + 320, + 233, + 115, + 126, + 22, + 383, + 356, + 254, + 36, + 19, + 95, + 80, + 327, + 107, + 42, + 327, + 70, + 107, + 45, + 119, + 323, + 83, + 81, + 68, + 261, + 195, + 76, + 45, + 172, + 6, + 154, + 305, + 108, + 263, + 249, + 146, + 120, + 112, + 298, + 207, + 382, + 231, + 371, + 102, + 87, + 155, + 168, + 387, + 309, + 70, + 166, + 95, + 12, + 343, + 302, + 266, + 113, + 41, + 173, + 268, + 350, + 224, + 42, + 70, + 353, + 6, + 319, + 39, + 144, + 223, + 240, + 68, + 11, + 36, + 326, + 364, + 31, + 7, + 329, + 295, + 392, + 147, + 250, + 192, + 24, + 334, + 27, + 272, + 21, + 49, + 398, + 222, + 150, + 255, + 326, + 100, + 149, + 33, + 357, + 143, + 15, + 246, + 30, + 72, + 101, + 398, + 120, + 398, + 87, + 210, + 355, + 354, + 364, + 244, + 360, + 81, + 293, + 140, + 384, + 197, + 371, + 357, + 157, + 139, + 73, + 198, + 151, + 253, + 79, + 155, + 184, + 24, + 99, + 121, + 66, + 330, + 351, + 279, + 280, + 284, + 362, + 384, + 294, + 262, + 80, + 232, + 62, + 15, + 395, + 102, + 287, + 147, + 20, + 380, + 37, + 211, + 292, + 53, + 265, + 159, + 17, + 141, + 22, + 348, + 311, + 224, + 372, + 116, + 138, + 360, + 170, + 210, + 118, + 208, + 367, + 248, + 267, + 194, + 273, + 162, + 124, + 128, + 45, + 30, + 353, + 258, + 204, + 329, + 49, + 101, + 232, + 133, + 95, + 371, + 186, + 128, + 214, + 318, + 233, + 20, + 37, + 253, + 291, + 152, + 223, + 254, + 321, + 277, + 224, + 68, + 346, + 395, + 89, + 23, + 5, + 136, + 52, + 369, + 158, + 2, + 48, + 34, + 102, + 187, + 101, + 117, + 344, + 301, + 294, + 302, + 349, + 272, + 148, + 169, + 82, + 108, + 10, + 302, + 9, + 81, + 124, + 209, + 327, + 371, + 247, + 270, + 26, + 337, + 109, + 128, + 13, + 53, + 148, + 73, + 162, + 390, + 89, + 173, + 86, + 156, + 114, + 394, + 90, + 105, + 61, + 388, + 24, + 318, + 366, + 260, + 34, + 340, + 159, + 293, + 205, + 266, + 87, + 142, + 370, + 355, + 57, + 69, + 369, + 385, + 136, + 379, + 59, + 298, + 141, + 199, + 274, + 137, + 241, + 109, + 253, + 159, + 384, + 180, + 174, + 263, + 302, + 350, + 371, + 273, + 292, + 298, + 184, + 215, + 279, + 60, + 103, + 137, + 50, + 317, + 154, + 380, + 360, + 284, + 68, + 178, + 4, + 125, + 165, + 196, + 36, + 151, + 392, + 99, + 59, + 236, + 197, + 107, + 98, + 207, + 231, + 369, + 240, + 213, + 313, + 36, + 259, + 151, + 189, + 387, + 348, + 392, + 69, + 350, + 214, + 17, + 228, + 29, + 215, + 243, + 216, + 17, + 55, + 113, + 200, + 347, + 217, + 132, + 52, + 57, + 109, + 253, + 288, + 377, + 258, + 281, + 251, + 230, + 298, + 98, + 252, + 347, + 232, + 50, + 157, + 213, + 288, + 381, + 142, + 192, + 142, + 156, + 161, + 24, + 257, + 344, + 160, + 242, + 294, + 214, + 151, + 290, + 274, + 142, + 383, + 219, + 309, + 227, + 110, + 137, + 256, + 127, + 299, + 319, + 34, + 153, + 164, + 168, + 341, + 143, + 200, + 205, + 324, + 225, + 216, + 149, + 237, + 89, + 280, + 244, + 256, + 159, + 394, + 135, + 394, + 99, + 267, + 309, + 159, + 176, + 110, + 393, + 268, + 291, + 55, + 102, + 68, + 85, + 158, + 11, + 224, + 84, + 150, + 272, + 342, + 152, + 7, + 67, + 237, + 202, + 286, + 361, + 179, + 52, + 118, + 182, + 121, + 319, + 92, + 216, + 312, + 163, + 100, + 162, + 53, + 244, + 369, + 307, + 64, + 282, + 354, + 135, + 255, + 5, + 97, + 147, + 384, + 290, + 115, + 83, + 17, + 249, + 308, + 129, + 279, + 199, + 162, + 304, + 392, + 331, + 185, + 305, + 333, + 298, + 243, + 124, + 120, + 231, + 378, + 74, + 311, + 85, + 40, + 43, + 14, + 266, + 169, + 175, + 342, + 133, + 151, + 329, + 186, + 295, + 35, + 324, + 291, + 124, + 187, + 11, + 135, + 195, + 341, + 255, + 281, + 255, + 362, + 329, + 274, + 338, + 182, + 52, + 172, + 219, + 141, + 14, + 64, + 87, + 105, + 132, + 156, + 69, + 106, + 6, + 117, + 249, + 297, + 113, + 123, + 388, + 17, + 164, + 348, + 278, + 93, + 86, + 199, + 385, + 283, + 237, + 80, + 30, + 352, + 51, + 58, + 133, + 127, + 100, + 128, + 234, + 380, + 234, + 42, + 310, + 304, + 32, + 18, + 300, + 215, + 391, + 169, + 107, + 324, + 49, + 157, + 207, + 317, + 282, + 90, + 48, + 145, + 339, + 349, + 120, + 226, + 174, + 64, + 397, + 274, + 295, + 261, + 341, + 157, + 165, + 263, + 186, + 194, + 56, + 128, + 3, + 284, + 57, + 88, + 304, + 151, + 43, + 65, + 86, + 350, + 9, + 203, + 31, + 126, + 249, + 387, + 377, + 298, + 43, + 236, + 310, + 247, + 102, + 143, + 14, + 114, + 262, + 156, + 182, + 108, + 398, + 372, + 100, + 393, + 329, + 359, + 285, + 388, + 59, + 184, + 221, + 303, + 327, + 145, + 124, + 144, + 9, + 107, + 142, + 18, + 56, + 36, + 313, + 329, + 98, + 54, + 367, + 201, + 102, + 325, + 37, + 205, + 123, + 299, + 241, + 84, + 112, + 235, + 46, + 357, + 214, + 361, + 392, + 220, + 171, + 3, + 240, + 388, + 167, + 7, + 293, + 4, + 194, + 269, + 197, + 125, + 78, + 162, + 301, + 222, + 157, + 248, + 74, + 278, + 110, + 156, + 273, + 239, + 161, + 290, + 117, + 27, + 356, + 377, + 328, + 80, + 152, + 302, + 193, + 180, + 256, + 365, + 237, + 194, + 354, + 178, + 199, + 248, + 154, + 336, + 249, + 267, + 315, + 356, + 200, + 379, + 224, + 215, + 104, + 51, + 146, + 28, + 77, + 232, + 346, + 22, + 43, + 16, + 12, + 212, + 120, + 209, + 268, + 213, + 159, + 193, + 260, + 232, + 298, + 153, + 278, + 129, + 109, + 375, + 121, + 151, + 34, + 256, + 7, + 260, + 139, + 255, + 384, + 376, + 130, + 108, + 215, + 103, + 179, + 181, + 24, + 328, + 385, + 213, + 20, + 41, + 74, + 8, + 365, + 195, + 56, + 23, + 310, + 325, + 235, + 307, + 322, + 320, + 218, + 26, + 363, + 220, + 181, + 353, + 369, + 315, + 366, + 78, + 125, + 138, + 177, + 333, + 164, + 54, + 128, + 315, + 1, + 173, + 254, + 259, + 33, + 302, + 219, + 248, + 235, + 72, + 279, + 97, + 389, + 79, + 313, + 198, + 301, + 324, + 338, + 293, + 378, + 124, + 270, + 325, + 170, + 375, + 118, + 224, + 254, + 78, + 117, + 103, + 180, + 303, + 94, + 259, + 54, + 375, + 147, + 399, + 299, + 128, + 122, + 364, + 23, + 330, + 288, + 314, + 71, + 162, + 398, + 96, + 176, + 371, + 30, + 12, + 21, + 130, + 190, + 205, + 52, + 20, + 102, + 262, + 268, + 122, + 23, + 354, + 104, + 221, + 191, + 129, + 33, + 51, + 339, + 198, + 111, + 159, + 395, + 295, + 93, + 272, + 124, + 114, + 254, + 116, + 127, + 272, + 41, + 210, + 384, + 83, + 34, + 393, + 84, + 359, + 137, + 355, + 228, + 316, + 175, + 75, + 280, + 221, + 98, + 43, + 68, + 197, + 194, + 40, + 242, + 50, + 123, + 149, + 206, + 331, + 158, + 224, + 142, + 88, + 201, + 250, + 251, + 186, + 42, + 191, + 317, + 282, + 3, + 250, + 137, + 139, + 305, + 110, + 165, + 269, + 333, + 378, + 360, + 292, + 183, + 370, + 78, + 100, + 344, + 186, + 137, + 120, + 220, + 14, + 302, + 303, + 55, + 381, + 234, + 382, + 93, + 342, + 168, + 213, + 155, + 180, + 201, + 191, + 386, + 296, + 303, + 82, + 131, + 218, + 299, + 360, + 282, + 253, + 49, + 215, + 225, + 67, + 378, + 23, + 109, + 398, + 48, + 15, + 235, + 138, + 373, + 270, + 366, + 7, + 150, + 92, + 372, + 110, + 123, + 57, + 66, + 98, + 210, + 164, + 338, + 341, + 171, + 92, + 277, + 20, + 33, + 280, + 214, + 28, + 363, + 79, + 291, + 256, + 161, + 252, + 322, + 372, + 134, + 203, + 108, + 54, + 127, + 392, + 128, + 180, + 185, + 99, + 7, + 75, + 141, + 188, + 37, + 309, + 1, + 316, + 377, + 345, + 177, + 229, + 133, + 160, + 312, + 294, + 198, + 130, + 363, + 118, + 72, + 52, + 198, + 375, + 52, + 306, + 336, + 300, + 140, + 130, + 395, + 386, + 205, + 263, + 30, + 155, + 301, + 389, + 59, + 47, + 162, + 120, + 360, + 311, + 281, + 102, + 41, + 197, + 46, + 271, + 36, + 179, + 303, + 106, + 316, + 253, + 283, + 292, + 103, + 218, + 199, + 158, + 144, + 54, + 127, + 53, + 293, + 36, + 215, + 168, + 110, + 233, + 192, + 377, + 1, + 170, + 245, + 225, + 363, + 172, + 56, + 110, + 165, + 134, + 139, + 248, + 325, + 84, + 340, + 53, + 78, + 395, + 9, + 288, + 223, + 105, + 165, + 230, + 317, + 189, + 72, + 252, + 296, + 169, + 214, + 75, + 179, + 256, + 60, + 178, + 30, + 138, + 376, + 327, + 98, + 191, + 48, + 14, + 320, + 39, + 172, + 183, + 229, + 291, + 88, + 110, + 400, + 12, + 238, + 159, + 309, + 256, + 170, + 26, + 348, + 191, + 296, + 236, + 275, + 314, + 280, + 126, + 231, + 185, + 263, + 306, + 35, + 35, + 378, + 198, + 162, + 49, + 212, + 224, + 66, + 40, + 47, + 24, + 154, + 226, + 198, + 98, + 193, + 398, + 51, + 130, + 64, + 73, + 378, + 189, + 71, + 158, + 314, + 47, + 209, + 339, + 197, + 372, + 201, + 116, + 33, + 215, + 169, + 211, + 155, + 378, + 11, + 226, + 125, + 188, + 182, + 341, + 102, + 318, + 81, + 359, + 388, + 11, + 174, + 241, + 179, + 367, + 368, + 311, + 232, + 9, + 131, + 174, + 384, + 45, + 355, + 209, + 289, + 372, + 339, + 86, + 40, + 385, + 79, + 15, + 161, + 386, + 386, + 124, + 368, + 305, + 299, + 301, + 384, + 315, + 389, + 378, + 95, + 249, + 394, + 393, + 174, + 291, + 259, + 290, + 268, + 373, + 340, + 39, + 253, + 294, + 254, + 212, + 222, + 164, + 27, + 379, + 39, + 50, + 70, + 153, + 191, + 292, + 21, + 9, + 254, + 100, + 115, + 80, + 117, + 387, + 389, + 236, + 257, + 226, + 292, + 169, + 238, + 92, + 36, + 190, + 73, + 177, + 301, + 24, + 173, + 168, + 242, + 208, + 91, + 366, + 87, + 206, + 247, + 161, + 340, + 105, + 151, + 108, + 26, + 124, + 228, + 268, + 371, + 176, + 360, + 334, + 164, + 190, + 10, + 59, + 63, + 67, + 2, + 135, + 334, + 166, + 266, + 350, + 153, + 142, + 32, + 261, + 107, + 389, + 170, + 1, + 27, + 19, + 331, + 288, + 190, + 311, + 189, + 82, + 34, + 369, + 89, + 127, + 217, + 344, + 248, + 312, + 233, + 215, + 86, + 5, + 203, + 362, + 54, + 278, + 33, + 310, + 342, + 154, + 168, + 376, + 378, + 16, + 140, + 285, + 336, + 237, + 185, + 303, + 222, + 10, + 120, + 341, + 110, + 125, + 16, + 180, + 211, + 362, + 344, + 244, + 199, + 168, + 146, + 114, + 55, + 347, + 242, + 318, + 392, + 298, + 316, + 230, + 109, + 23, + 271, + 289, + 169, + 26, + 96, + 47, + 114, + 159, + 119, + 320, + 367, + 10, + 36, + 171, + 349, + 270, + 384, + 245, + 15, + 393, + 192, + 43, + 356, + 247, + 68, + 320, + 215, + 21, + 366, + 58, + 186, + 335, + 131, + 321, + 7, + 280, + 239, + 224, + 159, + 237, + 271, + 13, + 129, + 231, + 396, + 221, + 359, + 14, + 372, + 253, + 267, + 349, + 375, + 290, + 361, + 243, + 252, + 1, + 261, + 397, + 60, + 375, + 393, + 234, + 105, + 342, + 301, + 380, + 143, + 393, + 282, + 6, + 279, + 321, + 308, + 148, + 143, + 358, + 114, + 192, + 206, + 220, + 382, + 343, + 207, + 186, + 194, + 395, + 144, + 77, + 264, + 19, + 251, + 336, + 60, + 57, + 182, + 363, + 19, + 225, + 226, + 241, + 333, + 260, + 267, + 380, + 375, + 234, + 340, + 27, + 132, + 335, + 379, + 143, + 225, + 50, + 8, + 209, + 306, + 223, + 122, + 127, + 302, + 244, + 194, + 301, + 251, + 393, + 326, + 239, + 50, + 98, 352, - 158, - 247, + 100, + 65, + 372, + 365, + 241, + 43, + 336, + 353, + 259, + 144, + 101, + 356, + 209, + 374, + 340, + 336, + 91, + 339, + 370, + 193, + 232, + 254, + 313, + 76, + 198, + 290, + 14, + 378, + 353, + 209, + 233, + 376, + 326, + 391, + 286, + 309, + 10, + 263, + 45, + 83, + 92, + 181, + 239, + 87, 82, - 368, - 24, - 41, - 307, + 171, + 217, + 52, + 127, + 323, + 157, + 270, + 21, + 114, + 172, + 51, + 290, + 276, + 308, + 47, + 296, + 84, + 122, + 365, + 373, + 324, + 104, + 100, + 6, + 382, + 211, + 363, + 210, + 308, + 291, + 128, + 282, + 225, + 218, + 333, + 13, + 377, + 400, + 33, + 348, + 232, + 364, + 276, + 350, + 187, + 47, + 147, + 345, + 198, + 146, + 395, + 294, + 32, + 300, + 322, + 128, + 352, + 334, + 343, + 169, + 355, + 336, + 71, + 15, + 213, + 131, + 25, + 389, + 125, + 107, + 156, + 68, + 111, + 126, + 320, + 276, + 360, + 73, + 92, + 310, + 12, + 346, + 25, + 110, + 396, + 52, + 234, + 348, + 94, + 20, + 250, + 377, + 226, + 10, + 372, + 193, + 108, + 83, + 360, + 322, + 303, + 396, + 94, + 316, + 160, + 102, + 388, + 212, + 357, + 1, + 142, + 63, + 131, + 166, + 221, + 115, + 172, + 375, + 108, + 293, + 210, + 222, + 226, + 137, + 260, + 166, + 260, + 199, + 19, + 344, + 166, + 381, + 304, + 325, + 344, + 343, + 122, + 282, + 16, + 71, + 257, + 306, + 323, + 54, + 366, + 47, + 264, + 262, + 8, + 213, + 64, + 186, + 6, + 222, + 389, + 122, + 178, + 176, + 337, + 380, + 315, + 359, + 169, + 305, + 77, + 30, + 113, + 291, + 341, + 317, 273, - 207, + 47, + 258, + 191, + 159, + 219, + 162, + 73, + 23, + 60, + 344, + 198, + 318, + 138, + 4, + 184, 16, - 121, 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, - 326, + 37, + 306, + 338, + 189, + 193, + 173, + 323, + 164, + 305, + 33, + 157, + 330, + 27, 16, - 252, + 335, + 339, + 352, + 191, + 10, + 36, + 222, + 77, + 307, + 103, + 358, + 196, + 333, + 169, + 386, + 308, + 152, + 34, + 75, + 348, + 219, + 343, + 48, + 11, + 2, + 23, + 367, + 365, + 294, + 275, + 39, + 338, + 154, + 335, + 245, + 313, + 264, + 107, + 223, + 304, + 61, + 306, + 186, + 108, + 147, + 236, + 283, + 147, + 397, + 343, + 111, + 184, + 313, + 264, + 132, + 398, + 49, + 298, + 325, + 370, + 400, + 208, + 146, + 381, + 43, + 153, + 188, + 309, + 212, + 243, + 278, + 184, + 388, + 222, + 46, + 32, 171, - 106, - 66, + 230, + 253, + 318, + 128, + 128, + 306, + 298, + 223, + 188, + 277, + 70, + 119, + 232, + 129, + 156, + 167, + 37, + 137, + 356, + 392, + 209, + 324, + 290, + 386, + 319, + 285, + 99, + 339, + 323, + 314, + 301, + 123, + 156, + 311, + 350, + 63, + 246, + 240, + 78, + 110, + 342, + 332, 374, + 286, + 20, + 253, + 332, + 340, + 37, + 210, + 174, + 324, + 236, + 243, + 395, + 375, + 134, 288, - 67, - 322, + 177, + 279, + 33, + 286, + 204, + 134, + 319, + 391, + 181, 211, + 355, + 32, + 312, + 62, + 69, + 124, + 297, + 38, + 388, + 37, + 350, + 53, + 2, + 129, + 24, + 234, + 372, + 394, + 231, + 168, + 367, + 139, + 345, + 46, + 279, + 180, + 147, + 89, + 364, + 168, + 153, + 94, + 63, + 62, + 127, + 110, + 245, + 229, + 4, + 298, + 352, + 262, + 41, + 269, + 121, + 129, + 40, + 228, + 254, + 114, + 128, + 118, + 73, + 261, + 375, + 65, + 14, + 175, + 128, + 367, + 110, + 50, + 366, + 65, + 59, + 170, + 260, + 58, + 12, + 224, + 246, + 87, + 210, + 12, + 130, + 354, + 123, + 122, + 299, + 143, + 311, + 187, + 298, + 372, + 201, + 159, + 395, + 356, + 15, + 142, + 352, + 212, + 302, + 212, + 213, + 58, + 265, + 209, + 156, + 392, + 261, + 313, + 323, + 293, + 302, + 299, + 171, + 258, + 353, + 382, 54, - 86, - 222, - 190, - 76, + 321, + 78, + 60, + 304, + 146, + 212, + 282, + 237, + 219, + 114, + 2, + 239, + 307, + 247, + 95, + 331, + 247, + 252, + 7, + 289, + 179, + 238, + 328, + 369, + 354, + 130, + 357, + 248, + 292, + 97, + 113, + 297, + 244, + 202, + 21, + 227, + 141, + 78, + 182, + 373, + 191, + 327, + 254, + 61, + 226, + 246, + 1, + 26, + 114, + 335, + 159, + 388, + 273, + 79, + 257, + 361, + 329, + 114, + 368, + 300, + 118, + 329, + 136, + 186, + 281, + 158, + 4, + 132, 30, + 396, + 361, + 154, + 118, + 151, + 380, + 178, + 238, + 315, + 195, + 179, + 207, + 341, + 231, + 47, + 78, + 37, + 389, + 115, + 329, + 191, + 169, + 217, + 367, + 116, + 61, + 113, + 12, + 21, + 123, + 213, + 128, + 184, + 321, + 260, + 131, + 119, + 34, + 15, + 178, + 58, + 117, + 54, + 35, + 292, + 92, + 271, + 181, + 62, + 168, + 82, + 72, + 310, 215, - 150, + 309, + 334, + 281, 72, + 351, + 333, + 171, + 207, + 85, + 221, 232, - 317, + 349, + 59, + 258, + 43, + 216, + 54, + 211, + 345, + 131, + 314, + 391, + 39, + 300, + 41, + 35, + 9, + 313, + 269, 86, - 267, - 232, - 249, - 352, - 373, - 162, - 245, - 140, - 149, + 239, + 189, 240, - 206, - 75, - 57, - 193, - 272, - 91, - 321, - 255, - 173, - 92, - 45, - 251, + 279, + 331, + 333, + 359, + 128, + 229, + 107, + 87, + 163, + 49, + 151, + 167, + 221, + 327, + 324, + 305, + 281, + 309, + 269, + 141, + 295, + 56, + 66, + 356, + 49, + 289, + 136, 139, - 263, - 400, - 280, + 117, 257, - 184, + 361, + 297, + 329, + 31, + 142, + 389, + 164, 32, - 396, - 182, - 355, - 300, - 339, + 96, + 210, + 149, + 145, + 106, + 51, + 273, + 80, + 211, + 61, + 60, + 106, + 99, + 216, + 309, + 175, + 314, + 370, + 204, + 236, + 148, + 395, + 283, + 55, + 159, + 343, + 292, + 375, + 39, + 237, + 347, + 126, + 192, + 356, + 188, + 357, + 346, + 280, + 308, + 188, + 186, + 159, + 121, + 33, + 52, + 217, + 14, + 191, + 90, + 373, + 5, + 147, + 291, + 332, + 191, + 100, + 27, 17, - 388, + 300, + 63, + 277, + 308, + 235, + 301, + 63, + 208, + 269, + 70, + 134, + 101, + 74, + 393, + 309, + 50, + 69, + 92, + 276, + 89, + 329, + 158, + 346, + 309, + 274, + 274, + 67, + 46, + 45, + 49, + 65, + 254, + 211, + 71, + 206, + 254, + 354, + 301, + 80, + 293, + 229, 156, - 186, - 286, - 360, - 342, - 143, - 248, - 135, - 394, - 353, - 366, - 150, + 139, + 155, + 37, + 189, + 159, + 213, + 359, + 284, + 341, + 118, + 307, + 223, + 267, + 345, + 310, + 22, + 136, + 211, + 329, + 209, + 117, + 199, + 164, + 47, + 255, + 281, + 170, + 22, + 313, + 17, + 327, + 304, + 147, 174, - 332, - 91, - 297 + 229, + 83, + 289, + 92, + 335, + 316, + 143, + 179, + 325, + 121, + 128, + 38, + 61, + 64, + 321, + 69, + 321, + 136, + 101, + 108 ] } diff --git a/calyx-py/test/correctness/sdn.py b/calyx-py/test/correctness/sdn.py index c22952306..f87f95079 100644 --- a/calyx-py/test/correctness/sdn.py +++ b/calyx-py/test/correctness/sdn.py @@ -114,6 +114,8 @@ def insert_main(prog, dataplane, controller, stats_component): values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) + ans_neq_0 = main.neq_use(dataplane_ans.out, 0) # ans != 0 + j = main.reg("j", 32) # The index on the answer-list we'll write to incr_j = main.incr(j) # j++ write_ans = main.mem_store_seq_d1(ans_mem, j.out, dataplane_ans.out, "write_ans") @@ -139,9 +141,12 @@ def insert_main(prog, dataplane, controller, stats_component): ref_component_err=dataplane_err, ref_stats_runner=stats, ), - # If the dataplane component has an answer, + # If the dataplane component has a nonzero answer, # write it to the answer-list and increment the index `j`. - cb.if_(has_ans.out, [write_ans, incr_j]), + cb.if_( + has_ans.out, + cb.if_with(ans_neq_0, [write_ans, incr_j]), + ), cb.invoke( # Invoke the controller component. controller, ref_stats_controller=stats, diff --git a/calyx-py/test/correctness/static/sdn_static.data b/calyx-py/test/correctness/static/sdn_static.data index a2f8b6cab..3fbb87182 100644 --- a/calyx-py/test/correctness/static/sdn_static.data +++ b/calyx-py/test/correctness/static/sdn_static.data @@ -1,12 +1,38 @@ { "commands": { "data": [ + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, 2, 2, 0, 2, + 2, + 2, + 2, 0, + 2, 0, + 2, 0, 0, 2, @@ -15,31 +41,51 @@ 2, 0, 0, + 2, + 0, 0, + 2, + 2, 0, 2, + 0, + 0, 2, 0, 2, 0, 0, 0, + 0, + 0, 2, 0, 0, + 2, + 2, + 0, + 2, 0, 0, + 2, 0, 0, 0, + 2, 0, 2, 2, + 2, + 2, + 2, + 0, 0, 0, 0, 0, 2, + 0, + 2, 2, 0, 2, @@ -48,28 +94,43 @@ 0, 2, 0, + 0, 2, + 0, 2, 0, 2, + 2, + 2, + 0, 0, 2, 2, 2, + 0, 2, 2, 0, + 0, + 0, + 0, + 2, 2, 2, 0, 0, 2, + 2, + 2, 0, 2, 2, 0, + 0, 2, 2, + 0, + 0, 2, 0, 2, @@ -79,146 +140,59785 @@ 0, 0, 2, + 0, 2, 2, 2, + 0, 2, 0, + 0, 2, 2, 0, + 0, + 0, + 2, + 0, 2, 0, + 2, 0, 2, + 0, 2, 0, 2, 2, 0, + 0, 2, + 0, 2, + 0, 2, 0, - 0 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 2 - } - }, - "values": { - "data": [ - 320, - 76, - 369, - 352, - 158, - 247, - 82, - 368, - 24, - 41, - 307, - 273, - 207, - 16, - 121, - 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, - 326, - 16, - 252, - 171, - 106, - 66, - 374, - 288, - 67, - 322, - 211, - 54, - 86, - 222, - 190, - 76, - 30, - 215, - 150, - 72, - 232, - 317, - 86, - 267, - 232, - 249, - 352, - 373, - 162, - 245, - 140, - 149, - 240, - 206, - 75, - 57, - 193, - 272, - 91, - 321, - 255, - 173, - 92, - 45, - 251, - 139, - 263, - 400, - 280, - 257, - 184, - 32, - 396, - 182, - 355, - 300, - 339, - 17, - 388, - 156, - 186, - 286, - 360, - 342, - 143, - 248, - 135, - 394, - 353, - 366, - 150, - 174, - 332, - 91, - 297, - 5 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 32 - } - }, - "ans_mem": { - "data": [ + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 2 + } + }, + "values": { + "data": [ + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, + 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, + 273, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, + 267, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, + 249, + 238, + 161, + 146, + 341, + 351, + 152, + 60, + 318, + 340, + 240, + 326, + 163, + 198, + 230, + 170, + 331, + 12, + 194, + 122, + 125, + 386, + 398, + 314, + 291, + 337, + 398, + 4, + 25, + 143, + 367, + 208, + 383, + 171, + 375, + 147, + 63, + 292, + 157, + 314, + 303, + 2, + 370, + 117, + 144, + 247, + 35, + 38, + 267, + 7, + 81, + 82, + 338, + 123, + 180, + 207, + 319, + 259, + 129, + 329, + 281, + 384, + 283, + 217, + 223, + 394, + 72, + 215, + 304, + 325, + 383, + 364, + 180, + 3, + 158, + 105, + 181, + 209, + 400, + 344, + 62, + 233, + 155, + 225, + 174, + 282, + 225, + 87, + 168, + 184, + 60, + 104, + 231, + 344, + 77, + 69, + 63, + 106, + 63, + 102, + 255, + 363, + 126, + 134, + 212, + 319, + 336, + 32, + 164, + 96, + 87, + 118, + 196, + 36, + 206, + 333, + 315, + 394, + 201, + 99, + 199, + 126, + 113, + 229, + 155, + 375, + 114, + 16, + 74, + 181, + 347, + 265, + 105, + 54, + 121, + 305, + 297, + 179, + 204, + 373, + 377, + 392, + 242, + 322, + 193, + 228, + 385, + 119, + 79, + 305, + 90, + 243, + 332, + 285, + 7, + 37, + 8, + 30, + 294, + 267, + 112, + 205, + 149, + 165, + 196, + 189, + 78, + 346, + 385, + 136, + 112, + 315, + 375, + 376, + 284, + 213, + 202, + 319, + 18, + 121, + 62, + 140, + 232, + 25, + 385, + 369, + 271, + 345, + 321, + 14, + 352, + 83, + 163, + 43, + 257, + 213, + 8, + 176, + 339, + 91, + 101, + 332, + 334, + 248, + 360, + 49, + 16, + 313, + 352, + 88, + 328, + 180, + 294, + 6, + 51, + 334, + 40, + 290, + 69, + 144, + 316, + 340, + 380, + 13, + 167, + 356, + 317, + 379, + 285, + 321, + 370, + 378, + 97, + 187, + 14, + 340, + 236, + 14, + 157, + 202, + 197, + 126, + 349, + 254, + 392, + 288, + 171, + 46, + 7, + 234, + 222, + 41, + 199, + 153, + 82, + 270, + 317, + 323, + 378, + 320, + 392, + 346, + 299, + 271, + 124, + 201, + 375, + 269, + 52, + 246, + 392, + 34, + 298, + 70, + 272, + 78, + 232, + 86, + 338, + 93, + 127, + 218, + 227, + 113, + 39, + 203, + 66, + 51, + 306, + 89, + 242, + 115, + 133, + 226, + 278, + 266, + 135, + 202, + 127, + 314, + 156, + 32, + 26, + 265, + 222, + 110, + 361, + 275, + 361, + 343, + 63, + 225, + 55, + 76, + 386, + 82, + 112, + 10, + 85, + 174, + 310, + 68, + 201, + 344, + 353, + 94, + 122, + 309, + 392, + 396, + 67, + 112, + 225, + 120, + 374, + 119, + 38, + 40, + 17, + 303, + 201, + 1, + 282, + 328, + 277, + 330, + 393, + 90, + 298, + 199, + 21, + 196, + 363, + 244, + 396, + 36, + 336, + 245, + 313, + 158, + 59, + 376, + 155, + 157, + 28, + 205, + 314, + 192, + 342, + 181, + 325, + 388, + 78, + 399, + 343, + 11, + 52, + 400, + 70, + 47, + 162, + 42, + 15, + 209, + 228, + 330, + 305, + 190, + 285, + 389, + 204, + 221, + 289, + 159, + 377, + 148, + 186, + 87, + 188, + 344, + 116, + 320, + 400, + 223, + 70, + 311, + 20, + 166, + 145, + 189, + 45, + 205, + 122, + 245, + 393, + 340, + 230, + 64, + 279, + 170, + 350, + 154, + 206, + 319, + 370, + 316, + 262, + 326, + 396, + 317, + 329, + 262, + 327, + 282, + 197, + 80, + 299, + 353, + 321, + 124, + 121, + 11, + 245, + 317, + 368, + 189, + 221, + 322, + 382, + 159, + 104, + 135, + 155, + 325, + 241, + 183, + 214, + 85, + 211, + 170, + 168, + 327, + 389, + 94, + 157, + 235, + 385, + 335, + 271, + 236, + 22, + 290, + 220, + 163, + 391, + 224, + 140, + 116, + 268, + 309, + 126, + 89, + 220, + 187, + 252, + 277, + 111, + 263, + 297, + 262, + 92, + 51, + 89, + 228, + 400, + 109, + 156, + 233, + 131, + 115, + 394, + 210, + 161, + 243, + 66, + 150, + 359, + 213, + 368, + 98, + 214, + 335, + 332, + 220, + 26, + 209, + 44, + 280, + 282, + 386, + 24, + 213, + 197, + 352, + 5, + 10, + 42, + 2, + 101, + 36, + 208, + 137, + 247, + 397, + 162, + 344, + 26, + 366, + 25, + 271, + 218, + 188, + 75, + 11, + 24, + 45, + 129, + 384, + 134, + 326, + 23, + 193, + 291, + 15, + 62, + 168, + 364, + 345, + 208, + 291, + 112, + 141, + 202, + 17, + 270, + 154, + 61, + 104, + 19, + 98, + 95, + 202, + 225, + 42, + 244, + 15, + 149, + 171, + 270, + 120, + 341, + 302, + 393, + 275, + 34, + 226, + 152, + 94, + 199, + 392, + 251, + 188, + 340, + 389, + 393, + 216, + 87, + 111, + 359, + 114, + 46, + 165, + 333, + 266, + 358, + 74, + 363, + 134, + 168, + 388, + 145, + 184, + 366, + 376, + 89, + 277, + 259, + 374, + 25, + 346, + 107, + 139, + 42, + 212, + 208, + 129, + 319, + 298, + 275, + 58, + 376, + 93, + 207, + 351, + 268, + 282, + 213, + 125, + 81, + 243, + 238, + 246, + 347, + 188, + 166, + 126, + 110, + 214, + 265, + 234, + 395, + 343, + 119, + 108, + 303, + 4, + 306, + 307, + 196, + 86, + 345, + 112, + 81, + 390, + 297, + 80, + 104, + 212, + 234, + 132, + 316, + 136, + 102, + 83, + 276, + 393, + 29, + 164, + 334, + 386, + 171, + 242, + 246, + 65, + 175, + 333, + 73, + 54, + 173, + 138, + 203, + 260, + 381, + 163, + 196, + 283, + 123, + 169, + 106, + 316, + 156, + 222, + 126, + 115, + 299, + 391, + 251, + 391, + 246, + 330, + 195, + 263, + 238, + 242, + 197, + 62, + 71, + 140, + 312, + 282, + 76, + 105, + 219, + 368, + 240, + 15, + 41, + 53, + 135, + 134, + 207, + 371, + 388, + 82, + 311, + 184, + 147, + 11, + 86, + 293, + 279, + 58, + 258, + 400, + 321, + 330, + 100, + 182, + 28, + 50, + 31, + 166, + 163, + 94, + 172, + 206, + 47, + 191, + 242, + 112, + 313, + 75, + 362, + 187, + 116, + 295, + 332, + 387, + 23, + 183, + 296, + 65, + 228, + 251, + 289, + 161, + 340, + 274, + 214, + 56, + 75, + 36, + 379, + 23, + 211, + 329, + 71, + 80, + 350, + 86, + 107, + 174, + 104, + 367, + 80, + 269, + 273, + 273, + 46, + 331, + 374, + 154, + 135, + 330, + 41, + 82, + 206, + 348, + 118, + 61, + 36, + 315, + 189, + 371, + 218, + 223, + 130, + 1, + 18, + 113, + 73, + 134, + 118, + 17, + 33, + 15, + 266, + 379, + 145, + 185, + 379, + 180, + 75, + 208, + 21, + 327, + 163, + 359, + 193, + 286, + 354, + 205, + 102, + 336, + 394, + 133, + 89, + 178, + 84, + 9, + 151, + 71, + 261, + 283, + 207, + 379, + 99, + 155, + 108, + 374, + 96, + 331, + 363, + 146, + 115, + 246, + 342, + 327, + 176, + 358, + 234, + 104, + 158, + 351, + 350, + 339, + 114, + 88, + 202, + 349, + 217, + 277, + 196, + 16, + 268, + 168, + 202, + 129, + 175, + 22, + 323, + 105, + 143, + 241, + 30, + 215, + 172, + 45, + 22, + 284, + 86, + 20, + 374, + 160, + 244, + 392, + 265, + 319, + 86, + 347, + 188, + 130, + 179, + 136, + 27, + 189, + 288, + 234, + 253, + 19, + 217, + 265, + 127, + 316, + 161, + 37, + 84, + 376, + 382, + 181, + 195, + 85, + 13, + 283, + 111, + 238, + 385, + 291, + 394, + 154, + 80, + 140, + 292, + 132, + 56, + 170, + 209, + 327, + 159, + 216, + 87, + 63, + 123, + 239, + 27, + 184, + 340, + 164, + 177, + 296, + 332, + 340, + 164, + 21, + 87, + 256, + 398, + 143, + 236, + 85, + 359, + 114, + 144, + 356, + 295, + 148, + 43, + 204, + 212, + 48, + 156, + 260, + 287, + 173, + 126, + 147, + 354, + 142, + 274, + 66, + 398, + 150, + 274, + 30, + 342, + 28, + 65, + 177, + 363, + 283, + 268, + 199, + 372, + 272, + 176, + 250, + 46, + 344, + 224, + 292, + 346, + 112, + 73, + 341, + 390, + 344, + 43, + 276, + 17, + 327, + 89, + 39, + 42, + 299, + 202, + 289, + 357, + 288, + 122, + 64, + 6, + 54, + 154, + 235, + 336, + 19, + 311, + 41, + 192, + 303, + 347, + 387, + 201, + 132, + 325, + 273, + 202, + 162, + 214, + 90, + 78, + 118, + 273, + 121, + 225, + 36, + 126, + 370, + 258, + 315, + 288, + 323, + 229, + 52, + 351, + 379, + 128, + 391, + 339, + 138, + 73, + 266, + 393, + 99, + 74, + 378, + 109, + 229, + 293, + 366, + 355, + 219, + 377, + 219, + 246, + 353, + 226, + 241, + 375, + 39, + 229, + 188, + 275, + 240, + 115, + 234, + 352, + 22, + 306, + 302, + 317, + 221, + 224, + 140, + 219, + 155, + 166, + 343, + 313, + 326, + 99, + 168, + 79, + 149, + 57, + 144, + 228, + 28, + 38, + 352, + 112, + 16, + 350, + 66, + 158, + 25, + 292, + 376, + 285, + 163, + 43, + 214, + 395, + 15, + 122, + 365, + 4, + 308, + 16, + 13, + 205, + 256, + 335, + 252, + 301, + 149, + 170, + 206, + 121, + 397, + 387, + 174, + 348, + 72, + 233, + 218, + 254, + 139, + 271, + 101, + 321, + 188, + 366, + 86, + 265, + 182, + 350, + 202, + 393, + 160, + 134, + 312, + 206, + 112, + 28, + 301, + 374, + 312, + 104, + 262, + 100, + 104, + 276, + 199, + 90, + 232, + 124, + 363, + 26, + 269, + 188, + 227, + 344, + 380, + 35, + 67, + 161, + 125, + 386, + 358, + 289, + 276, + 25, + 398, + 105, + 334, + 360, + 273, + 293, + 50, + 350, + 94, + 326, + 23, + 380, + 349, + 123, + 132, + 283, + 121, + 211, + 327, + 186, + 146, + 362, + 307, + 31, + 74, + 338, + 177, + 173, + 132, + 336, + 35, + 273, + 46, + 265, + 110, + 262, + 229, + 197, + 166, + 122, + 13, + 289, + 312, + 229, + 58, + 347, + 2, + 49, + 303, + 195, + 69, + 312, + 223, + 319, + 278, + 151, + 97, + 216, + 197, + 295, + 84, + 204, + 179, + 157, + 380, + 224, + 93, + 58, + 287, + 378, + 56, + 37, + 168, + 370, + 33, + 4, + 362, + 347, + 132, + 351, + 163, + 207, + 109, + 214, + 170, + 327, + 383, + 218, + 64, + 105, + 345, + 212, + 318, + 395, + 384, + 237, + 387, + 83, + 203, + 55, + 163, + 226, + 131, + 203, + 260, + 132, + 214, + 16, + 210, + 239, + 25, + 280, + 295, + 363, + 315, + 326, + 274, + 211, + 272, + 202, + 239, + 63, + 357, + 366, + 181, + 267, + 170, + 378, + 318, + 195, + 178, + 97, + 56, + 354, + 96, + 212, + 376, + 138, + 229, + 261, + 32, + 49, + 256, + 52, + 190, + 227, + 164, + 342, + 228, + 393, + 290, + 24, + 95, + 385, + 281, + 304, + 130, + 235, + 150, + 10, + 297, + 396, + 61, + 235, + 87, + 116, + 189, + 5, + 231, + 45, + 303, + 297, + 347, + 271, + 37, + 195, + 223, + 270, + 309, + 247, + 247, + 203, + 294, + 307, + 238, + 313, + 41, + 323, + 290, + 84, + 391, + 368, + 160, + 236, + 337, + 61, + 85, + 141, + 54, + 48, + 62, + 168, + 245, + 163, + 66, + 323, + 173, + 145, + 184, + 198, + 154, + 347, + 366, + 284, + 257, + 32, + 281, + 344, + 387, + 18, + 196, + 65, + 52, + 233, + 388, + 35, + 68, + 362, + 78, + 275, + 84, + 59, + 172, + 13, + 283, + 218, + 14, + 206, + 203, + 100, + 234, + 376, + 364, + 240, + 82, + 101, + 336, + 1, + 182, + 354, + 385, + 365, + 154, + 390, + 302, + 239, + 46, + 345, + 353, + 107, + 329, + 292, + 145, + 300, + 135, + 320, + 342, + 107, + 349, + 120, + 233, + 55, + 189, + 390, + 201, + 315, + 289, + 310, + 291, + 315, + 196, + 15, + 92, + 326, + 89, + 196, + 286, + 19, + 265, + 370, + 394, + 67, + 138, + 281, + 98, + 201, + 309, + 154, + 37, + 266, + 32, + 345, + 130, + 98, + 250, + 263, + 24, + 315, + 326, + 375, + 362, + 347, + 85, + 50, + 241, + 344, + 67, + 241, + 302, + 162, + 377, + 179, + 80, + 73, + 155, + 75, + 55, + 35, + 273, + 175, + 370, + 234, + 273, + 57, + 91, + 74, + 8, + 44, + 28, + 118, + 356, + 190, + 359, + 243, + 388, + 273, + 381, + 332, + 12, + 106, + 250, + 155, + 70, + 361, + 15, + 124, + 321, + 337, + 44, + 353, + 35, + 247, + 22, + 84, + 301, + 297, + 132, + 225, + 66, + 105, + 348, + 133, + 212, + 152, + 328, + 79, + 49, + 223, + 121, + 74, + 126, + 320, + 67, + 374, + 228, + 173, + 17, + 236, + 12, + 117, + 218, + 192, + 346, + 370, + 138, + 266, + 270, + 391, + 167, + 132, + 233, + 207, + 162, + 65, + 251, + 14, + 173, + 72, + 191, + 165, + 38, + 8, + 204, + 204, + 376, + 203, + 105, + 182, + 336, + 121, + 20, + 69, + 275, + 254, + 40, + 149, + 343, + 197, + 262, + 21, + 259, + 330, + 246, + 383, + 43, + 325, + 46, + 40, + 338, + 262, + 116, + 75, + 266, + 2, + 389, + 90, + 29, + 101, + 244, + 363, + 58, + 3, + 68, + 137, + 195, + 344, + 105, + 113, + 378, + 19, + 107, + 208, + 83, + 250, + 201, + 238, + 283, + 135, + 372, + 74, + 200, + 159, + 216, + 334, + 29, + 108, + 156, + 303, + 300, + 55, + 37, + 366, + 225, + 323, + 181, + 217, + 388, + 143, + 313, + 369, + 81, + 389, + 128, + 139, + 179, + 222, + 110, + 154, + 166, + 5, + 95, + 294, + 339, + 277, + 171, + 320, + 105, + 216, + 374, + 266, + 8, + 78, + 296, + 119, + 367, + 95, + 357, + 180, + 175, + 43, + 7, + 15, + 348, + 26, + 116, + 327, + 321, + 19, + 297, + 62, + 377, + 112, + 175, + 240, + 1, + 178, + 3, + 90, + 149, + 377, + 103, + 296, + 40, + 22, + 43, + 232, + 212, + 343, + 228, + 276, + 68, + 140, + 112, + 314, + 72, + 7, + 274, + 163, + 252, + 153, + 388, + 304, + 218, + 73, + 107, + 246, + 145, + 200, + 211, + 22, + 85, + 197, + 326, + 200, + 373, + 310, + 263, + 86, + 13, + 388, + 309, + 246, + 248, + 305, + 388, + 304, + 165, + 221, + 303, + 397, + 56, + 245, + 246, + 48, + 87, + 266, + 108, + 56, + 144, + 140, + 93, + 245, + 256, + 97, + 226, + 273, + 347, + 165, + 212, + 228, + 207, + 169, + 305, + 371, + 186, + 334, + 396, + 244, + 100, + 352, + 358, + 326, + 339, + 270, + 396, + 301, + 284, + 11, + 177, + 191, + 126, + 68, + 227, + 33, + 366, + 298, + 359, + 193, + 122, + 393, + 122, + 203, + 30, + 303, + 194, + 392, + 151, + 366, + 31, + 293, + 174, + 53, + 26, + 218, + 85, + 136, + 306, + 113, + 10, + 61, + 173, + 48, + 56, + 97, + 70, + 146, + 399, + 283, + 50, + 278, + 366, + 185, + 35, + 323, + 13, + 344, + 144, + 141, + 33, + 279, + 89, + 383, + 267, + 101, + 396, + 337, + 247, + 341, + 224, + 376, + 360, + 9, + 196, + 136, + 104, + 376, + 263, + 383, + 3, + 124, + 314, + 136, + 23, + 46, + 346, + 318, + 338, + 249, + 270, + 205, + 145, + 179, + 232, + 245, + 228, + 230, + 50, + 263, + 119, + 7, + 240, + 2, + 149, + 158, + 120, + 175, + 163, + 63, + 25, + 16, + 263, + 219, + 340, + 339, + 186, + 128, + 29, + 354, + 195, + 387, + 145, + 121, + 184, + 268, + 344, + 9, + 87, + 242, + 355, + 309, + 99, + 220, + 131, + 247, + 82, + 101, + 373, + 220, + 119, + 373, + 332, + 125, + 264, + 247, + 118, + 307, + 305, + 303, + 348, + 275, + 60, + 325, + 154, + 189, + 374, + 374, + 58, + 365, + 353, + 257, + 372, + 315, + 352, + 259, + 312, + 395, + 320, + 181, + 125, + 206, + 195, + 161, + 322, + 389, + 398, + 113, + 77, + 376, + 162, + 8, + 350, + 14, + 298, + 48, + 217, + 217, + 33, + 86, + 224, + 239, + 206, + 35, + 321, + 330, + 287, + 89, + 7, + 134, + 191, + 149, + 274, + 228, + 229, + 108, + 372, + 313, + 237, + 211, + 178, + 101, + 396, + 55, + 86, + 137, + 61, + 118, + 67, + 336, + 327, + 88, + 317, + 32, + 385, + 275, + 164, + 331, + 286, + 49, + 66, + 242, + 20, + 141, + 11, + 313, + 313, + 2, + 324, + 128, + 172, + 282, + 199, + 384, + 313, + 148, + 73, + 200, + 366, + 75, + 260, + 133, + 299, + 269, + 29, + 399, + 355, + 358, + 174, + 102, + 169, + 194, + 343, + 174, + 170, + 171, + 80, + 395, + 329, + 147, + 64, + 328, + 372, + 364, + 228, + 357, + 151, + 85, + 95, + 185, + 345, + 307, + 300, + 312, + 237, + 125, + 132, + 164, + 392, + 70, + 400, + 67, + 126, + 155, + 317, + 57, + 54, + 276, + 146, + 184, + 137, + 107, + 376, + 362, + 6, + 95, + 273, + 327, + 100, + 110, + 352, + 90, + 144, + 288, + 323, + 126, + 200, + 400, + 220, + 59, + 34, + 289, + 354, + 118, + 241, + 148, + 199, + 322, + 40, + 312, + 140, + 77, + 112, + 223, + 140, + 13, + 1, + 185, + 388, + 24, + 131, + 398, + 318, + 280, + 63, + 175, + 47, + 134, + 327, + 206, + 52, + 48, + 64, + 194, + 178, + 377, + 55, + 55, + 107, + 265, + 338, + 263, + 27, + 92, + 373, + 357, + 295, + 207, + 324, + 133, + 119, + 151, + 175, + 2, + 77, + 288, + 151, + 116, + 168, + 371, + 245, + 20, + 142, + 174, + 112, + 203, + 98, + 209, + 73, + 328, + 15, + 33, + 40, + 377, + 124, + 370, + 396, + 25, + 215, + 368, + 135, + 133, + 151, + 282, + 80, + 304, + 280, + 67, + 327, + 177, + 333, + 178, + 151, + 146, + 56, + 76, + 312, + 186, + 212, + 132, + 31, + 296, + 141, + 60, + 75, + 209, + 382, + 49, + 179, + 389, + 106, + 146, + 103, + 158, + 300, + 91, + 239, + 221, + 305, + 164, + 148, + 351, + 270, + 121, + 129, + 383, + 296, + 375, + 49, + 259, + 231, + 272, + 275, + 352, + 222, + 339, + 299, + 54, + 20, + 348, + 80, + 332, + 342, + 227, + 27, + 286, + 243, + 162, + 147, + 164, + 1, + 259, + 222, + 398, + 371, + 322, + 178, + 327, + 33, + 319, + 175, + 272, + 351, + 245, + 247, + 55, + 154, + 325, + 300, + 344, + 8, + 207, + 79, + 138, + 76, + 159, + 115, + 3, + 166, + 336, + 235, + 300, + 344, + 89, + 276, + 110, + 117, + 37, + 52, + 370, + 20, + 345, + 290, + 198, + 158, + 127, + 226, + 355, + 239, + 381, + 158, + 51, + 62, + 152, + 355, + 148, + 97, + 108, + 238, + 107, + 127, + 103, + 332, + 77, + 238, + 258, + 211, + 86, + 374, + 172, + 60, + 339, + 309, + 220, + 63, + 387, + 132, + 222, + 369, + 243, + 388, + 64, + 375, + 264, + 212, + 33, + 121, + 187, + 326, + 35, + 154, + 292, + 303, + 337, + 25, + 18, + 307, + 136, + 197, + 241, + 150, + 181, + 335, + 306, + 208, + 388, + 379, + 75, + 133, + 295, + 343, + 86, + 255, + 193, + 126, + 128, + 200, + 307, + 76, + 79, + 145, + 213, + 249, + 24, + 240, + 384, + 245, + 333, + 72, + 145, + 21, + 306, + 86, + 173, + 172, + 211, + 258, + 226, + 235, + 109, + 286, + 169, + 25, + 331, + 125, + 369, + 176, + 370, + 310, + 235, + 390, + 179, + 136, + 223, + 129, + 155, + 337, + 82, + 292, + 111, + 332, + 252, + 3, + 178, + 201, + 31, + 143, + 154, + 3, + 92, + 263, + 171, + 6, + 151, + 251, + 267, + 29, + 157, + 153, + 29, + 155, + 360, + 338, + 81, + 96, + 166, + 93, + 382, + 7, + 176, + 53, + 43, + 393, + 210, + 87, + 3, + 92, + 384, + 148, + 152, + 181, + 378, + 353, + 202, + 196, + 212, + 235, + 246, + 227, + 236, + 304, + 180, + 201, + 336, + 19, + 17, + 185, + 255, + 99, + 133, + 98, + 227, + 72, + 260, + 260, + 1, + 331, + 219, + 41, + 32, + 344, + 335, + 326, + 98, + 42, + 86, + 90, + 282, + 381, + 88, + 34, + 191, + 96, + 147, + 378, + 354, + 218, + 251, + 384, + 240, + 337, + 120, + 364, + 51, + 95, + 159, + 230, + 373, + 52, + 81, + 249, + 194, + 368, + 374, + 108, + 380, + 57, + 66, + 393, + 222, + 300, + 147, + 158, + 391, + 226, + 64, + 347, + 241, + 134, + 274, + 162, + 293, + 167, + 372, + 176, + 390, + 232, + 354, + 250, + 311, + 191, + 329, + 177, + 208, + 88, + 204, + 342, + 364, + 296, + 222, + 339, + 247, + 144, + 372, + 342, + 233, + 83, + 223, + 210, + 330, + 68, + 282, + 171, + 177, + 203, + 264, + 383, + 308, + 341, + 246, + 352, + 55, + 143, + 193, + 319, + 54, + 311, + 237, + 52, + 9, + 391, + 294, + 96, + 47, + 46, + 132, + 312, + 120, + 231, + 68, + 134, + 61, + 326, + 323, + 314, + 393, + 288, + 322, + 177, + 326, + 322, + 244, + 117, + 322, + 253, + 385, + 258, + 296, + 48, + 189, + 2, + 329, + 351, + 237, + 92, + 69, + 105, + 388, + 37, + 399, + 165, + 300, + 268, + 143, + 322, + 299, + 376, + 221, + 363, + 158, + 156, + 224, + 336, + 126, + 51, + 205, + 107, + 56, + 289, + 395, + 312, + 48, + 310, + 384, + 190, + 173, + 332, + 346, + 227, + 362, + 48, + 270, + 387, + 232, + 303, + 113, + 368, + 295, + 278, + 200, + 20, + 181, + 111, + 16, + 185, + 225, + 282, + 350, + 380, + 156, + 20, + 135, + 302, + 199, + 180, + 194, + 15, + 4, + 341, + 106, + 353, + 294, + 300, + 208, + 161, + 332, + 224, + 387, + 285, + 236, + 262, + 294, + 90, + 50, + 65, + 215, + 111, + 5, + 191, + 138, + 168, + 139, + 369, + 325, + 137, + 273, + 399, + 54, + 314, + 75, + 286, + 349, + 36, + 276, + 306, + 129, + 7, + 165, + 103, + 373, + 227, + 376, + 173, + 326, + 378, + 347, + 63, + 280, + 319, + 46, + 325, + 232, + 170, + 322, + 288, + 364, + 218, + 260, + 86, + 95, + 393, + 190, + 76, + 48, + 378, + 136, + 316, + 223, + 83, + 314, + 42, + 398, + 252, + 384, + 90, + 76, + 310, + 100, + 209, + 301, + 317, + 120, + 324, + 137, + 324, + 35, + 167, + 215, + 235, + 331, + 316, + 310, + 192, + 395, + 180, + 375, + 142, + 105, + 213, + 183, + 82, + 330, + 336, + 130, + 162, + 166, + 124, + 28, + 222, + 332, + 322, + 246, + 31, + 184, + 85, + 111, + 126, + 373, + 393, + 343, + 80, + 50, + 140, + 394, + 9, + 14, + 345, + 10, + 180, + 375, + 313, + 266, + 95, + 287, + 52, + 93, + 239, + 57, + 397, + 175, + 250, + 52, + 64, + 317, + 112, + 330, + 370, + 150, + 224, + 248, + 134, + 143, + 11, + 221, + 203, + 266, + 46, + 297, + 105, + 276, + 255, + 39, + 112, + 9, + 344, + 94, + 61, + 299, + 16, + 190, + 112, + 83, + 208, + 173, + 19, + 258, + 392, + 106, + 208, + 103, + 280, + 137, + 127, + 193, + 335, + 287, + 314, + 390, + 69, + 121, + 162, + 285, + 55, + 364, + 96, + 376, + 314, + 90, + 43, + 214, + 208, + 190, + 125, + 188, + 233, + 297, + 320, + 210, + 217, + 8, + 149, + 70, + 183, + 365, + 90, + 147, + 244, + 5, + 168, + 235, + 60, + 153, + 128, + 214, + 94, + 227, + 159, + 218, + 277, + 134, + 119, + 383, + 113, + 190, + 144, + 77, + 75, + 224, + 272, + 84, + 240, + 98, + 394, + 394, + 40, + 69, + 24, + 27, + 266, + 26, + 22, + 33, + 196, + 210, + 63, + 226, + 31, + 132, + 199, + 28, + 35, + 22, + 79, + 80, + 59, + 365, + 309, + 112, + 133, + 38, + 396, + 159, + 385, + 375, + 8, + 393, + 144, + 55, + 254, + 246, + 359, + 316, + 126, + 362, + 213, + 81, + 357, + 385, + 104, + 97, + 168, + 273, + 234, + 42, + 223, + 18, + 387, + 139, + 50, + 399, + 387, + 227, + 134, + 199, + 204, + 151, + 318, + 217, + 2, + 141, + 167, + 110, + 247, + 380, + 257, + 205, + 119, + 5, + 186, + 236, + 249, + 358, + 65, + 203, + 379, + 372, + 288, + 359, + 342, + 50, + 350, + 244, + 248, + 348, + 294, + 189, + 369, + 188, + 64, + 65, + 24, + 43, + 45, + 215, + 386, + 108, + 1, + 222, + 137, + 239, + 295, + 74, + 183, + 134, + 252, + 376, + 379, + 361, + 394, + 165, + 234, + 285, + 158, + 181, + 201, + 282, + 116, + 260, + 246, + 317, + 27, + 15, + 144, + 119, + 246, + 94, + 272, + 35, + 250, + 291, + 97, + 350, + 37, + 308, + 267, + 166, + 248, + 36, + 242, + 91, + 177, + 111, + 278, + 15, + 353, + 268, + 45, + 189, + 151, + 23, + 322, + 235, + 328, + 240, + 156, + 176, + 57, + 247, + 8, + 81, + 186, + 15, + 254, + 97, + 66, + 253, + 143, + 18, + 345, + 37, + 86, + 255, + 3, + 45, + 373, + 306, + 102, + 379, + 44, + 398, + 365, + 224, + 312, + 14, + 1, + 313, + 268, + 35, + 227, + 47, + 291, + 154, + 208, + 230, + 348, + 394, + 5, + 338, + 318, + 355, + 87, + 181, + 248, + 97, + 321, + 290, + 135, + 352, + 113, + 119, + 390, + 136, + 51, + 119, + 43, + 141, + 38, + 75, + 137, + 14, + 356, + 70, + 100, + 73, + 168, + 44, + 290, + 342, + 113, + 82, + 333, + 187, + 70, + 46, + 125, + 320, + 96, + 228, + 252, + 151, + 343, + 21, + 22, + 196, + 28, + 354, + 331, + 257, + 305, + 289, + 30, + 237, + 156, + 250, + 88, + 184, + 32, + 272, + 171, + 27, + 97, + 265, + 337, + 197, + 67, + 339, + 133, + 16, + 216, + 324, + 388, + 248, + 131, + 357, + 135, + 371, + 392, + 290, + 230, + 90, + 254, + 40, + 359, + 309, + 357, + 336, + 334, + 173, + 155, + 282, + 1, + 263, + 155, + 369, + 332, + 100, + 147, + 383, + 65, + 351, + 209, + 105, + 331, + 100, + 270, + 114, + 108, + 128, + 220, + 375, + 141, + 69, + 19, + 278, + 352, + 365, + 250, + 278, + 234, + 141, + 380, + 43, + 169, + 2, + 256, + 329, + 97, + 368, + 32, + 240, + 374, + 373, + 48, + 268, + 386, + 149, + 7, + 46, + 277, + 127, + 243, + 102, + 294, + 80, + 28, + 71, + 328, + 193, + 87, + 346, + 122, + 276, + 392, + 175, + 227, + 163, + 29, + 91, + 157, + 379, + 114, + 220, + 141, + 29, + 207, + 248, + 130, + 22, + 51, + 383, + 172, + 61, + 25, + 28, + 102, + 103, + 134, + 364, + 74, + 126, + 261, + 288, + 87, + 311, + 274, + 388, + 58, + 400, + 184, + 53, + 123, + 170, + 366, + 175, + 277, + 348, + 243, + 322, + 315, + 35, + 50, + 20, + 388, + 213, + 82, + 34, + 53, + 297, + 369, + 3, + 68, + 152, + 119, + 393, + 57, + 220, + 129, + 97, + 171, + 338, + 282, + 195, + 176, + 257, + 277, + 47, + 237, + 332, + 151, + 383, + 185, + 185, + 106, + 161, + 327, + 45, + 265, + 236, + 170, + 252, + 172, + 64, + 298, + 144, + 262, + 389, + 179, + 308, + 126, + 189, + 128, + 20, + 272, + 129, + 60, + 166, + 217, + 147, + 250, + 248, + 325, + 177, + 84, + 347, + 305, + 363, + 177, + 93, + 29, + 377, + 350, + 284, + 109, + 363, + 178, + 237, + 145, + 115, + 59, + 166, + 168, + 76, + 35, + 25, + 357, + 56, + 157, + 157, + 302, + 222, + 80, + 265, + 392, + 110, + 163, + 300, + 33, + 57, + 88, + 29, + 66, + 106, + 75, + 210, + 331, + 23, + 291, + 377, + 385, + 369, + 327, + 106, + 193, + 36, + 213, + 231, + 195, + 22, + 123, + 308, + 50, + 256, + 372, + 388, + 240, + 399, + 251, + 360, + 41, + 21, + 304, + 298, + 390, + 196, + 105, + 56, + 396, + 102, + 327, + 39, + 91, + 269, + 317, + 127, + 358, + 322, + 301, + 319, + 94, + 268, + 61, + 301, + 259, + 293, + 234, + 311, + 135, + 233, + 143, + 3, + 380, + 179, + 81, + 102, + 314, + 3, + 43, + 62, + 160, + 86, + 39, + 15, + 333, + 288, + 377, + 10, + 253, + 163, + 5, + 273, + 285, + 183, + 116, + 6, + 259, + 374, + 38, + 365, + 345, + 336, + 103, + 51, + 48, + 92, + 146, + 80, + 205, + 185, + 362, + 228, + 257, + 225, + 176, + 49, + 366, + 371, + 308, + 343, + 386, + 9, + 343, + 265, + 284, + 137, + 373, + 372, + 255, + 233, + 154, + 64, + 136, + 48, + 377, + 179, + 153, + 327, + 385, + 349, + 273, + 130, + 261, + 207, + 215, + 311, + 49, + 117, + 78, + 292, + 315, + 70, + 383, + 160, + 21, + 56, + 201, + 328, + 99, + 181, + 68, + 203, + 114, + 180, + 262, + 378, + 397, + 230, + 165, + 355, + 10, + 296, + 109, + 264, + 80, + 202, + 255, + 381, + 55, + 193, + 334, + 397, + 386, + 216, + 356, + 356, + 45, + 9, + 304, + 186, + 334, + 60, + 128, + 317, + 163, + 151, + 234, + 115, + 386, + 77, + 345, + 149, + 240, + 221, + 84, + 143, + 332, + 344, + 204, + 83, + 22, + 304, + 183, + 337, + 311, + 274, + 93, + 276, + 341, + 94, + 174, + 346, + 74, + 90, + 348, + 120, + 291, + 202, + 220, + 3, + 316, + 19, + 212, + 276, + 388, + 228, + 302, + 120, + 150, + 206, + 30, + 130, + 270, + 263, + 358, + 374, + 84, + 208, + 306, + 187, + 258, + 90, + 6, + 355, + 101, + 239, + 80, + 241, + 285, + 368, + 94, + 118, + 380, + 152, + 164, + 400, + 185, + 115, + 270, + 19, + 271, + 298, + 56, + 118, + 253, + 270, + 184, + 372, + 169, + 382, + 327, + 349, + 352, + 177, + 202, + 24, + 129, + 129, + 93, + 42, + 377, + 2, + 249, + 249, + 188, + 82, + 318, + 72, + 349, + 180, + 103, + 308, + 385, + 189, + 370, + 334, + 348, + 161, + 284, + 17, + 166, + 198, + 307, + 323, + 225, + 170, + 219, + 369, + 81, + 247, + 232, + 138, + 57, + 11, + 142, + 236, + 151, + 308, + 14, + 329, + 184, + 170, + 28, + 13, + 49, + 11, + 163, + 10, + 51, + 140, + 96, + 318, + 258, + 149, + 362, + 133, + 39, + 113, + 47, + 100, + 52, + 364, + 34, + 14, + 181, + 354, + 13, + 226, + 258, + 178, + 371, + 321, + 303, + 310, + 131, + 317, + 199, + 52, + 178, + 204, + 8, + 326, + 63, + 53, + 399, + 64, + 5, + 106, + 177, + 258, + 133, + 283, + 346, + 114, + 185, + 313, + 126, + 101, + 342, + 17, + 99, + 321, + 35, + 102, + 395, + 212, + 129, + 147, + 381, + 301, + 206, + 34, + 380, + 127, + 260, + 136, + 258, + 97, + 387, + 150, + 103, + 281, + 302, + 208, + 18, + 198, + 304, + 337, + 311, + 83, + 393, + 112, + 231, + 378, + 392, + 212, + 267, + 32, + 144, + 78, + 193, + 355, + 263, + 84, + 195, + 116, + 143, + 5, + 109, + 199, + 208, + 381, + 53, + 241, + 353, + 90, + 325, + 51, + 186, + 323, + 273, + 208, + 14, + 69, + 88, + 396, + 380, + 353, + 15, + 170, + 333, + 116, + 373, + 262, + 149, + 222, + 312, + 56, + 190, + 247, + 292, + 10, + 53, + 342, + 87, + 65, + 1, + 394, + 43, + 253, + 107, + 112, + 172, + 108, + 164, + 286, + 358, + 259, + 269, + 362, + 217, + 283, + 284, + 200, + 118, + 55, + 201, + 194, + 324, + 374, + 126, + 329, + 177, + 20, + 187, + 53, + 349, + 115, + 189, + 394, + 183, + 55, + 346, + 175, + 1, + 285, + 351, + 309, + 171, + 17, + 268, + 312, + 50, + 45, + 35, + 43, + 70, + 328, + 55, + 200, + 99, + 306, + 147, + 81, + 74, + 247, + 196, + 307, + 91, + 85, + 186, + 398, + 242, + 118, + 244, + 142, + 309, + 32, + 351, + 221, + 176, + 12, + 83, + 102, + 188, + 353, + 127, + 345, + 164, + 169, + 310, + 93, + 240, + 282, + 80, + 204, + 345, + 127, + 59, + 19, + 31, + 225, + 229, + 209, + 154, + 332, + 243, + 186, + 77, + 7, + 207, + 328, + 363, + 81, + 108, + 194, + 388, + 165, + 300, + 184, + 43, + 102, + 392, + 393, + 377, + 267, + 303, + 249, + 178, + 286, + 351, + 297, + 263, + 153, + 347, + 91, + 18, + 341, + 283, + 129, + 124, + 8, + 263, + 204, + 4, + 156, + 177, + 148, + 228, + 207, + 334, + 338, + 382, + 343, + 137, + 116, + 160, + 270, + 223, + 91, + 53, + 349, + 386, + 346, + 126, + 47, + 233, + 320, + 315, + 309, + 363, + 169, + 75, + 368, + 153, + 118, + 101, + 309, + 186, + 89, + 127, + 293, + 31, + 122, + 340, + 125, + 157, + 142, + 88, + 241, + 180, + 225, + 225, + 132, + 236, + 114, + 223, + 129, + 65, + 40, + 397, + 111, + 261, + 314, + 160, + 203, + 346, + 263, + 142, + 398, + 215, + 1, + 120, + 274, + 285, + 341, + 151, + 38, + 119, + 257, + 314, + 332, + 378, + 64, + 206, + 151, + 311, + 283, + 338, + 362, + 19, + 90, + 293, + 21, + 267, + 102, + 181, + 253, + 80, + 251, + 134, + 254, + 276, + 70, + 308, + 228, + 241, + 235, + 68, + 312, + 394, + 276, + 221, + 372, + 31, + 167, + 262, + 358, + 21, + 159, + 70, + 371, + 149, + 132, + 136, + 66, + 171, + 308, + 148, + 301, + 22, + 368, + 50, + 236, + 219, + 159, + 317, + 387, + 357, + 94, + 199, + 263, + 383, + 330, + 112, + 162, + 323, + 263, + 20, + 70, + 96, + 292, + 17, + 309, + 45, + 297, + 355, + 75, + 260, + 232, + 147, + 277, + 368, + 264, + 101, + 23, + 156, + 24, + 318, + 322, + 153, + 256, + 6, + 188, + 176, + 158, + 160, + 200, + 112, + 384, + 52, + 241, + 128, + 56, + 135, + 306, + 239, + 228, + 263, + 152, + 14, + 274, + 273, + 307, + 374, + 76, + 355, + 91, + 326, + 335, + 314, + 400, + 280, + 267, + 44, + 230, + 61, + 385, + 109, + 31, + 6, + 291, + 298, + 65, + 229, + 30, + 188, + 241, + 151, + 59, + 168, + 105, + 308, + 174, + 340, + 393, + 250, + 180, + 327, + 389, + 395, + 314, + 17, + 310, + 197, + 341, + 90, + 128, + 379, + 175, + 7, + 398, + 150, + 261, + 283, + 196, + 168, + 278, + 277, + 120, + 268, + 138, + 340, + 359, + 333, + 100, + 284, + 50, + 11, + 243, + 6, + 149, + 55, + 11, + 104, + 217, + 88, + 254, + 44, + 306, + 48, + 227, + 30, + 205, + 71, + 175, + 241, + 300, + 203, + 73, + 343, + 269, + 20, + 175, + 122, + 70, + 104, + 105, + 66, + 28, + 22, + 196, + 192, + 150, + 328, + 394, + 400, + 9, + 88, + 75, + 361, + 9, + 199, + 228, + 275, + 45, + 399, + 390, + 59, + 144, + 341, + 179, + 11, + 323, + 400, + 392, + 223, + 396, + 304, + 131, + 295, + 136, + 391, + 298, + 390, + 228, + 343, + 390, + 183, + 137, + 129, + 8, + 315, + 27, + 9, + 330, + 9, + 342, + 14, + 86, + 243, + 303, + 133, + 229, + 46, + 144, + 317, + 243, + 219, + 196, + 203, + 244, + 92, + 364, + 85, + 180, + 172, + 346, + 127, + 133, + 224, + 151, + 199, + 243, + 53, + 138, + 165, + 314, + 248, + 248, + 12, + 173, + 273, + 345, + 168, + 70, + 346, + 94, + 364, + 206, + 170, + 244, + 230, + 300, + 387, + 195, + 206, + 185, + 165, + 100, + 133, + 400, + 259, + 373, + 46, + 104, + 352, + 335, + 208, + 297, + 93, + 361, + 119, + 99, + 54, + 63, + 222, + 106, + 91, + 391, + 171, + 268, + 36, + 304, + 284, + 288, + 249, + 233, + 235, + 371, + 226, + 235, + 112, + 42, + 274, + 108, + 101, + 123, + 123, + 167, + 259, + 149, + 133, + 98, + 223, + 78, + 106, + 39, + 220, + 254, + 186, + 12, + 270, + 291, + 273, + 369, + 336, + 44, + 184, + 281, + 30, + 15, + 64, + 231, + 280, + 57, + 110, + 182, + 250, + 326, + 75, + 140, + 110, + 21, + 130, + 278, + 127, + 389, + 60, + 61, + 114, + 259, + 125, + 98, + 327, + 128, + 144, + 317, + 213, + 53, + 231, + 299, + 170, + 312, + 170, + 348, + 72, + 128, + 60, + 173, + 163, + 235, + 149, + 25, + 62, + 385, + 328, + 79, + 155, + 218, + 45, + 171, + 92, + 254, + 42, + 152, + 263, + 22, + 129, + 257, + 253, + 365, + 296, + 388, + 1, + 385, + 366, + 58, + 228, + 172, + 73, + 349, + 207, + 292, + 1, + 208, + 392, + 315, + 18, + 73, + 119, + 326, + 344, + 194, + 90, + 73, + 88, + 26, + 230, + 288, + 342, + 123, + 97, + 286, + 302, + 114, + 88, + 197, + 209, + 360, + 219, + 37, + 143, + 99, + 14, + 27, + 57, + 272, + 26, + 169, + 316, + 209, + 165, + 243, + 377, + 245, + 339, + 100, + 238, + 330, + 110, + 350, + 67, + 213, + 122, + 355, + 55, + 137, + 350, + 172, + 300, + 142, + 214, + 288, + 296, + 154, + 107, + 47, + 226, + 262, + 79, + 305, + 355, + 155, + 137, + 211, + 169, + 91, + 278, + 69, + 314, + 336, + 373, + 383, + 373, + 68, + 166, + 362, + 346, + 6, + 65, + 395, + 94, + 337, + 318, + 87, + 274, + 73, + 389, + 137, + 71, + 369, + 197, + 36, + 19, + 286, + 336, + 98, + 74, + 95, + 205, + 53, + 255, + 256, + 158, + 201, + 54, + 343, + 344, + 30, + 380, + 124, + 344, + 74, + 269, + 346, + 225, + 49, + 172, + 371, + 355, + 103, + 275, + 118, + 365, + 196, + 186, + 180, + 159, + 2, + 110, + 189, + 183, + 362, + 314, + 196, + 304, + 171, + 380, + 63, + 196, + 364, + 118, + 371, + 220, + 163, + 128, + 177, + 326, + 77, + 77, + 296, + 330, + 380, + 304, + 36, + 340, + 314, + 309, + 258, + 238, + 138, + 26, + 15, + 351, + 88, + 84, + 101, + 98, + 224, + 376, + 376, + 243, + 249, + 399, + 221, + 224, + 18, + 177, + 163, + 150, + 378, + 353, + 285, + 45, + 243, + 24, + 344, + 202, + 335, + 248, + 241, + 122, + 371, + 209, + 178, + 232, + 218, + 183, + 72, + 400, + 212, + 379, + 180, + 178, + 284, + 107, + 393, + 151, + 277, + 262, + 162, + 293, + 135, + 357, + 97, + 343, + 9, + 181, + 95, + 347, + 120, + 363, + 88, + 311, + 320, + 64, + 21, + 43, + 354, + 184, + 343, + 387, + 195, + 381, + 262, + 320, + 377, + 188, + 284, + 225, + 316, + 327, + 321, + 368, + 276, + 232, + 119, + 124, + 59, + 284, + 84, + 201, + 289, + 253, + 301, + 233, + 5, + 316, + 300, + 242, + 343, + 30, + 50, + 101, + 51, + 294, + 387, + 292, + 245, + 27, + 210, + 226, + 273, + 232, + 24, + 275, + 122, + 154, + 138, + 221, + 386, + 355, + 44, + 95, + 32, + 136, + 12, + 277, + 260, + 301, + 292, + 172, + 112, + 96, + 217, + 72, + 304, + 89, + 29, + 33, + 35, + 8, + 378, + 94, + 327, + 35, + 279, + 396, + 368, + 251, + 85, + 138, + 357, + 60, + 1, + 209, + 171, + 363, + 324, + 203, + 355, + 98, + 120, + 392, + 285, + 297, + 105, + 134, + 123, + 167, + 134, + 304, + 61, + 257, + 166, + 40, + 214, + 328, + 179, + 330, + 261, + 325, + 78, + 67, + 167, + 395, + 306, + 89, + 305, + 386, + 115, + 4, + 121, + 69, + 41, + 83, + 3, + 10, + 56, + 94, + 338, + 233, + 179, + 378, + 8, + 101, + 216, + 59, + 49, + 95, + 366, + 117, + 355, + 356, + 15, + 287, + 266, + 268, + 189, + 289, + 392, + 204, + 69, + 310, + 264, + 240, + 171, + 277, + 397, + 173, + 397, + 218, + 81, + 124, + 354, + 240, + 166, + 100, + 73, + 274, + 302, + 110, + 268, + 17, + 74, + 62, + 41, + 86, + 106, + 363, + 200, + 67, + 94, + 56, + 161, + 12, + 127, + 184, + 355, + 259, + 95, + 299, + 316, + 247, + 84, + 35, + 33, + 235, + 280, + 376, + 295, + 394, + 179, + 299, + 174, + 325, + 131, + 54, + 295, + 13, + 327, + 231, + 367, + 67, + 353, + 104, + 66, + 381, + 87, + 63, + 45, + 89, + 21, + 263, + 357, + 331, + 183, + 264, + 367, + 250, + 44, + 149, + 94, + 147, + 131, + 327, + 189, + 212, + 172, + 360, + 244, + 206, + 177, + 115, + 79, + 38, + 349, + 152, + 104, + 261, + 265, + 299, + 328, + 242, + 1, + 305, + 216, + 182, + 127, + 332, + 192, + 162, + 225, + 35, + 11, + 390, + 66, + 41, + 266, + 175, + 397, + 156, + 365, + 57, + 363, + 50, + 56, + 301, + 233, + 22, + 136, + 381, + 300, + 4, + 7, + 18, + 359, + 341, + 229, + 29, + 1, + 399, + 146, + 242, + 289, + 230, + 352, + 92, + 105, + 382, + 334, + 233, + 229, + 326, + 50, + 335, + 276, + 196, + 354, + 6, + 104, + 156, + 75, + 301, + 265, + 179, + 383, + 34, + 112, + 29, + 294, + 69, + 249, + 246, + 143, + 191, + 301, + 163, + 309, + 244, + 321, + 78, + 13, + 179, + 236, + 275, + 240, + 283, + 186, + 317, + 105, + 84, + 160, + 308, + 138, + 87, + 37, + 211, + 7, + 85, + 333, + 195, + 265, + 246, + 56, + 16, + 226, + 102, + 171, + 310, + 328, + 63, + 300, + 160, + 136, + 114, + 386, + 247, + 43, + 95, + 217, + 223, + 186, + 130, + 354, + 398, + 132, + 341, + 34, + 249, + 218, + 51, + 197, + 97, + 80, + 25, + 61, + 119, + 28, + 137, + 160, + 222, + 119, + 132, + 44, + 273, + 61, + 110, + 217, + 12, + 32, + 15, + 47, + 260, + 149, + 132, + 92, + 238, + 330, + 116, + 203, + 317, + 306, + 227, + 79, + 193, + 245, + 309, + 54, + 282, + 199, + 108, + 185, + 48, + 73, + 18, + 154, + 379, + 186, + 244, + 209, + 191, + 69, + 187, + 13, + 192, + 45, + 170, + 300, + 23, + 274, + 143, + 128, + 341, + 91, + 65, + 186, + 48, + 154, + 291, + 350, + 301, + 179, + 245, + 33, + 395, + 333, + 155, + 364, + 83, + 79, + 268, + 306, + 252, + 335, + 398, + 90, + 128, + 267, + 146, + 185, + 127, + 300, + 2, + 376, + 345, + 368, + 95, + 287, + 143, + 159, + 216, + 150, + 95, + 272, + 393, + 376, + 355, + 244, + 191, + 270, + 20, + 366, + 235, + 121, + 75, + 40, + 398, + 67, + 354, + 267, + 87, + 336, + 231, + 24, + 111, + 247, + 306, + 400, + 225, + 50, + 329, + 330, + 101, + 97, + 331, + 244, + 323, + 146, + 214, + 63, + 253, + 44, + 6, + 21, + 334, + 60, + 286, + 130, + 11, + 316, + 346, + 232, + 301, + 63, + 24, + 272, + 289, + 60, + 232, + 292, + 333, + 256, + 302, + 305, + 80, + 330, + 13, + 310, + 222, + 358, + 103, + 148, + 277, + 292, + 109, + 90, + 191, + 76, + 277, + 52, + 200, + 184, + 163, + 359, + 323, + 326, + 219, + 295, + 173, + 57, + 351, + 236, + 346, + 254, + 221, + 304, + 91, + 327, + 310, + 345, + 355, + 18, + 19, + 206, + 267, + 356, + 108, + 113, + 173, + 8, + 180, + 374, + 30, + 270, + 249, + 335, + 375, + 350, + 326, + 169, + 343, + 383, + 340, + 54, + 104, + 160, + 6, + 37, + 46, + 36, + 215, + 146, + 324, + 354, + 130, + 156, + 331, + 204, + 235, + 310, + 85, + 102, + 6, + 63, + 98, + 323, + 241, + 191, + 400, + 32, + 399, + 290, + 93, + 70, + 215, + 113, + 349, + 321, + 71, + 60, + 137, + 209, + 135, + 234, + 11, + 94, + 108, + 139, + 66, + 43, + 73, + 280, + 336, + 58, + 329, + 143, + 269, + 39, + 141, + 23, + 133, + 225, + 43, + 323, + 19, + 317, + 342, + 23, + 63, + 177, + 85, + 180, + 153, + 252, + 3, + 186, + 202, + 303, + 338, + 317, + 9, + 50, + 299, + 239, + 263, + 351, + 368, + 256, + 299, + 272, + 326, + 163, + 145, + 346, + 307, + 75, + 390, + 132, + 249, + 139, + 275, + 378, + 226, + 290, + 306, + 141, + 61, + 372, + 205, + 152, + 372, + 225, + 127, + 63, + 307, + 98, + 142, + 131, + 260, + 199, + 97, + 152, + 268, + 21, + 340, + 326, + 238, + 235, + 198, + 45, + 147, + 294, + 2, + 378, + 323, + 337, + 200, + 134, + 391, + 167, + 59, + 129, + 194, + 359, + 276, + 65, + 195, + 245, + 376, + 385, + 277, + 170, + 330, + 12, + 372, + 259, + 374, + 13, + 169, + 27, + 206, + 186, + 85, + 77, + 134, + 343, + 325, + 134, + 385, + 334, + 234, + 329, + 381, + 178, + 211, + 218, + 261, + 245, + 195, + 244, + 389, + 281, + 298, + 132, + 180, + 391, + 237, + 138, + 352, + 99, + 17, + 261, + 368, + 81, + 172, + 143, + 238, + 138, + 88, + 200, + 275, + 168, + 313, + 352, + 26, + 2, + 73, + 348, + 173, + 275, + 327, + 289, + 34, + 90, + 38, + 299, + 212, + 69, + 95, + 186, + 288, + 345, + 138, + 387, + 168, + 32, + 53, + 257, + 181, + 153, + 288, + 24, + 307, + 339, + 165, + 104, + 305, + 279, + 84, + 341, + 259, + 342, + 227, + 359, + 109, + 117, + 28, + 128, + 172, + 228, + 321, + 178, + 161, + 284, + 227, + 241, + 355, + 225, + 154, + 328, + 167, + 184, + 345, + 238, + 156, + 342, + 372, + 378, + 20, + 134, + 192, + 378, + 176, + 277, + 81, + 26, + 120, + 70, + 80, + 192, + 354, + 225, + 8, + 378, + 45, + 342, + 92, + 162, + 113, + 239, + 164, + 125, + 113, + 386, + 69, + 69, + 297, + 170, + 317, + 42, + 162, + 309, + 134, + 301, + 82, + 44, + 153, + 183, + 29, + 350, + 73, + 90, + 53, + 351, + 261, + 69, + 144, + 291, + 199, + 96, + 60, + 230, + 176, + 157, + 180, + 148, + 54, + 131, + 123, + 388, + 64, + 326, + 13, + 263, + 60, + 300, + 68, + 287, + 160, + 41, + 292, + 176, + 291, + 11, + 143, + 334, + 353, + 377, + 283, + 243, + 1, + 247, + 136, + 103, + 124, + 216, + 65, + 349, + 369, + 395, + 310, + 184, + 399, + 85, + 341, + 47, + 361, + 7, + 115, + 88, + 5, + 226, + 102, + 219, + 348, + 259, + 245, + 2, + 351, + 281, + 116, + 380, + 153, + 31, + 187, + 39, + 266, + 107, + 317, + 351, + 27, + 289, + 158, + 275, + 191, + 197, + 326, + 214, + 305, + 275, + 41, + 187, + 266, + 17, + 377, + 338, + 267, + 395, + 2, + 55, + 249, + 374, + 265, + 163, + 339, + 42, + 384, + 185, + 365, + 99, + 156, + 176, + 149, + 291, + 87, + 177, + 40, + 86, + 317, + 24, + 221, + 74, + 25, + 305, + 383, + 285, + 224, + 289, + 72, + 341, + 334, + 36, + 39, + 253, + 20, + 390, + 304, + 194, + 150, + 309, + 29, + 252, + 21, + 101, + 194, + 101, + 358, + 68, + 356, + 1, + 195, + 220, + 63, + 293, + 127, + 205, + 131, + 206, + 69, + 13, + 201, + 373, + 43, + 235, + 387, + 384, + 49, + 356, + 312, + 242, + 68, + 9, + 316, + 85, + 363, + 272, + 216, + 338, + 229, + 283, + 49, + 18, + 69, + 224, + 47, + 127, + 54, + 379, + 15, + 263, + 5, + 75, + 123, + 258, + 218, + 205, + 5, + 202, + 112, + 102, + 268, + 202, + 364, + 104, + 101, + 346, + 357, + 332, + 161, + 354, + 275, + 34, + 237, + 361, + 72, + 137, + 121, + 85, + 74, + 78, + 113, + 397, + 208, + 84, + 10, + 158, + 254, + 172, + 189, + 7, + 69, + 23, + 388, + 283, + 239, + 113, + 185, + 4, + 149, + 313, + 78, + 331, + 193, + 76, + 342, + 326, + 324, + 249, + 249, + 12, + 13, + 192, + 63, + 296, + 230, + 71, + 74, + 391, + 389, + 92, + 247, + 53, + 267, + 311, + 383, + 112, + 33, + 352, + 194, + 379, + 150, + 55, + 344, + 219, + 391, + 232, + 346, + 395, + 322, + 300, + 282, + 317, + 300, + 121, + 370, + 325, + 43, + 22, + 374, + 24, + 121, + 16, + 34, + 234, + 127, + 237, + 369, + 157, + 167, + 277, + 295, + 247, + 382, + 217, + 319, + 227, + 349, + 296, + 369, + 325, + 80, + 72, + 340, + 355, + 88, + 111, + 131, + 128, + 11, + 383, + 167, + 126, + 286, + 303, + 89, + 308, + 83, + 333, + 113, + 312, + 193, + 114, + 15, + 374, + 386, + 269, + 391, + 113, + 43, + 177, + 70, + 142, + 13, + 84, + 204, + 305, + 141, + 167, + 27, + 349, + 333, + 250, + 92, + 193, + 332, + 224, + 328, + 87, + 29, + 73, + 331, + 80, + 194, + 75, + 49, + 312, + 283, + 233, + 152, + 215, + 361, + 170, + 45, + 70, + 92, + 185, + 381, + 120, + 76, + 19, + 79, + 170, + 14, + 48, + 358, + 153, + 354, + 200, + 173, + 250, + 180, + 72, + 202, + 330, + 312, + 37, + 235, + 48, + 17, + 337, + 144, + 301, + 376, + 197, + 179, + 380, + 30, + 61, + 150, + 146, + 170, + 393, + 109, + 374, + 141, + 15, + 77, + 332, + 153, + 400, + 334, + 195, + 87, + 108, + 360, + 321, + 11, + 144, + 17, + 146, + 342, + 301, + 247, + 69, + 239, + 263, + 327, + 1, + 109, + 62, + 82, + 315, + 9, + 192, + 57, + 91, + 98, + 197, + 237, + 398, + 217, + 324, + 76, + 366, + 215, + 111, + 161, + 213, + 228, + 332, + 182, + 278, + 289, + 279, + 138, + 351, + 255, + 356, + 301, + 180, + 378, + 67, + 245, + 204, + 337, + 337, + 397, + 39, + 212, + 387, + 378, + 38, + 213, + 76, + 81, + 33, + 202, + 149, + 68, + 398, + 243, + 375, + 303, + 163, + 150, + 366, + 20, + 156, + 108, + 150, + 41, + 119, + 22, + 67, + 394, + 120, + 90, + 195, + 321, + 361, + 74, + 310, + 372, + 282, + 34, + 394, + 316, + 131, + 143, + 119, + 278, + 86, + 306, + 365, + 238, + 196, + 222, + 330, + 393, + 190, + 35, + 318, + 83, + 67, + 67, + 3, + 43, + 219, + 197, + 264, + 250, + 319, + 131, + 47, + 220, + 255, + 334, + 372, + 358, + 2, + 392, + 32, + 217, + 207, + 271, + 204, + 39, + 338, + 348, + 109, + 246, + 16, + 367, + 198, + 93, + 141, + 248, + 197, + 163, + 264, + 66, + 54, + 293, + 253, + 377, + 233, + 290, + 53, + 351, + 240, + 399, + 74, + 249, + 185, + 137, + 53, + 247, + 334, + 18, + 112, + 162, + 387, + 227, + 7, + 326, + 132, + 22, + 26, + 314, + 359, + 72, + 194, + 148, + 393, + 160, + 49, + 275, + 120, + 346, + 164, + 97, + 317, + 267, + 212, + 297, + 201, + 350, + 332, + 350, + 329, + 223, + 385, + 24, + 167, + 279, + 374, + 128, + 392, + 117, + 41, + 143, + 38, + 312, + 226, + 313, + 78, + 209, + 351, + 320, + 194, + 192, + 333, + 242, + 254, + 340, + 290, + 72, + 359, + 370, + 220, + 241, + 48, + 197, + 31, + 297, + 282, + 375, + 181, + 97, + 70, + 87, + 363, + 63, + 286, + 166, + 114, + 344, + 332, + 31, + 167, + 278, + 75, + 340, + 138, + 83, + 189, + 263, + 221, + 243, + 366, + 190, + 336, + 79, + 235, + 338, + 290, + 128, + 100, + 80, + 347, + 341, + 351, + 160, + 328, + 183, + 351, + 361, + 157, + 91, + 95, + 217, + 365, + 124, + 325, + 293, + 212, + 170, + 376, + 296, + 178, + 140, + 127, + 86, + 200, + 216, + 23, + 239, + 385, + 134, + 316, + 187, + 391, + 71, + 19, + 9, + 286, + 46, + 42, + 172, + 292, + 58, + 67, + 84, + 4, + 159, + 110, + 66, + 213, + 3, + 320, + 40, + 23, + 97, + 86, + 102, + 83, + 119, + 237, + 242, + 171, + 320, + 268, + 377, + 53, + 65, + 133, + 144, + 389, + 275, + 215, + 100, + 134, + 185, + 94, + 213, + 307, + 297, + 250, + 321, + 252, + 106, + 400, + 265, + 266, + 176, + 141, + 14, + 201, + 250, + 295, + 202, + 287, + 301, + 179, + 133, + 68, + 347, + 113, + 181, + 148, + 346, + 356, + 258, + 69, + 130, + 84, + 244, + 85, + 109, + 139, + 268, + 83, + 367, + 129, + 52, + 287, + 217, + 164, + 123, + 202, + 122, + 163, + 79, + 321, + 202, + 302, + 93, + 256, + 29, + 16, + 209, + 348, + 315, + 282, + 391, + 51, + 247, + 184, + 351, + 40, + 96, + 60, + 39, + 278, + 108, + 81, + 389, + 344, + 149, + 176, + 64, + 344, + 165, + 262, + 40, + 75, + 263, + 46, + 392, + 266, + 47, + 8, + 278, + 262, + 192, + 260, + 329, + 332, + 25, + 314, + 15, + 22, + 146, + 101, + 343, + 245, + 238, + 354, + 222, + 69, + 259, + 139, + 352, + 73, + 46, + 223, + 294, + 122, + 292, + 312, + 382, + 338, + 260, + 334, + 165, + 341, + 62, + 108, + 227, + 232, + 208, + 40, + 342, + 281, + 120, + 62, + 185, + 165, + 348, + 114, + 26, + 65, + 146, + 33, + 34, + 340, + 156, + 275, + 68, + 187, + 396, + 205, + 366, + 26, + 298, + 64, + 220, + 73, + 192, + 303, + 57, + 382, + 273, + 313, + 385, + 134, + 261, + 327, + 307, + 325, + 108, + 386, + 251, + 305, + 114, + 392, + 114, + 147, + 72, + 312, + 108, + 264, + 378, + 316, + 398, + 169, + 217, + 39, + 58, + 46, + 12, + 265, + 7, + 187, + 105, + 53, + 133, + 44, + 244, + 115, + 129, + 282, + 22, + 340, + 200, + 121, + 90, + 209, + 97, + 388, + 133, + 345, + 113, + 289, + 298, + 312, + 284, + 72, + 98, + 259, + 201, + 111, + 357, + 337, + 369, + 286, + 346, + 206, + 159, + 20, + 266, + 177, + 386, + 114, + 16, + 334, + 132, + 277, + 214, + 375, + 229, + 29, + 124, + 19, + 95, + 169, + 65, + 318, + 120, + 245, + 31, + 301, + 306, + 197, + 261, + 102, + 290, + 156, + 69, + 330, + 346, + 139, + 159, + 287, + 284, + 126, + 301, + 57, + 274, + 386, + 106, + 147, + 19, + 344, + 11, + 276, + 31, + 252, + 87, + 133, + 73, + 259, + 20, + 85, + 334, + 311, + 352, + 197, + 282, + 348, + 359, + 120, + 18, + 250, + 389, + 233, + 6, + 75, + 395, + 191, + 51, + 156, + 387, + 377, + 155, + 355, + 343, + 49, + 270, + 308, + 95, + 41, + 66, + 380, + 335, + 224, + 162, + 198, + 366, + 44, + 259, + 232, + 170, + 177, + 251, + 256, + 10, + 337, + 175, + 82, + 230, + 54, + 275, + 34, + 113, + 228, + 288, + 151, + 199, + 361, + 244, + 221, + 336, + 336, + 30, + 105, + 228, + 317, + 356, + 227, + 251, + 58, + 6, + 165, + 150, + 400, + 271, + 48, + 343, + 383, + 48, + 144, + 289, + 270, + 147, + 18, + 131, + 302, + 191, + 249, + 143, + 32, + 279, + 245, + 350, + 176, + 154, + 103, + 355, + 359, + 167, + 239, + 121, + 361, + 10, + 217, + 78, + 207, + 391, + 309, + 16, + 65, + 309, + 185, + 299, + 299, + 372, + 86, + 146, + 316, + 207, + 96, + 196, + 97, + 28, + 28, + 128, + 234, + 123, + 108, + 88, + 359, + 124, + 27, + 76, + 377, + 318, + 155, + 251, + 231, + 148, + 352, + 378, + 3, + 93, + 400, + 34, + 235, + 299, + 360, + 118, + 211, + 22, + 282, + 57, + 270, + 295, + 150, + 283, + 204, + 12, + 357, + 231, + 119, + 20, + 173, + 55, + 129, + 61, + 286, + 382, + 303, + 135, + 89, + 249, + 384, + 77, + 379, + 142, + 333, + 178, + 295, + 198, + 293, + 338, + 150, + 10, + 17, + 354, + 177, + 157, + 76, + 38, + 293, + 236, + 205, + 98, + 169, + 265, + 109, + 91, + 172, + 218, + 125, + 298, + 50, + 339, + 115, + 168, + 165, + 26, + 53, + 84, + 236, + 13, + 97, + 400, + 387, + 37, + 243, + 172, + 180, + 285, + 94, + 209, + 125, + 353, + 67, + 257, + 34, + 168, + 360, + 78, + 251, + 320, + 278, + 376, + 317, + 148, + 263, + 32, + 356, + 160, + 208, + 289, + 235, + 249, + 357, + 318, + 55, + 155, + 283, + 134, + 60, + 156, + 21, + 295, + 20, + 65, + 46, + 215, + 321, + 39, + 12, + 346, + 108, + 321, + 270, + 156, + 136, + 334, + 364, + 318, + 168, + 365, + 79, + 90, + 123, + 325, + 330, + 189, + 52, + 123, + 310, + 267, + 231, + 289, + 133, + 293, + 32, + 346, + 288, + 313, + 108, + 398, + 62, + 321, + 25, + 362, + 268, + 313, + 123, + 280, + 353, + 129, + 100, + 170, + 54, + 13, + 348, + 167, + 82, + 167, + 176, + 41, + 235, + 45, + 400, + 216, + 211, + 233, + 297, + 310, + 240, + 193, + 248, + 242, + 375, + 371, + 170, + 342, + 197, + 190, + 367, + 43, + 71, + 249, + 251, + 299, + 317, + 291, + 345, + 69, + 60, + 333, + 21, + 312, + 194, + 6, + 285, + 320, + 201, + 8, + 218, + 286, + 127, + 388, + 183, + 27, + 181, + 263, + 102, + 246, + 134, + 37, + 236, + 262, + 196, + 186, + 157, + 281, + 266, + 263, + 219, + 345, + 120, + 22, + 210, + 246, + 72, + 29, + 121, + 299, + 240, + 167, + 270, + 47, + 229, + 84, + 226, + 26, + 70, + 85, + 197, + 218, + 198, + 278, + 232, + 36, + 1, + 298, + 144, + 130, + 2, + 240, + 86, + 216, + 288, + 135, + 98, + 68, + 41, + 142, + 192, + 301, + 169, + 114, + 261, + 11, + 322, + 148, + 66, + 196, + 358, + 280, + 347, + 15, + 9, + 212, + 383, + 394, + 127, + 194, + 277, + 135, + 231, + 223, + 84, + 284, + 98, + 286, + 367, + 28, + 299, + 74, + 187, + 260, + 273, + 300, + 206, + 23, + 244, + 291, + 364, + 21, + 12, + 52, + 362, + 20, + 353, + 38, + 370, + 188, + 64, + 320, + 226, + 103, + 206, + 25, + 197, + 35, + 348, + 213, + 182, + 364, + 249, + 118, + 352, + 286, + 166, + 101, + 375, + 292, + 258, + 62, + 372, + 102, + 149, + 250, + 223, + 97, + 180, + 129, + 394, + 184, + 132, + 29, + 88, + 104, + 180, + 50, + 97, + 192, + 339, + 166, + 234, + 374, + 219, + 233, + 141, + 337, + 317, + 274, + 44, + 165, + 189, + 112, + 363, + 156, + 291, + 44, + 288, + 142, + 391, + 289, + 17, + 341, + 335, + 6, + 177, + 219, + 285, + 224, + 62, + 20, + 258, + 270, + 91, + 254, + 334, + 124, + 185, + 120, + 8, + 13, + 339, + 306, + 333, + 255, + 41, + 7, + 316, + 236, + 80, + 145, + 247, + 368, + 312, + 124, + 346, + 116, + 1, + 108, + 9, + 126, + 303, + 357, + 5, + 223, + 83, + 172, + 205, + 242, + 77, + 61, + 159, + 121, + 268, + 256, + 331, + 203, + 70, + 217, + 122, + 310, + 142, + 156, + 108, + 379, + 321, + 289, + 379, + 63, + 264, + 372, + 395, + 261, + 190, + 11, + 291, + 148, + 72, + 215, + 259, + 304, + 381, + 38, + 216, + 134, + 62, + 211, + 279, + 213, + 125, + 27, + 254, + 81, + 43, + 150, + 256, + 371, + 295, + 219, + 335, + 230, + 79, + 177, + 159, + 241, + 304, + 63, + 247, + 107, + 143, + 400, + 262, + 369, + 242, + 90, + 82, + 105, + 229, + 162, + 222, + 383, + 363, + 223, + 211, + 114, + 134, + 162, + 245, + 371, + 95, + 329, + 124, + 216, + 201, + 195, + 157, + 85, + 309, + 271, + 384, + 143, + 51, + 366, + 183, + 326, + 170, + 49, + 326, + 351, + 107, + 141, + 334, + 102, + 323, + 286, + 12, + 215, + 4, + 228, + 322, + 255, + 256, + 323, + 69, + 168, + 274, + 148, + 237, + 194, + 331, + 203, + 132, + 151, + 238, + 215, + 46, + 106, + 35, + 225, + 360, + 124, + 386, + 37, + 111, + 331, + 340, + 12, + 181, + 143, + 249, + 348, + 165, + 10, + 282, + 18, + 359, + 346, + 371, + 267, + 355, + 15, + 212, + 68, + 382, + 222, + 110, + 54, + 270, + 53, + 245, + 213, + 152, + 80, + 323, + 6, + 264, + 149, + 360, + 388, + 323, + 284, + 315, + 125, + 119, + 95, + 243, + 218, + 360, + 394, + 383, + 221, + 289, + 113, + 294, + 359, + 140, + 113, + 292, + 48, + 266, + 386, + 30, + 186, + 65, + 384, + 351, + 228, + 31, + 144, + 359, + 352, + 50, + 362, + 362, + 202, + 27, + 294, + 9, + 68, + 164, + 105, + 37, + 137, + 251, + 394, + 20, + 306, + 145, + 176, + 74, + 229, + 235, + 211, + 174, + 14, + 221, + 165, + 116, + 374, + 198, + 136, + 148, + 198, + 271, + 222, + 48, + 143, + 19, + 399, + 386, + 125, + 378, + 40, + 140, + 183, + 78, + 100, + 26, + 66, + 233, + 114, + 122, + 23, + 183, + 115, + 338, + 357, + 255, + 71, + 230, + 65, + 115, + 75, + 86, + 110, + 100, + 90, + 389, + 159, + 318, + 397, + 40, + 70, + 41, + 106, + 55, + 49, + 181, + 344, + 381, + 132, + 26, + 52, + 306, + 172, + 323, + 197, + 116, + 126, + 39, + 154, + 77, + 256, + 48, + 39, + 317, + 384, + 347, + 66, + 178, + 266, + 1, + 110, + 162, + 153, + 2, + 86, + 192, + 145, + 245, + 193, + 396, + 366, + 205, + 369, + 88, + 158, + 160, + 217, + 58, + 287, + 384, + 110, + 345, + 369, + 36, + 366, + 71, + 233, + 246, + 213, + 300, + 68, + 291, + 245, + 208, + 356, + 303, + 212, + 152, + 181, + 292, + 67, + 379, + 354, + 388, + 372, + 30, + 304, + 135, + 123, + 118, + 281, + 380, + 344, + 20, + 53, + 107, + 3, + 216, + 381, + 22, + 363, + 271, + 269, + 196, + 97, + 40, + 399, + 115, + 361, + 219, + 128, + 340, + 15, + 308, + 186, + 8, + 292, + 183, + 63, + 42, + 8, + 273, + 45, + 195, + 108, + 140, + 324, + 230, + 306, + 159, + 324, + 172, + 72, + 109, + 203, + 188, + 329, + 186, + 61, + 174, + 362, + 143, + 10, + 388, + 66, + 211, + 227, + 13, + 239, + 201, + 198, + 96, + 208, + 26, + 345, + 336, + 21, + 145, + 1, + 206, + 393, + 81, + 251, + 303, + 195, + 11, + 68, + 205, + 341, + 144, + 178, + 256, + 348, + 70, + 12, + 6, + 385, + 201, + 108, + 92, + 284, + 140, + 43, + 51, + 106, + 172, + 148, + 195, + 218, + 370, + 73, + 335, + 189, + 138, + 13, + 227, + 227, + 208, + 338, + 137, + 379, + 68, + 308, + 236, + 258, + 293, + 287, + 13, + 129, + 132, + 60, + 174, + 126, + 319, + 185, + 189, + 318, + 232, + 359, + 275, + 364, + 46, + 256, + 179, + 172, + 368, + 45, + 68, + 132, + 201, + 21, + 285, + 99, + 338, + 340, + 140, + 300, + 270, + 208, + 380, + 187, + 188, + 22, + 112, + 304, + 55, + 39, + 198, + 20, + 355, + 257, + 298, + 91, + 235, + 18, + 235, + 58, + 77, + 397, + 232, + 51, + 277, + 284, + 292, + 360, + 369, + 188, + 350, + 158, + 125, + 158, + 49, + 160, + 111, + 64, + 21, + 368, + 390, + 287, + 279, + 104, + 291, + 246, + 294, + 196, + 400, + 161, + 133, + 319, + 310, + 62, + 118, + 205, + 320, + 164, + 44, + 81, + 10, + 270, + 51, + 23, + 265, + 121, + 184, + 389, + 120, + 355, + 221, + 167, + 105, + 289, + 147, + 174, + 133, + 185, + 225, + 228, + 309, + 218, + 320, + 233, + 115, + 126, + 22, + 383, + 356, + 254, + 36, + 19, + 95, + 80, + 327, + 107, + 42, + 327, + 70, + 107, + 45, + 119, + 323, + 83, + 81, + 68, + 261, + 195, + 76, + 45, + 172, + 6, + 154, + 305, + 108, + 263, + 249, + 146, + 120, + 112, + 298, + 207, + 382, + 231, + 371, + 102, + 87, + 155, + 168, + 387, + 309, + 70, + 166, + 95, + 12, + 343, + 302, + 266, + 113, + 41, + 173, + 268, + 350, + 224, + 42, + 70, + 353, + 6, + 319, + 39, + 144, + 223, + 240, + 68, + 11, + 36, + 326, + 364, + 31, + 7, + 329, + 295, + 392, + 147, + 250, + 192, + 24, + 334, + 27, + 272, + 21, + 49, + 398, + 222, + 150, + 255, + 326, + 100, + 149, + 33, + 357, + 143, + 15, + 246, + 30, + 72, + 101, + 398, + 120, + 398, + 87, + 210, + 355, + 354, + 364, + 244, + 360, + 81, + 293, + 140, + 384, + 197, + 371, + 357, + 157, + 139, + 73, + 198, + 151, + 253, + 79, + 155, + 184, + 24, + 99, + 121, + 66, + 330, + 351, + 279, + 280, + 284, + 362, + 384, + 294, + 262, + 80, + 232, + 62, + 15, + 395, + 102, + 287, + 147, + 20, + 380, + 37, + 211, + 292, + 53, + 265, + 159, + 17, + 141, + 22, + 348, + 311, + 224, + 372, + 116, + 138, + 360, + 170, + 210, + 118, + 208, + 367, + 248, + 267, + 194, + 273, + 162, + 124, + 128, + 45, + 30, + 353, + 258, + 204, + 329, + 49, + 101, + 232, + 133, + 95, + 371, + 186, + 128, + 214, + 318, + 233, + 20, + 37, + 253, + 291, + 152, + 223, + 254, + 321, + 277, + 224, + 68, + 346, + 395, + 89, + 23, + 5, + 136, + 52, + 369, + 158, + 2, + 48, + 34, + 102, + 187, + 101, + 117, + 344, + 301, + 294, + 302, + 349, + 272, + 148, + 169, + 82, + 108, + 10, + 302, + 9, + 81, + 124, + 209, + 327, + 371, + 247, + 270, + 26, + 337, + 109, + 128, + 13, + 53, + 148, + 73, + 162, + 390, + 89, + 173, + 86, + 156, + 114, + 394, + 90, + 105, + 61, + 388, + 24, + 318, + 366, + 260, + 34, + 340, + 159, + 293, + 205, + 266, + 87, + 142, + 370, + 355, + 57, + 69, + 369, + 385, + 136, + 379, + 59, + 298, + 141, + 199, + 274, + 137, + 241, + 109, + 253, + 159, + 384, + 180, + 174, + 263, + 302, + 350, + 371, + 273, + 292, + 298, + 184, + 215, + 279, + 60, + 103, + 137, + 50, + 317, + 154, + 380, + 360, + 284, + 68, + 178, + 4, + 125, + 165, + 196, + 36, + 151, + 392, + 99, + 59, + 236, + 197, + 107, + 98, + 207, + 231, + 369, + 240, + 213, + 313, + 36, + 259, + 151, + 189, + 387, + 348, + 392, + 69, + 350, + 214, + 17, + 228, + 29, + 215, + 243, + 216, + 17, + 55, + 113, + 200, + 347, + 217, + 132, + 52, + 57, + 109, + 253, + 288, + 377, + 258, + 281, + 251, + 230, + 298, + 98, + 252, + 347, + 232, + 50, + 157, + 213, + 288, + 381, + 142, + 192, + 142, + 156, + 161, + 24, + 257, + 344, + 160, + 242, + 294, + 214, + 151, + 290, + 274, + 142, + 383, + 219, + 309, + 227, + 110, + 137, + 256, + 127, + 299, + 319, + 34, + 153, + 164, + 168, + 341, + 143, + 200, + 205, + 324, + 225, + 216, + 149, + 237, + 89, + 280, + 244, + 256, + 159, + 394, + 135, + 394, + 99, + 267, + 309, + 159, + 176, + 110, + 393, + 268, + 291, + 55, + 102, + 68, + 85, + 158, + 11, + 224, + 84, + 150, + 272, + 342, + 152, + 7, + 67, + 237, + 202, + 286, + 361, + 179, + 52, + 118, + 182, + 121, + 319, + 92, + 216, + 312, + 163, + 100, + 162, + 53, + 244, + 369, + 307, + 64, + 282, + 354, + 135, + 255, + 5, + 97, + 147, + 384, + 290, + 115, + 83, + 17, + 249, + 308, + 129, + 279, + 199, + 162, + 304, + 392, + 331, + 185, + 305, + 333, + 298, + 243, + 124, + 120, + 231, + 378, + 74, + 311, + 85, + 40, + 43, + 14, + 266, + 169, + 175, + 342, + 133, + 151, + 329, + 186, + 295, + 35, + 324, + 291, + 124, + 187, + 11, + 135, + 195, + 341, + 255, + 281, + 255, + 362, + 329, + 274, + 338, + 182, + 52, + 172, + 219, + 141, + 14, + 64, + 87, + 105, + 132, + 156, + 69, + 106, + 6, + 117, + 249, + 297, + 113, + 123, + 388, + 17, + 164, + 348, + 278, + 93, + 86, + 199, + 385, + 283, + 237, + 80, + 30, + 352, + 51, + 58, + 133, + 127, + 100, + 128, + 234, + 380, + 234, + 42, + 310, + 304, + 32, + 18, + 300, + 215, + 391, + 169, + 107, + 324, + 49, + 157, + 207, + 317, + 282, + 90, + 48, + 145, + 339, + 349, + 120, + 226, + 174, + 64, + 397, + 274, + 295, + 261, + 341, + 157, + 165, + 263, + 186, + 194, + 56, + 128, + 3, + 284, + 57, + 88, + 304, + 151, + 43, + 65, + 86, + 350, + 9, + 203, + 31, + 126, + 249, + 387, + 377, + 298, + 43, + 236, + 310, + 247, + 102, + 143, + 14, + 114, + 262, + 156, + 182, + 108, + 398, + 372, + 100, + 393, + 329, + 359, + 285, + 388, + 59, + 184, + 221, + 303, + 327, + 145, + 124, + 144, + 9, + 107, + 142, + 18, + 56, + 36, + 313, + 329, + 98, + 54, + 367, + 201, + 102, + 325, + 37, + 205, + 123, + 299, + 241, + 84, + 112, + 235, + 46, + 357, + 214, + 361, + 392, + 220, + 171, + 3, + 240, + 388, + 167, + 7, + 293, + 4, + 194, + 269, + 197, + 125, + 78, + 162, + 301, + 222, + 157, + 248, + 74, + 278, + 110, + 156, + 273, + 239, + 161, + 290, + 117, + 27, + 356, + 377, + 328, + 80, + 152, + 302, + 193, + 180, + 256, + 365, + 237, + 194, + 354, + 178, + 199, + 248, + 154, + 336, + 249, + 267, + 315, + 356, + 200, + 379, + 224, + 215, + 104, + 51, + 146, + 28, + 77, + 232, + 346, + 22, + 43, + 16, + 12, + 212, + 120, + 209, + 268, + 213, + 159, + 193, + 260, + 232, + 298, + 153, + 278, + 129, + 109, + 375, + 121, + 151, + 34, + 256, + 7, + 260, + 139, + 255, + 384, + 376, + 130, + 108, + 215, + 103, + 179, + 181, + 24, + 328, + 385, + 213, + 20, + 41, + 74, + 8, + 365, + 195, + 56, + 23, + 310, + 325, + 235, + 307, + 322, + 320, + 218, + 26, + 363, + 220, + 181, + 353, + 369, + 315, + 366, + 78, + 125, + 138, + 177, + 333, + 164, + 54, + 128, + 315, + 1, + 173, + 254, + 259, + 33, + 302, + 219, + 248, + 235, + 72, + 279, + 97, + 389, + 79, + 313, + 198, + 301, + 324, + 338, + 293, + 378, + 124, + 270, + 325, + 170, + 375, + 118, + 224, + 254, + 78, + 117, + 103, + 180, + 303, + 94, + 259, + 54, + 375, + 147, + 399, + 299, + 128, + 122, + 364, + 23, + 330, + 288, + 314, + 71, + 162, + 398, + 96, + 176, + 371, + 30, + 12, + 21, + 130, + 190, + 205, + 52, + 20, + 102, + 262, + 268, + 122, + 23, + 354, + 104, + 221, + 191, + 129, + 33, + 51, + 339, + 198, + 111, + 159, + 395, + 295, + 93, + 272, + 124, + 114, + 254, + 116, + 127, + 272, + 41, + 210, + 384, + 83, + 34, + 393, + 84, + 359, + 137, + 355, + 228, + 316, + 175, + 75, + 280, + 221, + 98, + 43, + 68, + 197, + 194, + 40, + 242, + 50, + 123, + 149, + 206, + 331, + 158, + 224, + 142, + 88, + 201, + 250, + 251, + 186, + 42, + 191, + 317, + 282, + 3, + 250, + 137, + 139, + 305, + 110, + 165, + 269, + 333, + 378, + 360, + 292, + 183, + 370, + 78, + 100, + 344, + 186, + 137, + 120, + 220, + 14, + 302, + 303, + 55, + 381, + 234, + 382, + 93, + 342, + 168, + 213, + 155, + 180, + 201, + 191, + 386, + 296, + 303, + 82, + 131, + 218, + 299, + 360, + 282, + 253, + 49, + 215, + 225, + 67, + 378, + 23, + 109, + 398, + 48, + 15, + 235, + 138, + 373, + 270, + 366, + 7, + 150, + 92, + 372, + 110, + 123, + 57, + 66, + 98, + 210, + 164, + 338, + 341, + 171, + 92, + 277, + 20, + 33, + 280, + 214, + 28, + 363, + 79, + 291, + 256, + 161, + 252, + 322, + 372, + 134, + 203, + 108, + 54, + 127, + 392, + 128, + 180, + 185, + 99, + 7, + 75, + 141, + 188, + 37, + 309, + 1, + 316, + 377, + 345, + 177, + 229, + 133, + 160, + 312, + 294, + 198, + 130, + 363, + 118, + 72, + 52, + 198, + 375, + 52, + 306, + 336, + 300, + 140, + 130, + 395, + 386, + 205, + 263, + 30, + 155, + 301, + 389, + 59, + 47, + 162, + 120, + 360, + 311, + 281, + 102, + 41, + 197, + 46, + 271, + 36, + 179, + 303, + 106, + 316, + 253, + 283, + 292, + 103, + 218, + 199, + 158, + 144, + 54, + 127, + 53, + 293, + 36, + 215, + 168, + 110, + 233, + 192, + 377, + 1, + 170, + 245, + 225, + 363, + 172, + 56, + 110, + 165, + 134, + 139, + 248, + 325, + 84, + 340, + 53, + 78, + 395, + 9, + 288, + 223, + 105, + 165, + 230, + 317, + 189, + 72, + 252, + 296, + 169, + 214, + 75, + 179, + 256, + 60, + 178, + 30, + 138, + 376, + 327, + 98, + 191, + 48, + 14, + 320, + 39, + 172, + 183, + 229, + 291, + 88, + 110, + 400, + 12, + 238, + 159, + 309, + 256, + 170, + 26, + 348, + 191, + 296, + 236, + 275, + 314, + 280, + 126, + 231, + 185, + 263, + 306, + 35, + 35, + 378, + 198, + 162, + 49, + 212, + 224, + 66, + 40, + 47, + 24, + 154, + 226, + 198, + 98, + 193, + 398, + 51, + 130, + 64, + 73, + 378, + 189, + 71, + 158, + 314, + 47, + 209, + 339, + 197, + 372, + 201, + 116, + 33, + 215, + 169, + 211, + 155, + 378, + 11, + 226, + 125, + 188, + 182, + 341, + 102, + 318, + 81, + 359, + 388, + 11, + 174, + 241, + 179, + 367, + 368, + 311, + 232, + 9, + 131, + 174, + 384, + 45, + 355, + 209, + 289, + 372, + 339, + 86, + 40, + 385, + 79, + 15, + 161, + 386, + 386, + 124, + 368, + 305, + 299, + 301, + 384, + 315, + 389, + 378, + 95, + 249, + 394, + 393, + 174, + 291, + 259, + 290, + 268, + 373, + 340, + 39, + 253, + 294, + 254, + 212, + 222, + 164, + 27, + 379, + 39, + 50, + 70, + 153, + 191, + 292, + 21, + 9, + 254, + 100, + 115, + 80, + 117, + 387, + 389, + 236, + 257, + 226, + 292, + 169, + 238, + 92, + 36, + 190, + 73, + 177, + 301, + 24, + 173, + 168, + 242, + 208, + 91, + 366, + 87, + 206, + 247, + 161, + 340, + 105, + 151, + 108, + 26, + 124, + 228, + 268, + 371, + 176, + 360, + 334, + 164, + 190, + 10, + 59, + 63, + 67, + 2, + 135, + 334, + 166, + 266, + 350, + 153, + 142, + 32, + 261, + 107, + 389, + 170, + 1, + 27, + 19, + 331, + 288, + 190, + 311, + 189, + 82, + 34, + 369, + 89, + 127, + 217, + 344, + 248, + 312, + 233, + 215, + 86, + 5, + 203, + 362, + 54, + 278, + 33, + 310, + 342, + 154, + 168, + 376, + 378, + 16, + 140, + 285, + 336, + 237, + 185, + 303, + 222, + 10, + 120, + 341, + 110, + 125, + 16, + 180, + 211, + 362, + 344, + 244, + 199, + 168, + 146, + 114, + 55, + 347, + 242, + 318, + 392, + 298, + 316, + 230, + 109, + 23, + 271, + 289, + 169, + 26, + 96, + 47, + 114, + 159, + 119, + 320, + 367, + 10, + 36, + 171, + 349, + 270, + 384, + 245, + 15, + 393, + 192, + 43, + 356, + 247, + 68, + 320, + 215, + 21, + 366, + 58, + 186, + 335, + 131, + 321, + 7, + 280, + 239, + 224, + 159, + 237, + 271, + 13, + 129, + 231, + 396, + 221, + 359, + 14, + 372, + 253, + 267, + 349, + 375, + 290, + 361, + 243, + 252, + 1, + 261, + 397, + 60, + 375, + 393, + 234, + 105, + 342, + 301, + 380, + 143, + 393, + 282, + 6, + 279, + 321, + 308, + 148, + 143, + 358, + 114, + 192, + 206, + 220, + 382, + 343, + 207, + 186, + 194, + 395, + 144, + 77, + 264, + 19, + 251, + 336, + 60, + 57, + 182, + 363, + 19, + 225, + 226, + 241, + 333, + 260, + 267, + 380, + 375, + 234, + 340, + 27, + 132, + 335, + 379, + 143, + 225, + 50, + 8, + 209, + 306, + 223, + 122, + 127, + 302, + 244, + 194, + 301, + 251, + 393, + 326, + 239, + 50, + 98, + 352, + 100, + 65, + 372, + 365, + 241, + 43, + 336, + 353, + 259, + 144, + 101, + 356, + 209, + 374, + 340, + 336, + 91, + 339, + 370, + 193, + 232, + 254, + 313, + 76, + 198, + 290, + 14, + 378, + 353, + 209, + 233, + 376, + 326, + 391, + 286, + 309, + 10, + 263, + 45, + 83, + 92, + 181, + 239, + 87, + 82, + 171, + 217, + 52, + 127, + 323, + 157, + 270, + 21, + 114, + 172, + 51, + 290, + 276, + 308, + 47, + 296, + 84, + 122, + 365, + 373, + 324, + 104, + 100, + 6, + 382, + 211, + 363, + 210, + 308, + 291, + 128, + 282, + 225, + 218, + 333, + 13, + 377, + 400, + 33, + 348, + 232, + 364, + 276, + 350, + 187, + 47, + 147, + 345, + 198, + 146, + 395, + 294, + 32, + 300, + 322, + 128, + 352, + 334, + 343, + 169, + 355, + 336, + 71, + 15, + 213, + 131, + 25, + 389, + 125, + 107, + 156, + 68, + 111, + 126, + 320, + 276, + 360, + 73, + 92, + 310, + 12, + 346, + 25, + 110, + 396, + 52, + 234, + 348, + 94, + 20, + 250, + 377, + 226, + 10, + 372, + 193, + 108, + 83, + 360, + 322, + 303, + 396, + 94, + 316, + 160, + 102, + 388, + 212, + 357, + 1, + 142, + 63, + 131, + 166, + 221, + 115, + 172, + 375, + 108, + 293, + 210, + 222, + 226, + 137, + 260, + 166, + 260, + 199, + 19, + 344, + 166, + 381, + 304, + 325, + 344, + 343, + 122, + 282, + 16, + 71, + 257, + 306, + 323, + 54, + 366, + 47, + 264, + 262, + 8, + 213, + 64, + 186, + 6, + 222, + 389, + 122, + 178, + 176, + 337, + 380, + 315, + 359, + 169, + 305, + 77, + 30, + 113, + 291, + 341, + 317, + 273, + 47, + 258, + 191, + 159, + 219, + 162, + 73, + 23, + 60, + 344, + 198, + 318, + 138, + 4, + 184, + 16, + 379, + 37, + 306, + 338, + 189, + 193, + 173, + 323, + 164, + 305, + 33, + 157, + 330, + 27, + 16, + 335, + 339, + 352, + 191, + 10, + 36, + 222, + 77, + 307, + 103, + 358, + 196, + 333, + 169, + 386, + 308, + 152, + 34, + 75, + 348, + 219, + 343, + 48, + 11, + 2, + 23, + 367, + 365, + 294, + 275, + 39, + 338, + 154, + 335, + 245, + 313, + 264, + 107, + 223, + 304, + 61, + 306, + 186, + 108, + 147, + 236, + 283, + 147, + 397, + 343, + 111, + 184, + 313, + 264, + 132, + 398, + 49, + 298, + 325, + 370, + 400, + 208, + 146, + 381, + 43, + 153, + 188, + 309, + 212, + 243, + 278, + 184, + 388, + 222, + 46, + 32, + 171, + 230, + 253, + 318, + 128, + 128, + 306, + 298, + 223, + 188, + 277, + 70, + 119, + 232, + 129, + 156, + 167, + 37, + 137, + 356, + 392, + 209, + 324, + 290, + 386, + 319, + 285, + 99, + 339, + 323, + 314, + 301, + 123, + 156, + 311, + 350, + 63, + 246, + 240, + 78, + 110, + 342, + 332, + 374, + 286, + 20, + 253, + 332, + 340, + 37, + 210, + 174, + 324, + 236, + 243, + 395, + 375, + 134, + 288, + 177, + 279, + 33, + 286, + 204, + 134, + 319, + 391, + 181, + 211, + 355, + 32, + 312, + 62, + 69, + 124, + 297, + 38, + 388, + 37, + 350, + 53, + 2, + 129, + 24, + 234, + 372, + 394, + 231, + 168, + 367, + 139, + 345, + 46, + 279, + 180, + 147, + 89, + 364, + 168, + 153, + 94, + 63, + 62, + 127, + 110, + 245, + 229, + 4, + 298, + 352, + 262, + 41, + 269, + 121, + 129, + 40, + 228, + 254, + 114, + 128, + 118, + 73, + 261, + 375, + 65, + 14, + 175, + 128, + 367, + 110, + 50, + 366, + 65, + 59, + 170, + 260, + 58, + 12, + 224, + 246, + 87, + 210, + 12, + 130, + 354, + 123, + 122, + 299, + 143, + 311, + 187, + 298, + 372, + 201, + 159, + 395, + 356, + 15, + 142, + 352, + 212, + 302, + 212, + 213, + 58, + 265, + 209, + 156, + 392, + 261, + 313, + 323, + 293, + 302, + 299, + 171, + 258, + 353, + 382, + 54, + 321, + 78, + 60, + 304, + 146, + 212, + 282, + 237, + 219, + 114, + 2, + 239, + 307, + 247, + 95, + 331, + 247, + 252, + 7, + 289, + 179, + 238, + 328, + 369, + 354, + 130, + 357, + 248, + 292, + 97, + 113, + 297, + 244, + 202, + 21, + 227, + 141, + 78, + 182, + 373, + 191, + 327, + 254, + 61, + 226, + 246, + 1, + 26, + 114, + 335, + 159, + 388, + 273, + 79, + 257, + 361, + 329, + 114, + 368, + 300, + 118, + 329, + 136, + 186, + 281, + 158, + 4, + 132, + 30, + 396, + 361, + 154, + 118, + 151, + 380, + 178, + 238, + 315, + 195, + 179, + 207, + 341, + 231, + 47, + 78, + 37, + 389, + 115, + 329, + 191, + 169, + 217, + 367, + 116, + 61, + 113, + 12, + 21, + 123, + 213, + 128, + 184, + 321, + 260, + 131, + 119, + 34, + 15, + 178, + 58, + 117, + 54, + 35, + 292, + 92, + 271, + 181, + 62, + 168, + 82, + 72, + 310, + 215, + 309, + 334, + 281, + 72, + 351, + 333, + 171, + 207, + 85, + 221, + 232, + 349, + 59, + 258, + 43, + 216, + 54, + 211, + 345, + 131, + 314, + 391, + 39, + 300, + 41, + 35, + 9, + 313, + 269, + 86, + 239, + 189, + 240, + 279, + 331, + 333, + 359, + 128, + 229, + 107, + 87, + 163, + 49, + 151, + 167, + 221, + 327, + 324, + 305, + 281, + 309, + 269, + 141, + 295, + 56, + 66, + 356, + 49, + 289, + 136, + 139, + 117, + 257, + 361, + 297, + 329, + 31, + 142, + 389, + 164, + 32, + 96, + 210, + 149, + 145, + 106, + 51, + 273, + 80, + 211, + 61, + 60, + 106, + 99, + 216, + 309, + 175, + 314, + 370, + 204, + 236, + 148, + 395, + 283, + 55, + 159, + 343, + 292, + 375, + 39, + 237, + 347, + 126, + 192, + 356, + 188, + 357, + 346, + 280, + 308, + 188, + 186, + 159, + 121, + 33, + 52, + 217, + 14, + 191, + 90, + 373, + 5, + 147, + 291, + 332, + 191, + 100, + 27, + 17, + 300, + 63, + 277, + 308, + 235, + 301, + 63, + 208, + 269, + 70, + 134, + 101, + 74, + 393, + 309, + 50, + 69, + 92, + 276, + 89, + 329, + 158, + 346, + 309, + 274, + 274, + 67, + 46, + 45, + 49, + 65, + 254, + 211, + 71, + 206, + 254, + 354, + 301, + 80, + 293, + 229, + 156, + 139, + 155, + 37, + 189, + 159, + 213, + 359, + 284, + 341, + 118, + 307, + 223, + 267, + 345, + 310, + 22, + 136, + 211, + 329, + 209, + 117, + 199, + 164, + 47, + 255, + 281, + 170, + 22, + 313, + 17, + 327, + 304, + 147, + 174, + 229, + 83, + 289, + 92, + 335, + 316, + 143, + 179, + 325, + 121, + 128, + 38, + 61, + 64, + 321, + 69, + 321, + 136, + 101, + 108 + ], + "format": { + "is_signed": false, + "numeric_type": "bitnum", + "width": 32 + } + }, + "ans_mem": { + "data": [ + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, diff --git a/calyx-py/test/correctness/static/sdn_static.expect b/calyx-py/test/correctness/static/sdn_static.expect index 3cbecc4ce..f84dae9ac 100644 --- a/calyx-py/test/correctness/static/sdn_static.expect +++ b/calyx-py/test/correctness/static/sdn_static.expect @@ -1,308 +1,60008 @@ { "ans_mem": [ - 76, - 320, - 352, - 24, - 273, - 41, - 304, + 87, + 327, + 190, + 248, + 14, + 289, + 110, + 293, + 61, + 331, + 120, + 378, + 17, + 235, + 172, + 373, + 64, + 265, + 115, + 325, + 31, + 373, + 180, + 300, + 85, + 359, 176, - 233, + 297, + 2, + 217, + 120, + 85, + 145, + 3, + 5, + 41, + 372, + 29, + 396, + 70, + 216, + 51, + 369, + 200, + 354, + 94, + 292, + 359, + 361, + 363, + 279, + 224, + 95, + 383, + 350, + 216, + 157, + 384, + 129, + 293, + 25, + 213, + 157, + 284, + 40, + 289, + 116, + 218, + 356, + 279, + 177, + 329, + 172, + 359, + 109, + 388, + 349, + 389, + 128, + 39, + 77, + 248, + 114, + 331, + 71, + 294, + 112, + 365, + 83, + 64, + 294, + 115, + 385, + 31, + 57, + 48, + 242, + 162, + 287, + 63, + 336, + 188, + 255, + 18, + 282, + 132, + 377, + 80, + 240, + 123, + 238, + 37, + 244, + 150, + 344, + 36, + 357, + 157, + 149, + 329, + 134, + 351, + 57, + 102, + 289, + 62, + 68, + 283, + 302, + 207, + 289, + 381, + 132, + 372, + 13, + 208, + 252, + 139, + 227, + 69, + 229, + 227, + 227, + 26, + 217, + 287, + 253, + 212, + 205, + 315, + 240, + 279, + 218, + 53, + 270, + 338, + 295, + 201, + 232, + 218, + 278, + 254, + 216, + 290, + 242, + 140, + 289, + 137, + 238, + 163, + 373, + 126, + 351, + 72, + 267, + 187, + 376, + 44, + 223, + 164, + 269, + 41, + 297, 28, - 322, - 67, + 254, + 143, + 399, + 62, + 211, + 134, + 219, + 21, + 346, + 140, + 306, + 98, + 341, + 175, + 339, + 93, + 289, + 39, + 278, + 47, + 396, + 14, + 340, + 75, + 249, + 68, + 281, + 100, + 366, + 63, + 306, + 211, + 342, + 206, + 94, + 347, + 102, + 237, + 13, + 375, + 148, + 329, + 96, + 198, + 55, + 129, + 273, + 29, + 209, 190, - 215, - 76, - 317, - 150, + 361, + 37, 267, + 121, + 222, + 224, + 55, + 368, + 170, + 330, + 372, + 130, + 203, + 172, + 385, + 26, + 370, + 156, + 399, + 130, + 289, + 158, + 219, + 101, + 232, 162, + 278, + 6, + 341, + 296, + 266, + 321, + 265, + 112, + 398, + 1, + 399, + 188, + 252, + 41, + 256, + 97, + 328, + 96, + 331, + 45, + 216, + 129, + 370, + 225, + 180, + 289, + 6, + 221, + 180, + 394, + 2, + 316, + 149, + 305, + 22, + 242, + 177, + 336, + 52, + 380, + 142, + 302, + 17, + 370, + 191, + 351, + 7, + 335, + 190, + 295, + 51, + 383, + 198, + 212, + 52, + 319, + 191, + 279, + 45, + 378, + 184, + 355, + 94, + 368, + 165, + 341, + 21, + 380, + 111, + 217, + 46, + 149, + 206, + 98, + 149, + 4, + 184, + 34, + 196, + 34, + 318, + 104, + 268, + 38, + 314, + 125, 232, + 69, + 218, + 122, + 393, + 8, + 254, + 166, + 300, + 170, + 255, + 182, + 290, + 64, + 201, + 144, + 346, + 54, + 371, + 179, + 341, + 58, + 340, + 188, + 312, + 99, + 156, + 13, + 235, + 170, + 280, + 36, + 294, + 176, + 260, + 95, + 344, + 30, + 238, + 33, + 303, + 11, + 366, + 142, + 347, + 83, + 277, + 188, + 236, + 46, + 307, + 180, + 383, + 55, + 315, + 141, + 337, + 30, + 283, + 99, + 360, + 113, + 370, + 50, + 347, + 394, + 142, + 272, + 342, + 167, + 248, + 41, + 313, + 130, + 385, + 57, + 202, + 102, + 373, + 242, + 113, + 382, + 255, + 47, + 306, + 150, + 299, + 205, + 221, + 2, + 215, + 167, + 230, + 15, + 338, + 171, + 286, + 66, + 391, + 61, + 209, + 45, + 378, + 56, + 249, + 181, + 312, + 6, + 383, + 175, + 389, + 31, + 249, + 102, + 394, + 30, + 235, + 183, + 389, + 46, + 287, + 127, + 357, + 96, + 367, + 113, + 394, 75, + 260, + 146, + 261, + 67, + 377, + 180, + 334, + 98, + 209, + 192, + 293, + 80, + 306, + 74, + 321, + 41, + 257, + 101, + 238, + 83, + 383, + 93, + 332, + 38, + 296, + 183, + 244, + 101, + 357, + 148, + 274, + 264, + 19, + 219, + 121, + 218, + 353, + 245, + 266, + 214, + 382, + 54, + 211, + 19, + 68, + 395, + 37, + 263, + 91, + 224, + 72, 352, + 177, + 286, + 13, + 346, + 120, + 341, + 149, + 324, + 200, + 273, + 271, + 89, + 205, + 297, + 230, + 16, + 292, + 274, + 165, + 226, + 208, + 233, + 384, + 204, + 95, + 354, + 129, + 238, + 2, + 372, + 22, + 271, + 103, + 314, + 51, + 395, + 162, + 18, + 273, + 143, + 26, + 112, + 308, + 70, + 328, + 148, + 246, + 49, + 342, + 147, + 204, + 110, + 233, + 70, + 217, + 167, + 276, + 130, + 400, + 117, + 351, + 114, + 301, + 196, + 226, + 342, + 258, + 376, + 383, + 219, + 112, + 231, + 64, + 371, + 145, + 241, + 5, + 328, + 137, + 252, + 124, + 228, + 152, + 322, + 239, + 51, + 303, + 326, 140, - 245, - 57, + 320, + 84, + 274, + 41, + 290, + 279, + 196, + 329, + 89, + 197, + 348, + 34, + 217, + 152, + 233, + 13, + 246, + 190, + 301, + 147, + 393, + 27, + 302, + 185, + 222, + 82, + 370, + 166, + 351, + 128, + 385, + 193, + 254, + 78, 240, - 149, - 255, - 91, + 131, + 307, + 26, + 375, + 90, + 253, + 200, + 238, + 56, + 317, + 119, + 232, + 81, + 394, + 93, + 216, + 351, + 290, + 123, + 309, + 104, + 362, + 171, + 261, + 147, + 323, + 200, + 291, + 83, + 386, + 196, + 271, + 12, + 224, + 124, + 270, + 371, + 236, + 14, + 228, + 94, + 206, + 125, + 252, + 17, + 273, + 191, + 388, + 84, + 367, + 153, + 263, + 6, + 244, + 191, + 245, + 62, + 303, + 158, + 364, + 10, + 221, + 305, + 32, + 159, + 335, + 71, + 353, + 397, + 16, + 144, + 66, + 306, + 143, + 301, + 175, + 330, + 1, + 303, + 172, + 361, + 7, + 373, + 146, + 253, + 161, + 360, + 351, + 203, + 183, + 335, + 111, + 300, + 332, + 29, + 147, + 81, + 295, + 146, + 264, + 148, + 263, + 134, + 227, + 292, + 29, + 146, + 42, + 138, + 280, + 52, + 163, + 344, + 72, + 253, + 14, + 209, + 52, + 381, + 134, + 260, + 84, + 393, + 151, + 338, + 181, + 388, + 279, + 11, + 350, + 228, + 179, + 268, + 87, + 257, + 187, + 333, + 32, + 247, + 151, + 206, + 77, + 371, + 195, + 379, + 83, 251, 173, + 391, + 27, + 272, + 118, + 379, + 79, + 395, + 167, + 334, + 53, + 314, + 101, + 237, + 63, + 282, + 103, 400, + 52, + 203, + 169, + 243, + 83, + 392, + 162, + 286, + 4, + 300, + 146, + 381, + 48, + 212, + 142, + 358, + 24, + 208, + 161, + 282, + 27, + 237, + 21, + 373, + 133, + 219, + 58, + 197, + 228, + 139, + 339, + 220, + 231, + 157, + 223, + 93, + 227, + 192, + 354, + 117, + 203, + 106, + 264, + 11, + 273, + 99, + 374, + 1, + 205, + 334, + 248, + 283, + 262, + 305, + 49, + 350, + 53, + 215, + 336, + 364, + 226, + 217, + 313, + 200, + 303, + 56, + 380, + 93, + 328, + 77, + 290, + 44, + 274, + 137, + 393, + 83, + 208, + 280, + 279, + 75, + 220, + 233, + 267, + 51, + 287, + 145, + 246, + 132, + 146, + 98, + 162, + 58, + 155, + 37, + 155, + 40, + 146, + 165, + 105, + 393, + 177, + 348, + 97, + 233, + 161, + 315, + 70, + 230, + 33, + 237, 45, + 257, + 64, + 382, + 164, + 9, + 381, + 31, + 56, + 51, + 37, + 365, + 64, + 383, + 152, + 55, + 190, + 27, + 240, + 169, + 66, + 138, + 48, + 316, + 166, + 388, + 62, + 150, + 106, + 382, + 34, + 249, + 151, + 136, + 121, + 21, + 155, + 244, + 39, + 239, + 186, + 231, + 189, + 296, + 35, + 262, + 170, + 316, + 169, + 229, + 106, + 322, + 143, + 151, + 156, + 188, + 57, + 281, + 195, + 82, + 169, + 62, + 146, + 168, + 338, + 102, + 211, + 40, + 222, + 134, + 302, + 193, + 305, + 137, + 211, + 92, + 292, + 238, + 178, + 317, + 17, + 356, + 4, 355, - 139, + 216, + 217, + 342, + 274, + 248, + 352, + 353, + 125, + 209, + 96, + 325, + 145, + 22, + 395, + 180, + 282, + 85, + 351, + 163, + 297, + 49, + 369, + 183, + 349, + 59, + 240, + 112, 300, - 17, - 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 - ], - "commands": [ - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, + 310, + 378, + 396, + 273, + 16, + 242, + 133, + 215, + 93, + 255, + 152, + 400, + 100, + 264, + 9, + 272, + 85, + 323, + 22, + 400, + 37, + 356, + 115, + 324, + 67, + 370, + 3, + 359, + 156, + 272, + 14, + 264, + 108, + 303, + 53, + 261, + 101, + 236, + 48, + 224, + 193, + 388, + 72, + 383, + 125, + 345, + 75, + 209, + 172, + 225, + 73, + 262, + 152, + 46, + 74, + 27, + 3, + 326, + 67, + 155, + 22, + 290, + 157, + 305, + 36, + 230, + 127, + 350, + 31, + 375, + 105, + 331, + 135, + 394, + 11, + 360, + 163, + 319, + 147, + 391, + 184, + 282, + 19, + 232, + 60, + 308, + 306, + 71, + 283, + 391, + 387, + 61, + 159, + 51, + 47, + 44, + 254, + 193, + 211, + 25, + 259, + 136, + 269, + 95, + 209, + 167, + 301, + 50, + 253, + 117, + 259, + 65, + 237, + 121, + 308, + 62, + 280, + 115, + 315, + 68, + 263, + 114, 2, - 0, - 0 - ], - "values": [ + 141, + 150, + 57, + 280, + 141, + 26, + 158, + 221, + 100, + 284, + 174, + 251, + 61, + 198, + 385, + 74, + 117, + 101, + 50, + 343, + 291, + 85, + 376, + 67, + 152, + 77, + 306, + 287, + 46, + 143, + 136, + 304, + 130, + 338, + 14, + 208, + 153, + 397, + 108, + 224, + 42, + 306, + 145, + 387, + 76, + 331, + 189, + 237, + 190, + 264, + 149, + 338, + 63, + 223, + 104, + 395, + 9, + 219, + 113, + 362, + 21, + 232, + 59, + 214, + 91, + 356, + 91, + 371, + 142, + 280, + 49, + 230, + 25, + 392, + 190, + 284, + 147, + 285, + 117, + 357, + 147, + 276, + 69, + 301, + 115, + 320, + 16, + 330, + 148, + 337, + 56, + 380, + 112, + 398, + 149, + 351, + 182, + 229, + 338, + 82, + 254, + 207, + 134, + 238, + 202, + 271, + 148, + 231, + 73, + 213, + 198, + 326, + 68, 320, + 123, + 201, + 25, + 288, + 149, + 342, + 163, + 210, + 170, + 263, + 152, + 234, + 210, + 314, + 204, + 347, + 60, + 163, + 366, + 134, + 204, + 185, + 74, + 68, + 309, + 276, + 89, + 207, + 7, + 336, + 151, + 381, + 50, + 304, + 157, + 268, + 148, + 243, + 166, + 256, + 177, + 341, + 25, + 165, + 394, + 106, + 335, + 122, + 243, + 37, + 252, + 135, + 389, + 105, + 316, + 166, + 252, + 30, + 262, + 130, + 378, 76, + 251, + 251, + 327, + 380, + 276, + 345, + 137, + 258, + 75, + 349, + 167, + 359, + 92, + 270, + 133, + 224, + 96, + 290, + 282, + 98, + 289, + 100, + 244, + 82, + 165, + 280, + 24, + 121, + 174, + 169, + 185, + 364, + 110, + 179, + 312, + 59, + 247, + 153, + 249, + 150, + 241, + 33, 369, + 169, + 391, + 48, + 284, + 181, + 208, + 62, + 268, + 121, + 228, + 41, + 299, + 141, + 207, + 143, + 217, + 61, + 356, + 122, + 358, + 36, + 327, + 120, + 285, + 83, + 339, + 117, + 331, + 9, + 210, + 135, + 397, + 55, + 297, + 129, + 288, + 69, + 333, + 157, + 383, + 91, + 239, + 200, + 276, + 3, + 200, + 324, + 98, + 105, + 25, + 183, + 385, + 67, + 356, + 56, + 391, + 143, + 299, + 88, + 233, + 150, + 299, + 96, + 247, + 103, + 340, + 50, + 307, + 187, + 212, + 46, + 292, + 161, + 322, + 52, + 236, + 163, + 72, + 132, + 48, + 384, + 159, + 97, + 102, + 58, + 270, + 132, + 258, + 96, + 318, + 111, + 302, + 82, + 393, + 131, + 373, + 17, + 281, + 164, + 272, + 83, + 321, + 15, + 319, + 30, + 240, + 264, + 143, + 239, + 12, + 251, + 146, + 217, + 155, + 248, + 177, + 230, + 117, + 264, + 179, + 255, + 137, + 219, + 131, + 398, + 131, + 337, + 94, + 384, + 112, + 258, + 104, + 201, + 174, + 274, + 74, + 337, + 144, + 314, + 96, + 220, + 110, + 374, + 180, + 344, + 180, + 331, + 138, + 364, + 28, + 305, + 101, + 235, + 141, + 392, + 107, + 189, + 248, + 150, + 199, + 344, + 171, + 293, + 152, + 384, + 291, + 254, + 322, + 351, + 239, + 64, + 398, + 8, + 118, + 329, + 47, + 335, + 123, + 335, + 58, + 375, + 104, + 328, + 20, + 268, + 170, + 245, + 23, + 355, + 68, + 390, + 73, + 352, + 200, + 336, + 11, + 205, + 59, + 248, + 53, + 256, + 188, + 248, + 79, + 240, + 176, + 349, + 13, + 277, + 162, + 262, + 93, + 253, + 181, + 261, + 79, + 214, + 107, + 395, + 73, + 393, + 175, + 227, + 63, + 231, + 155, + 295, + 18, + 336, + 16, + 218, + 56, + 368, + 42, + 209, + 268, + 16, + 210, + 205, + 7, + 359, + 195, + 298, + 137, + 242, + 36, + 399, + 382, + 5, + 241, + 329, + 297, + 396, + 29, + 272, + 75, + 240, + 186, + 247, + 18, + 271, + 71, + 203, + 74, + 351, + 143, + 347, + 58, + 379, + 151, + 384, + 18, + 258, + 124, + 252, + 16, + 215, + 106, + 218, + 32, + 257, + 133, + 237, + 51, + 284, + 139, + 257, + 25, + 244, + 142, + 208, + 35, + 391, + 147, + 303, + 188, + 292, + 40, + 272, + 110, + 220, + 3, + 351, + 157, + 362, + 53, + 398, + 170, + 385, + 2, + 213, + 168, + 394, + 17, + 302, + 189, + 8, + 333, + 200, + 358, + 10, + 323, + 200, + 355, + 63, + 360, + 185, + 205, + 27, + 351, + 188, + 228, + 29, + 238, + 187, + 303, + 6, + 348, + 175, + 266, + 96, + 331, + 181, + 270, + 51, + 340, + 172, + 239, + 43, + 296, + 159, + 337, + 29, + 317, + 115, + 332, + 12, + 271, + 138, + 65, + 218, + 148, + 380, + 49, + 184, + 96, + 200, + 306, + 23, + 398, + 120, + 218, + 85, + 343, + 131, + 211, + 15, + 316, + 143, + 288, + 32, + 113, + 29, + 228, + 143, + 372, + 34, + 356, + 166, + 274, + 100, + 350, + 111, + 62, + 101, + 361, + 42, + 195, + 23, + 52, + 206, + 17, + 331, + 53, + 240, + 67, + 340, + 183, + 260, + 35, + 266, + 193, + 280, + 67, + 389, + 156, + 241, + 91, + 298, + 168, + 396, + 2, + 303, + 134, + 282, + 40, + 291, + 183, + 362, + 52, + 283, + 157, + 317, + 188, + 364, + 69, + 381, + 133, + 318, + 44, + 278, + 193, + 264, + 30, + 257, + 127, + 252, + 77, + 322, + 173, + 216, + 44, + 354, + 155, + 280, + 189, + 288, + 139, + 367, + 373, + 140, + 343, + 297, + 334, + 92, + 388, + 193, + 13, + 236, + 197, + 169, + 25, + 345, + 30, + 87, + 102, + 39, + 288, + 158, + 256, + 87, + 272, + 197, + 264, + 20, + 399, + 129, + 283, + 53, + 131, + 393, + 99, + 124, + 58, + 152, + 251, + 42, + 237, + 35, + 362, + 66, + 213, + 297, + 288, + 292, + 325, + 142, + 358, + 44, + 360, + 140, + 213, + 117, + 303, + 71, + 249, + 38, + 366, + 72, + 253, + 89, + 353, + 163, + 392, + 16, + 353, + 78, + 282, + 126, + 355, + 47, + 273, + 129, + 342, + 2, + 301, + 91, + 235, + 70, + 304, + 345, + 346, + 121, + 216, + 83, + 204, + 120, + 389, + 130, + 305, + 32, + 252, + 134, + 216, + 16, + 296, + 31, + 255, + 11, + 202, + 167, + 396, + 90, + 389, + 120, + 245, + 75, + 262, + 185, + 307, + 89, + 374, + 134, + 331, + 51, + 342, + 145, + 205, + 27, + 282, + 145, + 57, + 398, + 165, + 212, + 33, + 290, + 160, + 384, + 53, + 218, + 132, + 381, + 41, + 298, + 40, + 260, + 348, + 300, + 218, + 6, + 381, + 65, + 220, + 41, + 255, + 174, + 289, + 77, + 400, + 110, + 316, + 66, + 248, + 69, + 254, + 10, + 398, + 28, + 261, + 98, + 314, + 76, + 396, + 39, + 322, + 160, + 395, + 206, + 13, + 300, + 169, + 304, + 92, + 287, + 150, + 240, + 293, + 80, + 399, + 167, + 354, + 196, + 211, + 168, + 251, + 356, + 18, + 343, + 194, + 350, + 132, + 318, + 222, + 323, + 151, + 218, + 126, + 342, + 103, + 285, + 147, + 352, + 250, + 317, + 167, + 213, + 387, + 195, + 274, + 103, + 331, + 337, + 289, + 369, + 399, + 333, + 286, + 385, + 366, + 400, + 25, + 341, + 141, + 221, + 73, + 246, + 184, + 338, + 92, + 332, + 101, + 204, + 181, + 321, + 132, + 360, + 4, + 331, + 112, + 210, + 53, + 243, + 189, + 399, + 52, + 378, + 119, + 260, + 85, + 341, + 193, + 263, + 74, + 295, + 127, + 311, + 154, + 315, + 37, + 371, + 152, + 251, + 25, + 249, + 320, + 41, + 316, + 37, + 225, + 368, + 68, + 367, + 389, + 361, + 250, + 338, + 355, + 186, + 347, + 325, + 202, + 88, + 377, + 175, + 303, + 79, + 317, + 138, + 346, + 80, + 317, + 186, + 364, + 88, + 248, + 68, + 362, + 69, + 92, + 211, + 55, + 231, + 92, + 337, + 87, + 277, + 17, + 358, + 15, + 327, + 196, + 264, + 92, + 211, + 140, + 203, + 17, + 393, + 185, + 385, + 316, + 54, + 293, + 252, + 386, + 359, + 54, + 351, + 148, + 351, + 207, + 37, + 257, + 188, + 386, + 81, + 321, + 132, + 310, + 44, + 296, + 188, + 228, + 39, + 338, + 156, + 229, + 52, + 385, + 142, + 97, + 139, + 258, + 77, + 316, + 189, + 114, + 136, + 278, + 128, + 328, + 84, + 309, + 112, + 232, + 194, + 344, + 119, + 281, + 105, + 295, + 105, + 251, + 39, + 317, + 179, + 360, + 100, + 260, + 76, + 386, + 37, + 334, + 238, + 299, + 90, + 330, + 311, + 126, + 385, + 61, + 385, + 200, + 356, + 64, + 167, + 56, + 108, + 305, + 26, + 214, + 82, + 284, + 19, + 324, + 54, + 246, + 133, + 247, + 57, + 258, + 157, + 302, + 74, + 330, + 103, + 365, + 87, + 121, + 226, + 88, + 348, + 57, + 305, + 37, + 315, + 97, + 312, + 266, + 307, + 33, + 311, + 393, + 315, + 311, + 166, + 390, + 138, + 313, + 34, + 358, + 200, + 280, + 15, + 386, + 168, + 266, + 4, + 249, + 192, + 365, + 99, + 365, + 59, + 400, + 25, + 381, + 104, + 357, + 16, + 359, + 126, + 394, + 54, + 86, + 322, + 343, + 313, + 260, + 222, + 165, + 243, + 230, + 355, + 73, + 204, + 279, + 324, + 149, + 223, + 352, + 80, + 264, + 114, + 319, + 73, + 318, + 145, + 255, + 99, + 289, + 187, + 281, + 8, + 381, + 178, + 261, + 29, + 142, + 46, + 109, + 121, + 300, + 113, + 308, + 57, + 313, + 138, + 221, + 37, + 380, + 89, + 310, + 38, + 357, + 38, + 332, + 117, + 345, + 29, + 319, + 123, + 320, + 61, + 239, + 109, + 224, + 5, + 228, + 168, + 228, + 100, + 156, + 52, + 50, + 356, + 50, + 161, + 283, + 149, + 215, + 65, + 267, + 142, + 216, + 20, + 334, + 160, + 373, + 77, + 203, + 170, + 362, + 73, + 219, + 156, + 249, + 52, + 386, + 105, + 360, + 84, + 385, + 111, + 229, + 197, + 308, + 111, + 385, + 191, + 267, + 153, + 302, + 32, + 302, + 130, + 361, + 143, + 260, + 183, + 313, + 168, + 386, + 53, + 355, + 190, + 305, + 42, + 255, + 112, + 317, + 116, + 271, + 80, + 202, + 154, + 214, + 50, + 296, + 25, + 377, + 28, + 255, + 96, + 297, + 181, + 342, + 78, + 365, + 253, + 374, + 243, + 345, + 254, + 297, + 354, + 373, + 276, + 313, + 88, + 43, + 246, + 76, + 201, + 179, + 385, + 60, + 367, + 111, + 373, + 85, + 373, + 171, + 268, + 42, + 292, + 159, + 285, + 58, + 267, + 192, + 223, + 19, + 110, + 246, + 47, + 330, + 168, + 201, + 22, + 282, + 199, + 236, + 61, + 307, + 115, + 310, + 29, + 331, + 115, + 378, + 26, + 241, + 171, + 260, + 83, + 262, + 101, + 335, + 74, + 293, + 178, + 355, + 49, + 218, + 167, + 283, + 2, + 293, + 9, + 269, + 30, + 284, + 47, + 274, + 16, + 336, + 371, + 378, + 343, + 379, + 235, + 316, + 62, + 292, + 207, + 213, + 335, + 393, + 136, + 357, + 67, + 345, + 63, + 310, + 105, + 242, + 84, + 202, + 163, + 326, + 64, + 344, + 80, + 256, + 267, + 374, + 200, + 367, + 50, + 320, + 340, + 172, + 241, + 100, + 378, + 191, + 223, + 322, + 132, + 385, + 43, + 305, + 24, + 239, + 157, + 252, + 47, + 255, + 178, + 261, + 99, + 302, + 170, + 378, + 28, + 292, + 142, + 277, + 154, + 282, + 189, + 307, + 43, + 280, + 102, + 299, + 159, + 273, + 186, + 321, + 181, + 257, + 125, + 222, + 158, + 238, + 141, + 265, + 18, + 285, + 134, + 345, + 24, + 258, + 160, + 301, + 32, + 182, + 175, + 55, + 46, + 335, + 178, + 360, + 116, + 300, + 46, + 321, + 107, + 317, + 95, + 237, + 101, + 40, + 182, + 16, + 46, + 34, + 78, + 372, + 37, + 234, + 314, + 182, + 346, + 20, + 391, + 114, + 397, + 3, + 344, + 144, + 243, + 168, + 267, + 34, + 273, + 121, + 273, + 68, + 298, + 141, + 399, + 96, + 358, + 177, + 248, + 84, + 364, + 176, + 224, + 18, + 383, + 154, + 291, + 25, + 323, + 123, + 392, + 52, + 311, + 185, + 330, + 41, + 320, + 168, + 368, + 83, + 343, + 129, + 294, + 5, + 279, + 102, + 299, + 235, + 262, + 25, + 234, + 221, + 203, + 185, + 399, + 37, + 362, + 390, + 369, + 58, + 310, + 30, + 302, + 355, + 253, + 380, + 205, + 182, + 220, + 62, + 288, + 108, + 295, + 96, + 343, + 125, + 257, + 25, + 279, + 62, + 300, + 6, + 221, + 196, + 202, + 4, + 319, + 170, + 363, + 73, + 271, + 195, + 240, + 86, + 144, + 26, + 6, + 128, + 353, + 95, + 379, + 116, + 238, + 85, + 149, + 77, + 188, + 336, + 74, + 283, + 254, + 81, + 202, + 332, + 358, + 237, + 213, + 335, + 313, + 112, + 55, + 146, + 50, + 228, + 190, + 286, + 96, + 238, + 131, + 328, + 56, + 302, + 151, + 332, + 112, + 312, + 131, + 236, + 138, + 335, + 325, + 60, + 343, + 337, + 47, + 316, + 222, + 91, + 208, + 50, + 278, + 375, + 260, + 254, + 149, + 390, + 275, + 157, + 347, + 176, + 361, + 116, + 344, + 165, + 337, + 103, + 239, + 359, + 89, + 149, + 65, + 160, + 113, + 287, + 95, + 159, + 351, + 50, + 96, + 382, + 161, + 323, + 293, + 263, + 293, + 262, + 266, + 41, + 261, + 190, + 228, + 119, + 222, + 22, + 272, + 184, + 353, + 36, + 368, + 133, + 254, + 9, + 249, + 136, + 257, + 125, + 285, + 143, + 280, + 289, + 164, + 210, + 195, + 248, + 63, + 393, + 172, + 378, + 81, + 333, + 47, + 297, + 36, + 369, + 52, + 373, + 25, + 271, + 164, + 219, + 69, + 258, + 158, + 294, + 2, + 396, + 160, + 203, + 70, + 260, + 182, + 319, + 24, + 317, + 190, + 329, + 4, + 271, + 146, + 386, + 49, + 334, + 113, + 254, + 25, + 313, + 107, + 252, + 45, + 250, + 138, + 208, + 87, + 388, + 121, + 310, + 39, + 360, + 27, + 357, + 42, + 278, + 135, + 294, + 84, + 324, + 343, + 172, + 354, + 180, + 374, + 22, + 259, + 117, + 263, + 4, + 327, + 109, + 182, + 188, + 356, + 76, + 379, + 377, + 173, + 234, + 38, + 298, + 175, + 218, + 91, + 239, + 81, + 313, + 102, + 377, + 91, + 215, + 151, + 257, + 77, + 388, + 122, + 343, + 10, + 323, + 141, + 377, + 40, + 364, + 190, + 202, + 65, + 326, + 36, + 254, + 53, + 395, + 128, + 220, + 63, + 326, + 55, + 334, + 128, + 284, + 19, + 216, + 138, + 205, + 8, + 290, + 34, + 222, + 24, + 303, + 200, + 255, + 99, + 239, + 55, + 289, + 71, + 237, + 199, + 231, + 32, + 309, + 45, + 223, + 109, + 318, + 34, + 310, + 118, + 311, + 8, + 333, + 103, + 214, + 55, + 229, + 154, + 209, + 53, + 271, + 108, + 390, + 57, + 135, + 36, + 371, + 162, + 25, + 115, + 40, + 13, + 240, + 80, + 108, + 275, + 59, + 32, + 399, + 52, + 317, + 98, + 337, + 120, + 252, + 59, + 209, + 18, + 259, + 2, + 248, + 35, + 375, + 31, + 233, + 190, + 242, + 251, + 243, + 80, + 218, + 192, + 263, + 148, + 223, + 368, + 163, + 230, + 48, + 262, + 134, + 331, + 68, + 272, + 390, + 298, + 323, + 262, + 272, + 187, + 336, + 66, + 373, + 166, + 217, + 82, + 257, + 259, + 297, + 213, + 225, + 320, + 288, + 154, + 227, + 99, + 210, + 164, + 289, + 165, + 226, + 189, + 250, + 313, + 105, + 386, + 399, + 191, + 310, + 338, + 314, + 155, + 228, + 232, + 386, + 165, + 256, + 331, + 80, + 320, + 131, + 334, + 327, + 286, + 22, + 253, + 108, + 289, + 77, + 208, + 118, + 310, + 45, + 398, + 164, + 341, + 50, + 362, + 109, + 353, + 36, + 205, + 181, + 326, + 91, + 304, + 188, + 395, + 131, + 328, + 337, + 392, + 145, + 263, + 258, + 245, + 130, + 284, + 372, + 233, + 286, + 348, + 38, + 335, + 214, + 241, + 277, + 85, + 264, + 172, + 55, + 355, + 118, + 376, + 47, + 228, + 182, + 291, + 35, + 229, + 126, + 384, + 5, + 234, + 109, + 296, + 4, + 272, + 134, + 84, + 286, + 188, + 22, + 192, + 89, + 187, + 339, + 77, + 180, + 77, + 239, + 110, + 349, + 172, + 225, + 74, + 348, + 125, + 357, + 79, + 225, + 101, + 387, + 4, + 398, + 123, + 226, + 166, + 347, + 55, + 165, + 96, + 299, + 144, + 209, + 75, + 385, + 153, + 348, + 68, + 324, + 135, + 217, + 75, + 367, + 146, + 261, + 12, + 399, + 126, + 220, + 62, + 300, + 120, + 286, + 40, + 270, + 86, + 24, + 388, + 189, + 252, + 137, + 279, + 148, + 145, + 219, + 107, + 305, + 272, + 58, + 370, + 156, + 302, + 17, + 292, + 37, + 398, + 72, + 261, + 130, + 319, + 26, + 346, + 35, + 69, + 188, + 300, + 31, + 306, + 120, + 225, + 86, + 267, + 105, + 344, + 19, + 314, + 148, + 365, + 46, + 376, + 148, + 265, + 20, + 267, + 181, + 235, + 27, + 208, + 124, + 238, + 64, + 339, + 156, + 284, + 29, + 327, + 161, + 285, + 31, + 377, + 5, + 267, + 238, + 305, + 389, + 10, + 380, + 104, + 204, + 92, + 354, + 154, + 239, + 33, + 273, + 155, + 366, + 71, + 373, + 186, + 319, + 46, + 247, + 120, + 217, + 78, + 343, + 122, + 205, + 190, + 2, + 368, + 183, + 67, + 292, + 198, + 368, + 40, + 245, + 113, + 359, + 33, + 244, + 187, + 240, + 34, + 286, + 178, + 292, + 71, + 384, + 166, + 288, + 81, + 317, + 190, + 32, + 261, + 111, + 242, + 14, + 248, + 157, + 212, + 84, + 218, + 66, + 261, + 143, + 253, + 83, + 358, + 139, + 382, + 7, + 235, + 160, + 271, + 100, + 286, + 114, + 318, + 76, + 354, + 101, + 292, + 78, + 285, + 182, + 291, + 55, + 350, + 195, + 325, + 6, + 301, + 195, + 210, + 35, + 215, + 12, + 308, + 97, + 273, + 156, + 278, + 80, + 246, + 184, + 268, + 67, + 294, + 172, + 374, + 98, + 228, + 171, + 307, + 81, + 392, + 33, + 231, + 21, + 294, + 308, + 348, + 203, + 333, + 351, + 219, + 272, + 267, + 225, + 152, + 307, + 47, + 221, + 128, + 339, + 313, + 66, + 369, + 60, + 368, + 52, + 103, + 125, + 269, + 78, + 147, + 157, + 96, + 384, + 124, + 385, + 132, + 299, + 103, + 277, + 166, + 276, + 208, + 325, + 91, + 353, + 184, + 369, + 8, + 290, + 169, + 202, + 23, + 293, + 78, + 388, + 178, + 229, + 37, + 278, + 169, + 391, + 60, + 206, + 174, + 377, + 70, + 400, + 196, + 257, + 31, + 384, + 1, + 312, + 39, + 219, + 199, + 376, + 85, + 345, + 178, + 88, + 31, + 11, + 80, + 53, + 119, + 204, + 15, + 329, + 197, + 213, + 50, + 379, + 149, + 221, + 76, + 226, + 143, + 85, + 57, + 3, + 392, + 160, + 69, + 135, + 339, + 83, + 347, + 197, + 180, + 69, + 48, + 237, + 73, + 58, + 294, + 138, + 364, + 39, + 282, + 100, + 244, + 161, + 293, + 37, + 315, + 160, + 377, + 76, + 262, + 34, + 327, + 99, + 329, + 27, + 284, + 52, + 374, + 155, + 325, + 99, + 242, + 111, + 383, + 29, + 322, + 120, + 225, + 50, + 376, + 130, + 299, + 46, + 362, + 21, + 326, + 332, + 305, + 227, + 325, + 129, + 262, + 11, + 332, + 229, + 365, + 374, + 25, + 310, + 172, + 391, + 100, + 286, + 357, + 315, + 283, + 338, + 136, + 233, + 23, + 356, + 166, + 283, + 302, + 271, + 209, + 340, + 74, + 377, + 108, + 345, + 83, + 328, + 181, + 287, + 86, + 382, + 144, + 359, + 50, + 336, + 185, + 321, + 3, + 313, + 166, + 363, + 1, + 231, + 165, + 384, + 23, + 385, + 194, + 381, + 79, + 354, + 182, + 266, + 26, + 216, + 135, + 313, + 130, + 370, + 105, + 396, + 131, + 205, + 42, + 207, + 9, + 271, + 367, + 257, + 322, + 137, + 278, + 99, + 258, + 22, + 221, + 321, + 105, + 168, + 349, + 196, + 360, + 133, + 323, + 35, + 310, + 106, + 292, + 87, + 309, + 127, + 202, + 187, + 355, + 398, + 281, + 157, + 241, + 259, + 247, + 279, + 256, + 131, + 400, + 105, + 400, + 169, + 307, + 158, + 204, + 131, + 303, + 162, + 397, + 190, + 204, + 105, + 341, + 163, + 244, + 179, + 331, + 62, + 270, + 232, + 304, + 378, + 145, + 317, + 318, + 374, + 254, + 212, + 331, + 367, + 306, + 91, + 230, + 119, + 387, + 139, + 249, + 361, + 91, + 256, + 179, + 393, + 115, + 245, + 195, + 374, + 255, + 128, + 266, + 121, + 324, + 4, + 274, + 320, + 398, + 327, + 330, + 231, + 39, + 297, + 139, + 230, + 61, + 293, + 198, + 282, + 51, + 366, + 188, + 276, + 78, + 380, + 140, + 361, + 64, + 279, + 200, + 347, + 66, + 395, + 153, + 7, + 103, + 52, + 227, + 181, + 353, + 21, + 326, + 195, + 327, + 37, + 287, + 118, + 317, + 28, + 379, + 186, + 382, + 40, + 352, + 173, + 383, + 94, + 213, + 178, + 313, + 200, + 400, + 7, + 252, + 114, + 296, + 48, + 377, + 103, + 201, + 215, + 372, + 368, + 257, + 61, + 349, + 115, + 274, + 89, + 212, + 47, + 231, + 200, + 260, + 69, + 303, + 146, + 303, + 49, + 360, + 157, + 235, + 97, + 193, + 156, + 348, + 64, + 257, + 115, + 362, + 73, + 243, + 178, + 330, + 102, + 36, + 166, + 153, + 64, + 175, + 7, + 198, + 70, + 296, + 195, + 51, + 176, + 274, + 138, + 253, + 144, + 263, + 127, + 246, + 6, + 278, + 167, + 361, + 7, + 124, + 86, + 103, + 216, + 85, + 376, + 176, + 72, + 88, + 69, + 82, + 394, + 151, + 258, + 43, + 371, + 109, + 329, + 1, + 203, + 110, + 361, + 78, + 250, + 177, + 325, + 50, + 398, + 8, + 322, + 90, + 391, + 31, + 358, + 30, + 260, + 81, + 224, + 132, + 219, + 52, + 337, + 193, + 229, + 90, + 274, + 162, + 109, + 246, + 159, + 260, + 70, + 352, + 110, + 328, + 83, + 375, + 171, + 298, + 10, + 314, + 126, + 246, + 42, + 250, + 160, + 201, + 6, + 205, + 57, + 44, + 143, + 65, + 106, + 65, + 192, + 71, + 307, + 106, + 294, + 48, + 257, + 174, + 203, + 66, + 372, + 179, + 251, + 21, + 356, + 134, + 301, + 6, + 245, + 190, + 362, + 79, + 305, + 138, + 210, + 1, + 239, + 39, + 203, + 75, + 311, + 80, + 330, + 9, + 332, + 196, + 247, + 2, + 369, + 174, + 292, + 311, + 154, + 272, + 78, + 212, + 355, + 257, + 249, + 197, + 357, + 79, + 241, + 106, + 363, + 82, + 243, + 103, + 257, + 79, + 330, + 132, + 205, + 18, + 293, + 322, + 299, + 198, + 231, + 22, + 357, + 114, + 240, + 23, + 351, + 105, + 323, + 74, + 233, + 121, + 127, + 186, + 326, + 168, + 221, + 357, + 347, + 149, + 370, + 82, + 324, + 108, + 325, + 38, + 233, + 162, + 244, + 194, + 394, + 3, + 223, + 191, + 204, + 32, + 379, + 114, + 264, + 212, + 385, + 1, + 278, + 175, + 267, + 25, + 344, + 110, + 238, + 21, + 288, + 148, + 236, + 98, + 126, + 28, + 138, + 53, + 180, + 209, + 68, + 142, + 23, + 169, + 14, + 162, + 248, + 42, + 107, + 377, + 58, + 399, + 181, + 276, + 6, + 284, + 117, + 293, + 264, + 197, + 334, + 30, + 380, + 39, + 216, + 126, + 222, + 12, + 328, + 126, + 217, + 17, + 226, + 168, + 257, + 148, + 275, + 157, + 276, + 114, + 342, + 40, + 379, + 125, + 228, + 28, + 280, + 84, + 149, + 19, + 59, + 385, + 107, + 243, + 2, + 324, + 191, + 213, + 186, + 255, + 92, + 300, + 150, + 254, + 8, + 242, + 193, + 253, + 82, + 361, + 165, + 330, + 21, + 374, + 153, + 240, + 77, + 261, + 159, + 257, + 27, + 293, + 161, + 228, + 31, + 369, + 139, + 324, + 20, + 330, + 155, + 226, + 79, + 394, + 187, + 298, + 92, + 253, + 160, + 287, + 152, + 217, + 157, + 202, + 124, + 359, + 138, + 230, + 1, + 330, + 156, + 319, + 82, + 283, + 182, + 342, + 184, + 229, + 141, + 314, + 135, + 383, + 344, + 296, + 162, + 353, + 37, + 218, + 156, + 209, + 17, + 262, + 136, + 239, + 309, + 132, + 221, + 201, + 81, + 391, + 395, + 390, + 206, + 227, + 395, + 35, + 208, + 357, + 151, + 240, + 89, + 220, + 155, + 279, + 383, + 70, + 221, + 34, + 282, + 99, + 268, + 186, + 376, + 61, + 290, + 189, + 382, + 88, + 173, + 248, + 9, + 175, + 17, + 330, + 67, + 254, + 25, + 245, + 54, + 125, + 76, + 78, + 212, + 138, + 361, + 40, + 209, + 160, + 232, + 184, + 343, + 78, + 354, + 105, + 221, + 15, + 319, + 146, + 100, + 232, + 142, + 180, + 120, + 339, + 132, + 335, + 84, + 396, + 146, + 296, + 126, + 279, + 163, + 241, + 187, + 373, + 143, + 226, + 22, + 382, + 110, + 329, + 13, + 333, + 182, + 274, + 161, + 181, + 266, + 84, + 394, + 174, + 294, + 87, + 219, + 166, + 201, + 90, + 235, + 181, + 346, + 93, + 385, + 152, + 385, + 91, + 283, + 110, + 298, + 74, + 245, + 199, + 374, + 107, + 312, + 10, + 251, + 136, + 252, + 170, + 382, + 140, + 280, + 183, + 395, + 374, + 330, + 234, + 381, + 344, + 369, + 263, + 244, + 141, + 398, + 247, + 235, + 16, + 238, + 158, + 284, + 52, + 288, + 197, + 392, + 75, + 204, + 166, + 260, + 35, + 258, + 23, + 319, + 277, + 162, + 273, + 33, + 144, + 92, + 358, + 72, + 235, + 79, + 91, + 47, + 380, + 120, + 201, + 47, + 193, + 302, + 181, + 250, + 49, + 115, + 121, + 278, + 69, + 348, + 178, + 395, + 145, + 218, + 44, + 349, + 168, + 248, + 109, + 345, + 167, + 271, + 115, + 334, + 157, + 272, + 100, + 274, + 103, + 214, + 61, + 272, + 163, + 277, + 24, + 264, + 199, + 369, + 37, + 336, + 186, + 260, + 61, + 378, + 146, + 324, + 83, + 288, + 180, + 283, + 50, + 369, + 148, + 382, + 92, + 316, + 127, + 251, + 89, + 321, + 67, + 359, + 31, + 318, + 23, + 327, + 376, + 245, + 369, + 311, + 283, + 43, + 361, + 243, + 396, + 38, + 204, + 201, + 200, + 365, + 330, + 147, + 243, + 120, + 66, + 377, + 183, + 222, + 58, + 344, + 39, + 385, + 194, + 236, + 5, + 250, + 103, + 247, + 68, + 258, + 21, + 337, + 341, + 273, + 389, + 199, + 300, + 74, + 253, + 13, + 358, + 58, + 354, + 224, + 87, + 355, + 44, + 217, + 85, + 214, + 24, + 341, + 103, + 303, + 31, + 203, + 47, + 311, + 199, + 367, + 59, + 262, + 192, + 242, + 59, + 253, + 198, + 359, + 25, + 226, + 70, + 366, + 67, + 357, + 24, + 329, + 180, + 290, + 41, + 222, + 148, + 244, + 89, + 306, + 105, + 305, + 147, + 213, + 37, + 309, + 173, + 279, + 11, + 394, + 193, + 308, + 74, + 257, + 198, + 322, + 46, + 246, + 3, + 315, + 113, + 381, + 332, + 383, + 18, + 267, + 21, + 236, + 258, + 386, + 15, + 279, + 61, + 269, + 151, + 205, + 16, + 318, + 188, + 359, + 52, + 212, + 97, + 242, + 240, + 289, + 328, + 266, + 135, + 143, + 210, + 199, + 307, + 214, + 10, + 47, + 148, + 254, + 389, + 185, + 379, + 124, + 291, + 136, + 370, + 14, + 263, + 130, + 348, + 27, + 338, + 171, + 229, + 1, + 298, + 184, + 43, + 293, + 126, + 224, + 6, + 276, + 150, + 397, + 61, + 396, + 189, + 330, + 27, + 323, + 180, + 66, + 270, + 156, + 18, + 166, + 3, + 108, + 28, + 159, + 364, + 37, + 380, + 146, + 64, + 141, + 290, + 39, + 130, + 63, + 374, + 155, + 328, + 24, + 274, + 138, + 280, + 29, + 303, + 99, + 296, + 89, + 223, + 75, + 229, + 13, + 309, + 7, + 219, + 87, + 273, + 111, + 317, + 25, + 328, + 109, + 345, + 17, + 291, + 168, + 267, + 29, + 383, + 189, + 263, + 37, + 251, + 90, + 351, + 385, + 7, + 228, + 20, + 278, + 199, + 273, + 18, + 377, + 171, + 221, + 11, + 228, + 138, + 335, + 179, + 201, + 192, + 277, + 170, + 316, + 112, + 387, + 100, + 350, + 161, + 312, + 112, + 385, + 69, + 303, + 126, + 217, + 16, + 374, + 156, + 227, + 181, + 396, + 114, + 226, + 353, + 220, + 294, + 331, + 257, + 126, + 248, + 85, + 328, + 200, + 331, + 81, + 339, + 124, + 381, + 87, + 343, + 144, + 396, + 197, + 338, + 155, + 283, + 159, + 273, + 59, + 229, + 118, + 367, + 38, + 345, + 146, + 329, + 94, + 260, + 114, + 313, + 4, + 248, + 117, + 328, + 94, + 210, + 46, + 351, + 130, + 379, + 30, + 275, + 149, + 298, + 93, + 337, + 49, + 344, + 353, + 171, + 397, + 54, + 205, + 47, + 216, + 278, + 331, + 265, + 48, + 363, + 3, + 78, + 260, + 179, + 247, + 67, + 243, + 9, + 320, + 166, + 257, + 36, + 317, + 130, + 208, + 38, + 102, + 33, + 192, + 161, + 351, + 60, + 318, + 326, + 198, + 170, + 12, + 122, + 386, + 398, + 25, + 314, + 143, + 291, + 63, + 398, + 157, + 367, + 35, + 375, + 314, + 123, + 303, + 82, + 370, + 180, + 247, + 72, + 267, + 129, + 338, + 180, + 259, + 62, + 329, + 158, + 281, + 87, + 283, + 181, + 223, + 60, + 304, + 155, + 383, + 77, + 400, + 184, + 282, + 69, + 255, + 102, + 333, + 63, + 315, + 126, + 394, + 32, + 201, + 164, + 229, + 96, + 347, + 118, + 305, + 16, + 204, + 199, + 377, + 155, + 392, + 181, + 322, + 7, + 385, + 121, + 205, + 37, + 193, + 8, + 112, + 189, + 315, + 136, + 375, + 112, + 376, + 213, + 140, + 385, + 25, + 271, + 163, + 352, + 14, + 257, + 101, + 213, + 83, + 248, + 91, + 313, + 352, + 180, + 6, + 51, + 290, + 144, + 316, + 13, + 340, + 356, + 379, + 97, + 378, + 14, + 340, + 157, + 126, + 254, + 288, + 46, + 234, + 7, + 222, + 270, + 323, + 320, + 346, + 271, + 201, + 269, + 246, + 34, + 298, + 127, + 272, + 70, + 232, + 113, + 218, + 86, + 242, + 115, + 278, + 93, + 266, + 156, + 314, + 26, + 222, + 110, + 361, + 361, + 76, + 112, + 82, + 10, + 344, + 85, + 309, + 122, + 392, + 68, + 374, + 112, + 303, + 38, + 201, + 120, + 282, + 40, + 277, + 119, + 393, + 90, + 396, + 196, + 21, + 155, + 342, + 36, + 325, + 59, + 399, + 28, + 78, + 47, + 42, + 209, + 228, + 330, + 159, + 285, + 87, + 389, + 148, + 204, + 70, + 289, + 166, + 344, + 20, + 320, + 122, + 223, + 64, + 205, + 154, + 245, + 393, + 279, + 80, + 319, + 370, + 121, + 316, + 11, + 396, + 317, + 104, + 329, + 85, + 353, + 135, + 245, + 168, + 322, + 382, + 325, + 241, + 214, + 327, + 389, + 140, + 335, + 126, + 271, + 187, + 236, + 309, + 220, + 263, + 51, + 228, + 109, + 400, + 89, + 233, + 66, + 243, + 359, + 213, + 335, + 220, + 209, + 280, + 24, + 282, + 5, + 352, + 2, + 208, + 137, + 247, + 36, + 344, + 188, + 271, + 26, + 129, + 45, + 326, + 193, + 291, + 168, + 364, + 345, + 17, + 208, + 154, + 202, + 19, + 225, + 171, + 244, + 98, + 341, + 120, + 302, + 42, + 275, + 152, + 251, + 15, + 340, + 188, + 393, + 87, + 359, + 111, + 333, + 46, + 388, + 114, + 376, + 89, + 277, + 134, + 259, + 42, + 346, + 184, + 298, + 93, + 275, + 107, + 268, + 81, + 282, + 129, + 213, + 4, + 246, + 188, + 234, + 81, + 395, + 166, + 303, + 110, + 306, + 112, + 345, + 83, + 316, + 29, + 334, + 65, + 386, + 73, + 242, + 333, + 203, + 196, + 381, + 169, + 222, + 106, + 391, + 156, + 251, + 126, + 391, + 195, + 246, + 197, + 330, + 263, + 53, + 242, + 134, + 312, + 219, + 184, + 368, + 11, + 388, + 86, + 279, + 182, + 258, + 58, + 321, + 172, + 28, + 242, + 112, + 362, + 50, + 295, + 116, + 332, + 23, + 228, + 183, + 289, + 65, + 274, + 161, + 214, + 56, + 379, + 107, + 211, + 36, + 374, + 174, + 330, + 80, + 371, + 104, + 218, + 80, + 154, + 46, + 266, + 118, + 82, + 379, + 118, + 327, + 61, + 359, + 180, + 286, + 36, + 354, + 102, + 394, + 1, + 151, + 207, + 73, + 379, + 155, + 374, + 17, + 331, + 15, + 246, + 75, + 327, + 9, + 234, + 339, + 88, + 349, + 277, + 16, + 268, + 202, + 105, + 323, + 22, + 241, + 172, + 284, + 30, + 374, + 188, + 392, + 86, + 319, + 136, + 234, + 20, + 253, + 127, + 265, + 86, + 382, + 161, + 283, + 19, + 385, + 195, + 394, + 37, + 327, + 111, + 239, + 13, + 340, + 140, + 296, + 80, + 332, + 132, + 256, + 63, + 398, + 170, + 359, + 27, + 356, + 123, + 295, + 85, + 260, + 144, + 354, + 43, + 398, + 126, + 274, + 66, + 342, + 147, + 268, + 65, + 272, + 142, + 224, + 46, + 292, + 112, + 341, + 73, + 390, + 122, + 202, + 43, + 311, + 154, + 17, + 192, + 325, + 89, + 202, + 42, + 214, + 121, + 225, + 6, + 54, + 41, + 288, + 78, + 351, + 52, + 391, + 138, + 339, + 73, + 378, + 109, + 293, + 366, + 355, + 188, + 219, + 22, + 377, + 115, + 219, + 353, + 226, + 241, + 234, + 352, + 57, + 306, + 149, + 221, + 28, + 219, + 158, + 343, + 16, + 313, + 163, + 326, + 66, + 350, + 122, + 292, + 25, + 395, + 149, + 256, + 15, + 335, + 170, + 233, + 4, + 218, + 121, + 271, + 16, + 366, + 188, + 265, + 72, + 202, + 182, + 206, + 100, + 301, + 112, + 374, + 26, + 312, + 262, + 35, + 227, + 67, + 358, + 25, + 289, + 50, + 276, + 398, + 123, + 334, + 23, + 293, + 380, + 146, + 349, + 31, + 283, + 177, + 307, + 46, + 273, + 173, + 132, + 110, + 122, + 312, + 58, + 347, + 195, + 303, + 2, + 278, + 151, + 216, + 49, + 204, + 69, + 380, + 97, + 224, + 132, + 287, + 84, + 370, + 56, + 214, + 105, + 383, + 37, + 218, + 163, + 345, + 33, + 318, + 4, + 395, + 83, + 384, + 16, + 237, + 226, + 260, + 295, + 315, + 326, + 202, + 181, + 267, + 195, + 318, + 178, + 212, + 96, + 229, + 138, + 261, + 49, + 227, + 190, + 228, + 24, + 393, + 164, + 385, + 10, + 281, + 130, + 231, + 87, + 116, + 347, + 37, + 271, + 195, + 223, + 41, + 247, + 294, + 238, + 313, + 323, + 290, + 141, + 391, + 54, + 163, + 48, + 347, + 184, + 62, + 198, + 344, + 66, + 154, + 32, + 233, + 52, + 362, + 172, + 275, + 68, + 283, + 78, + 203, + 101, + 240, + 84, + 336, + 154, + 354, + 59, + 239, + 145, + 345, + 13, + 292, + 135, + 320, + 100, + 349, + 189, + 233, + 82, + 390, + 196, + 289, + 1, + 310, + 46, + 315, + 19, + 326, + 130, + 286, + 67, + 394, + 32, + 281, + 98, + 201, + 162, + 345, + 24, + 375, + 179, + 347, + 85, + 344, + 155, + 241, + 50, + 273, + 175, + 234, + 35, + 356, + 155, + 243, + 57, + 332, + 8, + 250, + 28, + 337, + 12, + 15, + 35, + 22, + 348, + 133, + 212, + 84, + 328, + 152, + 223, + 66, + 320, + 121, + 228, + 79, + 236, + 126, + 218, + 14, + 346, + 117, + 370, + 72, + 266, + 132, + 391, + 69, + 207, + 165, + 251, + 182, + 376, + 21, + 336, + 121, + 262, + 43, + 330, + 116, + 246, + 46, + 383, + 40, + 266, + 2, + 389, + 195, + 344, + 19, + 378, + 113, + 208, + 83, + 250, + 159, + 201, + 29, + 372, + 108, + 303, + 55, + 225, + 143, + 369, + 37, + 139, + 222, + 81, + 110, + 294, + 95, + 339, + 171, + 277, + 78, + 320, + 119, + 374, + 95, + 296, + 180, + 367, + 19, + 327, + 112, + 321, + 62, + 297, + 240, + 377, + 22, + 296, + 43, + 232, + 68, + 314, + 112, + 252, + 72, + 388, + 153, + 304, + 7, + 211, + 200, + 326, + 73, + 197, + 22, + 246, + 13, + 305, + 304, + 56, + 221, + 397, + 245, + 144, + 246, + 93, + 266, + 140, + 256, + 97, + 273, + 165, + 347, + 186, + 212, + 11, + 228, + 177, + 305, + 68, + 334, + 126, + 244, + 33, + 326, + 193, + 396, + 30, + 284, + 122, + 298, + 31, + 366, + 113, + 293, + 53, + 173, + 26, + 56, + 97, + 50, + 35, + 344, + 144, + 13, + 383, + 141, + 337, + 101, + 341, + 376, + 360, + 104, + 263, + 3, + 314, + 124, + 346, + 23, + 318, + 46, + 338, + 50, + 249, + 270, + 205, + 232, + 175, + 263, + 63, + 340, + 163, + 354, + 25, + 387, + 186, + 242, + 16, + 355, + 128, + 309, + 87, + 195, + 99, + 332, + 184, + 131, + 125, + 305, + 60, + 303, + 154, + 348, + 58, + 374, + 257, + 372, + 315, + 312, + 125, + 195, + 322, + 113, + 389, + 162, + 350, + 14, + 217, + 48, + 224, + 33, + 239, + 191, + 206, + 35, + 330, + 178, + 287, + 86, + 228, + 101, + 372, + 61, + 313, + 67, + 237, + 32, + 211, + 141, + 396, + 49, + 385, + 128, + 331, + 66, + 286, + 148, + 324, + 11, + 282, + 200, + 313, + 2, + 299, + 174, + 269, + 75, + 399, + 102, + 395, + 80, + 329, + 194, + 328, + 147, + 364, + 67, + 357, + 125, + 345, + 57, + 307, + 132, + 312, + 6, + 400, + 126, + 327, + 90, + 352, + 155, + 288, + 146, + 220, + 144, + 289, + 200, + 354, + 77, + 241, + 118, + 312, + 13, + 223, + 131, + 388, + 1, + 318, + 134, + 280, + 63, + 206, + 55, + 377, + 338, + 27, + 373, + 357, + 133, + 324, + 2, + 288, + 151, + 371, + 77, + 245, + 151, + 203, + 98, + 328, + 142, + 377, + 33, + 304, + 174, + 327, + 40, + 124, + 25, + 133, + 80, + 151, + 151, + 212, + 31, + 141, + 60, + 75, + 179, + 106, + 103, + 300, + 164, + 239, + 121, + 221, + 305, + 351, + 296, + 375, + 231, + 222, + 299, + 20, + 348, + 80, + 332, + 286, + 147, + 259, + 1, + 371, + 178, + 327, + 319, + 272, + 245, + 247, + 300, + 344, + 138, + 207, + 3, + 235, + 159, + 300, + 52, + 276, + 115, + 370, + 166, + 345, + 62, + 290, + 110, + 355, + 198, + 239, + 77, + 238, + 158, + 332, + 63, + 238, + 158, + 258, + 64, + 374, + 107, + 309, + 127, + 222, + 172, + 212, + 132, + 292, + 187, + 307, + 154, + 306, + 75, + 208, + 136, + 388, + 86, + 379, + 197, + 255, + 79, + 150, + 24, + 193, + 72, + 126, + 128, + 145, + 211, + 173, + 258, + 286, + 25, + 125, + 370, + 176, + 235, + 129, + 390, + 155, + 223, + 3, + 337, + 178, + 292, + 3, + 201, + 151, + 263, + 92, + 251, + 155, + 267, + 29, + 360, + 81, + 382, + 7, + 384, + 148, + 43, + 152, + 212, + 87, + 246, + 181, + 227, + 92, + 304, + 180, + 201, + 185, + 260, + 72, + 331, + 41, + 344, + 98, + 326, + 86, + 282, + 191, + 354, + 88, + 251, + 147, + 364, + 34, + 230, + 120, + 249, + 51, + 368, + 194, + 374, + 95, + 380, + 108, + 393, + 64, + 222, + 147, + 300, + 134, + 391, + 274, + 293, + 390, + 232, + 354, + 311, + 329, + 208, + 204, + 364, + 339, + 247, + 342, + 233, + 55, + 330, + 143, + 264, + 383, + 9, + 341, + 96, + 246, + 237, + 120, + 312, + 68, + 326, + 134, + 323, + 314, + 393, + 288, + 48, + 322, + 189, + 326, + 322, + 69, + 258, + 37, + 300, + 165, + 322, + 299, + 376, + 156, + 224, + 51, + 126, + 289, + 48, + 395, + 173, + 312, + 48, + 346, + 227, + 270, + 200, + 387, + 295, + 278, + 185, + 225, + 20, + 350, + 135, + 380, + 4, + 353, + 180, + 332, + 194, + 224, + 106, + 285, + 90, + 215, + 161, + 369, + 50, + 325, + 168, + 273, + 65, + 349, + 137, + 306, + 5, + 227, + 129, + 36, + 165, + 280, + 173, + 325, + 170, + 288, + 218, + 86, + 393, + 190, + 378, + 95, + 223, + 136, + 314, + 76, + 398, + 137, + 384, + 90, + 317, + 76, + 324, + 100, + 324, + 105, + 215, + 35, + 331, + 130, + 395, + 330, + 336, + 332, + 322, + 85, + 126, + 393, + 80, + 394, + 140, + 345, + 50, + 180, + 239, + 9, + 175, + 14, + 95, + 317, + 52, + 330, + 150, + 134, + 221, + 46, + 266, + 143, + 297, + 39, + 276, + 105, + 344, + 94, + 299, + 112, + 258, + 83, + 335, + 190, + 390, + 69, + 285, + 112, + 364, + 43, + 376, + 173, + 214, + 8, + 217, + 106, + 137, + 127, + 5, + 121, + 60, + 214, + 190, + 94, + 277, + 188, + 149, + 183, + 128, + 224, + 119, + 272, + 40, + 240, + 113, + 394, + 27, + 144, + 22, + 226, + 132, + 33, + 31, + 35, + 309, + 112, + 385, + 79, + 393, + 159, + 246, + 80, + 359, + 144, + 316, + 38, + 234, + 168, + 223, + 8, + 387, + 134, + 204, + 55, + 217, + 199, + 81, + 257, + 119, + 205, + 97, + 236, + 186, + 358, + 18, + 288, + 50, + 244, + 189, + 248, + 2, + 348, + 5, + 215, + 65, + 222, + 24, + 239, + 45, + 252, + 376, + 158, + 379, + 27, + 361, + 181, + 394, + 35, + 234, + 116, + 201, + 97, + 282, + 177, + 317, + 37, + 246, + 36, + 272, + 45, + 291, + 308, + 176, + 248, + 57, + 353, + 8, + 322, + 81, + 235, + 15, + 240, + 97, + 247, + 37, + 253, + 86, + 379, + 3, + 398, + 35, + 365, + 47, + 313, + 5, + 268, + 181, + 291, + 135, + 208, + 113, + 348, + 119, + 355, + 38, + 290, + 136, + 14, + 119, + 70, + 137, + 100, + 320, + 168, + 73, + 125, + 82, + 46, + 22, + 354, + 28, + 257, + 156, + 305, + 30, + 237, + 184, + 265, + 88, + 197, + 216, + 32, + 324, + 135, + 388, + 97, + 357, + 40, + 371, + 173, + 290, + 155, + 357, + 100, + 336, + 147, + 334, + 105, + 332, + 114, + 351, + 108, + 331, + 375, + 278, + 352, + 250, + 43, + 278, + 169, + 329, + 32, + 368, + 149, + 240, + 7, + 374, + 102, + 268, + 46, + 386, + 80, + 277, + 71, + 294, + 392, + 157, + 379, + 141, + 207, + 130, + 51, + 172, + 61, + 102, + 364, + 74, + 288, + 134, + 274, + 58, + 126, + 123, + 366, + 277, + 348, + 315, + 50, + 213, + 20, + 34, + 369, + 3, + 393, + 68, + 129, + 97, + 282, + 195, + 257, + 151, + 277, + 237, + 106, + 327, + 265, + 236, + 64, + 252, + 144, + 298, + 20, + 389, + 179, + 217, + 189, + 128, + 347, + 93, + 305, + 129, + 363, + 166, + 377, + 59, + 350, + 147, + 357, + 76, + 302, + 177, + 222, + 25, + 392, + 178, + 300, + 56, + 331, + 157, + 291, + 80, + 106, + 33, + 57, + 213, + 195, + 231, + 123, + 308, + 21, + 256, + 196, + 372, + 388, + 39, + 240, + 251, + 94, + 360, + 61, + 396, + 327, + 269, + 358, + 322, + 179, + 301, + 81, + 319, + 62, + 301, + 86, + 234, + 15, + 311, + 183, + 333, + 10, + 288, + 116, + 273, + 5, + 285, + 146, + 345, + 6, + 362, + 185, + 48, + 371, + 80, + 343, + 343, + 137, + 284, + 373, + 255, + 48, + 233, + 153, + 327, + 273, + 261, + 215, + 49, + 292, + 117, + 315, + 78, + 383, + 70, + 328, + 180, + 203, + 68, + 230, + 10, + 296, + 264, + 202, + 255, + 334, + 397, + 45, + 356, + 186, + 356, + 60, + 317, + 151, + 386, + 149, + 345, + 240, + 221, + 83, + 204, + 22, + 304, + 174, + 337, + 93, + 311, + 120, + 274, + 74, + 276, + 291, + 202, + 212, + 388, + 206, + 270, + 263, + 358, + 374, + 306, + 6, + 355, + 80, + 285, + 118, + 380, + 94, + 152, + 19, + 185, + 115, + 253, + 184, + 382, + 24, + 327, + 169, + 349, + 352, + 2, + 202, + 249, + 318, + 349, + 103, + 385, + 370, + 161, + 348, + 166, + 284, + 307, + 219, + 369, + 138, + 232, + 11, + 236, + 151, + 14, + 28, + 49, + 163, + 51, + 318, + 149, + 362, + 96, + 364, + 133, + 47, + 113, + 371, + 100, + 310, + 181, + 317, + 34, + 204, + 199, + 326, + 14, + 399, + 106, + 8, + 346, + 185, + 126, + 342, + 17, + 321, + 395, + 129, + 381, + 34, + 301, + 127, + 380, + 136, + 260, + 258, + 387, + 281, + 83, + 208, + 393, + 392, + 212, + 144, + 193, + 263, + 195, + 208, + 53, + 381, + 116, + 241, + 51, + 353, + 143, + 273, + 14, + 396, + 109, + 353, + 69, + 333, + 199, + 373, + 56, + 222, + 186, + 247, + 10, + 342, + 149, + 253, + 1, + 358, + 108, + 362, + 43, + 217, + 164, + 283, + 20, + 201, + 118, + 374, + 53, + 329, + 194, + 346, + 17, + 285, + 115, + 309, + 45, + 312, + 175, + 306, + 35, + 307, + 147, + 244, + 99, + 118, + 81, + 142, + 85, + 176, + 353, + 32, + 310, + 164, + 282, + 169, + 204, + 59, + 225, + 19, + 229, + 31, + 209, + 108, + 332, + 243, + 207, + 363, + 388, + 392, + 377, + 267, + 249, + 286, + 153, + 351, + 91, + 283, + 129, + 18, + 124, + 8, + 207, + 177, + 334, + 137, + 116, + 160, + 349, + 53, + 126, + 233, + 315, + 363, + 75, + 368, + 101, + 186, + 127, + 31, + 122, + 157, + 241, + 88, + 225, + 132, + 65, + 397, + 114, + 261, + 129, + 314, + 1, + 203, + 142, + 346, + 120, + 263, + 274, + 285, + 257, + 206, + 338, + 19, + 293, + 102, + 267, + 181, + 254, + 134, + 308, + 68, + 241, + 167, + 235, + 21, + 312, + 159, + 394, + 66, + 276, + 149, + 372, + 22, + 308, + 132, + 236, + 50, + 219, + 148, + 387, + 70, + 330, + 159, + 292, + 96, + 297, + 199, + 355, + 24, + 277, + 112, + 264, + 162, + 256, + 101, + 156, + 241, + 56, + 306, + 176, + 228, + 158, + 263, + 76, + 273, + 160, + 374, + 61, + 326, + 128, + 335, + 31, + 314, + 30, + 280, + 105, + 267, + 59, + 230, + 174, + 385, + 197, + 298, + 128, + 340, + 175, + 393, + 150, + 327, + 196, + 395, + 314, + 11, + 310, + 341, + 55, + 278, + 11, + 277, + 88, + 268, + 44, + 359, + 71, + 333, + 284, + 175, + 217, + 20, + 241, + 105, + 203, + 70, + 269, + 192, + 400, + 22, + 361, + 75, + 275, + 399, + 144, + 390, + 179, + 400, + 223, + 136, + 396, + 304, + 295, + 137, + 390, + 27, + 228, + 129, + 343, + 9, + 315, + 133, + 330, + 14, + 342, + 180, + 229, + 86, + 317, + 172, + 219, + 85, + 203, + 127, + 224, + 70, + 243, + 199, + 314, + 138, + 248, + 195, + 273, + 206, + 244, + 230, + 259, + 46, + 352, + 119, + 335, + 93, + 208, + 171, + 361, + 91, + 222, + 391, + 268, + 304, + 108, + 284, + 288, + 249, + 235, + 133, + 274, + 39, + 259, + 106, + 223, + 12, + 273, + 186, + 369, + 44, + 336, + 110, + 30, + 182, + 64, + 110, + 57, + 21, + 60, + 114, + 98, + 125, + 144, + 213, + 53, + 312, + 170, + 348, + 72, + 235, + 170, + 385, + 62, + 263, + 128, + 257, + 79, + 365, + 173, + 388, + 45, + 385, + 163, + 349, + 92, + 208, + 149, + 42, + 326, + 129, + 344, + 58, + 194, + 18, + 123, + 209, + 90, + 114, + 73, + 197, + 26, + 88, + 99, + 316, + 169, + 243, + 27, + 377, + 165, + 245, + 339, + 55, + 350, + 213, + 350, + 214, + 154, + 288, + 79, + 226, + 262, + 137, + 211, + 91, + 278, + 169, + 336, + 373, + 383, + 65, + 94, + 318, + 73, + 274, + 389, + 197, + 19, + 336, + 98, + 205, + 158, + 201, + 74, + 53, + 380, + 74, + 344, + 103, + 269, + 346, + 196, + 225, + 2, + 371, + 159, + 355, + 110, + 362, + 196, + 380, + 196, + 371, + 128, + 220, + 326, + 330, + 304, + 340, + 138, + 309, + 258, + 88, + 238, + 101, + 224, + 376, + 243, + 399, + 177, + 163, + 150, + 243, + 45, + 344, + 248, + 122, + 371, + 178, + 209, + 183, + 379, + 180, + 284, + 151, + 277, + 162, + 97, + 135, + 181, + 347, + 88, + 311, + 120, + 320, + 21, + 387, + 184, + 381, + 43, + 377, + 195, + 321, + 59, + 276, + 188, + 232, + 84, + 284, + 124, + 201, + 5, + 289, + 101, + 301, + 122, + 300, + 343, + 44, + 294, + 387, + 12, + 245, + 210, + 275, + 96, + 386, + 72, + 355, + 29, + 277, + 8, + 260, + 35, + 304, + 378, + 138, + 357, + 209, + 363, + 203, + 98, + 392, + 297, + 134, + 304, + 123, + 257, + 134, + 214, + 179, + 330, + 67, + 395, + 89, + 305, + 115, + 69, + 83, + 10, + 56, + 233, + 179, + 216, + 59, + 101, + 49, + 117, + 15, + 268, + 69, + 289, + 171, + 392, + 81, + 204, + 124, + 310, + 100, + 264, + 166, + 277, + 74, + 218, + 106, + 354, + 62, + 274, + 41, + 259, + 86, + 316, + 179, + 247, + 94, + 280, + 131, + 394, + 12, + 325, + 104, + 295, + 95, + 327, + 84, + 263, + 35, + 357, + 33, + 250, + 67, + 147, + 327, + 66, + 212, + 189, + 244, + 44, + 206, + 172, + 349, + 79, + 261, + 104, + 265, + 182, + 305, + 11, + 225, + 127, + 266, + 66, + 365, + 156, + 233, + 57, + 300, + 56, + 359, + 22, + 229, + 146, + 4, + 230, + 105, + 382, + 92, + 233, + 196, + 229, + 75, + 326, + 104, + 335, + 112, + 301, + 69, + 249, + 143, + 301, + 78, + 309, + 179, + 244, + 275, + 317, + 84, + 160, + 87, + 37, + 85, + 265, + 195, + 246, + 56, + 226, + 102, + 310, + 16, + 300, + 136, + 386, + 63, + 223, + 114, + 354, + 80, + 249, + 186, + 218, + 61, + 130, + 132, + 119, + 137, + 32, + 132, + 260, + 92, + 238, + 132, + 203, + 116, + 317, + 54, + 306, + 193, + 48, + 199, + 154, + 209, + 186, + 191, + 187, + 300, + 170, + 143, + 91, + 128, + 48, + 186, + 301, + 33, + 245, + 179, + 395, + 83, + 333, + 128, + 268, + 79, + 306, + 185, + 252, + 2, + 398, + 159, + 267, + 95, + 345, + 95, + 287, + 75, + 393, + 111, + 376, + 40, + 244, + 67, + 270, + 101, + 366, + 24, + 267, + 50, + 306, + 130, + 331, + 44, + 244, + 21, + 323, + 11, + 214, + 60, + 334, + 13, + 316, + 103, + 232, + 90, + 272, + 148, + 232, + 76, + 333, + 109, + 256, + 191, + 222, + 184, + 359, + 91, + 351, + 18, + 254, + 113, + 221, + 304, + 327, + 310, + 345, + 355, + 206, + 356, + 375, + 350, + 6, + 326, + 146, + 343, + 46, + 383, + 340, + 85, + 215, + 191, + 354, + 6, + 235, + 113, + 310, + 63, + 323, + 137, + 241, + 98, + 215, + 135, + 234, + 93, + 280, + 139, + 60, + 323, + 143, + 342, + 11, + 141, + 66, + 252, + 133, + 202, + 73, + 239, + 153, + 263, + 58, + 351, + 186, + 256, + 85, + 346, + 163, + 275, + 3, + 378, + 145, + 372, + 9, + 225, + 139, + 307, + 50, + 260, + 152, + 75, + 127, + 294, + 63, + 378, + 152, + 323, + 98, + 337, + 198, + 359, + 97, + 276, + 147, + 376, + 45, + 385, + 194, + 372, + 195, + 206, + 77, + 343, + 186, + 325, + 178, + 334, + 195, + 234, + 132, + 381, + 99, + 218, + 138, + 261, + 17, + 245, + 172, + 244, + 81, + 281, + 143, + 237, + 26, + 275, + 138, + 348, + 73, + 327, + 168, + 289, + 38, + 299, + 186, + 345, + 69, + 257, + 168, + 288, + 24, + 279, + 104, + 259, + 84, + 342, + 117, + 227, + 128, + 359, + 178, + 284, + 20, + 355, + 161, + 342, + 70, + 372, + 167, + 378, + 92, + 378, + 134, + 277, + 69, + 225, + 192, + 378, + 42, + 239, + 120, + 386, + 82, + 317, + 192, + 301, + 44, + 261, + 125, + 291, + 29, + 113, + 96, + 326, + 144, + 60, + 300, + 199, + 292, + 54, + 291, + 176, + 334, + 64, + 353, + 131, + 377, + 41, + 160, + 11, + 310, + 136, + 399, + 47, + 103, + 7, + 226, + 184, + 219, + 348, + 259, + 31, + 245, + 187, + 281, + 380, + 27, + 275, + 158, + 326, + 305, + 41, + 266, + 377, + 338, + 55, + 267, + 163, + 374, + 185, + 384, + 99, + 291, + 176, + 87, + 177, + 40, + 383, + 24, + 285, + 25, + 224, + 194, + 390, + 72, + 304, + 150, + 252, + 36, + 358, + 101, + 220, + 20, + 293, + 194, + 205, + 68, + 206, + 101, + 235, + 13, + 384, + 195, + 312, + 43, + 316, + 49, + 216, + 18, + 229, + 15, + 283, + 224, + 379, + 112, + 205, + 102, + 202, + 268, + 161, + 364, + 346, + 237, + 85, + 361, + 137, + 208, + 74, + 254, + 121, + 78, + 113, + 239, + 158, + 172, + 149, + 331, + 78, + 342, + 193, + 326, + 63, + 324, + 71, + 249, + 74, + 391, + 53, + 247, + 112, + 352, + 33, + 219, + 194, + 391, + 322, + 121, + 300, + 22, + 282, + 121, + 317, + 370, + 325, + 157, + 237, + 167, + 295, + 382, + 217, + 227, + 349, + 340, + 88, + 131, + 383, + 11, + 286, + 303, + 83, + 333, + 193, + 15, + 269, + 114, + 391, + 113, + 142, + 204, + 27, + 349, + 141, + 333, + 29, + 250, + 167, + 224, + 80, + 328, + 193, + 283, + 75, + 233, + 152, + 361, + 45, + 354, + 120, + 76, + 202, + 170, + 330, + 19, + 337, + 153, + 301, + 79, + 380, + 200, + 374, + 72, + 144, + 17, + 197, + 146, + 334, + 170, + 109, + 195, + 11, + 144, + 17, + 146, + 239, + 1, + 263, + 192, + 315, + 62, + 82, + 9, + 324, + 111, + 366, + 98, + 332, + 182, + 76, + 138, + 255, + 180, + 301, + 67, + 204, + 337, + 337, + 397, + 212, + 81, + 202, + 149, + 243, + 375, + 20, + 303, + 150, + 366, + 41, + 394, + 22, + 321, + 67, + 372, + 34, + 316, + 131, + 119, + 306, + 196, + 365, + 190, + 393, + 318, + 67, + 219, + 43, + 264, + 131, + 220, + 334, + 358, + 32, + 392, + 217, + 16, + 207, + 198, + 271, + 93, + 204, + 163, + 338, + 348, + 293, + 253, + 351, + 399, + 249, + 53, + 247, + 137, + 18, + 326, + 112, + 26, + 162, + 72, + 194, + 275, + 49, + 346, + 148, + 317, + 120, + 212, + 164, + 201, + 350, + 350, + 385, + 41, + 279, + 312, + 226, + 194, + 209, + 351, + 320, + 72, + 254, + 197, + 290, + 48, + 359, + 220, + 70, + 282, + 363, + 166, + 114, + 31, + 167, + 340, + 83, + 263, + 243, + 190, + 336, + 235, + 100, + 347, + 128, + 341, + 91, + 328, + 183, + 351, + 95, + 365, + 157, + 325, + 86, + 212, + 124, + 296, + 23, + 140, + 286, + 71, + 292, + 200, + 213, + 19, + 172, + 46, + 110, + 58, + 84, + 320, + 4, + 3, + 389, + 144, + 215, + 23, + 134, + 97, + 250, + 185, + 321, + 86, + 252, + 106, + 265, + 83, + 266, + 179, + 250, + 53, + 295, + 113, + 301, + 65, + 244, + 130, + 14, + 139, + 68, + 321, + 129, + 302, + 69, + 256, + 123, + 315, + 84, + 282, + 122, + 351, + 85, + 163, + 83, + 108, + 344, + 79, + 149, + 51, + 165, + 263, + 60, + 75, + 278, + 192, + 46, + 332, + 47, + 146, + 245, + 15, + 354, + 101, + 222, + 22, + 223, + 139, + 294, + 73, + 260, + 122, + 232, + 46, + 342, + 108, + 62, + 120, + 348, + 26, + 146, + 275, + 33, + 156, + 34, + 366, + 26, + 298, + 64, + 220, + 57, + 273, + 261, + 108, + 307, + 325, + 114, + 72, + 114, + 147, + 378, + 39, + 398, + 169, + 217, + 58, + 244, + 105, + 46, + 133, + 44, + 200, + 209, + 90, + 345, + 133, + 289, + 97, + 259, + 98, + 357, + 369, + 20, + 286, + 346, + 206, + 266, + 386, + 29, + 277, + 214, + 169, + 375, + 120, + 31, + 306, + 197, + 290, + 156, + 330, + 139, + 346, + 159, + 284, + 19, + 301, + 106, + 344, + 31, + 252, + 73, + 20, + 85, + 282, + 359, + 18, + 250, + 233, + 395, + 156, + 51, + 355, + 155, + 308, + 49, + 95, + 66, + 162, + 366, + 44, + 170, + 251, + 256, + 337, + 230, + 275, + 113, + 228, + 151, + 288, + 199, + 244, + 58, + 221, + 105, + 336, + 6, + 228, + 165, + 227, + 48, + 400, + 144, + 383, + 18, + 289, + 176, + 270, + 154, + 279, + 10, + 245, + 103, + 361, + 78, + 217, + 196, + 207, + 16, + 309, + 123, + 299, + 86, + 299, + 108, + 207, + 96, + 234, + 148, + 377, + 88, + 231, + 76, + 378, + 3, + 299, + 22, + 211, + 270, + 12, + 231, + 20, + 55, + 286, + 61, + 382, + 142, + 249, + 77, + 384, + 150, + 379, + 17, + 333, + 177, + 293, + 98, + 338, + 157, + 91, + 109, + 172, + 125, + 26, + 115, + 400, + 53, + 285, + 165, + 209, + 84, + 353, + 172, + 360, + 13, + 320, + 180, + 278, + 37, + 263, + 168, + 356, + 67, + 318, + 155, + 134, + 156, + 295, + 20, + 65, + 46, + 346, + 108, + 321, + 79, + 334, + 168, + 364, + 52, + 318, + 123, + 365, + 189, + 325, + 123, + 293, + 62, + 398, + 108, + 321, + 25, + 268, + 123, + 313, + 100, + 235, + 129, + 400, + 54, + 211, + 167, + 297, + 193, + 240, + 43, + 248, + 170, + 371, + 71, + 342, + 194, + 251, + 60, + 299, + 183, + 317, + 21, + 291, + 181, + 345, + 37, + 320, + 102, + 201, + 22, + 286, + 134, + 281, + 72, + 263, + 196, + 345, + 29, + 270, + 186, + 226, + 36, + 218, + 121, + 232, + 167, + 240, + 68, + 216, + 198, + 301, + 41, + 322, + 130, + 358, + 11, + 280, + 135, + 66, + 192, + 169, + 194, + 223, + 284, + 286, + 28, + 260, + 187, + 273, + 74, + 300, + 23, + 206, + 12, + 52, + 38, + 320, + 103, + 206, + 197, + 348, + 182, + 249, + 286, + 101, + 375, + 258, + 102, + 250, + 97, + 394, + 129, + 29, + 184, + 50, + 339, + 97, + 234, + 141, + 374, + 44, + 337, + 165, + 317, + 189, + 291, + 142, + 391, + 341, + 335, + 224, + 20, + 258, + 124, + 270, + 8, + 254, + 185, + 306, + 13, + 316, + 120, + 236, + 7, + 247, + 116, + 368, + 9, + 312, + 5, + 357, + 223, + 121, + 256, + 203, + 217, + 142, + 310, + 379, + 321, + 289, + 264, + 261, + 11, + 148, + 259, + 72, + 304, + 38, + 381, + 62, + 213, + 27, + 254, + 43, + 256, + 230, + 177, + 241, + 63, + 107, + 143, + 369, + 90, + 242, + 162, + 383, + 363, + 162, + 223, + 95, + 211, + 124, + 329, + 85, + 216, + 195, + 201, + 51, + 309, + 157, + 366, + 12, + 183, + 107, + 102, + 255, + 69, + 323, + 168, + 274, + 194, + 203, + 238, + 106, + 225, + 124, + 360, + 386, + 181, + 331, + 10, + 249, + 348, + 359, + 267, + 15, + 382, + 68, + 270, + 54, + 213, + 152, + 264, + 80, + 149, + 284, + 95, + 315, + 119, + 394, + 221, + 289, + 140, + 294, + 48, + 266, + 186, + 384, + 30, + 228, + 65, + 352, + 50, + 362, + 27, + 137, + 394, + 9, + 306, + 145, + 229, + 68, + 211, + 174, + 221, + 20, + 374, + 136, + 386, + 14, + 378, + 148, + 40, + 233, + 198, + 78, + 122, + 338, + 100, + 357, + 115, + 230, + 71, + 110, + 65, + 397, + 70, + 41, + 55, + 344, + 381, + 52, + 172, + 197, + 39, + 126, + 77, + 39, + 384, + 66, + 266, + 162, + 1, + 153, + 245, + 145, + 396, + 88, + 366, + 158, + 205, + 58, + 384, + 71, + 366, + 233, + 246, + 213, + 208, + 152, + 356, + 30, + 292, + 181, + 379, + 123, + 354, + 53, + 388, + 3, + 372, + 344, + 196, + 269, + 399, + 15, + 361, + 128, + 219, + 63, + 340, + 183, + 308, + 42, + 292, + 195, + 324, + 159, + 230, + 172, + 329, + 10, + 211, + 109, + 13, + 208, + 186, + 96, + 143, + 198, + 206, + 145, + 251, + 195, + 303, + 341, + 178, + 256, + 12, + 385, + 92, + 201, + 43, + 284, + 148, + 218, + 370, + 189, + 13, + 227, + 68, + 208, + 338, + 379, + 13, + 287, + 132, + 319, + 60, + 318, + 126, + 364, + 46, + 189, + 45, + 132, + 21, + 338, + 140, + 340, + 99, + 187, + 22, + 304, + 55, + 39, + 257, + 298, + 18, + 58, + 397, + 51, + 277, + 188, + 292, + 49, + 360, + 125, + 368, + 64, + 390, + 158, + 279, + 62, + 291, + 160, + 294, + 44, + 400, + 196, + 310, + 10, + 320, + 133, + 355, + 23, + 228, + 118, + 309, + 22, + 320, + 120, + 383, + 167, + 356, + 105, + 147, + 327, + 70, + 133, + 323, + 83, + 185, + 68, + 195, + 172, + 305, + 108, + 263, + 120, + 249, + 87, + 382, + 168, + 231, + 95, + 371, + 12, + 387, + 173, + 268, + 41, + 224, + 42, + 353, + 6, + 319, + 147, + 223, + 39, + 326, + 68, + 364, + 150, + 295, + 36, + 250, + 143, + 398, + 7, + 357, + 101, + 398, + 24, + 354, + 27, + 293, + 140, + 21, + 197, + 100, + 157, + 253, + 15, + 198, + 72, + 121, + 351, + 87, + 79, + 24, + 384, + 80, + 294, + 62, + 287, + 102, + 380, + 211, + 53, + 265, + 141, + 348, + 17, + 224, + 116, + 360, + 170, + 210, + 45, + 248, + 118, + 273, + 30, + 329, + 194, + 371, + 49, + 214, + 162, + 233, + 95, + 291, + 124, + 223, + 37, + 277, + 133, + 346, + 68, + 369, + 186, + 301, + 23, + 302, + 102, + 349, + 52, + 371, + 101, + 247, + 2, + 148, + 48, + 108, + 10, + 124, + 394, + 9, + 148, + 13, + 162, + 260, + 73, + 340, + 156, + 205, + 89, + 370, + 114, + 355, + 90, + 369, + 159, + 274, + 61, + 241, + 142, + 253, + 69, + 384, + 136, + 302, + 59, + 350, + 137, + 273, + 50, + 292, + 137, + 215, + 4, + 279, + 178, + 284, + 36, + 236, + 197, + 369, + 99, + 213, + 107, + 313, + 59, + 387, + 36, + 348, + 113, + 214, + 69, + 243, + 200, + 17, + 258, + 132, + 281, + 17, + 251, + 157, + 230, + 52, + 347, + 156, + 213, + 98, + 381, + 160, + 257, + 50, + 344, + 151, + 274, + 34, + 219, + 110, + 309, + 164, + 227, + 89, + 299, + 143, + 319, + 159, + 205, + 324, + 225, + 394, + 394, + 393, + 55, + 291, + 158, + 224, + 68, + 272, + 152, + 342, + 85, + 202, + 179, + 361, + 7, + 319, + 182, + 244, + 53, + 369, + 162, + 307, + 64, + 255, + 147, + 290, + 83, + 279, + 115, + 304, + 129, + 331, + 298, + 124, + 231, + 120, + 266, + 85, + 342, + 175, + 40, + 186, + 324, + 43, + 14, + 11, + 195, + 255, + 281, + 255, + 182, + 362, + 219, + 14, + 105, + 87, + 156, + 249, + 6, + 117, + 17, + 123, + 278, + 93, + 385, + 199, + 86, + 30, + 133, + 234, + 127, + 380, + 32, + 310, + 128, + 215, + 18, + 391, + 107, + 324, + 90, + 317, + 145, + 349, + 48, + 274, + 64, + 295, + 186, + 3, + 194, + 88, + 128, + 65, + 350, + 151, + 249, + 31, + 387, + 126, + 298, + 43, + 247, + 143, + 398, + 14, + 372, + 108, + 329, + 100, + 359, + 145, + 303, + 9, + 327, + 142, + 313, + 18, + 201, + 102, + 98, + 299, + 123, + 241, + 84, + 235, + 46, + 214, + 3, + 240, + 194, + 388, + 7, + 293, + 197, + 222, + 74, + 248, + 278, + 161, + 290, + 356, + 152, + 377, + 328, + 302, + 365, + 237, + 199, + 248, + 154, + 336, + 200, + 249, + 51, + 356, + 104, + 346, + 77, + 146, + 268, + 16, + 260, + 120, + 232, + 159, + 193, + 129, + 7, + 121, + 151, + 376, + 139, + 215, + 24, + 108, + 103, + 20, + 74, + 195, + 8, + 310, + 235, + 307, + 320, + 363, + 181, + 369, + 78, + 366, + 138, + 333, + 54, + 254, + 177, + 219, + 1, + 279, + 128, + 389, + 173, + 301, + 124, + 338, + 293, + 378, + 270, + 224, + 117, + 180, + 259, + 94, + 147, + 299, + 122, + 364, + 288, + 71, + 162, + 96, + 130, + 30, + 190, + 262, + 12, + 21, + 52, + 221, + 23, + 33, + 339, + 198, + 295, + 159, + 124, + 114, + 272, + 127, + 210, + 34, + 384, + 137, + 359, + 75, + 355, + 197, + 280, + 43, + 221, + 123, + 331, + 40, + 224, + 158, + 201, + 88, + 251, + 142, + 317, + 186, + 250, + 137, + 305, + 78, + 333, + 137, + 370, + 100, + 344, + 120, + 302, + 14, + 382, + 155, + 55, + 296, + 180, + 218, + 131, + 282, + 49, + 253, + 225, + 378, + 15, + 398, + 138, + 270, + 150, + 372, + 57, + 210, + 123, + 338, + 98, + 171, + 214, + 92, + 291, + 33, + 256, + 79, + 203, + 134, + 392, + 99, + 127, + 75, + 309, + 128, + 316, + 185, + 377, + 141, + 177, + 160, + 363, + 72, + 198, + 52, + 336, + 140, + 386, + 130, + 30, + 155, + 59, + 47, + 360, + 281, + 41, + 46, + 36, + 303, + 106, + 316, + 199, + 253, + 127, + 283, + 36, + 292, + 192, + 293, + 215, + 172, + 377, + 245, + 134, + 363, + 84, + 248, + 165, + 340, + 53, + 395, + 189, + 288, + 78, + 230, + 178, + 317, + 9, + 252, + 172, + 214, + 98, + 256, + 183, + 376, + 48, + 327, + 110, + 291, + 14, + 296, + 159, + 236, + 26, + 275, + 170, + 280, + 35, + 263, + 126, + 212, + 24, + 398, + 198, + 98, + 162, + 314, + 71, + 209, + 198, + 47, + 193, + 211, + 11, + 378, + 189, + 116, + 359, + 81, + 388, + 169, + 155, + 125, + 232, + 9, + 384, + 182, + 355, + 174, + 209, + 79, + 372, + 174, + 386, + 161, + 299, + 384, + 315, + 378, + 394, + 174, + 291, + 39, + 259, + 290, + 373, + 294, + 50, + 254, + 70, + 212, + 379, + 292, + 115, + 389, + 80, + 226, + 117, + 292, + 169, + 73, + 301, + 168, + 24, + 366, + 91, + 206, + 105, + 247, + 26, + 268, + 151, + 360, + 176, + 59, + 164, + 334, + 67, + 350, + 135, + 261, + 32, + 153, + 27, + 331, + 190, + 82, + 189, + 89, + 127, + 248, + 233, + 215, + 54, + 203, + 168, + 362, + 16, + 278, + 140, + 310, + 10, + 342, + 185, + 376, + 125, + 336, + 180, + 303, + 55, + 222, + 168, + 341, + 23, + 347, + 169, + 316, + 47, + 230, + 159, + 271, + 119, + 289, + 349, + 43, + 384, + 192, + 245, + 68, + 247, + 186, + 320, + 7, + 366, + 131, + 335, + 14, + 321, + 159, + 224, + 129, + 237, + 359, + 267, + 375, + 290, + 143, + 261, + 6, + 397, + 143, + 375, + 192, + 393, + 234, + 380, + 77, + 393, + 144, + 321, + 308, + 358, + 182, + 343, + 207, + 363, + 226, + 241, + 333, + 132, + 267, + 340, + 225, + 8, + 306, + 122, + 302, + 194, + 251, + 50, + 393, + 100, + 326, + 372, + 241, + 353, + 259, + 356, + 374, + 193, + 336, + 91, + 339, + 76, + 370, + 313, + 290, + 376, + 391, + 10, + 286, + 45, + 239, + 181, + 171, + 52, + 323, + 270, + 114, + 51, + 276, + 122, + 296, + 47, + 324, + 104, + 382, + 84, + 210, + 6, + 308, + 13, + 218, + 333, + 232, + 187, + 364, + 147, + 276, + 32, + 294, + 198, + 352, + 343, + 71, + 355, + 15, + 336, + 389, + 156, + 68, + 276, + 126, + 73, + 346, + 12, + 396, + 94, + 234, + 20, + 348, + 193, + 250, + 83, + 226, + 102, + 360, + 94, + 322, + 142, + 303, + 63, + 396, + 166, + 316, + 19, + 212, + 172, + 375, + 166, + 210, + 71, + 260, + 166, + 381, + 54, + 304, + 186, + 325, + 47, + 282, + 122, + 257, + 8, + 323, + 113, + 222, + 77, + 389, + 191, + 380, + 159, + 291, + 162, + 273, + 4, + 258, + 138, + 318, + 16, + 306, + 173, + 338, + 33, + 323, + 164, + 352, + 36, + 191, + 77, + 358, + 196, + 386, + 169, + 75, + 219, + 48, + 343, + 2, + 294, + 39, + 338, + 335, + 245, + 223, + 61, + 306, + 147, + 283, + 111, + 397, + 184, + 343, + 132, + 398, + 298, + 188, + 325, + 184, + 400, + 208, + 381, + 171, + 309, + 128, + 212, + 230, + 188, + 306, + 70, + 119, + 129, + 167, + 392, + 324, + 99, + 290, + 319, + 156, + 285, + 63, + 339, + 110, + 301, + 246, + 332, + 37, + 286, + 253, + 332, + 243, + 134, + 395, + 33, + 288, + 177, + 319, + 181, + 312, + 32, + 388, + 129, + 350, + 62, + 372, + 69, + 394, + 180, + 231, + 38, + 367, + 147, + 279, + 53, + 364, + 153, + 245, + 2, + 229, + 129, + 352, + 24, + 41, + 118, + 261, + 375, + 175, + 367, + 50, + 366, + 110, + 260, + 65, + 246, + 170, + 210, + 12, + 123, + 372, + 122, + 201, + 15, + 356, + 143, + 302, + 142, + 212, + 265, + 209, + 171, + 261, + 302, + 54, + 299, + 146, + 321, + 78, + 282, + 114, + 247, + 60, + 331, + 130, + 252, + 2, + 289, + 97, + 238, + 141, + 328, + 78, + 369, + 1, + 354, + 114, + 292, + 297, + 114, + 244, + 373, + 327, + 158, + 254, + 30, + 226, + 118, + 335, + 388, + 257, + 329, + 300, + 179, + 329, + 47, + 281, + 78, + 396, + 191, + 341, + 21, + 231, + 169, + 217, + 113, + 367, + 34, + 213, + 184, + 271, + 15, + 178, + 58, + 117, + 334, + 54, + 281, + 168, + 351, + 62, + 333, + 82, + 207, + 72, + 232, + 85, + 345, + 59, + 300, + 54, + 313, + 189, + 240, + 41, + 279, + 128, + 333, + 87, + 359, + 107, + 324, + 49, + 305, + 163, + 269, + 56, + 356, + 167, + 289, + 66, + 297, + 139, + 210, + 32, + 164, + 80, + 309, + 149, + 314, + 99, + 370, + 145, + 395, + 39, + 283, + 106, + 343, + 126, + 292, + 192, + 237, + 33, + 347, + 188, + 308, + 14, + 217, + 188, + 373, + 100, + 300, + 191, + 277, + 63, + 308, + 191, + 301, + 63, + 208, + 70, + 309, + 50, + 276, + 92, + 309, + 46, + 254, + 45, + 211, + 139, + 254, + 49, + 301, + 229, + 359, + 284, + 22, + 341, + 199, + 223, + 47, + 267, + 22, + 345, + 174, + 310, + 211, + 329, + 209, + 143, + 255, + 313, + 327, + 61, + 316, + 325, + 321, + 101, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "commands": [ + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 2, + 0, + 0, + 2, + 2, + 2, + 2, + 2, + 0, + 2, + 2, + 2, + 0, + 2, + 0, + 2, + 2, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 2, + 2, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 2, + 0, + 2, + 0 + ], + "values": [ + 87, + 389, + 327, + 304, + 190, + 248, + 14, + 289, + 151, + 325, + 293, + 323, + 331, + 110, + 378, + 235, + 280, + 369, + 373, + 42, + 61, + 265, + 120, + 394, + 17, + 64, + 325, + 172, + 191, + 373, + 336, + 31, + 151, + 28, + 85, + 2, + 204, + 115, + 2, + 103, + 300, + 168, + 184, + 180, + 359, + 400, + 176, + 118, + 15, + 120, + 6, + 297, + 123, + 84, + 52, + 202, + 239, + 85, + 234, + 353, + 3, + 217, + 119, + 5, + 50, + 29, + 145, + 50, + 389, + 156, + 41, + 120, + 29, + 372, + 70, + 396, + 216, + 280, + 164, + 217, + 161, + 305, + 51, + 90, + 94, + 369, + 29, + 354, + 200, + 21, + 259, + 292, + 164, + 113, + 359, + 28, + 361, + 70, + 363, + 279, + 224, + 363, + 203, + 383, + 350, + 216, + 22, + 95, + 384, + 392, + 359, + 93, + 113, + 157, + 293, + 129, + 78, + 223, + 157, + 116, + 213, + 7, + 284, + 25, + 67, + 222, + 289, + 40, + 342, + 359, + 218, + 365, + 356, + 321, + 136, + 307, + 356, + 356, + 279, + 73, + 177, + 172, + 329, + 128, + 359, + 236, + 174, + 388, + 109, + 11, + 131, + 84, + 349, + 375, + 389, + 342, + 128, + 27, + 39, + 116, + 77, + 342, + 114, + 248, + 31, + 371, + 331, + 182, + 71, + 341, + 294, + 272, + 112, + 368, + 365, + 129, + 83, + 218, + 64, + 261, + 294, + 385, + 115, + 111, + 375, + 67, + 31, + 25, + 57, + 186, + 48, + 43, + 242, + 287, + 162, + 185, + 188, + 336, + 255, + 282, + 340, + 377, + 63, + 18, + 240, + 238, + 351, + 132, + 72, + 123, + 146, + 188, + 23, + 10, + 197, + 150, + 157, + 244, + 292, + 80, + 367, + 369, + 108, + 361, + 344, + 400, + 37, + 364, + 36, + 270, + 177, + 65, + 282, + 357, + 106, + 387, + 149, + 146, + 134, + 329, + 340, + 77, + 57, + 62, + 351, + 364, + 102, + 194, + 68, + 308, + 289, + 3, + 138, + 321, + 283, + 302, + 250, + 231, + 207, + 380, + 289, + 381, + 16, + 176, + 132, + 130, + 13, + 372, + 289, + 121, + 208, + 355, + 252, + 397, + 227, + 139, + 207, + 229, + 301, + 227, + 69, + 40, + 227, + 310, + 181, + 217, + 296, + 26, + 287, + 52, + 261, + 253, + 309, + 166, + 212, + 382, + 205, + 315, + 240, + 203, + 264, + 349, + 279, + 218, + 145, + 270, + 53, + 270, + 338, + 295, + 355, + 277, + 201, + 232, + 218, + 49, + 310, + 90, + 195, + 169, + 278, + 254, + 93, + 150, + 216, + 377, + 290, + 26, + 242, + 391, + 140, + 137, + 289, + 93, + 3, + 325, + 238, + 329, + 373, + 351, + 163, + 279, + 126, + 267, + 376, + 64, + 236, + 72, + 213, + 220, + 44, + 41, + 28, + 223, + 269, + 187, + 381, + 222, + 164, + 297, + 62, + 316, + 21, + 254, + 110, + 98, + 395, + 379, + 399, + 130, + 93, + 211, + 323, + 39, + 267, + 60, + 143, + 125, + 207, + 47, + 284, + 148, + 134, + 47, + 109, + 219, + 241, + 346, + 15, + 306, + 140, + 302, + 156, + 175, + 341, + 147, + 214, + 198, + 14, + 339, + 289, + 91, + 278, + 396, + 75, + 340, + 284, + 68, + 108, + 261, + 366, + 317, + 249, + 100, + 309, + 281, + 63, + 400, + 366, + 306, + 194, + 331, + 211, + 342, + 67, + 49, + 206, + 299, + 87, + 238, + 72, + 379, + 347, + 349, + 266, + 394, + 120, + 94, + 237, + 375, + 397, + 102, + 148, + 198, + 329, + 13, + 96, + 129, + 274, + 43, + 109, + 196, + 55, + 285, + 291, + 164, + 358, + 162, + 47, + 270, + 29, + 273, + 37, + 190, + 209, + 114, + 366, + 192, + 121, + 162, + 361, + 308, + 267, + 136, + 222, + 224, + 139, + 368, + 133, + 301, + 319, + 55, + 170, + 142, + 68, + 330, + 372, + 265, + 386, + 58, + 130, + 203, + 385, + 172, + 370, + 156, + 399, + 112, + 361, + 332, + 26, + 34, + 114, + 134, + 130, + 376, + 158, + 289, + 219, + 232, + 278, + 389, + 147, + 341, + 359, + 296, + 89, + 347, + 101, + 266, + 321, + 383, + 162, + 265, + 398, + 241, + 399, + 106, + 252, + 6, + 42, + 201, + 37, + 256, + 328, + 93, + 384, + 246, + 69, + 1, + 331, + 112, + 216, + 124, + 370, + 225, + 341, + 295, + 188, + 41, + 211, + 289, + 46, + 97, + 91, + 151, + 189, + 156, + 191, + 96, + 221, + 141, + 164, + 394, + 316, + 45, + 12, + 330, + 129, + 129, + 141, + 137, + 305, + 180, + 242, + 5, + 180, + 6, + 18, + 149, + 306, + 336, + 16, + 177, + 2, + 22, + 311, + 190, + 142, + 380, + 162, + 239, + 269, + 52, + 213, + 302, + 191, + 328, + 17, + 190, + 282, + 78, + 397, + 198, + 362, + 191, + 152, + 184, + 262, + 370, + 351, + 199, + 397, + 273, + 270, + 7, + 335, + 295, + 383, + 212, + 263, + 319, + 32, + 96, + 276, + 51, + 165, + 299, + 279, + 390, + 378, + 128, + 307, + 52, + 45, + 94, + 222, + 252, + 111, + 21, + 319, + 90, + 241, + 355, + 60, + 203, + 396, + 368, + 124, + 11, + 149, + 318, + 341, + 46, + 357, + 126, + 98, + 380, + 217, + 105, + 149, + 4, + 34, + 34, + 180, + 360, + 375, + 161, + 343, + 184, + 206, + 241, + 196, + 361, + 178, + 104, + 394, + 76, + 125, + 38, + 384, + 156, + 223, + 318, + 268, + 69, + 225, + 191, + 122, + 314, + 166, + 336, + 232, + 121, + 170, + 81, + 176, + 192, + 218, + 393, + 321, + 254, + 300, + 255, + 54, + 182, + 3, + 8, + 334, + 302, + 150, + 335, + 18, + 144, + 290, + 165, + 204, + 201, + 346, + 2, + 318, + 64, + 54, + 58, + 31, + 171, + 246, + 179, + 115, + 99, + 13, + 371, + 36, + 371, + 137, + 188, + 20, + 341, + 340, + 312, + 260, + 68, + 163, + 95, + 286, + 45, + 156, + 170, + 23, + 29, + 376, + 235, + 114, + 280, + 294, + 30, + 357, + 381, + 363, + 176, + 260, + 344, + 202, + 238, + 303, + 366, + 330, + 114, + 33, + 272, + 243, + 347, + 146, + 56, + 247, + 11, + 291, + 277, + 120, + 142, + 83, + 236, + 365, + 307, + 317, + 383, + 119, + 188, + 153, + 315, + 337, + 364, + 46, + 283, + 129, + 360, + 325, + 178, + 180, + 279, + 370, + 347, + 394, + 141, + 61, + 55, + 281, + 272, + 193, + 30, + 71, + 205, + 342, + 248, + 174, + 99, + 279, + 313, + 11, + 81, + 204, + 113, + 155, + 50, + 385, + 65, + 338, + 225, + 202, + 373, + 257, + 142, + 242, + 316, + 309, + 385, + 167, + 295, + 220, + 41, + 130, + 151, + 70, + 57, + 364, + 63, + 382, + 97, + 388, + 102, + 255, + 387, + 132, + 348, + 113, + 239, + 306, + 299, + 319, + 205, + 9, + 150, + 47, + 62, + 221, + 61, + 119, + 215, + 364, + 230, + 338, + 400, + 397, + 2, + 167, + 286, + 15, + 305, + 391, + 66, + 148, + 142, + 322, + 209, + 378, + 61, + 249, + 198, + 171, + 331, + 45, + 16, + 304, + 312, + 56, + 383, + 289, + 279, + 6, + 31, + 272, + 192, + 10, + 151, + 200, + 181, + 389, + 204, + 30, + 67, + 249, + 166, + 46, + 213, + 175, + 391, + 134, + 102, + 76, + 394, + 362, + 11, + 248, + 183, + 235, + 389, + 158, + 287, + 357, + 385, + 96, + 238, + 75, + 127, + 67, + 314, + 389, + 143, + 98, + 350, + 367, + 113, + 148, + 80, + 74, + 394, + 354, + 146, + 238, + 260, + 260, + 278, + 180, + 261, + 87, + 377, + 187, + 334, + 329, + 30, + 361, + 230, + 375, + 116, + 287, + 41, + 192, + 139, + 209, + 293, + 342, + 83, + 93, + 314, + 306, + 321, + 257, + 38, + 284, + 238, + 358, + 4, + 383, + 332, + 381, + 54, + 22, + 101, + 394, + 94, + 392, + 296, + 244, + 314, + 384, + 37, + 57, + 211, + 357, + 183, + 153, + 101, + 274, + 239, + 264, + 112, + 195, + 255, + 148, + 170, + 62, + 219, + 50, + 218, + 19, + 399, + 353, + 245, + 266, + 214, + 161, + 121, + 19, + 13, + 21, + 192, + 41, + 382, + 211, + 190, + 27, + 54, + 268, + 256, + 19, + 68, + 169, + 127, + 395, + 37, + 91, + 163, + 263, + 224, + 188, + 72, + 28, + 13, + 352, + 4, + 286, + 343, + 37, + 346, + 177, + 341, + 120, + 149, + 324, + 46, + 284, + 200, + 24, + 273, + 297, + 212, + 397, + 46, + 207, + 100, + 271, + 59, + 100, + 181, + 89, + 205, + 297, + 257, + 185, + 230, + 341, + 292, + 274, + 27, + 16, + 16, + 134, + 355, + 165, + 226, + 208, + 238, + 233, + 28, + 366, + 384, + 204, + 37, + 112, + 339, + 95, + 354, + 129, + 323, + 158, + 375, + 238, + 2, + 372, + 356, + 379, + 89, + 22, + 284, + 271, + 51, + 103, + 375, + 162, + 314, + 341, + 18, + 395, + 180, + 26, + 8, + 90, + 143, + 211, + 230, + 273, + 245, + 112, + 169, + 200, + 335, + 308, + 70, + 328, + 311, + 246, + 49, + 342, + 204, + 282, + 148, + 123, + 39, + 233, + 217, + 270, + 147, + 104, + 110, + 359, + 386, + 276, + 269, + 97, + 70, + 400, + 351, + 301, + 226, + 167, + 87, + 176, + 130, + 137, + 170, + 161, + 368, + 342, + 258, + 376, + 213, + 117, + 114, + 45, + 383, + 196, + 241, + 219, + 50, + 193, + 317, + 144, + 299, + 231, + 367, + 63, + 41, + 107, + 371, + 112, + 145, + 44, + 241, + 215, + 328, + 252, + 228, + 64, + 5, + 200, + 370, + 25, + 137, + 344, + 322, + 4, + 375, + 274, + 239, + 124, + 152, + 303, + 290, + 37, + 349, + 137, + 129, + 326, + 313, + 51, + 179, + 64, + 323, + 320, + 140, + 18, + 274, + 84, + 290, + 64, + 41, + 122, + 131, + 314, + 286, + 279, + 113, + 196, + 329, + 89, + 155, + 197, + 104, + 1, + 33, + 152, + 190, + 348, + 192, + 217, + 34, + 233, + 147, + 185, + 124, + 246, + 215, + 211, + 301, + 50, + 13, + 393, + 302, + 222, + 374, + 222, + 62, + 370, + 351, + 17, + 367, + 385, + 137, + 254, + 27, + 219, + 240, + 349, + 166, + 307, + 375, + 29, + 82, + 354, + 191, + 284, + 398, + 157, + 253, + 128, + 337, + 238, + 317, + 27, + 193, + 131, + 71, + 232, + 394, + 400, + 78, + 57, + 216, + 203, + 351, + 224, + 372, + 26, + 164, + 90, + 259, + 304, + 200, + 56, + 313, + 81, + 290, + 66, + 324, + 336, + 93, + 104, + 119, + 176, + 38, + 309, + 86, + 362, + 261, + 150, + 210, + 377, + 323, + 291, + 373, + 216, + 386, + 123, + 271, + 293, + 104, + 348, + 29, + 171, + 247, + 147, + 224, + 270, + 362, + 200, + 371, + 73, + 215, + 236, + 157, + 196, + 204, + 83, + 12, + 382, + 246, + 305, + 45, + 376, + 166, + 124, + 296, + 386, + 152, + 228, + 206, + 191, + 181, + 14, + 94, + 76, + 252, + 273, + 37, + 388, + 17, + 223, + 227, + 125, + 353, + 242, + 367, + 150, + 191, + 153, + 191, + 84, + 78, + 208, + 263, + 64, + 319, + 244, + 135, + 181, + 105, + 6, + 245, + 96, + 62, + 320, + 158, + 345, + 73, + 384, + 303, + 364, + 195, + 323, + 221, + 45, + 10, + 162, + 305, + 289, + 357, + 32, + 21, + 159, + 71, + 133, + 335, + 353, + 86, + 133, + 128, + 397, + 292, + 16, + 150, + 66, + 144, + 274, + 180, + 306, + 301, + 143, + 394, + 145, + 175, + 73, + 113, + 330, + 172, + 1, + 146, + 349, + 303, + 336, + 161, + 361, + 7, + 373, + 253, + 387, + 151, + 105, + 149, + 360, + 351, + 239, + 66, + 118, + 203, + 22, + 166, + 334, + 5, + 183, + 335, + 343, + 168, + 300, + 111, + 332, + 103, + 134, + 197, + 147, + 29, + 112, + 343, + 81, + 43, + 146, + 295, + 34, + 344, + 264, + 148, + 263, + 126, + 134, + 14, + 244, + 152, + 227, + 292, + 120, + 232, + 29, + 141, + 146, + 42, + 52, + 72, + 121, + 14, + 300, + 138, + 163, + 202, + 280, + 259, + 396, + 77, + 344, + 253, + 209, + 381, + 311, + 260, + 334, + 86, + 393, + 338, + 52, + 235, + 270, + 388, + 295, + 137, + 279, + 350, + 228, + 268, + 134, + 294, + 151, + 181, + 121, + 84, + 213, + 225, + 41, + 43, + 257, + 91, + 150, + 333, + 99, + 247, + 11, + 64, + 206, + 194, + 10, + 371, + 179, + 87, + 250, + 379, + 143, + 113, + 187, + 367, + 32, + 242, + 251, + 151, + 195, + 173, + 177, + 342, + 391, + 107, + 77, + 272, + 351, + 248, + 373, + 49, + 138, + 83, + 400, + 218, + 27, + 118, + 379, + 167, + 101, + 322, + 79, + 395, + 238, + 53, + 39, + 63, + 106, + 334, + 392, + 103, + 291, + 323, + 52, + 40, + 323, + 280, + 314, + 237, + 325, + 282, + 282, + 384, + 169, + 117, + 400, + 203, + 83, + 210, + 377, + 347, + 380, + 255, + 162, + 243, + 349, + 4, + 392, + 146, + 253, + 286, + 22, + 48, + 24, + 287, + 300, + 160, + 273, + 230, + 27, + 77, + 60, + 381, + 212, + 142, + 358, + 114, + 293, + 123, + 14, + 208, + 80, + 80, + 214, + 21, + 119, + 120, + 161, + 247, + 282, + 237, + 10, + 26, + 373, + 58, + 161, + 133, + 44, + 219, + 58, + 101, + 197, + 208, + 329, + 377, + 228, + 280, + 139, + 49, + 339, + 220, + 231, + 256, + 223, + 227, + 354, + 203, + 134, + 324, + 264, + 273, + 157, + 284, + 192, + 93, + 374, + 117, + 346, + 240, + 205, + 106, + 40, + 193, + 398, + 33, + 334, + 248, + 225, + 391, + 119, + 11, + 339, + 99, + 102, + 1, + 283, + 262, + 66, + 281, + 397, + 305, + 350, + 267, + 215, + 191, + 383, + 336, + 147, + 75, + 106, + 49, + 41, + 211, + 53, + 237, + 364, + 226, + 217, + 394, + 77, + 313, + 266, + 303, + 173, + 380, + 32, + 390, + 200, + 63, + 56, + 328, + 93, + 290, + 1, + 136, + 77, + 44, + 268, + 91, + 274, + 83, + 69, + 169, + 247, + 393, + 208, + 43, + 381, + 137, + 280, + 279, + 230, + 212, + 224, + 220, + 233, + 29, + 30, + 175, + 75, + 108, + 140, + 267, + 20, + 16, + 51, + 27, + 287, + 169, + 145, + 132, + 170, + 146, + 246, + 162, + 120, + 155, + 388, + 288, + 98, + 58, + 155, + 146, + 37, + 133, + 153, + 40, + 187, + 88, + 165, + 385, + 272, + 334, + 105, + 177, + 333, + 204, + 129, + 393, + 228, + 348, + 70, + 137, + 97, + 8, + 233, + 70, + 315, + 161, + 38, + 230, + 237, + 191, + 33, + 257, + 4, + 45, + 382, + 81, + 209, + 64, + 140, + 9, + 243, + 98, + 31, + 3, + 66, + 164, + 176, + 198, + 261, + 381, + 56, + 196, + 20, + 101, + 51, + 255, + 37, + 35, + 365, + 64, + 59, + 246, + 383, + 297, + 152, + 142, + 55, + 190, + 27, + 301, + 169, + 66, + 138, + 222, + 64, + 240, + 364, + 48, + 365, + 166, + 393, + 62, + 150, + 72, + 165, + 316, + 7, + 388, + 92, + 119, + 179, + 161, + 106, + 297, + 382, + 151, + 34, + 276, + 325, + 249, + 136, + 170, + 390, + 373, + 121, + 374, + 21, + 129, + 155, + 39, + 385, + 244, + 394, + 52, + 239, + 186, + 189, + 170, + 194, + 231, + 296, + 21, + 392, + 262, + 169, + 8, + 285, + 106, + 35, + 316, + 108, + 107, + 229, + 77, + 322, + 143, + 38, + 313, + 52, + 386, + 211, + 78, + 151, + 37, + 156, + 232, + 188, + 114, + 57, + 63, + 195, + 169, + 82, + 281, + 230, + 146, + 312, + 168, + 174, + 181, + 62, + 352, + 287, + 71, + 102, + 338, + 211, + 222, + 148, + 302, + 134, + 6, + 332, + 305, + 193, + 40, + 272, + 211, + 292, + 91, + 238, + 317, + 89, + 137, + 383, + 356, + 355, + 216, + 325, + 181, + 92, + 177, + 217, + 92, + 342, + 42, + 283, + 20, + 178, + 17, + 297, + 207, + 274, + 248, + 277, + 4, + 62, + 352, + 85, + 56, + 330, + 386, + 280, + 353, + 399, + 151, + 78, + 353, + 209, + 96, + 125, + 145, + 96, + 325, + 254, + 89, + 143, + 22, + 204, + 310, + 180, + 163, + 395, + 282, + 85, + 183, + 351, + 297, + 49, + 45, + 65, + 392, + 65, + 369, + 18, + 349, + 240, + 59, + 271, + 313, + 300, + 204, + 129, + 310, + 47, + 378, + 112, + 396, + 273, + 331, + 242, + 215, + 62, + 162, + 227, + 388, + 397, + 39, + 255, + 142, + 400, + 191, + 133, + 264, + 16, + 272, + 331, + 93, + 100, + 270, + 152, + 9, + 373, + 85, + 255, + 95, + 362, + 22, + 323, + 37, + 234, + 170, + 19, + 104, + 67, + 14, + 18, + 3, + 400, + 14, + 356, + 324, + 287, + 103, + 268, + 370, + 73, + 305, + 359, + 272, + 115, + 264, + 215, + 53, + 44, + 365, + 208, + 48, + 378, + 303, + 378, + 306, + 156, + 31, + 366, + 261, + 269, + 108, + 5, + 72, + 373, + 236, + 75, + 366, + 139, + 101, + 193, + 126, + 125, + 224, + 388, + 122, + 184, + 307, + 73, + 14, + 383, + 131, + 345, + 261, + 46, + 172, + 63, + 220, + 74, + 57, + 209, + 225, + 46, + 173, + 133, + 27, + 171, + 262, + 3, + 347, + 87, + 152, + 201, + 59, + 173, + 224, + 67, + 29, + 5, + 326, + 203, + 56, + 155, + 22, + 149, + 363, + 290, + 23, + 305, + 36, + 157, + 95, + 31, + 370, + 127, + 105, + 230, + 135, + 163, + 90, + 350, + 375, + 144, + 330, + 190, + 331, + 46, + 35, + 94, + 390, + 251, + 147, + 11, + 184, + 394, + 347, + 360, + 319, + 201, + 105, + 391, + 241, + 204, + 290, + 310, + 282, + 201, + 389, + 19, + 111, + 232, + 137, + 60, + 64, + 308, + 267, + 306, + 283, + 277, + 71, + 391, + 164, + 253, + 387, + 195, + 321, + 61, + 51, + 320, + 159, + 108, + 47, + 91, + 44, + 199, + 312, + 193, + 254, + 241, + 25, + 211, + 136, + 259, + 269, + 123, + 61, + 221, + 255, + 95, + 209, + 322, + 50, + 65, + 167, + 28, + 117, + 121, + 166, + 301, + 350, + 115, + 253, + 247, + 343, + 259, + 237, + 40, + 75, + 308, + 62, + 114, + 25, + 68, + 254, + 67, + 348, + 141, + 150, + 4, + 280, + 141, + 2, + 79, + 158, + 101, + 79, + 270, + 315, + 263, + 356, + 114, + 41, + 174, + 257, + 91, + 394, + 299, + 57, + 182, + 280, + 26, + 100, + 83, + 106, + 198, + 361, + 108, + 221, + 123, + 284, + 87, + 251, + 101, + 125, + 355, + 117, + 61, + 322, + 162, + 385, + 74, + 286, + 101, + 350, + 367, + 149, + 50, + 315, + 343, + 7, + 291, + 1, + 376, + 85, + 6, + 67, + 17, + 91, + 77, + 152, + 310, + 177, + 306, + 287, + 181, + 142, + 46, + 310, + 143, + 136, + 130, + 114, + 263, + 153, + 304, + 352, + 338, + 108, + 23, + 325, + 208, + 14, + 5, + 343, + 397, + 239, + 145, + 224, + 184, + 140, + 42, + 367, + 321, + 306, + 387, + 69, + 98, + 243, + 331, + 237, + 189, + 264, + 190, + 149, + 76, + 146, + 361, + 113, + 334, + 108, + 355, + 45, + 338, + 107, + 104, + 63, + 223, + 115, + 194, + 395, + 113, + 9, + 21, + 219, + 10, + 59, + 158, + 105, + 303, + 362, + 375, + 232, + 91, + 233, + 214, + 339, + 356, + 371, + 68, + 280, + 230, + 13, + 60, + 392, + 91, + 49, + 284, + 269, + 285, + 42, + 71, + 357, + 276, + 142, + 69, + 90, + 85, + 25, + 18, + 388, + 105, + 58, + 301, + 320, + 190, + 147, + 117, + 147, + 335, + 326, + 330, + 115, + 230, + 337, + 253, + 380, + 155, + 195, + 398, + 356, + 148, + 69, + 390, + 209, + 207, + 112, + 380, + 16, + 351, + 274, + 140, + 149, + 80, + 229, + 56, + 338, + 298, + 254, + 224, + 182, + 226, + 257, + 18, + 207, + 238, + 234, + 255, + 202, + 141, + 307, + 100, + 68, + 82, + 271, + 265, + 385, + 344, + 231, + 134, + 213, + 116, + 68, + 320, + 326, + 320, + 201, + 296, + 288, + 148, + 198, + 34, + 123, + 73, + 342, + 397, + 68, + 145, + 333, + 163, + 185, + 210, + 25, + 138, + 343, + 149, + 163, + 170, + 36, + 274, + 263, + 75, + 203, + 155, + 196, + 234, + 210, + 107, + 152, + 311, + 314, + 204, + 358, + 213, + 102, + 281, + 203, + 224, + 123, + 347, + 54, + 60, + 163, + 49, + 134, + 2, + 366, + 307, + 204, + 193, + 120, + 185, + 362, + 74, + 35, + 68, + 141, + 309, + 120, + 276, + 166, + 89, + 91, + 207, + 7, + 336, + 262, + 257, + 165, + 151, + 257, + 50, + 381, + 304, + 268, + 265, + 157, + 378, + 9, + 243, + 53, + 346, + 148, + 166, + 261, + 177, + 256, + 28, + 193, + 279, + 165, + 320, + 341, + 106, + 353, + 25, + 179, + 57, + 122, + 394, + 100, + 335, + 243, + 103, + 252, + 332, + 135, + 103, + 389, + 316, + 252, + 262, + 378, + 356, + 37, + 254, + 178, + 251, + 328, + 251, + 105, + 349, + 166, + 130, + 327, + 372, + 350, + 380, + 35, + 281, + 30, + 276, + 364, + 345, + 52, + 62, + 258, + 76, + 103, + 320, + 203, + 387, + 186, + 132, + 10, + 349, + 359, + 270, + 154, + 75, + 137, + 92, + 224, + 167, + 390, + 290, + 92, + 282, + 336, + 391, + 133, + 43, + 103, + 260, + 91, + 116, + 289, + 96, + 358, + 157, + 178, + 168, + 244, + 98, + 175, + 100, + 367, + 82, + 86, + 124, + 356, + 165, + 24, + 73, + 280, + 242, + 121, + 117, + 174, + 169, + 331, + 92, + 185, + 210, + 142, + 110, + 364, + 179, + 322, + 317, + 170, + 59, + 312, + 247, + 249, + 149, + 388, + 241, + 369, + 69, + 153, + 150, + 217, + 357, + 169, + 391, + 220, + 33, + 284, + 208, + 392, + 181, + 48, + 62, + 268, + 386, + 367, + 228, + 121, + 385, + 41, + 231, + 208, + 141, + 33, + 299, + 207, + 126, + 143, + 388, + 122, + 257, + 374, + 217, + 188, + 356, + 120, + 201, + 192, + 314, + 117, + 63, + 200, + 230, + 61, + 358, + 36, + 327, + 285, + 364, + 83, + 116, + 190, + 339, + 135, + 62, + 1, + 9, + 395, + 331, + 55, + 288, + 254, + 210, + 310, + 62, + 397, + 297, + 228, + 288, + 283, + 333, + 69, + 105, + 231, + 129, + 163, + 110, + 201, + 143, + 22, + 91, + 40, + 3, + 360, + 383, + 157, + 148, + 98, + 25, + 332, + 239, + 200, + 298, + 299, + 92, + 276, + 22, + 67, + 190, + 287, + 200, + 105, + 250, + 56, + 185, + 324, + 183, + 212, + 145, + 254, + 240, + 18, + 385, + 328, + 356, + 391, + 299, + 233, + 299, + 48, + 181, + 88, + 32, + 143, + 306, + 150, + 247, + 96, + 103, + 187, + 3, + 340, + 14, + 368, + 50, + 307, + 181, + 365, + 161, + 212, + 194, + 46, + 38, + 52, + 99, + 292, + 400, + 231, + 163, + 299, + 72, + 383, + 72, + 132, + 136, + 356, + 159, + 271, + 48, + 102, + 322, + 236, + 4, + 218, + 112, + 228, + 357, + 86, + 45, + 97, + 46, + 58, + 384, + 304, + 96, + 316, + 22, + 82, + 132, + 111, + 103, + 17, + 385, + 270, + 191, + 148, + 258, + 318, + 302, + 35, + 384, + 336, + 393, + 131, + 261, + 373, + 314, + 164, + 281, + 272, + 321, + 24, + 136, + 180, + 319, + 240, + 339, + 228, + 83, + 15, + 157, + 30, + 337, + 354, + 395, + 22, + 345, + 33, + 264, + 235, + 332, + 239, + 303, + 12, + 143, + 45, + 251, + 233, + 146, + 155, + 177, + 214, + 347, + 217, + 278, + 248, + 230, + 264, + 279, + 255, + 107, + 17, + 242, + 117, + 27, + 219, + 398, + 42, + 179, + 254, + 337, + 137, + 164, + 131, + 339, + 363, + 131, + 112, + 104, + 174, + 92, + 384, + 144, + 258, + 53, + 246, + 110, + 244, + 201, + 180, + 303, + 94, + 1, + 370, + 212, + 274, + 180, + 138, + 315, + 190, + 337, + 179, + 87, + 189, + 101, + 74, + 16, + 314, + 141, + 193, + 107, + 137, + 220, + 96, + 121, + 374, + 178, + 320, + 338, + 344, + 69, + 331, + 364, + 97, + 35, + 163, + 210, + 367, + 178, + 305, + 28, + 187, + 235, + 124, + 380, + 189, + 26, + 83, + 392, + 162, + 108, + 274, + 248, + 286, + 150, + 199, + 79, + 64, + 344, + 370, + 293, + 171, + 152, + 227, + 284, + 192, + 384, + 291, + 254, + 224, + 34, + 322, + 351, + 324, + 196, + 239, + 327, + 398, + 107, + 64, + 311, + 8, + 284, + 47, + 19, + 118, + 123, + 104, + 182, + 329, + 335, + 325, + 58, + 143, + 192, + 206, + 335, + 375, + 328, + 20, + 268, + 331, + 245, + 134, + 30, + 355, + 208, + 23, + 170, + 115, + 68, + 73, + 120, + 390, + 13, + 352, + 336, + 205, + 211, + 248, + 312, + 256, + 243, + 47, + 248, + 160, + 11, + 276, + 309, + 200, + 240, + 51, + 59, + 349, + 380, + 93, + 53, + 34, + 277, + 79, + 115, + 183, + 366, + 170, + 188, + 327, + 176, + 234, + 262, + 253, + 13, + 162, + 192, + 261, + 262, + 177, + 214, + 110, + 181, + 395, + 199, + 365, + 93, + 4, + 393, + 79, + 40, + 227, + 96, + 107, + 165, + 382, + 231, + 73, + 274, + 160, + 295, + 192, + 196, + 141, + 67, + 336, + 32, + 175, + 276, + 63, + 250, + 18, + 16, + 218, + 84, + 399, + 155, + 57, + 134, + 368, + 87, + 134, + 128, + 88, + 209, + 268, + 212, + 56, + 210, + 94, + 42, + 205, + 51, + 302, + 280, + 359, + 306, + 298, + 16, + 210, + 158, + 254, + 7, + 253, + 150, + 195, + 106, + 137, + 188, + 280, + 242, + 399, + 36, + 10, + 382, + 241, + 329, + 334, + 297, + 365, + 22, + 5, + 324, + 10, + 396, + 177, + 223, + 272, + 68, + 29, + 240, + 97, + 140, + 75, + 247, + 18, + 61, + 71, + 186, + 271, + 21, + 131, + 235, + 203, + 310, + 74, + 351, + 347, + 389, + 192, + 379, + 384, + 322, + 58, + 258, + 324, + 143, + 18, + 252, + 16, + 150, + 151, + 142, + 183, + 215, + 32, + 42, + 124, + 371, + 261, + 106, + 218, + 257, + 178, + 62, + 237, + 30, + 32, + 210, + 132, + 229, + 293, + 284, + 133, + 359, + 311, + 51, + 139, + 257, + 58, + 244, + 142, + 208, + 147, + 25, + 391, + 179, + 375, + 303, + 25, + 289, + 188, + 267, + 40, + 394, + 292, + 272, + 35, + 206, + 220, + 173, + 351, + 305, + 347, + 362, + 274, + 390, + 133, + 93, + 40, + 3, + 398, + 53, + 110, + 154, + 157, + 189, + 385, + 166, + 191, + 2, + 213, + 46, + 170, + 255, + 341, + 361, + 168, + 189, + 208, + 17, + 198, + 2, + 152, + 394, + 200, + 4, + 61, + 200, + 107, + 302, + 8, + 185, + 10, + 371, + 150, + 276, + 395, + 63, + 156, + 269, + 333, + 358, + 27, + 351, + 18, + 329, + 188, + 323, + 355, + 360, + 244, + 205, + 187, + 300, + 175, + 138, + 269, + 351, + 29, + 301, + 6, + 13, + 228, + 337, + 238, + 173, + 100, + 78, + 96, + 51, + 40, + 181, + 303, + 141, + 172, + 233, + 350, + 86, + 348, + 266, + 331, + 322, + 270, + 397, + 200, + 41, + 113, + 331, + 213, + 159, + 22, + 340, + 228, + 274, + 239, + 43, + 324, + 296, + 351, + 115, + 29, + 363, + 12, + 141, + 350, + 337, + 317, + 65, + 332, + 396, + 138, + 145, + 155, + 49, + 96, + 271, + 148, + 23, + 23, + 287, + 184, + 218, + 77, + 284, + 85, + 144, + 200, + 15, + 77, + 218, + 130, + 32, + 367, + 29, + 380, + 365, + 120, + 1, + 332, + 372, + 128, + 306, + 34, + 398, + 218, + 141, + 343, + 329, + 131, + 251, + 309, + 347, + 143, + 211, + 168, + 316, + 100, + 86, + 113, + 153, + 62, + 260, + 288, + 378, + 49, + 143, + 166, + 102, + 111, + 15, + 294, + 42, + 6, + 312, + 228, + 364, + 23, + 176, + 372, + 286, + 331, + 356, + 274, + 374, + 252, + 350, + 54, + 13, + 240, + 93, + 52, + 101, + 399, + 10, + 195, + 361, + 17, + 284, + 315, + 141, + 53, + 289, + 311, + 206, + 98, + 48, + 331, + 145, + 256, + 67, + 240, + 206, + 340, + 310, + 260, + 266, + 241, + 35, + 183, + 343, + 193, + 156, + 165, + 280, + 168, + 389, + 241, + 32, + 42, + 67, + 319, + 91, + 2, + 298, + 396, + 265, + 139, + 52, + 236, + 113, + 85, + 208, + 134, + 303, + 282, + 291, + 362, + 40, + 283, + 224, + 183, + 256, + 385, + 157, + 193, + 317, + 364, + 91, + 381, + 265, + 238, + 52, + 120, + 347, + 201, + 246, + 101, + 318, + 29, + 278, + 264, + 188, + 133, + 140, + 185, + 201, + 257, + 69, + 282, + 380, + 252, + 249, + 193, + 322, + 44, + 30, + 124, + 216, + 77, + 215, + 127, + 328, + 339, + 173, + 155, + 251, + 189, + 76, + 65, + 325, + 354, + 44, + 280, + 280, + 288, + 189, + 334, + 139, + 59, + 158, + 230, + 152, + 339, + 367, + 373, + 393, + 359, + 329, + 292, + 150, + 256, + 343, + 140, + 59, + 24, + 297, + 324, + 334, + 265, + 92, + 13, + 388, + 392, + 193, + 379, + 323, + 178, + 236, + 197, + 323, + 169, + 54, + 372, + 25, + 30, + 87, + 132, + 345, + 135, + 389, + 70, + 39, + 102, + 158, + 260, + 197, + 129, + 360, + 87, + 288, + 20, + 256, + 184, + 150, + 272, + 264, + 53, + 131, + 328, + 99, + 172, + 223, + 124, + 255, + 399, + 275, + 311, + 399, + 152, + 283, + 107, + 40, + 258, + 361, + 393, + 58, + 365, + 182, + 57, + 345, + 348, + 42, + 251, + 387, + 106, + 237, + 35, + 371, + 279, + 66, + 362, + 213, + 42, + 9, + 297, + 288, + 292, + 325, + 367, + 31, + 175, + 72, + 377, + 358, + 142, + 360, + 399, + 64, + 213, + 303, + 44, + 140, + 215, + 249, + 322, + 267, + 117, + 366, + 74, + 55, + 71, + 38, + 253, + 367, + 113, + 196, + 166, + 72, + 328, + 172, + 389, + 89, + 353, + 19, + 163, + 392, + 93, + 16, + 35, + 353, + 78, + 282, + 355, + 273, + 269, + 342, + 194, + 21, + 301, + 57, + 148, + 47, + 235, + 126, + 52, + 304, + 345, + 250, + 2, + 62, + 346, + 94, + 129, + 91, + 216, + 384, + 366, + 70, + 124, + 200, + 331, + 204, + 240, + 189, + 41, + 389, + 305, + 32, + 103, + 121, + 351, + 252, + 216, + 33, + 296, + 83, + 13, + 120, + 130, + 381, + 247, + 89, + 363, + 367, + 32, + 255, + 134, + 16, + 62, + 99, + 31, + 383, + 76, + 202, + 396, + 199, + 149, + 389, + 245, + 211, + 11, + 262, + 391, + 122, + 56, + 90, + 307, + 167, + 120, + 75, + 284, + 294, + 89, + 58, + 374, + 331, + 249, + 21, + 185, + 244, + 267, + 231, + 122, + 342, + 205, + 282, + 308, + 149, + 134, + 146, + 145, + 51, + 27, + 335, + 91, + 3, + 116, + 51, + 339, + 131, + 193, + 57, + 33, + 145, + 238, + 198, + 53, + 398, + 278, + 212, + 41, + 165, + 290, + 40, + 233, + 384, + 84, + 133, + 160, + 218, + 381, + 254, + 296, + 359, + 298, + 9, + 132, + 260, + 43, + 250, + 310, + 348, + 109, + 245, + 117, + 357, + 288, + 300, + 293, + 218, + 389, + 381, + 6, + 65, + 237, + 220, + 255, + 41, + 77, + 254, + 289, + 233, + 173, + 400, + 66, + 72, + 69, + 10, + 198, + 174, + 316, + 28, + 110, + 370, + 205, + 98, + 323, + 218, + 248, + 32, + 199, + 259, + 254, + 171, + 260, + 76, + 184, + 398, + 23, + 218, + 261, + 52, + 39, + 314, + 258, + 345, + 200, + 396, + 367, + 396, + 90, + 160, + 322, + 395, + 370, + 206, + 300, + 50, + 109, + 277, + 13, + 304, + 24, + 169, + 287, + 287, + 91, + 92, + 150, + 137, + 331, + 240, + 232, + 235, + 227, + 293, + 250, + 80, + 3, + 399, + 167, + 196, + 354, + 211, + 251, + 145, + 356, + 104, + 343, + 168, + 320, + 122, + 296, + 151, + 317, + 350, + 334, + 318, + 194, + 18, + 183, + 370, + 29, + 132, + 222, + 275, + 222, + 323, + 73, + 275, + 396, + 151, + 218, + 342, + 176, + 15, + 285, + 352, + 250, + 317, + 213, + 387, + 274, + 126, + 103, + 100, + 147, + 207, + 34, + 331, + 202, + 371, + 360, + 337, + 340, + 289, + 369, + 220, + 399, + 333, + 167, + 9, + 286, + 349, + 95, + 195, + 385, + 223, + 366, + 155, + 103, + 326, + 352, + 136, + 38, + 368, + 400, + 41, + 279, + 27, + 211, + 318, + 50, + 25, + 73, + 141, + 341, + 221, + 184, + 169, + 246, + 338, + 101, + 238, + 247, + 92, + 181, + 332, + 204, + 246, + 132, + 321, + 360, + 335, + 331, + 73, + 210, + 317, + 243, + 222, + 132, + 68, + 112, + 198, + 399, + 80, + 130, + 172, + 378, + 260, + 341, + 89, + 27, + 4, + 189, + 80, + 119, + 282, + 221, + 53, + 263, + 133, + 295, + 195, + 327, + 315, + 226, + 52, + 311, + 297, + 315, + 371, + 85, + 142, + 74, + 252, + 251, + 314, + 249, + 373, + 320, + 121, + 193, + 1, + 187, + 316, + 127, + 141, + 154, + 193, + 152, + 359, + 270, + 326, + 391, + 225, + 37, + 368, + 71, + 367, + 7, + 25, + 274, + 389, + 361, + 241, + 250, + 366, + 101, + 267, + 41, + 363, + 37, + 146, + 338, + 210, + 139, + 168, + 68, + 355, + 347, + 302, + 395, + 115, + 185, + 304, + 158, + 325, + 162, + 186, + 363, + 269, + 320, + 202, + 360, + 88, + 79, + 56, + 377, + 280, + 303, + 317, + 346, + 175, + 80, + 27, + 138, + 395, + 180, + 341, + 88, + 55, + 186, + 68, + 317, + 364, + 368, + 69, + 178, + 261, + 92, + 248, + 55, + 236, + 333, + 52, + 92, + 250, + 87, + 17, + 36, + 362, + 3, + 321, + 362, + 15, + 211, + 187, + 153, + 231, + 381, + 92, + 337, + 372, + 277, + 63, + 358, + 327, + 79, + 135, + 284, + 149, + 340, + 27, + 196, + 368, + 264, + 17, + 140, + 211, + 203, + 31, + 55, + 61, + 11, + 121, + 308, + 393, + 385, + 194, + 185, + 376, + 168, + 316, + 293, + 252, + 62, + 54, + 204, + 386, + 359, + 378, + 54, + 30, + 133, + 54, + 351, + 275, + 46, + 148, + 351, + 207, + 257, + 398, + 147, + 296, + 37, + 188, + 111, + 201, + 26, + 386, + 321, + 145, + 81, + 310, + 132, + 296, + 230, + 295, + 188, + 128, + 16, + 228, + 44, + 39, + 52, + 156, + 20, + 97, + 35, + 285, + 142, + 327, + 213, + 338, + 79, + 229, + 399, + 238, + 385, + 139, + 325, + 1, + 121, + 150, + 189, + 77, + 25, + 258, + 316, + 377, + 58, + 143, + 114, + 374, + 136, + 60, + 157, + 278, + 128, + 383, + 220, + 112, + 328, + 309, + 232, + 344, + 281, + 194, + 84, + 10, + 119, + 105, + 295, + 254, + 251, + 380, + 110, + 105, + 179, + 78, + 225, + 317, + 234, + 150, + 385, + 363, + 185, + 360, + 144, + 39, + 204, + 100, + 344, + 260, + 246, + 76, + 40, + 386, + 303, + 154, + 314, + 82, + 388, + 334, + 37, + 45, + 238, + 133, + 75, + 299, + 102, + 90, + 67, + 330, + 120, + 311, + 276, + 126, + 385, + 385, + 200, + 61, + 386, + 167, + 163, + 124, + 108, + 64, + 307, + 356, + 210, + 255, + 188, + 197, + 56, + 340, + 354, + 26, + 82, + 19, + 305, + 54, + 214, + 82, + 284, + 324, + 246, + 168, + 57, + 31, + 337, + 208, + 247, + 128, + 61, + 267, + 74, + 313, + 133, + 258, + 87, + 88, + 288, + 252, + 157, + 324, + 302, + 33, + 57, + 330, + 112, + 103, + 37, + 217, + 365, + 75, + 170, + 121, + 289, + 341, + 49, + 6, + 226, + 97, + 348, + 183, + 169, + 305, + 148, + 315, + 119, + 125, + 312, + 266, + 263, + 117, + 225, + 370, + 166, + 307, + 61, + 311, + 393, + 33, + 315, + 267, + 315, + 311, + 140, + 60, + 185, + 166, + 390, + 313, + 276, + 138, + 39, + 254, + 32, + 358, + 200, + 280, + 34, + 263, + 386, + 10, + 250, + 266, + 387, + 15, + 342, + 4, + 249, + 168, + 99, + 365, + 365, + 374, + 59, + 217, + 400, + 85, + 381, + 192, + 312, + 160, + 23, + 194, + 293, + 357, + 31, + 6, + 25, + 208, + 276, + 104, + 316, + 16, + 207, + 41, + 126, + 44, + 359, + 394, + 272, + 394, + 54, + 27, + 86, + 174, + 328, + 322, + 313, + 343, + 313, + 184, + 260, + 287, + 379, + 222, + 368, + 243, + 165, + 230, + 320, + 71, + 355, + 204, + 308, + 279, + 347, + 73, + 262, + 170, + 324, + 336, + 257, + 223, + 352, + 264, + 149, + 56, + 106, + 224, + 80, + 114, + 319, + 337, + 73, + 100, + 99, + 318, + 144, + 308, + 34, + 255, + 289, + 8, + 145, + 187, + 281, + 59, + 257, + 222, + 387, + 29, + 156, + 191, + 217, + 13, + 381, + 261, + 178, + 142, + 46, + 109, + 379, + 167, + 280, + 121, + 40, + 278, + 57, + 249, + 200, + 113, + 300, + 138, + 115, + 330, + 57, + 308, + 313, + 221, + 252, + 19, + 6, + 37, + 45, + 380, + 89, + 37, + 310, + 179, + 97, + 262, + 357, + 38, + 38, + 332, + 233, + 374, + 92, + 29, + 194, + 117, + 345, + 317, + 61, + 123, + 17, + 5, + 237, + 244, + 319, + 100, + 310, + 261, + 320, + 239, + 224, + 129, + 365, + 228, + 109, + 168, + 397, + 158, + 361, + 19, + 265, + 228, + 156, + 292, + 76, + 256, + 273, + 52, + 393, + 50, + 50, + 93, + 356, + 93, + 23, + 161, + 46, + 149, + 283, + 68, + 215, + 267, + 24, + 216, + 334, + 65, + 373, + 142, + 212, + 335, + 160, + 337, + 203, + 394, + 362, + 61, + 219, + 20, + 249, + 15, + 386, + 390, + 360, + 391, + 77, + 25, + 170, + 385, + 45, + 280, + 121, + 229, + 73, + 308, + 32, + 260, + 126, + 156, + 288, + 228, + 52, + 184, + 5, + 385, + 105, + 267, + 134, + 111, + 197, + 339, + 111, + 302, + 84, + 16, + 161, + 302, + 191, + 290, + 254, + 153, + 353, + 361, + 101, + 350, + 139, + 130, + 376, + 380, + 396, + 195, + 32, + 143, + 183, + 41, + 16, + 260, + 313, + 386, + 73, + 216, + 151, + 203, + 334, + 168, + 190, + 355, + 305, + 1, + 312, + 322, + 255, + 53, + 317, + 266, + 271, + 137, + 42, + 117, + 15, + 385, + 112, + 400, + 202, + 7, + 313, + 116, + 154, + 108, + 214, + 296, + 377, + 255, + 297, + 342, + 80, + 29, + 17, + 50, + 365, + 233, + 25, + 90, + 253, + 329, + 248, + 59, + 303, + 28, + 374, + 107, + 96, + 243, + 345, + 272, + 254, + 287, + 297, + 200, + 181, + 350, + 329, + 354, + 339, + 78, + 194, + 30, + 373, + 221, + 18, + 34, + 376, + 276, + 129, + 326, + 348, + 193, + 313, + 39, + 66, + 88, + 153, + 43, + 372, + 76, + 246, + 238, + 322, + 201, + 244, + 179, + 385, + 111, + 60, + 367, + 171, + 73, + 159, + 170, + 373, + 85, + 373, + 268, + 42, + 27, + 82, + 192, + 58, + 345, + 43, + 19, + 137, + 346, + 263, + 47, + 105, + 22, + 110, + 168, + 292, + 80, + 285, + 347, + 304, + 199, + 267, + 398, + 129, + 61, + 223, + 311, + 29, + 217, + 115, + 272, + 253, + 101, + 26, + 246, + 330, + 37, + 201, + 142, + 279, + 151, + 237, + 373, + 282, + 140, + 115, + 171, + 236, + 72, + 307, + 310, + 187, + 257, + 22, + 331, + 378, + 83, + 323, + 370, + 93, + 185, + 359, + 199, + 241, + 260, + 220, + 262, + 335, + 101, + 178, + 247, + 387, + 384, + 12, + 74, + 293, + 49, + 250, + 185, + 1, + 193, + 2, + 91, + 70, + 355, + 194, + 266, + 9, + 218, + 167, + 283, + 293, + 269, + 170, + 284, + 30, + 274, + 201, + 47, + 194, + 175, + 358, + 336, + 134, + 371, + 146, + 297, + 50, + 268, + 16, + 50, + 378, + 150, + 195, + 343, + 23, + 379, + 235, + 316, + 8, + 86, + 313, + 106, + 320, + 62, + 292, + 207, + 398, + 140, + 213, + 335, + 393, + 15, + 158, + 222, + 74, + 357, + 345, + 67, + 310, + 63, + 242, + 136, + 202, + 326, + 357, + 247, + 397, + 330, + 352, + 84, + 344, + 105, + 141, + 202, + 163, + 127, + 64, + 21, + 23, + 16, + 260, + 196, + 80, + 172, + 283, + 256, + 276, + 267, + 324, + 374, + 20, + 200, + 162, + 367, + 375, + 50, + 320, + 90, + 340, + 241, + 216, + 378, + 213, + 223, + 172, + 82, + 167, + 191, + 100, + 179, + 322, + 301, + 195, + 243, + 17, + 385, + 132, + 305, + 143, + 85, + 43, + 24, + 239, + 17, + 44, + 252, + 255, + 66, + 310, + 157, + 178, + 170, + 373, + 14, + 142, + 154, + 47, + 358, + 99, + 189, + 77, + 261, + 39, + 14, + 28, + 302, + 132, + 102, + 365, + 378, + 159, + 186, + 292, + 372, + 181, + 284, + 277, + 187, + 268, + 280, + 282, + 307, + 280, + 358, + 125, + 341, + 138, + 299, + 214, + 273, + 43, + 345, + 321, + 248, + 257, + 49, + 222, + 250, + 261, + 29, + 75, + 355, + 238, + 219, + 18, + 265, + 2, + 158, + 290, + 321, + 285, + 141, + 227, + 392, + 93, + 18, + 24, + 134, + 32, + 41, + 345, + 160, + 258, + 182, + 301, + 229, + 54, + 172, + 39, + 29, + 224, + 175, + 318, + 15, + 226, + 385, + 88, + 55, + 329, + 46, + 255, + 335, + 178, + 176, + 116, + 360, + 300, + 321, + 317, + 327, + 278, + 237, + 107, + 326, + 46, + 84, + 283, + 341, + 95, + 320, + 101, + 40, + 129, + 395, + 45, + 371, + 235, + 16, + 46, + 182, + 34, + 256, + 240, + 78, + 37, + 308, + 143, + 195, + 372, + 73, + 129, + 234, + 17, + 314, + 346, + 391, + 184, + 182, + 15, + 216, + 20, + 208, + 1, + 114, + 144, + 168, + 397, + 121, + 344, + 243, + 382, + 141, + 142, + 3, + 28, + 177, + 219, + 267, + 228, + 170, + 206, + 273, + 34, + 176, + 186, + 68, + 283, + 333, + 273, + 298, + 399, + 65, + 358, + 35, + 248, + 364, + 224, + 134, + 154, + 267, + 230, + 383, + 118, + 96, + 82, + 118, + 322, + 348, + 84, + 260, + 18, + 203, + 7, + 27, + 164, + 298, + 123, + 291, + 286, + 323, + 392, + 311, + 25, + 239, + 56, + 330, + 52, + 306, + 185, + 1, + 320, + 41, + 83, + 253, + 251, + 168, + 368, + 352, + 57, + 184, + 280, + 104, + 5, + 343, + 108, + 294, + 341, + 279, + 299, + 10, + 195, + 129, + 102, + 358, + 235, + 56, + 56, + 17, + 348, + 262, + 221, + 321, + 364, + 234, + 221, + 25, + 209, + 203, + 399, + 72, + 114, + 110, + 362, + 390, + 369, + 185, + 31, + 261, + 37, + 345, + 211, + 308, + 310, + 206, + 58, + 30, + 151, + 302, + 355, + 253, + 386, + 16, + 358, + 380, + 205, + 218, + 146, + 123, + 268, + 220, + 182, + 60, + 128, + 62, + 96, + 25, + 94, + 108, + 288, + 295, + 343, + 10, + 134, + 250, + 62, + 125, + 6, + 295, + 257, + 353, + 279, + 204, + 4, + 300, + 121, + 231, + 73, + 226, + 292, + 155, + 290, + 196, + 221, + 202, + 86, + 8, + 384, + 319, + 170, + 363, + 358, + 26, + 23, + 271, + 195, + 6, + 283, + 275, + 240, + 93, + 320, + 1, + 340, + 287, + 140, + 144, + 58, + 184, + 39, + 128, + 258, + 353, + 116, + 149, + 95, + 379, + 85, + 164, + 275, + 238, + 3, + 356, + 23, + 152, + 372, + 77, + 188, + 37, + 81, + 74, + 336, + 77, + 189, + 283, + 254, + 56, + 267, + 81, + 218, + 202, + 332, + 133, + 358, + 237, + 181, + 213, + 335, + 126, + 66, + 313, + 36, + 138, + 207, + 112, + 164, + 146, + 55, + 290, + 297, + 50, + 39, + 228, + 286, + 190, + 238, + 165, + 74, + 301, + 328, + 302, + 96, + 332, + 131, + 151, + 79, + 340, + 112, + 312, + 56, + 87, + 258, + 131, + 138, + 236, + 335, + 313, + 210, + 325, + 343, + 124, + 255, + 193, + 180, + 392, + 348, + 361, + 314, + 240, + 60, + 163, + 114, + 337, + 162, + 316, + 222, + 47, + 117, + 208, + 366, + 98, + 278, + 375, + 260, + 254, + 91, + 395, + 305, + 390, + 50, + 275, + 155, + 190, + 59, + 3, + 287, + 347, + 149, + 292, + 52, + 187, + 157, + 120, + 176, + 135, + 299, + 361, + 193, + 116, + 223, + 344, + 22, + 165, + 337, + 103, + 117, + 341, + 239, + 32, + 137, + 359, + 72, + 89, + 65, + 149, + 160, + 148, + 73, + 280, + 225, + 113, + 387, + 159, + 287, + 95, + 139, + 351, + 325, + 351, + 44, + 50, + 370, + 96, + 377, + 161, + 382, + 323, + 168, + 324, + 309, + 293, + 128, + 263, + 293, + 262, + 266, + 261, + 71, + 385, + 287, + 237, + 190, + 119, + 41, + 184, + 228, + 222, + 258, + 379, + 152, + 272, + 242, + 321, + 22, + 24, + 353, + 133, + 36, + 214, + 9, + 368, + 254, + 249, + 298, + 216, + 320, + 257, + 347, + 136, + 26, + 263, + 79, + 361, + 285, + 280, + 289, + 96, + 125, + 210, + 143, + 248, + 393, + 225, + 324, + 305, + 21, + 378, + 333, + 247, + 297, + 369, + 244, + 373, + 197, + 271, + 164, + 373, + 75, + 195, + 321, + 62, + 63, + 240, + 81, + 172, + 219, + 189, + 47, + 75, + 238, + 258, + 36, + 38, + 24, + 35, + 43, + 52, + 25, + 69, + 111, + 255, + 294, + 396, + 50, + 2, + 203, + 164, + 86, + 164, + 70, + 284, + 24, + 254, + 358, + 36, + 158, + 24, + 72, + 201, + 160, + 182, + 190, + 4, + 171, + 49, + 344, + 260, + 319, + 398, + 332, + 25, + 126, + 296, + 317, + 329, + 271, + 344, + 392, + 386, + 334, + 140, + 45, + 166, + 363, + 234, + 146, + 254, + 113, + 168, + 313, + 383, + 107, + 175, + 138, + 149, + 252, + 121, + 250, + 334, + 291, + 208, + 388, + 111, + 112, + 87, + 39, + 207, + 205, + 173, + 310, + 96, + 252, + 121, + 27, + 360, + 205, + 357, + 337, + 373, + 380, + 177, + 91, + 278, + 189, + 294, + 338, + 324, + 37, + 343, + 354, + 129, + 42, + 374, + 259, + 354, + 135, + 333, + 84, + 228, + 280, + 99, + 244, + 297, + 172, + 263, + 237, + 180, + 240, + 117, + 178, + 22, + 327, + 4, + 109, + 306, + 140, + 182, + 178, + 2, + 4, + 78, + 233, + 325, + 13, + 188, + 231, + 356, + 379, + 377, + 114, + 76, + 82, + 96, + 234, + 365, + 173, + 343, + 101, + 38, + 138, + 175, + 298, + 91, + 150, + 44, + 218, + 239, + 167, + 157, + 81, + 197, + 91, + 63, + 313, + 102, + 151, + 377, + 77, + 138, + 215, + 337, + 257, + 353, + 233, + 388, + 342, + 343, + 10, + 309, + 122, + 40, + 323, + 377, + 352, + 337, + 65, + 173, + 78, + 135, + 364, + 141, + 36, + 191, + 62, + 202, + 53, + 366, + 63, + 326, + 254, + 12, + 55, + 247, + 361, + 190, + 162, + 395, + 19, + 52, + 220, + 6, + 326, + 227, + 8, + 102, + 334, + 358, + 284, + 69, + 216, + 173, + 128, + 58, + 205, + 213, + 84, + 290, + 34, + 379, + 24, + 275, + 222, + 129, + 128, + 384, + 327, + 303, + 138, + 61, + 106, + 124, + 255, + 378, + 194, + 137, + 99, + 357, + 258, + 371, + 131, + 200, + 55, + 71, + 239, + 289, + 343, + 141, + 237, + 112, + 5, + 39, + 32, + 231, + 309, + 37, + 175, + 199, + 45, + 227, + 241, + 332, + 223, + 318, + 310, + 395, + 219, + 275, + 109, + 272, + 187, + 34, + 114, + 311, + 8, + 249, + 55, + 118, + 333, + 53, + 214, + 340, + 133, + 229, + 103, + 154, + 251, + 265, + 153, + 12, + 293, + 108, + 209, + 334, + 277, + 57, + 366, + 36, + 339, + 25, + 135, + 40, + 240, + 271, + 315, + 13, + 390, + 100, + 380, + 26, + 162, + 80, + 88, + 390, + 371, + 339, + 239, + 200, + 115, + 120, + 106, + 59, + 98, + 240, + 15, + 32, + 91, + 108, + 95, + 52, + 275, + 160, + 195, + 98, + 53, + 399, + 59, + 388, + 317, + 337, + 252, + 209, + 68, + 348, + 375, + 18, + 120, + 259, + 248, + 248, + 2, + 35, + 375, + 39, + 23, + 355, + 233, + 31, + 371, + 388, + 319, + 335, + 242, + 374, + 77, + 381, + 251, + 243, + 389, + 262, + 190, + 117, + 324, + 218, + 397, + 263, + 386, + 80, + 360, + 223, + 192, + 177, + 207, + 148, + 75, + 368, + 73, + 395, + 236, + 163, + 230, + 134, + 162, + 262, + 48, + 331, + 162, + 201, + 68, + 209, + 192, + 272, + 331, + 390, + 298, + 227, + 323, + 43, + 297, + 144, + 262, + 64, + 272, + 241, + 137, + 187, + 58, + 336, + 157, + 373, + 66, + 217, + 257, + 336, + 259, + 82, + 77, + 166, + 185, + 385, + 172, + 106, + 309, + 297, + 213, + 377, + 212, + 225, + 239, + 320, + 288, + 316, + 3, + 227, + 154, + 99, + 208, + 210, + 289, + 338, + 226, + 362, + 37, + 250, + 164, + 313, + 315, + 68, + 165, + 386, + 189, + 140, + 103, + 399, + 397, + 229, + 238, + 105, + 100, + 155, + 181, + 310, + 191, + 338, + 314, + 36, + 228, + 293, + 151, + 232, + 170, + 155, + 374, + 272, + 386, + 256, + 331, + 348, + 400, + 165, + 164, + 108, + 320, + 320, + 80, + 131, + 156, + 66, + 83, + 334, + 362, + 327, + 286, + 301, + 300, + 22, + 253, + 108, + 120, + 289, + 118, + 77, + 164, + 124, + 208, + 19, + 45, + 98, + 310, + 338, + 223, + 109, + 398, + 341, + 362, + 25, + 305, + 104, + 181, + 94, + 50, + 353, + 36, + 205, + 96, + 72, + 354, + 281, + 326, + 304, + 395, + 328, + 377, + 188, + 10, + 91, + 185, + 337, + 341, + 392, + 324, + 130, + 193, + 263, + 131, + 258, + 245, + 235, + 14, + 202, + 356, + 155, + 284, + 225, + 372, + 72, + 145, + 290, + 258, + 142, + 233, + 9, + 130, + 245, + 286, + 116, + 132, + 348, + 63, + 335, + 245, + 232, + 38, + 214, + 127, + 246, + 302, + 241, + 176, + 277, + 264, + 22, + 85, + 120, + 172, + 91, + 55, + 52, + 221, + 118, + 355, + 137, + 182, + 209, + 376, + 228, + 47, + 291, + 229, + 384, + 126, + 234, + 267, + 364, + 345, + 250, + 64, + 296, + 35, + 150, + 196, + 381, + 142, + 5, + 122, + 337, + 109, + 183, + 272, + 4, + 191, + 243, + 134, + 36, + 49, + 84, + 377, + 22, + 188, + 89, + 286, + 77, + 160, + 77, + 192, + 331, + 99, + 148, + 34, + 187, + 219, + 339, + 180, + 368, + 110, + 159, + 172, + 125, + 101, + 364, + 156, + 239, + 304, + 349, + 56, + 123, + 225, + 348, + 357, + 47, + 126, + 166, + 165, + 144, + 74, + 51, + 79, + 199, + 45, + 153, + 27, + 225, + 299, + 135, + 387, + 175, + 4, + 347, + 398, + 10, + 358, + 226, + 269, + 307, + 347, + 72, + 196, + 17, + 55, + 96, + 346, + 75, + 196, + 223, + 266, + 299, + 209, + 385, + 146, + 68, + 348, + 395, + 324, + 84, + 256, + 126, + 182, + 75, + 218, + 57, + 217, + 145, + 75, + 283, + 396, + 367, + 290, + 12, + 120, + 261, + 21, + 115, + 39, + 26, + 399, + 62, + 204, + 220, + 300, + 396, + 380, + 129, + 244, + 357, + 362, + 286, + 40, + 29, + 109, + 270, + 86, + 376, + 5, + 24, + 47, + 388, + 123, + 252, + 189, + 137, + 375, + 16, + 148, + 391, + 279, + 396, + 322, + 145, + 123, + 219, + 305, + 272, + 188, + 107, + 376, + 315, + 370, + 251, + 58, + 302, + 17, + 156, + 322, + 376, + 37, + 72, + 43, + 292, + 166, + 398, + 258, + 328, + 261, + 58, + 393, + 43, + 245, + 26, + 130, + 319, + 346, + 35, + 197, + 69, + 131, + 378, + 47, + 231, + 245, + 31, + 188, + 27, + 300, + 20, + 363, + 306, + 225, + 120, + 86, + 219, + 19, + 79, + 105, + 267, + 344, + 284, + 314, + 108, + 202, + 242, + 148, + 46, + 365, + 20, + 226, + 376, + 265, + 148, + 38, + 122, + 267, + 241, + 235, + 398, + 133, + 208, + 238, + 214, + 181, + 124, + 310, + 27, + 156, + 99, + 201, + 16, + 339, + 64, + 134, + 77, + 44, + 157, + 284, + 182, + 29, + 107, + 69, + 161, + 31, + 327, + 82, + 5, + 285, + 377, + 246, + 267, + 244, + 139, + 63, + 238, + 57, + 228, + 200, + 305, + 104, + 389, + 79, + 152, + 201, + 380, + 246, + 383, + 10, + 100, + 304, + 204, + 92, + 104, + 302, + 354, + 33, + 31, + 239, + 273, + 208, + 77, + 366, + 373, + 154, + 123, + 103, + 319, + 71, + 155, + 247, + 106, + 46, + 186, + 78, + 181, + 120, + 280, + 308, + 217, + 288, + 33, + 122, + 241, + 376, + 343, + 190, + 374, + 182, + 154, + 186, + 205, + 192, + 184, + 298, + 115, + 62, + 2, + 324, + 183, + 368, + 198, + 113, + 299, + 67, + 178, + 40, + 131, + 292, + 92, + 368, + 370, + 399, + 200, + 33, + 187, + 245, + 327, + 359, + 17, + 166, + 34, + 340, + 244, + 178, + 240, + 71, + 104, + 74, + 286, + 292, + 384, + 242, + 229, + 166, + 127, + 190, + 184, + 166, + 288, + 252, + 317, + 81, + 32, + 77, + 231, + 204, + 277, + 347, + 345, + 79, + 14, + 261, + 84, + 242, + 111, + 274, + 157, + 315, + 248, + 352, + 66, + 243, + 212, + 83, + 218, + 261, + 126, + 10, + 134, + 135, + 7, + 281, + 166, + 253, + 358, + 108, + 382, + 235, + 271, + 143, + 139, + 286, + 32, + 228, + 387, + 242, + 190, + 177, + 318, + 122, + 354, + 100, + 76, + 160, + 274, + 382, + 114, + 163, + 78, + 55, + 101, + 153, + 130, + 292, + 285, + 291, + 152, + 107, + 11, + 57, + 117, + 173, + 6, + 110, + 182, + 350, + 325, + 195, + 139, + 301, + 210, + 102, + 35, + 195, + 272, + 272, + 393, + 12, + 215, + 97, + 91, + 308, + 162, + 395, + 273, + 244, + 278, + 246, + 327, + 293, + 80, + 265, + 282, + 318, + 268, + 52, + 93, + 294, + 156, + 36, + 184, + 374, + 172, + 291, + 64, + 327, + 208, + 67, + 346, + 228, + 393, + 121, + 387, + 307, + 263, + 392, + 98, + 231, + 294, + 340, + 308, + 270, + 81, + 171, + 160, + 331, + 141, + 204, + 26, + 348, + 33, + 81, + 203, + 24, + 333, + 21, + 351, + 359, + 219, + 203, + 272, + 61, + 321, + 267, + 35, + 225, + 98, + 346, + 253, + 122, + 307, + 20, + 152, + 128, + 121, + 307, + 47, + 74, + 221, + 367, + 339, + 290, + 329, + 313, + 330, + 103, + 369, + 66, + 60, + 169, + 52, + 368, + 90, + 392, + 213, + 45, + 103, + 98, + 125, + 124, + 269, + 74, + 147, + 157, + 78, + 279, + 48, + 396, + 96, + 27, + 384, + 124, + 385, + 132, + 299, + 178, + 98, + 343, + 226, + 277, + 69, + 276, + 208, + 325, + 353, + 369, + 290, + 103, + 301, + 166, + 252, + 202, + 33, + 293, + 195, + 151, + 388, + 345, + 184, + 91, + 8, + 120, + 160, + 23, + 229, + 211, + 169, + 278, + 364, + 78, + 279, + 391, + 351, + 37, + 364, + 249, + 17, + 117, + 55, + 60, + 327, + 178, + 206, + 307, + 70, + 31, + 377, + 400, + 269, + 1, + 274, + 169, + 141, + 174, + 326, + 72, + 257, + 244, + 196, + 78, + 384, + 312, + 229, + 331, + 39, + 85, + 235, + 88, + 165, + 219, + 234, + 31, + 303, + 388, + 364, + 271, + 144, + 376, + 129, + 11, + 199, + 12, + 376, + 178, + 130, + 80, + 53, + 345, + 299, + 15, + 23, + 178, + 189, + 9, + 36, + 288, + 326, + 119, + 20, + 197, + 204, + 329, + 149, + 311, + 143, + 223, + 213, + 242, + 379, + 50, + 55, + 76, + 362, + 308, + 221, + 226, + 27, + 88, + 165, + 315, + 85, + 327, + 168, + 251, + 57, + 3, + 231, + 128, + 392, + 347, + 160, + 386, + 69, + 135, + 377, + 197, + 83, + 339, + 28, + 83, + 117, + 347, + 44, + 234, + 180, + 166, + 69, + 48, + 233, + 252, + 237, + 73, + 58, + 60, + 188, + 98, + 294, + 30, + 39, + 364, + 138, + 160, + 282, + 100, + 167, + 195, + 37, + 76, + 244, + 293, + 290, + 34, + 99, + 315, + 377, + 262, + 173, + 400, + 161, + 5, + 160, + 27, + 337, + 271, + 128, + 2, + 327, + 312, + 163, + 52, + 322, + 329, + 284, + 374, + 99, + 29, + 237, + 124, + 8, + 325, + 293, + 222, + 16, + 242, + 50, + 383, + 94, + 322, + 225, + 155, + 309, + 111, + 169, + 376, + 201, + 94, + 299, + 163, + 167, + 362, + 152, + 194, + 326, + 332, + 305, + 193, + 227, + 120, + 340, + 325, + 294, + 263, + 130, + 262, + 152, + 332, + 25, + 161, + 46, + 337, + 229, + 21, + 170, + 365, + 259, + 23, + 1, + 299, + 374, + 310, + 285, + 243, + 391, + 11, + 129, + 75, + 286, + 140, + 357, + 315, + 390, + 256, + 237, + 245, + 283, + 194, + 338, + 25, + 100, + 188, + 233, + 172, + 158, + 266, + 333, + 77, + 356, + 358, + 241, + 74, + 41, + 46, + 136, + 7, + 283, + 302, + 271, + 23, + 151, + 85, + 209, + 252, + 340, + 166, + 318, + 128, + 75, + 114, + 321, + 69, + 74, + 83, + 62, + 108, + 377, + 86, + 232, + 345, + 225, + 328, + 35, + 268, + 105, + 287, + 181, + 135, + 27, + 48, + 382, + 359, + 144, + 336, + 50, + 3, + 321, + 389, + 313, + 291, + 1, + 363, + 231, + 156, + 185, + 384, + 394, + 245, + 208, + 23, + 385, + 166, + 301, + 165, + 63, + 194, + 83, + 209, + 320, + 229, + 381, + 169, + 182, + 79, + 110, + 20, + 354, + 266, + 26, + 216, + 268, + 303, + 1, + 222, + 135, + 297, + 45, + 313, + 130, + 54, + 242, + 9, + 354, + 370, + 105, + 396, + 205, + 38, + 224, + 131, + 207, + 317, + 225, + 344, + 242, + 241, + 271, + 239, + 42, + 110, + 367, + 257, + 9, + 279, + 107, + 310, + 276, + 322, + 293, + 44, + 99, + 22, + 278, + 137, + 258, + 111, + 221, + 335, + 321, + 153, + 382, + 97, + 58, + 64, + 105, + 170, + 168, + 196, + 136, + 349, + 33, + 57, + 360, + 224, + 133, + 323, + 310, + 292, + 309, + 146, + 35, + 106, + 87, + 202, + 127, + 355, + 156, + 398, + 116, + 281, + 136, + 241, + 231, + 315, + 62, + 301, + 398, + 259, + 247, + 187, + 208, + 15, + 215, + 233, + 124, + 157, + 210, + 279, + 256, + 400, + 102, + 353, + 400, + 392, + 293, + 63, + 131, + 236, + 105, + 307, + 275, + 204, + 169, + 303, + 191, + 397, + 204, + 158, + 341, + 229, + 131, + 244, + 58, + 331, + 368, + 55, + 270, + 162, + 258, + 232, + 237, + 190, + 108, + 105, + 391, + 371, + 304, + 378, + 29, + 201, + 163, + 232, + 317, + 36, + 396, + 318, + 179, + 374, + 286, + 254, + 273, + 251, + 62, + 155, + 41, + 212, + 51, + 380, + 292, + 145, + 331, + 14, + 367, + 306, + 230, + 299, + 157, + 387, + 356, + 181, + 249, + 361, + 376, + 256, + 340, + 111, + 376, + 91, + 76, + 89, + 119, + 67, + 398, + 139, + 378, + 82, + 202, + 91, + 179, + 115, + 215, + 136, + 393, + 245, + 159, + 195, + 400, + 153, + 262, + 187, + 374, + 255, + 98, + 392, + 128, + 266, + 5, + 19, + 121, + 324, + 309, + 274, + 320, + 56, + 398, + 327, + 4, + 330, + 231, + 95, + 96, + 279, + 252, + 297, + 122, + 70, + 18, + 39, + 300, + 61, + 230, + 8, + 293, + 139, + 198, + 282, + 366, + 57, + 241, + 188, + 86, + 276, + 140, + 380, + 119, + 200, + 207, + 153, + 51, + 256, + 322, + 63, + 78, + 158, + 361, + 5, + 264, + 189, + 279, + 162, + 64, + 347, + 383, + 66, + 7, + 110, + 117, + 52, + 74, + 103, + 168, + 181, + 395, + 90, + 317, + 21, + 244, + 78, + 328, + 208, + 195, + 227, + 353, + 340, + 37, + 66, + 118, + 341, + 326, + 148, + 349, + 327, + 28, + 287, + 317, + 178, + 379, + 382, + 186, + 40, + 204, + 344, + 334, + 352, + 383, + 154, + 213, + 108, + 94, + 291, + 313, + 400, + 255, + 173, + 238, + 252, + 31, + 296, + 212, + 267, + 223, + 63, + 138, + 377, + 364, + 178, + 200, + 201, + 215, + 175, + 370, + 90, + 372, + 7, + 77, + 114, + 226, + 368, + 22, + 48, + 228, + 51, + 323, + 103, + 24, + 257, + 164, + 11, + 394, + 99, + 349, + 99, + 20, + 61, + 89, + 47, + 275, + 355, + 69, + 115, + 49, + 274, + 212, + 142, + 41, + 97, + 8, + 281, + 231, + 156, + 260, + 303, + 14, + 200, + 184, + 303, + 146, + 157, + 94, + 193, + 154, + 367, + 360, + 156, + 35, + 182, + 235, + 262, + 295, + 392, + 146, + 115, + 355, + 282, + 131, + 348, + 64, + 361, + 257, + 362, + 287, + 283, + 243, + 330, + 73, + 178, + 357, + 185, + 98, + 318, + 299, + 102, + 268, + 88, + 36, + 227, + 166, + 153, + 317, + 107, + 64, + 3, + 7, + 70, + 175, + 17, + 198, + 158, + 195, + 354, + 261, + 51, + 176, + 296, + 138, + 144, + 288, + 13, + 299, + 325, + 274, + 187, + 33, + 253, + 391, + 349, + 127, + 167, + 124, + 263, + 85, + 49, + 246, + 278, + 361, + 6, + 7, + 286, + 145, + 116, + 126, + 106, + 285, + 103, + 86, + 85, + 30, + 176, + 72, + 253, + 199, + 88, + 216, + 163, + 69, + 217, + 376, + 256, + 82, + 385, + 361, + 116, + 193, + 195, + 394, + 151, + 258, + 182, + 43, + 286, + 109, + 110, + 1, + 176, + 78, + 371, + 219, + 192, + 329, + 50, + 168, + 203, + 214, + 128, + 361, + 250, + 263, + 177, + 337, + 143, + 8, + 178, + 325, + 122, + 204, + 90, + 287, + 398, + 322, + 368, + 176, + 391, + 31, + 358, + 260, + 288, + 30, + 224, + 125, + 362, + 400, + 81, + 74, + 15, + 52, + 209, + 219, + 28, + 182, + 132, + 193, + 183, + 356, + 337, + 315, + 67, + 229, + 102, + 274, + 334, + 391, + 90, + 58, + 162, + 249, + 139, + 109, + 275, + 159, + 246, + 260, + 392, + 138, + 169, + 70, + 83, + 352, + 328, + 110, + 251, + 375, + 153, + 171, + 176, + 393, + 298, + 34, + 89, + 202, + 314, + 246, + 250, + 367, + 10, + 126, + 309, + 42, + 201, + 351, + 41, + 98, + 265, + 6, + 160, + 30, + 112, + 205, + 219, + 356, + 24, + 57, + 224, + 44, + 168, + 143, + 225, + 106, + 192, + 65, + 65, + 8, + 84, + 244, + 394, + 71, + 5, + 307, + 106, + 48, + 66, + 21, + 294, + 235, + 257, + 6, + 203, + 179, + 372, + 161, + 174, + 187, + 359, + 9, + 251, + 318, + 400, + 356, + 301, + 245, + 362, + 305, + 179, + 345, + 134, + 25, + 306, + 361, + 228, + 210, + 239, + 297, + 247, + 203, + 248, + 190, + 138, + 311, + 79, + 232, + 330, + 37, + 157, + 332, + 247, + 151, + 255, + 91, + 1, + 39, + 313, + 369, + 10, + 75, + 292, + 122, + 311, + 311, + 272, + 312, + 212, + 372, + 351, + 80, + 70, + 33, + 9, + 355, + 17, + 290, + 196, + 2, + 181, + 174, + 106, + 3, + 259, + 228, + 247, + 59, + 257, + 154, + 144, + 367, + 78, + 249, + 357, + 246, + 115, + 229, + 241, + 303, + 240, + 197, + 3, + 106, + 363, + 243, + 257, + 79, + 330, + 82, + 148, + 264, + 103, + 205, + 120, + 83, + 207, + 132, + 215, + 293, + 59, + 79, + 88, + 322, + 299, + 390, + 358, + 160, + 360, + 112, + 231, + 18, + 298, + 334, + 223, + 224, + 198, + 244, + 22, + 357, + 114, + 23, + 257, + 387, + 240, + 115, + 351, + 255, + 74, + 104, + 56, + 284, + 105, + 121, + 63, + 127, + 186, + 323, + 233, + 93, + 396, + 45, + 254, + 375, + 188, + 168, + 326, + 221, + 357, + 347, + 289, + 172, + 220, + 361, + 370, + 288, + 149, + 324, + 240, + 325, + 233, + 244, + 129, + 82, + 183, + 108, + 318, + 10, + 84, + 394, + 162, + 194, + 38, + 223, + 204, + 379, + 264, + 354, + 333, + 212, + 126, + 298, + 226, + 191, + 3, + 206, + 32, + 58, + 385, + 278, + 114, + 12, + 271, + 304, + 171, + 59, + 131, + 10, + 267, + 167, + 142, + 1, + 389, + 333, + 344, + 175, + 25, + 295, + 17, + 21, + 110, + 83, + 238, + 319, + 98, + 148, + 288, + 236, + 126, + 87, + 395, + 28, + 200, + 77, + 53, + 138, + 387, + 314, + 4, + 68, + 180, + 23, + 14, + 42, + 303, + 138, + 58, + 325, + 142, + 91, + 186, + 209, + 169, + 162, + 194, + 192, + 239, + 45, + 48, + 6, + 107, + 15, + 109, + 248, + 396, + 114, + 376, + 377, + 399, + 374, + 276, + 56, + 181, + 156, + 320, + 229, + 284, + 59, + 342, + 293, + 117, + 176, + 107, + 264, + 174, + 334, + 197, + 149, + 380, + 216, + 30, + 133, + 166, + 319, + 222, + 328, + 39, + 393, + 144, + 126, + 126, + 217, + 168, + 194, + 226, + 86, + 148, + 12, + 17, + 257, + 108, + 275, + 157, + 273, + 184, + 1, + 276, + 342, + 12, + 110, + 379, + 158, + 73, + 323, + 188, + 114, + 246, + 125, + 41, + 349, + 60, + 40, + 228, + 104, + 88, + 231, + 28, + 280, + 164, + 76, + 196, + 84, + 326, + 149, + 19, + 69, + 142, + 59, + 290, + 385, + 311, + 243, + 324, + 107, + 163, + 63, + 213, + 255, + 191, + 186, + 2, + 300, + 253, + 369, + 254, + 247, + 150, + 50, + 242, + 253, + 77, + 239, + 361, + 92, + 330, + 8, + 374, + 315, + 193, + 15, + 165, + 194, + 111, + 153, + 159, + 207, + 82, + 146, + 21, + 397, + 161, + 150, + 240, + 29, + 77, + 371, + 60, + 27, + 11, + 291, + 261, + 30, + 289, + 369, + 139, + 32, + 158, + 257, + 307, + 293, + 9, + 155, + 228, + 187, + 369, + 393, + 331, + 88, + 160, + 324, + 267, + 31, + 330, + 226, + 387, + 20, + 376, + 394, + 298, + 231, + 138, + 57, + 152, + 253, + 157, + 31, + 287, + 62, + 380, + 79, + 92, + 195, + 367, + 124, + 217, + 8, + 22, + 255, + 202, + 359, + 261, + 138, + 230, + 229, + 156, + 103, + 182, + 235, + 184, + 310, + 330, + 105, + 47, + 141, + 297, + 319, + 283, + 160, + 174, + 342, + 1, + 84, + 229, + 286, + 82, + 40, + 391, + 57, + 216, + 314, + 383, + 344, + 4, + 296, + 353, + 182, + 218, + 354, + 135, + 280, + 378, + 109, + 337, + 10, + 298, + 189, + 209, + 150, + 162, + 388, + 262, + 37, + 239, + 145, + 13, + 137, + 309, + 221, + 201, + 391, + 156, + 17, + 153, + 112, + 273, + 210, + 395, + 136, + 234, + 390, + 173, + 206, + 225, + 132, + 227, + 279, + 330, + 13, + 81, + 262, + 336, + 339, + 365, + 395, + 273, + 293, + 122, + 35, + 208, + 216, + 357, + 143, + 7, + 240, + 151, + 220, + 361, + 64, + 89, + 279, + 180, + 155, + 353, + 178, + 390, + 383, + 39, + 70, + 360, + 34, + 221, + 98, + 99, + 178, + 282, + 257, + 268, + 348, + 61, + 186, + 317, + 189, + 376, + 290, + 140, + 173, + 88, + 83, + 9, + 383, + 321, + 382, + 290, + 392, + 398, + 200, + 248, + 17, + 175, + 67, + 53, + 371, + 62, + 131, + 25, + 330, + 54, + 254, + 157, + 214, + 31, + 76, + 229, + 245, + 114, + 259, + 125, + 353, + 78, + 120, + 336, + 138, + 160, + 212, + 184, + 105, + 146, + 136, + 149, + 40, + 361, + 209, + 204, + 297, + 232, + 142, + 294, + 343, + 180, + 241, + 48, + 80, + 354, + 267, + 78, + 307, + 221, + 4, + 34, + 15, + 100, + 126, + 274, + 319, + 82, + 338, + 237, + 120, + 132, + 232, + 193, + 50, + 338, + 124, + 339, + 129, + 335, + 253, + 146, + 126, + 78, + 163, + 187, + 84, + 205, + 396, + 296, + 279, + 143, + 381, + 285, + 110, + 182, + 135, + 241, + 298, + 157, + 4, + 343, + 161, + 181, + 373, + 226, + 87, + 378, + 26, + 340, + 382, + 22, + 329, + 174, + 83, + 333, + 13, + 228, + 335, + 166, + 298, + 303, + 115, + 274, + 181, + 351, + 378, + 311, + 68, + 152, + 84, + 87, + 266, + 143, + 394, + 12, + 110, + 123, + 242, + 294, + 325, + 90, + 219, + 201, + 93, + 71, + 20, + 181, + 235, + 346, + 385, + 158, + 199, + 91, + 306, + 107, + 318, + 380, + 96, + 346, + 193, + 385, + 365, + 136, + 99, + 283, + 103, + 298, + 170, + 245, + 140, + 145, + 74, + 374, + 381, + 61, + 312, + 251, + 352, + 252, + 299, + 382, + 272, + 280, + 43, + 395, + 26, + 10, + 400, + 50, + 70, + 164, + 220, + 183, + 221, + 374, + 355, + 330, + 169, + 136, + 318, + 23, + 234, + 381, + 184, + 344, + 299, + 289, + 369, + 265, + 263, + 252, + 244, + 398, + 247, + 315, + 168, + 235, + 233, + 141, + 4, + 251, + 201, + 166, + 158, + 16, + 365, + 238, + 52, + 93, + 197, + 88, + 284, + 288, + 116, + 33, + 392, + 164, + 204, + 75, + 343, + 248, + 260, + 258, + 319, + 277, + 166, + 179, + 35, + 287, + 214, + 263, + 48, + 23, + 297, + 273, + 355, + 237, + 127, + 162, + 33, + 142, + 92, + 236, + 144, + 307, + 108, + 72, + 305, + 358, + 79, + 91, + 47, + 54, + 400, + 235, + 193, + 80, + 104, + 235, + 380, + 292, + 120, + 201, + 145, + 209, + 47, + 149, + 193, + 159, + 302, + 181, + 322, + 250, + 205, + 49, + 115, + 149, + 121, + 164, + 316, + 345, + 278, + 338, + 69, + 178, + 66, + 145, + 348, + 395, + 168, + 227, + 233, + 272, + 218, + 122, + 44, + 349, + 257, + 173, + 197, + 109, + 248, + 152, + 345, + 271, + 21, + 334, + 280, + 167, + 130, + 105, + 272, + 115, + 22, + 284, + 274, + 9, + 214, + 272, + 157, + 277, + 82, + 357, + 264, + 100, + 369, + 336, + 260, + 355, + 103, + 158, + 163, + 209, + 61, + 11, + 199, + 188, + 113, + 167, + 378, + 324, + 186, + 361, + 24, + 146, + 172, + 67, + 259, + 288, + 37, + 61, + 253, + 342, + 152, + 8, + 83, + 50, + 391, + 283, + 106, + 196, + 180, + 92, + 187, + 219, + 345, + 369, + 382, + 316, + 89, + 313, + 251, + 318, + 67, + 326, + 321, + 148, + 247, + 31, + 117, + 359, + 388, + 215, + 127, + 318, + 233, + 327, + 265, + 376, + 301, + 8, + 207, + 245, + 23, + 369, + 201, + 8, + 289, + 345, + 259, + 329, + 311, + 241, + 283, + 3, + 361, + 243, + 155, + 110, + 389, + 396, + 349, + 43, + 204, + 64, + 337, + 248, + 201, + 86, + 38, + 304, + 204, + 365, + 233, + 200, + 330, + 198, + 359, + 313, + 147, + 116, + 243, + 7, + 120, + 365, + 66, + 381, + 377, + 222, + 58, + 344, + 385, + 236, + 250, + 183, + 247, + 319, + 164, + 60, + 258, + 39, + 337, + 398, + 78, + 2, + 5, + 341, + 149, + 273, + 194, + 103, + 76, + 161, + 149, + 82, + 279, + 68, + 178, + 268, + 338, + 21, + 228, + 117, + 389, + 48, + 22, + 91, + 300, + 199, + 253, + 358, + 338, + 340, + 74, + 354, + 275, + 262, + 13, + 58, + 52, + 62, + 263, + 224, + 242, + 306, + 87, + 355, + 38, + 44, + 85, + 217, + 135, + 33, + 357, + 29, + 214, + 24, + 312, + 341, + 209, + 303, + 103, + 8, + 112, + 31, + 203, + 311, + 367, + 65, + 118, + 47, + 262, + 59, + 247, + 59, + 18, + 199, + 192, + 80, + 242, + 253, + 359, + 226, + 247, + 25, + 185, + 198, + 337, + 70, + 377, + 366, + 206, + 373, + 357, + 329, + 316, + 290, + 293, + 300, + 67, + 222, + 148, + 76, + 24, + 31, + 41, + 303, + 244, + 210, + 130, + 306, + 368, + 335, + 180, + 303, + 305, + 392, + 68, + 213, + 309, + 148, + 279, + 89, + 255, + 394, + 6, + 162, + 308, + 257, + 290, + 161, + 105, + 362, + 147, + 22, + 351, + 248, + 332, + 173, + 37, + 193, + 11, + 105, + 125, + 70, + 228, + 322, + 74, + 246, + 91, + 315, + 381, + 332, + 374, + 198, + 11, + 222, + 383, + 267, + 143, + 46, + 180, + 183, + 236, + 258, + 16, + 3, + 102, + 4, + 386, + 143, + 113, + 322, + 200, + 61, + 164, + 81, + 18, + 21, + 152, + 252, + 279, + 269, + 82, + 205, + 183, + 91, + 108, + 15, + 61, + 342, + 126, + 181, + 318, + 394, + 16, + 52, + 151, + 91, + 188, + 359, + 126, + 212, + 3, + 14, + 163, + 342, + 67, + 304, + 242, + 97, + 240, + 292, + 228, + 1, + 289, + 328, + 18, + 266, + 29, + 123, + 135, + 79, + 143, + 162, + 210, + 211, + 307, + 199, + 175, + 214, + 214, + 366, + 10, + 378, + 47, + 61, + 148, + 17, + 254, + 389, + 302, + 164, + 185, + 124, + 136, + 379, + 291, + 34, + 130, + 370, + 141, + 171, + 263, + 348, + 381, + 184, + 126, + 338, + 245, + 356, + 14, + 90, + 265, + 150, + 229, + 137, + 38, + 189, + 180, + 67, + 156, + 27, + 30, + 298, + 286, + 1, + 85, + 43, + 155, + 26, + 6, + 61, + 44, + 203, + 352, + 293, + 112, + 224, + 360, + 184, + 276, + 177, + 196, + 166, + 348, + 27, + 397, + 245, + 389, + 66, + 396, + 18, + 214, + 330, + 81, + 3, + 352, + 108, + 323, + 28, + 265, + 37, + 274, + 221, + 355, + 64, + 159, + 270, + 62, + 59, + 187, + 63, + 316, + 39, + 62, + 13, + 151, + 63, + 364, + 380, + 330, + 329, + 22, + 146, + 36, + 141, + 62, + 24, + 294, + 130, + 290, + 254, + 112, + 308, + 155, + 88, + 374, + 328, + 363, + 137, + 274, + 280, + 303, + 154, + 2, + 296, + 29, + 99, + 266, + 138, + 48, + 223, + 89, + 75, + 91, + 229, + 309, + 234, + 13, + 219, + 219, + 7, + 385, + 225, + 273, + 87, + 326, + 317, + 371, + 168, + 294, + 25, + 328, + 345, + 183, + 173, + 291, + 390, + 267, + 383, + 121, + 263, + 58, + 111, + 331, + 331, + 369, + 138, + 109, + 17, + 29, + 192, + 394, + 155, + 353, + 71, + 37, + 251, + 168, + 351, + 385, + 82, + 100, + 196, + 228, + 243, + 189, + 90, + 278, + 327, + 90, + 273, + 56, + 321, + 259, + 377, + 157, + 160, + 7, + 221, + 228, + 72, + 275, + 20, + 358, + 18, + 240, + 335, + 199, + 171, + 372, + 11, + 201, + 277, + 112, + 138, + 55, + 115, + 179, + 192, + 328, + 316, + 128, + 114, + 170, + 387, + 25, + 350, + 319, + 312, + 271, + 181, + 265, + 112, + 322, + 385, + 82, + 139, + 344, + 105, + 100, + 303, + 217, + 161, + 296, + 267, + 374, + 163, + 292, + 227, + 396, + 112, + 104, + 126, + 36, + 67, + 226, + 353, + 220, + 69, + 83, + 294, + 271, + 156, + 148, + 16, + 198, + 181, + 254, + 114, + 277, + 173, + 104, + 228, + 76, + 100, + 195, + 166, + 112, + 331, + 326, + 257, + 400, + 296, + 248, + 126, + 200, + 328, + 328, + 85, + 216, + 81, + 331, + 124, + 87, + 339, + 87, + 381, + 343, + 299, + 396, + 338, + 262, + 144, + 54, + 69, + 299, + 197, + 256, + 388, + 155, + 42, + 283, + 175, + 304, + 273, + 338, + 353, + 44, + 229, + 163, + 354, + 159, + 118, + 368, + 367, + 345, + 59, + 38, + 94, + 103, + 73, + 394, + 155, + 329, + 146, + 43, + 114, + 276, + 45, + 4, + 260, + 313, + 117, + 229, + 71, + 248, + 2, + 384, + 135, + 39, + 321, + 328, + 94, + 385, + 210, + 351, + 128, + 127, + 24, + 46, + 61, + 379, + 30, + 142, + 130, + 147, + 149, + 5, + 275, + 246, + 246, + 93, + 49, + 298, + 200, + 337, + 344, + 320, + 2, + 101, + 260, + 353, + 161, + 205, + 95, + 171, + 397, + 78, + 205, + 216, + 54, + 47, + 278, + 352, + 193, + 295, + 135, + 331, + 116, + 83, + 154, + 265, + 308, + 48, + 363, + 45, + 10, + 3, + 190, + 78, + 267, + 260, + 67, + 247, + 179, + 9, + 231, + 243, + 15, + 36, + 14, + 359, + 320, + 303, + 172, + 266, + 166, + 257, + 130, + 267, + 317, + 119, + 102, + 306, + 114, + 38, + 112, + 192, + 208, + 284, + 107, + 33, + 249, + 238, + 161, + 146, + 341, + 351, + 152, + 60, + 318, + 340, + 240, + 326, + 163, + 198, + 230, + 170, + 331, + 12, + 194, + 122, + 125, + 386, + 398, + 314, + 291, + 337, + 398, + 4, + 25, + 143, + 367, + 208, + 383, + 171, + 375, + 147, + 63, + 292, + 157, + 314, + 303, + 2, + 370, + 117, + 144, + 247, + 35, + 38, + 267, + 7, + 81, + 82, + 338, + 123, + 180, + 207, + 319, + 259, + 129, + 329, + 281, + 384, + 283, + 217, + 223, + 394, + 72, + 215, + 304, + 325, + 383, + 364, + 180, + 3, + 158, + 105, + 181, + 209, + 400, + 344, + 62, + 233, + 155, + 225, + 174, + 282, + 225, + 87, + 168, + 184, + 60, + 104, + 231, + 344, + 77, + 69, + 63, + 106, + 63, + 102, + 255, + 363, + 126, + 134, + 212, + 319, + 336, + 32, + 164, + 96, + 87, + 118, + 196, + 36, + 206, + 333, + 315, + 394, + 201, + 99, + 199, + 126, + 113, + 229, + 155, + 375, + 114, + 16, + 74, + 181, + 347, + 265, + 105, + 54, + 121, + 305, + 297, + 179, + 204, + 373, + 377, + 392, + 242, + 322, + 193, + 228, + 385, + 119, + 79, + 305, + 90, + 243, + 332, + 285, + 7, + 37, + 8, + 30, + 294, + 267, + 112, + 205, + 149, + 165, + 196, + 189, + 78, + 346, + 385, + 136, + 112, + 315, + 375, + 376, + 284, + 213, + 202, + 319, + 18, + 121, + 62, + 140, + 232, + 25, + 385, + 369, + 271, + 345, + 321, + 14, + 352, + 83, + 163, + 43, + 257, + 213, + 8, + 176, + 339, + 91, + 101, + 332, + 334, + 248, + 360, + 49, + 16, + 313, + 352, + 88, + 328, + 180, + 294, + 6, + 51, + 334, + 40, + 290, + 69, + 144, + 316, + 340, + 380, + 13, + 167, + 356, + 317, + 379, + 285, + 321, + 370, + 378, + 97, + 187, + 14, + 340, + 236, + 14, + 157, + 202, + 197, + 126, + 349, + 254, + 392, + 288, + 171, + 46, + 7, + 234, + 222, + 41, + 199, + 153, + 82, + 270, + 317, + 323, + 378, + 320, + 392, + 346, + 299, + 271, + 124, + 201, + 375, + 269, + 52, + 246, + 392, + 34, + 298, + 70, + 272, + 78, + 232, + 86, + 338, + 93, + 127, + 218, + 227, + 113, + 39, + 203, + 66, + 51, + 306, + 89, + 242, + 115, + 133, + 226, + 278, + 266, + 135, + 202, + 127, + 314, + 156, + 32, + 26, + 265, + 222, + 110, + 361, + 275, + 361, + 343, + 63, + 225, + 55, + 76, + 386, + 82, + 112, + 10, + 85, + 174, + 310, + 68, + 201, + 344, + 353, + 94, + 122, + 309, + 392, + 396, + 67, + 112, + 225, + 120, + 374, + 119, + 38, + 40, + 17, + 303, + 201, + 1, + 282, + 328, + 277, + 330, + 393, + 90, + 298, + 199, + 21, + 196, + 363, + 244, + 396, + 36, + 336, + 245, + 313, + 158, + 59, + 376, + 155, + 157, + 28, + 205, + 314, + 192, + 342, + 181, + 325, + 388, + 78, + 399, + 343, + 11, + 52, + 400, + 70, + 47, + 162, + 42, + 15, + 209, + 228, + 330, + 305, + 190, + 285, + 389, + 204, + 221, + 289, + 159, + 377, + 148, + 186, + 87, + 188, + 344, + 116, + 320, + 400, + 223, + 70, + 311, + 20, + 166, + 145, + 189, + 45, + 205, + 122, + 245, + 393, + 340, + 230, + 64, + 279, + 170, + 350, + 154, + 206, + 319, + 370, + 316, + 262, + 326, + 396, + 317, + 329, + 262, + 327, + 282, + 197, + 80, + 299, + 353, + 321, + 124, + 121, + 11, + 245, + 317, + 368, + 189, + 221, + 322, + 382, + 159, + 104, + 135, + 155, + 325, + 241, + 183, + 214, + 85, + 211, + 170, + 168, + 327, + 389, + 94, + 157, + 235, + 385, + 335, + 271, + 236, + 22, + 290, + 220, + 163, + 391, + 224, + 140, + 116, + 268, + 309, + 126, + 89, + 220, + 187, + 252, + 277, + 111, + 263, + 297, + 262, + 92, + 51, + 89, + 228, + 400, + 109, + 156, + 233, + 131, + 115, + 394, + 210, + 161, + 243, + 66, + 150, + 359, + 213, + 368, + 98, + 214, + 335, + 332, + 220, + 26, + 209, + 44, + 280, + 282, + 386, + 24, + 213, + 197, + 352, + 5, + 10, + 42, + 2, + 101, + 36, + 208, + 137, + 247, + 397, + 162, + 344, + 26, + 366, + 25, + 271, + 218, + 188, + 75, + 11, + 24, + 45, + 129, + 384, + 134, + 326, + 23, + 193, + 291, + 15, + 62, + 168, + 364, + 345, + 208, + 291, + 112, + 141, + 202, + 17, + 270, + 154, + 61, + 104, + 19, + 98, + 95, + 202, + 225, + 42, + 244, + 15, + 149, + 171, + 270, + 120, + 341, + 302, + 393, + 275, + 34, + 226, + 152, + 94, + 199, + 392, + 251, + 188, + 340, + 389, + 393, + 216, + 87, + 111, + 359, + 114, + 46, + 165, + 333, + 266, + 358, + 74, + 363, + 134, + 168, + 388, + 145, + 184, + 366, + 376, + 89, + 277, + 259, + 374, + 25, + 346, + 107, + 139, + 42, + 212, + 208, + 129, + 319, + 298, + 275, + 58, + 376, + 93, + 207, + 351, + 268, + 282, + 213, + 125, + 81, + 243, + 238, + 246, + 347, + 188, + 166, + 126, + 110, + 214, + 265, + 234, + 395, + 343, + 119, + 108, + 303, + 4, + 306, + 307, + 196, + 86, + 345, + 112, + 81, + 390, + 297, + 80, + 104, + 212, + 234, + 132, + 316, + 136, + 102, + 83, + 276, + 393, + 29, + 164, + 334, + 386, + 171, + 242, + 246, + 65, + 175, + 333, + 73, + 54, + 173, + 138, + 203, + 260, + 381, + 163, + 196, + 283, + 123, + 169, + 106, + 316, + 156, + 222, + 126, + 115, + 299, + 391, + 251, + 391, + 246, + 330, + 195, + 263, + 238, + 242, + 197, + 62, + 71, + 140, + 312, + 282, + 76, + 105, + 219, + 368, + 240, + 15, + 41, + 53, + 135, + 134, + 207, + 371, + 388, + 82, + 311, + 184, + 147, + 11, + 86, + 293, + 279, + 58, + 258, + 400, + 321, + 330, + 100, + 182, + 28, + 50, + 31, + 166, + 163, + 94, + 172, + 206, + 47, + 191, + 242, + 112, + 313, + 75, + 362, + 187, + 116, + 295, + 332, + 387, + 23, + 183, + 296, + 65, + 228, + 251, + 289, + 161, + 340, + 274, + 214, + 56, + 75, + 36, + 379, + 23, + 211, + 329, + 71, + 80, + 350, + 86, + 107, + 174, + 104, + 367, + 80, + 269, + 273, + 273, + 46, + 331, + 374, + 154, + 135, + 330, + 41, + 82, + 206, + 348, + 118, + 61, + 36, + 315, + 189, + 371, + 218, + 223, + 130, + 1, + 18, + 113, + 73, + 134, + 118, + 17, + 33, + 15, + 266, + 379, + 145, + 185, + 379, + 180, + 75, + 208, + 21, + 327, + 163, + 359, + 193, + 286, + 354, + 205, + 102, + 336, + 394, + 133, + 89, + 178, + 84, + 9, + 151, + 71, + 261, + 283, + 207, + 379, + 99, + 155, + 108, + 374, + 96, + 331, + 363, + 146, + 115, + 246, + 342, + 327, + 176, + 358, + 234, + 104, + 158, + 351, + 350, + 339, + 114, + 88, + 202, + 349, + 217, + 277, + 196, + 16, + 268, + 168, + 202, + 129, + 175, + 22, + 323, + 105, + 143, + 241, + 30, + 215, + 172, + 45, + 22, + 284, + 86, + 20, + 374, + 160, + 244, + 392, + 265, + 319, + 86, + 347, + 188, + 130, + 179, + 136, + 27, + 189, + 288, + 234, + 253, + 19, + 217, + 265, + 127, + 316, + 161, + 37, + 84, + 376, + 382, + 181, + 195, + 85, + 13, + 283, + 111, + 238, + 385, + 291, + 394, + 154, + 80, + 140, + 292, + 132, + 56, + 170, + 209, + 327, + 159, + 216, + 87, + 63, + 123, + 239, + 27, + 184, + 340, + 164, + 177, + 296, + 332, + 340, + 164, + 21, + 87, + 256, + 398, + 143, + 236, + 85, + 359, + 114, + 144, + 356, + 295, + 148, + 43, + 204, + 212, + 48, + 156, + 260, + 287, + 173, + 126, + 147, + 354, + 142, + 274, + 66, + 398, + 150, + 274, + 30, + 342, + 28, + 65, + 177, + 363, + 283, + 268, + 199, + 372, + 272, + 176, + 250, + 46, + 344, + 224, + 292, + 346, + 112, + 73, + 341, + 390, + 344, + 43, + 276, + 17, + 327, + 89, + 39, + 42, + 299, + 202, + 289, + 357, + 288, + 122, + 64, + 6, + 54, + 154, + 235, + 336, + 19, + 311, + 41, + 192, + 303, + 347, + 387, + 201, + 132, + 325, + 273, + 202, + 162, + 214, + 90, + 78, + 118, + 273, + 121, + 225, + 36, + 126, + 370, + 258, + 315, + 288, + 323, + 229, + 52, + 351, + 379, + 128, + 391, + 339, + 138, + 73, + 266, + 393, + 99, + 74, + 378, + 109, + 229, + 293, + 366, + 355, + 219, + 377, + 219, + 246, + 353, + 226, + 241, + 375, + 39, + 229, + 188, + 275, + 240, + 115, + 234, + 352, + 22, + 306, + 302, + 317, + 221, + 224, + 140, + 219, + 155, + 166, + 343, + 313, + 326, + 99, + 168, + 79, + 149, + 57, + 144, + 228, + 28, + 38, + 352, + 112, + 16, + 350, + 66, + 158, + 25, + 292, + 376, + 285, + 163, + 43, + 214, + 395, + 15, + 122, + 365, + 4, + 308, + 16, + 13, + 205, + 256, + 335, + 252, + 301, + 149, + 170, + 206, + 121, + 397, + 387, + 174, + 348, + 72, + 233, + 218, + 254, + 139, + 271, + 101, + 321, + 188, + 366, + 86, + 265, + 182, + 350, + 202, + 393, + 160, + 134, + 312, + 206, + 112, + 28, + 301, + 374, + 312, + 104, + 262, + 100, + 104, + 276, + 199, + 90, + 232, + 124, + 363, + 26, + 269, + 188, + 227, + 344, + 380, + 35, + 67, + 161, + 125, + 386, + 358, + 289, + 276, + 25, + 398, + 105, + 334, + 360, + 273, + 293, + 50, + 350, + 94, + 326, + 23, + 380, + 349, + 123, + 132, + 283, + 121, + 211, + 327, + 186, + 146, + 362, + 307, + 31, + 74, + 338, + 177, + 173, + 132, + 336, + 35, + 273, + 46, + 265, + 110, + 262, + 229, + 197, + 166, + 122, + 13, + 289, + 312, + 229, + 58, + 347, + 2, + 49, + 303, + 195, + 69, + 312, + 223, + 319, + 278, + 151, + 97, + 216, + 197, + 295, + 84, + 204, + 179, + 157, + 380, + 224, + 93, + 58, + 287, + 378, + 56, + 37, + 168, + 370, + 33, + 4, + 362, + 347, + 132, + 351, + 163, + 207, + 109, + 214, + 170, + 327, + 383, + 218, + 64, + 105, + 345, + 212, + 318, + 395, + 384, + 237, + 387, + 83, + 203, + 55, + 163, + 226, + 131, + 203, + 260, + 132, + 214, + 16, + 210, + 239, + 25, + 280, + 295, + 363, + 315, + 326, + 274, + 211, + 272, + 202, + 239, + 63, + 357, + 366, + 181, + 267, + 170, + 378, + 318, + 195, + 178, + 97, + 56, + 354, + 96, + 212, + 376, + 138, + 229, + 261, + 32, + 49, + 256, + 52, + 190, + 227, + 164, + 342, + 228, + 393, + 290, + 24, + 95, + 385, + 281, + 304, + 130, + 235, + 150, + 10, + 297, + 396, + 61, + 235, + 87, + 116, + 189, + 5, + 231, + 45, + 303, + 297, + 347, + 271, + 37, + 195, + 223, + 270, + 309, + 247, + 247, + 203, + 294, + 307, + 238, + 313, + 41, + 323, + 290, + 84, + 391, + 368, + 160, + 236, + 337, + 61, + 85, + 141, + 54, + 48, + 62, + 168, + 245, + 163, + 66, + 323, + 173, + 145, + 184, + 198, + 154, + 347, + 366, + 284, + 257, + 32, + 281, + 344, + 387, + 18, + 196, + 65, + 52, + 233, + 388, + 35, + 68, + 362, + 78, + 275, + 84, + 59, + 172, + 13, + 283, + 218, + 14, + 206, + 203, + 100, + 234, + 376, + 364, + 240, + 82, + 101, + 336, + 1, + 182, + 354, + 385, + 365, + 154, + 390, + 302, + 239, + 46, + 345, + 353, + 107, + 329, + 292, + 145, + 300, + 135, + 320, + 342, + 107, + 349, + 120, + 233, + 55, + 189, + 390, + 201, + 315, + 289, + 310, + 291, + 315, + 196, + 15, + 92, + 326, + 89, + 196, + 286, + 19, + 265, + 370, + 394, + 67, + 138, + 281, + 98, + 201, + 309, + 154, + 37, + 266, + 32, + 345, + 130, + 98, + 250, + 263, + 24, + 315, + 326, + 375, + 362, + 347, + 85, + 50, + 241, + 344, + 67, + 241, + 302, + 162, + 377, + 179, + 80, + 73, + 155, + 75, + 55, + 35, + 273, + 175, + 370, + 234, + 273, + 57, + 91, + 74, + 8, + 44, + 28, + 118, + 356, + 190, + 359, + 243, + 388, + 273, + 381, + 332, + 12, + 106, + 250, + 155, + 70, + 361, + 15, + 124, + 321, + 337, + 44, + 353, + 35, + 247, + 22, + 84, + 301, + 297, + 132, + 225, + 66, + 105, + 348, + 133, + 212, + 152, + 328, + 79, + 49, + 223, + 121, + 74, + 126, + 320, + 67, + 374, + 228, + 173, + 17, + 236, + 12, + 117, + 218, + 192, + 346, + 370, + 138, + 266, + 270, + 391, + 167, + 132, + 233, + 207, + 162, + 65, + 251, + 14, + 173, + 72, + 191, + 165, + 38, + 8, + 204, + 204, + 376, + 203, + 105, + 182, + 336, + 121, + 20, + 69, + 275, + 254, + 40, + 149, + 343, + 197, + 262, + 21, + 259, + 330, + 246, + 383, + 43, + 325, + 46, + 40, + 338, + 262, + 116, + 75, + 266, + 2, + 389, + 90, + 29, + 101, + 244, + 363, + 58, + 3, + 68, + 137, + 195, + 344, + 105, + 113, + 378, + 19, + 107, + 208, + 83, + 250, + 201, + 238, + 283, + 135, + 372, + 74, + 200, + 159, + 216, + 334, + 29, + 108, + 156, + 303, + 300, + 55, + 37, + 366, + 225, + 323, + 181, + 217, + 388, + 143, + 313, + 369, + 81, + 389, + 128, + 139, + 179, + 222, + 110, + 154, + 166, + 5, + 95, + 294, + 339, + 277, + 171, + 320, + 105, + 216, + 374, + 266, + 8, + 78, + 296, + 119, + 367, + 95, + 357, + 180, + 175, + 43, + 7, + 15, + 348, + 26, + 116, + 327, + 321, + 19, + 297, + 62, + 377, + 112, + 175, + 240, + 1, + 178, + 3, + 90, + 149, + 377, + 103, + 296, + 40, + 22, + 43, + 232, + 212, + 343, + 228, + 276, + 68, + 140, + 112, + 314, + 72, + 7, + 274, + 163, + 252, + 153, + 388, + 304, + 218, + 73, + 107, + 246, + 145, + 200, + 211, + 22, + 85, + 197, + 326, + 200, + 373, + 310, + 263, + 86, + 13, + 388, + 309, + 246, + 248, + 305, + 388, + 304, + 165, + 221, + 303, + 397, + 56, + 245, + 246, + 48, + 87, + 266, + 108, + 56, + 144, + 140, + 93, + 245, + 256, + 97, + 226, + 273, + 347, + 165, + 212, + 228, + 207, + 169, + 305, + 371, + 186, + 334, + 396, + 244, + 100, + 352, + 358, + 326, + 339, + 270, + 396, + 301, + 284, + 11, + 177, + 191, + 126, + 68, + 227, + 33, + 366, + 298, + 359, + 193, + 122, + 393, + 122, + 203, + 30, + 303, + 194, + 392, + 151, + 366, + 31, + 293, + 174, + 53, + 26, + 218, + 85, + 136, + 306, + 113, + 10, + 61, + 173, + 48, + 56, + 97, + 70, + 146, + 399, + 283, + 50, + 278, + 366, + 185, + 35, + 323, + 13, + 344, + 144, + 141, + 33, + 279, + 89, + 383, + 267, + 101, + 396, + 337, + 247, + 341, + 224, + 376, + 360, + 9, + 196, + 136, + 104, + 376, + 263, + 383, + 3, + 124, + 314, + 136, + 23, + 46, + 346, + 318, + 338, + 249, + 270, + 205, + 145, + 179, + 232, + 245, + 228, + 230, + 50, + 263, + 119, + 7, + 240, + 2, + 149, + 158, + 120, + 175, + 163, + 63, + 25, + 16, + 263, + 219, + 340, + 339, + 186, + 128, + 29, + 354, + 195, + 387, + 145, + 121, + 184, + 268, + 344, + 9, + 87, + 242, + 355, + 309, + 99, + 220, + 131, + 247, + 82, + 101, + 373, + 220, + 119, + 373, + 332, + 125, + 264, + 247, + 118, + 307, + 305, + 303, + 348, + 275, + 60, + 325, + 154, + 189, + 374, + 374, + 58, + 365, + 353, + 257, + 372, + 315, + 352, + 259, + 312, + 395, + 320, + 181, + 125, + 206, + 195, + 161, + 322, + 389, + 398, + 113, + 77, + 376, + 162, + 8, + 350, + 14, + 298, + 48, + 217, + 217, + 33, + 86, + 224, + 239, + 206, + 35, + 321, + 330, + 287, + 89, + 7, + 134, + 191, + 149, + 274, + 228, + 229, + 108, + 372, + 313, + 237, + 211, + 178, + 101, + 396, + 55, + 86, + 137, + 61, + 118, + 67, + 336, + 327, + 88, + 317, + 32, + 385, + 275, + 164, + 331, + 286, + 49, + 66, + 242, + 20, + 141, + 11, + 313, + 313, + 2, + 324, + 128, + 172, + 282, + 199, + 384, + 313, + 148, + 73, + 200, + 366, + 75, + 260, + 133, + 299, + 269, + 29, + 399, + 355, + 358, + 174, + 102, + 169, + 194, + 343, + 174, + 170, + 171, + 80, + 395, + 329, + 147, + 64, + 328, + 372, + 364, + 228, + 357, + 151, + 85, + 95, + 185, + 345, + 307, + 300, + 312, + 237, + 125, + 132, + 164, + 392, + 70, + 400, + 67, + 126, + 155, + 317, + 57, + 54, + 276, + 146, + 184, + 137, + 107, + 376, + 362, + 6, + 95, + 273, + 327, + 100, + 110, + 352, + 90, + 144, + 288, + 323, + 126, + 200, + 400, + 220, + 59, + 34, + 289, + 354, + 118, + 241, + 148, + 199, + 322, + 40, + 312, + 140, + 77, + 112, + 223, + 140, + 13, + 1, + 185, + 388, + 24, + 131, + 398, + 318, + 280, + 63, + 175, + 47, + 134, + 327, + 206, + 52, + 48, + 64, + 194, + 178, + 377, + 55, + 55, + 107, + 265, + 338, + 263, + 27, + 92, + 373, + 357, + 295, + 207, + 324, + 133, + 119, + 151, + 175, + 2, + 77, + 288, + 151, + 116, + 168, + 371, + 245, + 20, + 142, + 174, + 112, + 203, + 98, + 209, + 73, + 328, + 15, + 33, + 40, + 377, + 124, + 370, + 396, + 25, + 215, + 368, + 135, + 133, + 151, + 282, + 80, + 304, + 280, + 67, + 327, + 177, + 333, + 178, + 151, + 146, + 56, + 76, + 312, + 186, + 212, + 132, + 31, + 296, + 141, + 60, + 75, + 209, + 382, + 49, + 179, + 389, + 106, + 146, + 103, + 158, + 300, + 91, + 239, + 221, + 305, + 164, + 148, + 351, + 270, + 121, + 129, + 383, + 296, + 375, + 49, + 259, + 231, + 272, + 275, + 352, + 222, + 339, + 299, + 54, + 20, + 348, + 80, + 332, + 342, + 227, + 27, + 286, + 243, + 162, + 147, + 164, + 1, + 259, + 222, + 398, + 371, + 322, + 178, + 327, + 33, + 319, + 175, + 272, + 351, + 245, + 247, + 55, + 154, + 325, + 300, + 344, + 8, + 207, + 79, + 138, + 76, + 159, + 115, + 3, + 166, + 336, + 235, + 300, + 344, + 89, + 276, + 110, + 117, + 37, + 52, + 370, + 20, + 345, + 290, + 198, + 158, + 127, + 226, + 355, + 239, + 381, + 158, + 51, + 62, + 152, + 355, + 148, + 97, + 108, + 238, + 107, + 127, + 103, + 332, + 77, + 238, + 258, + 211, + 86, + 374, + 172, + 60, + 339, + 309, + 220, + 63, + 387, + 132, + 222, + 369, + 243, + 388, + 64, + 375, + 264, + 212, + 33, + 121, + 187, + 326, + 35, + 154, + 292, + 303, + 337, + 25, + 18, + 307, + 136, + 197, + 241, + 150, + 181, + 335, + 306, + 208, + 388, + 379, + 75, + 133, + 295, + 343, + 86, + 255, + 193, + 126, + 128, + 200, + 307, + 76, + 79, + 145, + 213, + 249, + 24, + 240, + 384, + 245, + 333, + 72, + 145, + 21, + 306, + 86, + 173, + 172, + 211, + 258, + 226, + 235, + 109, + 286, + 169, + 25, + 331, + 125, + 369, + 176, + 370, + 310, + 235, + 390, + 179, + 136, + 223, + 129, + 155, + 337, + 82, + 292, + 111, + 332, + 252, + 3, + 178, + 201, + 31, + 143, + 154, + 3, + 92, + 263, + 171, + 6, + 151, + 251, + 267, + 29, + 157, + 153, + 29, + 155, + 360, + 338, + 81, + 96, + 166, + 93, + 382, + 7, + 176, + 53, + 43, + 393, + 210, + 87, + 3, + 92, + 384, + 148, + 152, + 181, + 378, + 353, + 202, + 196, + 212, + 235, + 246, + 227, + 236, + 304, + 180, + 201, + 336, + 19, + 17, + 185, + 255, + 99, + 133, + 98, + 227, + 72, + 260, + 260, + 1, + 331, + 219, + 41, + 32, + 344, + 335, + 326, + 98, + 42, + 86, + 90, + 282, + 381, + 88, + 34, + 191, + 96, + 147, + 378, + 354, + 218, + 251, + 384, + 240, + 337, + 120, + 364, + 51, + 95, + 159, + 230, + 373, + 52, + 81, + 249, + 194, + 368, + 374, + 108, + 380, + 57, + 66, + 393, + 222, + 300, + 147, + 158, + 391, + 226, + 64, + 347, + 241, + 134, + 274, + 162, + 293, + 167, + 372, + 176, + 390, + 232, + 354, + 250, + 311, + 191, + 329, + 177, + 208, + 88, + 204, + 342, + 364, + 296, + 222, + 339, + 247, + 144, + 372, + 342, + 233, + 83, + 223, + 210, + 330, + 68, + 282, + 171, + 177, + 203, + 264, + 383, + 308, + 341, + 246, + 352, + 55, + 143, + 193, + 319, + 54, + 311, + 237, + 52, + 9, + 391, + 294, + 96, + 47, + 46, + 132, + 312, + 120, + 231, + 68, + 134, + 61, + 326, + 323, + 314, + 393, + 288, + 322, + 177, + 326, + 322, + 244, + 117, + 322, + 253, + 385, + 258, + 296, + 48, + 189, + 2, + 329, + 351, + 237, + 92, + 69, + 105, + 388, + 37, + 399, + 165, + 300, + 268, + 143, + 322, + 299, + 376, + 221, + 363, + 158, + 156, + 224, + 336, + 126, + 51, + 205, + 107, + 56, + 289, + 395, + 312, + 48, + 310, + 384, + 190, + 173, + 332, + 346, + 227, + 362, + 48, + 270, + 387, + 232, + 303, + 113, + 368, + 295, + 278, + 200, + 20, + 181, + 111, + 16, + 185, + 225, + 282, + 350, + 380, + 156, + 20, + 135, + 302, + 199, + 180, + 194, + 15, + 4, + 341, + 106, + 353, + 294, + 300, + 208, + 161, + 332, + 224, + 387, + 285, + 236, + 262, + 294, + 90, + 50, + 65, + 215, + 111, + 5, + 191, + 138, + 168, + 139, + 369, + 325, + 137, + 273, + 399, + 54, + 314, + 75, + 286, + 349, + 36, + 276, + 306, + 129, + 7, + 165, + 103, + 373, + 227, + 376, + 173, + 326, + 378, + 347, + 63, + 280, + 319, + 46, + 325, + 232, + 170, + 322, + 288, + 364, + 218, + 260, + 86, + 95, + 393, + 190, + 76, + 48, + 378, + 136, + 316, + 223, + 83, + 314, + 42, + 398, + 252, + 384, + 90, + 76, + 310, + 100, + 209, + 301, + 317, + 120, + 324, + 137, + 324, + 35, + 167, + 215, + 235, + 331, + 316, + 310, + 192, + 395, + 180, + 375, + 142, + 105, + 213, + 183, + 82, + 330, + 336, + 130, + 162, + 166, + 124, + 28, + 222, + 332, + 322, + 246, + 31, + 184, + 85, + 111, + 126, + 373, + 393, + 343, + 80, + 50, + 140, + 394, + 9, + 14, + 345, + 10, + 180, + 375, + 313, + 266, + 95, + 287, + 52, + 93, + 239, + 57, + 397, + 175, + 250, + 52, + 64, + 317, + 112, + 330, + 370, + 150, + 224, + 248, + 134, + 143, + 11, + 221, + 203, + 266, + 46, + 297, + 105, + 276, + 255, + 39, + 112, + 9, + 344, + 94, + 61, + 299, + 16, + 190, + 112, + 83, + 208, + 173, + 19, + 258, + 392, + 106, + 208, + 103, + 280, + 137, + 127, + 193, + 335, + 287, + 314, + 390, + 69, + 121, + 162, + 285, + 55, + 364, + 96, + 376, + 314, + 90, + 43, + 214, + 208, + 190, + 125, + 188, + 233, + 297, + 320, + 210, + 217, + 8, + 149, + 70, + 183, + 365, + 90, + 147, + 244, + 5, + 168, + 235, + 60, + 153, + 128, + 214, + 94, + 227, + 159, + 218, + 277, + 134, + 119, + 383, + 113, + 190, + 144, + 77, + 75, + 224, + 272, + 84, + 240, + 98, + 394, + 394, + 40, + 69, + 24, + 27, + 266, + 26, + 22, + 33, + 196, + 210, + 63, + 226, + 31, + 132, + 199, + 28, + 35, + 22, + 79, + 80, + 59, + 365, + 309, + 112, + 133, + 38, + 396, + 159, + 385, + 375, + 8, + 393, + 144, + 55, + 254, + 246, + 359, + 316, + 126, + 362, + 213, + 81, + 357, + 385, + 104, + 97, + 168, + 273, + 234, + 42, + 223, + 18, + 387, + 139, + 50, + 399, + 387, + 227, + 134, + 199, + 204, + 151, + 318, + 217, + 2, + 141, + 167, + 110, + 247, + 380, + 257, + 205, + 119, + 5, + 186, + 236, + 249, + 358, + 65, + 203, + 379, + 372, + 288, + 359, + 342, + 50, + 350, + 244, + 248, + 348, + 294, + 189, + 369, + 188, + 64, + 65, + 24, + 43, + 45, + 215, + 386, + 108, + 1, + 222, + 137, + 239, + 295, + 74, + 183, + 134, + 252, + 376, + 379, + 361, + 394, + 165, + 234, + 285, + 158, + 181, + 201, + 282, + 116, + 260, + 246, + 317, + 27, + 15, + 144, + 119, + 246, + 94, + 272, + 35, + 250, + 291, + 97, + 350, + 37, + 308, + 267, + 166, + 248, + 36, + 242, + 91, + 177, + 111, + 278, + 15, + 353, + 268, + 45, + 189, + 151, + 23, + 322, + 235, + 328, + 240, + 156, + 176, + 57, + 247, + 8, + 81, + 186, + 15, + 254, + 97, + 66, + 253, + 143, + 18, + 345, + 37, + 86, + 255, + 3, + 45, + 373, + 306, + 102, + 379, + 44, + 398, + 365, + 224, + 312, + 14, + 1, + 313, + 268, + 35, + 227, + 47, + 291, + 154, + 208, + 230, + 348, + 394, + 5, + 338, + 318, + 355, + 87, + 181, + 248, + 97, + 321, + 290, + 135, + 352, + 113, + 119, + 390, + 136, + 51, + 119, + 43, + 141, + 38, + 75, + 137, + 14, + 356, + 70, + 100, + 73, + 168, + 44, + 290, + 342, + 113, + 82, + 333, + 187, + 70, + 46, + 125, + 320, + 96, + 228, + 252, + 151, + 343, + 21, + 22, + 196, + 28, + 354, + 331, + 257, + 305, + 289, + 30, + 237, + 156, + 250, + 88, + 184, + 32, + 272, + 171, + 27, + 97, + 265, + 337, + 197, + 67, + 339, + 133, + 16, + 216, + 324, + 388, + 248, + 131, + 357, + 135, + 371, + 392, + 290, + 230, + 90, + 254, + 40, + 359, + 309, + 357, + 336, + 334, + 173, + 155, + 282, + 1, + 263, + 155, + 369, + 332, + 100, + 147, + 383, + 65, + 351, + 209, + 105, + 331, + 100, + 270, + 114, + 108, + 128, + 220, + 375, + 141, + 69, + 19, + 278, + 352, + 365, + 250, + 278, + 234, + 141, + 380, + 43, + 169, + 2, + 256, + 329, + 97, + 368, + 32, + 240, + 374, + 373, + 48, + 268, + 386, + 149, + 7, + 46, + 277, + 127, + 243, + 102, + 294, + 80, + 28, + 71, + 328, + 193, + 87, + 346, + 122, + 276, + 392, + 175, + 227, + 163, + 29, + 91, + 157, + 379, + 114, + 220, + 141, + 29, + 207, + 248, + 130, + 22, + 51, + 383, + 172, + 61, + 25, + 28, + 102, + 103, + 134, + 364, + 74, + 126, + 261, + 288, + 87, + 311, + 274, + 388, + 58, + 400, + 184, + 53, + 123, + 170, + 366, + 175, + 277, + 348, + 243, + 322, + 315, + 35, + 50, + 20, + 388, + 213, + 82, + 34, + 53, + 297, + 369, + 3, + 68, + 152, + 119, + 393, + 57, + 220, + 129, + 97, + 171, + 338, + 282, + 195, + 176, + 257, + 277, + 47, + 237, + 332, + 151, + 383, + 185, + 185, + 106, + 161, + 327, + 45, + 265, + 236, + 170, + 252, + 172, + 64, + 298, + 144, + 262, + 389, + 179, + 308, + 126, + 189, + 128, + 20, + 272, + 129, + 60, + 166, + 217, + 147, + 250, + 248, + 325, + 177, + 84, + 347, + 305, + 363, + 177, + 93, + 29, + 377, + 350, + 284, + 109, + 363, + 178, + 237, + 145, + 115, + 59, + 166, + 168, + 76, + 35, + 25, + 357, + 56, + 157, + 157, + 302, + 222, + 80, + 265, + 392, + 110, + 163, + 300, + 33, + 57, + 88, + 29, + 66, + 106, + 75, + 210, + 331, + 23, + 291, + 377, + 385, + 369, + 327, + 106, + 193, + 36, + 213, + 231, + 195, + 22, + 123, + 308, + 50, + 256, + 372, + 388, + 240, + 399, + 251, + 360, + 41, + 21, + 304, + 298, + 390, + 196, + 105, + 56, + 396, + 102, + 327, + 39, + 91, + 269, + 317, + 127, + 358, + 322, + 301, + 319, + 94, + 268, + 61, + 301, + 259, + 293, + 234, + 311, + 135, + 233, + 143, + 3, + 380, + 179, + 81, + 102, + 314, + 3, + 43, + 62, + 160, + 86, + 39, + 15, + 333, + 288, + 377, + 10, + 253, + 163, + 5, + 273, + 285, + 183, + 116, + 6, + 259, + 374, + 38, + 365, + 345, + 336, + 103, + 51, + 48, + 92, + 146, + 80, + 205, + 185, + 362, + 228, + 257, + 225, + 176, + 49, + 366, + 371, + 308, + 343, + 386, + 9, + 343, + 265, + 284, + 137, + 373, + 372, + 255, + 233, + 154, + 64, + 136, + 48, + 377, + 179, + 153, + 327, + 385, + 349, + 273, + 130, + 261, + 207, + 215, + 311, + 49, + 117, + 78, + 292, + 315, + 70, + 383, + 160, + 21, + 56, + 201, + 328, + 99, + 181, + 68, + 203, + 114, + 180, + 262, + 378, + 397, + 230, + 165, + 355, + 10, + 296, + 109, + 264, + 80, + 202, + 255, + 381, + 55, + 193, + 334, + 397, + 386, + 216, + 356, + 356, + 45, + 9, + 304, + 186, + 334, + 60, + 128, + 317, + 163, + 151, + 234, + 115, + 386, + 77, + 345, + 149, + 240, + 221, + 84, + 143, + 332, + 344, + 204, + 83, + 22, + 304, + 183, + 337, + 311, + 274, + 93, + 276, + 341, + 94, + 174, + 346, + 74, + 90, + 348, + 120, + 291, + 202, + 220, + 3, + 316, + 19, + 212, + 276, + 388, + 228, + 302, + 120, + 150, + 206, + 30, + 130, + 270, + 263, + 358, + 374, + 84, + 208, + 306, + 187, + 258, + 90, + 6, + 355, + 101, + 239, + 80, + 241, + 285, + 368, + 94, + 118, + 380, + 152, + 164, + 400, + 185, + 115, + 270, + 19, + 271, + 298, + 56, + 118, + 253, + 270, + 184, + 372, + 169, + 382, + 327, + 349, + 352, + 177, + 202, + 24, + 129, + 129, + 93, + 42, + 377, + 2, + 249, + 249, + 188, + 82, + 318, + 72, + 349, + 180, + 103, + 308, + 385, + 189, + 370, + 334, + 348, + 161, + 284, + 17, + 166, + 198, + 307, + 323, + 225, + 170, + 219, + 369, + 81, + 247, + 232, + 138, + 57, + 11, + 142, + 236, + 151, + 308, + 14, + 329, + 184, + 170, + 28, + 13, + 49, + 11, + 163, + 10, + 51, + 140, + 96, + 318, + 258, + 149, + 362, + 133, + 39, + 113, + 47, + 100, + 52, + 364, + 34, + 14, + 181, + 354, + 13, + 226, + 258, + 178, + 371, + 321, + 303, + 310, + 131, + 317, + 199, + 52, + 178, + 204, + 8, + 326, + 63, + 53, + 399, + 64, + 5, + 106, + 177, + 258, + 133, + 283, + 346, + 114, + 185, + 313, + 126, + 101, + 342, + 17, + 99, + 321, + 35, + 102, + 395, + 212, + 129, + 147, + 381, + 301, + 206, + 34, + 380, + 127, + 260, + 136, + 258, + 97, + 387, + 150, + 103, + 281, + 302, + 208, + 18, + 198, + 304, + 337, + 311, + 83, + 393, + 112, + 231, + 378, + 392, + 212, + 267, + 32, + 144, + 78, + 193, + 355, + 263, + 84, + 195, + 116, + 143, + 5, + 109, + 199, + 208, + 381, + 53, + 241, + 353, + 90, + 325, + 51, + 186, + 323, + 273, + 208, + 14, + 69, + 88, + 396, + 380, + 353, + 15, + 170, + 333, + 116, + 373, + 262, + 149, + 222, + 312, + 56, + 190, + 247, + 292, + 10, + 53, + 342, + 87, + 65, + 1, + 394, + 43, + 253, + 107, + 112, + 172, + 108, + 164, + 286, + 358, + 259, + 269, + 362, + 217, + 283, + 284, + 200, + 118, + 55, + 201, + 194, + 324, + 374, + 126, + 329, + 177, + 20, + 187, + 53, + 349, + 115, + 189, + 394, + 183, + 55, + 346, + 175, + 1, + 285, + 351, + 309, + 171, + 17, + 268, + 312, + 50, + 45, + 35, + 43, + 70, + 328, + 55, + 200, + 99, + 306, + 147, + 81, + 74, + 247, + 196, + 307, + 91, + 85, + 186, + 398, + 242, + 118, + 244, + 142, + 309, + 32, + 351, + 221, + 176, + 12, + 83, + 102, + 188, + 353, + 127, + 345, + 164, + 169, + 310, + 93, + 240, + 282, + 80, + 204, + 345, + 127, + 59, + 19, + 31, + 225, + 229, + 209, + 154, + 332, + 243, + 186, + 77, + 7, + 207, + 328, + 363, + 81, + 108, + 194, + 388, + 165, + 300, + 184, + 43, + 102, + 392, + 393, + 377, + 267, + 303, + 249, + 178, + 286, + 351, + 297, + 263, + 153, + 347, + 91, + 18, + 341, + 283, + 129, + 124, + 8, + 263, + 204, + 4, + 156, + 177, + 148, + 228, + 207, + 334, + 338, + 382, + 343, + 137, + 116, + 160, + 270, + 223, + 91, + 53, + 349, + 386, + 346, + 126, + 47, + 233, + 320, + 315, + 309, + 363, + 169, + 75, + 368, + 153, + 118, + 101, + 309, + 186, + 89, + 127, + 293, + 31, + 122, + 340, + 125, + 157, + 142, + 88, + 241, + 180, + 225, + 225, + 132, + 236, + 114, + 223, + 129, + 65, + 40, + 397, + 111, + 261, + 314, + 160, + 203, + 346, + 263, + 142, + 398, + 215, + 1, + 120, + 274, + 285, + 341, + 151, + 38, + 119, + 257, + 314, + 332, + 378, + 64, + 206, + 151, + 311, + 283, + 338, + 362, + 19, + 90, + 293, + 21, + 267, + 102, + 181, + 253, + 80, + 251, + 134, + 254, + 276, + 70, + 308, + 228, + 241, + 235, + 68, + 312, + 394, + 276, + 221, + 372, + 31, + 167, + 262, + 358, + 21, + 159, + 70, + 371, + 149, + 132, + 136, + 66, + 171, + 308, + 148, + 301, + 22, + 368, + 50, + 236, + 219, + 159, + 317, + 387, + 357, + 94, + 199, + 263, + 383, + 330, + 112, + 162, + 323, + 263, + 20, + 70, + 96, + 292, + 17, + 309, + 45, + 297, + 355, + 75, + 260, + 232, + 147, + 277, + 368, + 264, + 101, + 23, + 156, + 24, + 318, + 322, + 153, + 256, + 6, + 188, + 176, + 158, + 160, + 200, + 112, + 384, + 52, + 241, + 128, + 56, + 135, + 306, + 239, + 228, + 263, + 152, + 14, + 274, + 273, + 307, + 374, + 76, + 355, + 91, + 326, + 335, + 314, + 400, + 280, + 267, + 44, + 230, + 61, + 385, + 109, + 31, + 6, + 291, + 298, + 65, + 229, + 30, + 188, + 241, + 151, + 59, + 168, + 105, + 308, + 174, + 340, + 393, + 250, + 180, + 327, + 389, + 395, + 314, + 17, + 310, + 197, + 341, + 90, + 128, + 379, + 175, + 7, + 398, + 150, + 261, + 283, + 196, + 168, + 278, + 277, + 120, + 268, + 138, + 340, + 359, + 333, + 100, + 284, + 50, + 11, + 243, + 6, + 149, + 55, + 11, + 104, + 217, + 88, + 254, + 44, + 306, + 48, + 227, + 30, + 205, + 71, + 175, + 241, + 300, + 203, + 73, + 343, + 269, + 20, + 175, + 122, + 70, + 104, + 105, + 66, + 28, + 22, + 196, + 192, + 150, + 328, + 394, + 400, + 9, + 88, + 75, + 361, + 9, + 199, + 228, + 275, + 45, + 399, + 390, + 59, + 144, + 341, + 179, + 11, + 323, + 400, + 392, + 223, + 396, + 304, + 131, + 295, + 136, + 391, + 298, + 390, + 228, + 343, + 390, + 183, + 137, + 129, + 8, + 315, + 27, + 9, + 330, + 9, + 342, + 14, + 86, + 243, + 303, + 133, + 229, + 46, + 144, + 317, + 243, + 219, + 196, + 203, + 244, + 92, + 364, + 85, + 180, + 172, + 346, + 127, + 133, + 224, + 151, + 199, + 243, + 53, + 138, + 165, + 314, + 248, + 248, + 12, + 173, + 273, + 345, + 168, + 70, + 346, + 94, + 364, + 206, + 170, + 244, + 230, + 300, + 387, + 195, + 206, + 185, + 165, + 100, + 133, + 400, + 259, + 373, + 46, + 104, + 352, + 335, + 208, + 297, + 93, + 361, + 119, + 99, + 54, + 63, + 222, + 106, + 91, + 391, + 171, + 268, + 36, + 304, + 284, + 288, + 249, + 233, + 235, + 371, + 226, + 235, + 112, + 42, + 274, + 108, + 101, + 123, + 123, + 167, + 259, + 149, + 133, + 98, + 223, + 78, + 106, + 39, + 220, + 254, + 186, + 12, + 270, + 291, + 273, + 369, + 336, + 44, + 184, + 281, + 30, + 15, + 64, + 231, + 280, + 57, + 110, + 182, + 250, + 326, + 75, + 140, + 110, + 21, + 130, + 278, + 127, + 389, + 60, + 61, + 114, + 259, + 125, + 98, + 327, + 128, + 144, + 317, + 213, + 53, + 231, + 299, + 170, + 312, + 170, + 348, + 72, + 128, + 60, + 173, + 163, + 235, + 149, + 25, + 62, + 385, + 328, + 79, + 155, + 218, + 45, + 171, + 92, + 254, + 42, + 152, + 263, + 22, + 129, + 257, + 253, + 365, + 296, + 388, + 1, + 385, + 366, + 58, + 228, + 172, + 73, + 349, + 207, + 292, + 1, + 208, + 392, + 315, + 18, + 73, + 119, + 326, + 344, + 194, + 90, + 73, + 88, + 26, + 230, + 288, + 342, + 123, + 97, + 286, + 302, + 114, + 88, + 197, + 209, + 360, + 219, + 37, + 143, + 99, + 14, + 27, + 57, + 272, + 26, + 169, + 316, + 209, + 165, + 243, + 377, + 245, + 339, + 100, + 238, + 330, + 110, + 350, + 67, + 213, + 122, + 355, + 55, + 137, + 350, + 172, + 300, + 142, + 214, + 288, + 296, + 154, + 107, + 47, + 226, + 262, + 79, + 305, + 355, + 155, + 137, + 211, + 169, + 91, + 278, + 69, + 314, + 336, + 373, + 383, + 373, + 68, + 166, + 362, + 346, + 6, + 65, + 395, + 94, + 337, + 318, + 87, + 274, + 73, + 389, + 137, + 71, + 369, + 197, + 36, + 19, + 286, + 336, + 98, + 74, + 95, + 205, + 53, + 255, + 256, + 158, + 201, + 54, + 343, + 344, + 30, + 380, + 124, + 344, + 74, + 269, + 346, + 225, + 49, + 172, + 371, + 355, + 103, + 275, + 118, + 365, + 196, + 186, + 180, + 159, + 2, + 110, + 189, + 183, + 362, + 314, + 196, + 304, + 171, + 380, + 63, + 196, + 364, + 118, + 371, + 220, + 163, + 128, + 177, + 326, + 77, + 77, + 296, + 330, + 380, + 304, + 36, + 340, + 314, + 309, + 258, + 238, + 138, + 26, + 15, + 351, + 88, + 84, + 101, + 98, + 224, + 376, + 376, + 243, + 249, + 399, + 221, + 224, + 18, + 177, + 163, + 150, + 378, + 353, + 285, + 45, + 243, + 24, + 344, + 202, + 335, + 248, + 241, + 122, + 371, + 209, + 178, + 232, + 218, + 183, + 72, + 400, + 212, + 379, + 180, + 178, + 284, + 107, + 393, + 151, + 277, + 262, + 162, + 293, + 135, + 357, + 97, + 343, + 9, + 181, + 95, + 347, + 120, + 363, + 88, + 311, + 320, + 64, + 21, + 43, + 354, + 184, + 343, + 387, + 195, + 381, + 262, + 320, + 377, + 188, + 284, + 225, + 316, + 327, + 321, + 368, + 276, + 232, + 119, + 124, + 59, + 284, + 84, + 201, + 289, + 253, + 301, + 233, + 5, + 316, + 300, + 242, + 343, + 30, + 50, + 101, + 51, + 294, + 387, + 292, + 245, + 27, + 210, + 226, + 273, + 232, + 24, + 275, + 122, + 154, + 138, + 221, + 386, + 355, + 44, + 95, + 32, + 136, + 12, + 277, + 260, + 301, + 292, + 172, + 112, + 96, + 217, + 72, + 304, + 89, + 29, + 33, + 35, + 8, + 378, + 94, + 327, + 35, + 279, + 396, + 368, + 251, + 85, + 138, + 357, + 60, + 1, + 209, + 171, + 363, + 324, + 203, + 355, + 98, + 120, + 392, + 285, + 297, + 105, + 134, + 123, + 167, + 134, + 304, + 61, + 257, + 166, + 40, + 214, + 328, + 179, + 330, + 261, + 325, + 78, + 67, + 167, + 395, + 306, + 89, + 305, + 386, + 115, + 4, + 121, + 69, + 41, + 83, + 3, + 10, + 56, + 94, + 338, + 233, + 179, + 378, + 8, + 101, + 216, + 59, + 49, + 95, + 366, + 117, + 355, + 356, + 15, + 287, + 266, + 268, + 189, + 289, + 392, + 204, + 69, + 310, + 264, + 240, + 171, + 277, + 397, + 173, + 397, + 218, + 81, + 124, + 354, + 240, + 166, + 100, + 73, + 274, + 302, + 110, + 268, + 17, + 74, + 62, + 41, + 86, + 106, + 363, + 200, + 67, + 94, + 56, + 161, + 12, + 127, + 184, + 355, + 259, + 95, + 299, + 316, + 247, + 84, + 35, + 33, + 235, + 280, + 376, + 295, + 394, + 179, + 299, + 174, + 325, + 131, + 54, + 295, + 13, + 327, + 231, + 367, + 67, + 353, + 104, + 66, + 381, + 87, + 63, + 45, + 89, + 21, + 263, + 357, + 331, + 183, + 264, + 367, + 250, + 44, + 149, + 94, + 147, + 131, + 327, + 189, + 212, + 172, + 360, + 244, + 206, + 177, + 115, + 79, + 38, + 349, + 152, + 104, + 261, + 265, + 299, + 328, + 242, + 1, + 305, + 216, + 182, + 127, + 332, + 192, + 162, + 225, + 35, + 11, + 390, + 66, + 41, + 266, + 175, + 397, + 156, + 365, + 57, + 363, + 50, + 56, + 301, + 233, + 22, + 136, + 381, + 300, + 4, + 7, + 18, + 359, + 341, + 229, + 29, + 1, + 399, + 146, + 242, + 289, + 230, + 352, + 92, + 105, + 382, + 334, + 233, + 229, + 326, + 50, + 335, + 276, + 196, + 354, + 6, + 104, + 156, + 75, + 301, + 265, + 179, + 383, + 34, + 112, + 29, + 294, + 69, + 249, + 246, + 143, + 191, + 301, + 163, + 309, + 244, + 321, + 78, + 13, + 179, + 236, + 275, + 240, + 283, + 186, + 317, + 105, + 84, + 160, + 308, + 138, + 87, + 37, + 211, + 7, + 85, + 333, + 195, + 265, + 246, + 56, + 16, + 226, + 102, + 171, + 310, + 328, + 63, + 300, + 160, + 136, + 114, + 386, + 247, + 43, + 95, + 217, + 223, + 186, + 130, + 354, + 398, + 132, + 341, + 34, + 249, + 218, + 51, + 197, + 97, + 80, + 25, + 61, + 119, + 28, + 137, + 160, + 222, + 119, + 132, + 44, + 273, + 61, + 110, + 217, + 12, + 32, + 15, + 47, + 260, + 149, + 132, + 92, + 238, + 330, + 116, + 203, + 317, + 306, + 227, + 79, + 193, + 245, + 309, + 54, + 282, + 199, + 108, + 185, + 48, + 73, + 18, + 154, + 379, + 186, + 244, + 209, + 191, + 69, + 187, + 13, + 192, + 45, + 170, + 300, + 23, + 274, + 143, + 128, + 341, + 91, + 65, + 186, + 48, + 154, + 291, + 350, + 301, + 179, + 245, + 33, + 395, + 333, + 155, + 364, + 83, + 79, + 268, + 306, + 252, + 335, + 398, + 90, + 128, + 267, + 146, + 185, + 127, + 300, + 2, + 376, + 345, + 368, + 95, + 287, + 143, + 159, + 216, + 150, + 95, + 272, + 393, + 376, + 355, + 244, + 191, + 270, + 20, + 366, + 235, + 121, + 75, + 40, + 398, + 67, + 354, + 267, + 87, + 336, + 231, + 24, + 111, + 247, + 306, + 400, + 225, + 50, + 329, + 330, + 101, + 97, + 331, + 244, + 323, + 146, + 214, + 63, + 253, + 44, + 6, + 21, + 334, + 60, + 286, + 130, + 11, + 316, + 346, + 232, + 301, + 63, + 24, + 272, + 289, + 60, + 232, + 292, + 333, + 256, + 302, + 305, + 80, + 330, + 13, + 310, + 222, + 358, + 103, + 148, + 277, + 292, + 109, + 90, + 191, + 76, + 277, + 52, + 200, + 184, + 163, + 359, + 323, + 326, + 219, + 295, + 173, + 57, + 351, + 236, + 346, + 254, + 221, + 304, + 91, + 327, + 310, + 345, + 355, + 18, + 19, + 206, + 267, + 356, + 108, + 113, + 173, + 8, + 180, + 374, + 30, + 270, + 249, + 335, + 375, + 350, + 326, + 169, + 343, + 383, + 340, + 54, + 104, + 160, + 6, + 37, + 46, + 36, + 215, + 146, + 324, + 354, + 130, + 156, + 331, + 204, + 235, + 310, + 85, + 102, + 6, + 63, + 98, + 323, + 241, + 191, + 400, + 32, + 399, + 290, + 93, + 70, + 215, + 113, + 349, + 321, + 71, + 60, + 137, + 209, + 135, + 234, + 11, + 94, + 108, + 139, + 66, + 43, + 73, + 280, + 336, + 58, + 329, + 143, + 269, + 39, + 141, + 23, + 133, + 225, + 43, + 323, + 19, + 317, + 342, + 23, + 63, + 177, + 85, + 180, + 153, + 252, + 3, + 186, + 202, + 303, + 338, + 317, + 9, + 50, + 299, + 239, + 263, + 351, + 368, + 256, + 299, + 272, + 326, + 163, + 145, + 346, + 307, + 75, + 390, + 132, + 249, + 139, + 275, + 378, + 226, + 290, + 306, + 141, + 61, + 372, + 205, + 152, + 372, + 225, + 127, + 63, + 307, + 98, + 142, + 131, + 260, + 199, + 97, + 152, + 268, + 21, + 340, + 326, + 238, + 235, + 198, + 45, + 147, + 294, + 2, + 378, + 323, + 337, + 200, + 134, + 391, + 167, + 59, + 129, + 194, + 359, + 276, + 65, + 195, + 245, + 376, + 385, + 277, + 170, + 330, + 12, + 372, + 259, + 374, + 13, + 169, + 27, + 206, + 186, + 85, + 77, + 134, + 343, + 325, + 134, + 385, + 334, + 234, + 329, + 381, + 178, + 211, + 218, + 261, + 245, + 195, + 244, + 389, + 281, + 298, + 132, + 180, + 391, + 237, + 138, + 352, + 99, + 17, + 261, + 368, + 81, + 172, + 143, + 238, + 138, + 88, + 200, + 275, + 168, + 313, + 352, + 26, + 2, + 73, + 348, + 173, + 275, + 327, + 289, + 34, + 90, + 38, + 299, + 212, + 69, + 95, + 186, + 288, + 345, + 138, + 387, + 168, + 32, + 53, + 257, + 181, + 153, + 288, + 24, + 307, + 339, + 165, + 104, + 305, + 279, + 84, + 341, + 259, + 342, + 227, + 359, + 109, + 117, + 28, + 128, + 172, + 228, + 321, + 178, + 161, + 284, + 227, + 241, + 355, + 225, + 154, + 328, + 167, + 184, + 345, + 238, + 156, + 342, + 372, + 378, + 20, + 134, + 192, + 378, + 176, + 277, + 81, + 26, + 120, + 70, + 80, + 192, + 354, + 225, + 8, + 378, + 45, + 342, + 92, + 162, + 113, + 239, + 164, + 125, + 113, + 386, + 69, + 69, + 297, + 170, + 317, + 42, + 162, + 309, + 134, + 301, + 82, + 44, + 153, + 183, + 29, + 350, + 73, + 90, + 53, + 351, + 261, + 69, + 144, + 291, + 199, + 96, + 60, + 230, + 176, + 157, + 180, + 148, + 54, + 131, + 123, + 388, + 64, + 326, + 13, + 263, + 60, + 300, + 68, + 287, + 160, + 41, + 292, + 176, + 291, + 11, + 143, + 334, + 353, + 377, + 283, + 243, + 1, + 247, + 136, + 103, + 124, + 216, + 65, + 349, + 369, + 395, + 310, + 184, + 399, + 85, + 341, + 47, + 361, + 7, + 115, + 88, + 5, + 226, + 102, + 219, + 348, + 259, + 245, + 2, + 351, + 281, + 116, + 380, + 153, + 31, + 187, + 39, + 266, + 107, + 317, + 351, + 27, + 289, + 158, + 275, + 191, + 197, + 326, + 214, + 305, + 275, + 41, + 187, + 266, + 17, + 377, + 338, + 267, + 395, + 2, + 55, + 249, + 374, + 265, + 163, + 339, + 42, + 384, + 185, + 365, + 99, + 156, + 176, + 149, + 291, + 87, + 177, + 40, + 86, + 317, + 24, + 221, + 74, + 25, + 305, + 383, + 285, + 224, + 289, + 72, + 341, + 334, + 36, + 39, + 253, + 20, + 390, + 304, + 194, + 150, + 309, + 29, + 252, + 21, + 101, + 194, + 101, + 358, + 68, + 356, + 1, + 195, + 220, + 63, + 293, + 127, + 205, + 131, + 206, + 69, + 13, + 201, + 373, + 43, + 235, + 387, + 384, + 49, + 356, + 312, + 242, + 68, + 9, + 316, + 85, + 363, + 272, + 216, + 338, + 229, + 283, + 49, + 18, + 69, + 224, + 47, + 127, + 54, + 379, + 15, + 263, + 5, + 75, + 123, + 258, + 218, + 205, + 5, + 202, + 112, + 102, + 268, + 202, + 364, + 104, + 101, + 346, + 357, + 332, + 161, + 354, + 275, + 34, + 237, + 361, + 72, + 137, + 121, + 85, + 74, + 78, + 113, + 397, + 208, + 84, + 10, + 158, + 254, + 172, + 189, + 7, + 69, + 23, + 388, + 283, + 239, + 113, + 185, + 4, + 149, + 313, + 78, + 331, + 193, + 76, + 342, + 326, + 324, + 249, + 249, + 12, + 13, + 192, + 63, + 296, + 230, + 71, + 74, + 391, + 389, + 92, + 247, + 53, + 267, + 311, + 383, + 112, + 33, + 352, + 194, + 379, + 150, + 55, + 344, + 219, + 391, + 232, + 346, + 395, + 322, + 300, + 282, + 317, + 300, + 121, + 370, + 325, + 43, + 22, + 374, + 24, + 121, + 16, + 34, + 234, + 127, + 237, + 369, + 157, + 167, + 277, + 295, + 247, + 382, + 217, + 319, + 227, + 349, + 296, + 369, + 325, + 80, + 72, + 340, + 355, + 88, + 111, + 131, + 128, + 11, + 383, + 167, + 126, + 286, + 303, + 89, + 308, + 83, + 333, + 113, + 312, + 193, + 114, + 15, + 374, + 386, + 269, + 391, + 113, + 43, + 177, + 70, + 142, + 13, + 84, + 204, + 305, + 141, + 167, + 27, + 349, + 333, + 250, + 92, + 193, + 332, + 224, + 328, + 87, + 29, + 73, + 331, + 80, + 194, + 75, + 49, + 312, + 283, + 233, + 152, + 215, + 361, + 170, + 45, + 70, + 92, + 185, + 381, + 120, + 76, + 19, + 79, + 170, + 14, + 48, + 358, + 153, + 354, + 200, + 173, + 250, + 180, + 72, + 202, + 330, + 312, + 37, + 235, + 48, + 17, + 337, + 144, + 301, + 376, + 197, + 179, + 380, + 30, + 61, + 150, + 146, + 170, + 393, + 109, + 374, + 141, + 15, + 77, + 332, + 153, + 400, + 334, + 195, + 87, + 108, + 360, + 321, + 11, + 144, + 17, + 146, + 342, + 301, + 247, + 69, + 239, + 263, + 327, + 1, + 109, + 62, + 82, + 315, + 9, + 192, + 57, + 91, + 98, + 197, + 237, + 398, + 217, + 324, + 76, + 366, + 215, + 111, + 161, + 213, + 228, + 332, + 182, + 278, + 289, + 279, + 138, + 351, + 255, + 356, + 301, + 180, + 378, + 67, + 245, + 204, + 337, + 337, + 397, + 39, + 212, + 387, + 378, + 38, + 213, + 76, + 81, + 33, + 202, + 149, + 68, + 398, + 243, + 375, + 303, + 163, + 150, + 366, + 20, + 156, + 108, + 150, + 41, + 119, + 22, + 67, + 394, + 120, + 90, + 195, + 321, + 361, + 74, + 310, + 372, + 282, + 34, + 394, + 316, + 131, + 143, + 119, + 278, + 86, + 306, + 365, + 238, + 196, + 222, + 330, + 393, + 190, + 35, + 318, + 83, + 67, + 67, + 3, + 43, + 219, + 197, + 264, + 250, + 319, + 131, + 47, + 220, + 255, + 334, + 372, + 358, + 2, + 392, + 32, + 217, + 207, + 271, + 204, + 39, + 338, + 348, + 109, + 246, + 16, + 367, + 198, + 93, + 141, + 248, + 197, + 163, + 264, + 66, + 54, + 293, + 253, + 377, + 233, + 290, + 53, + 351, + 240, + 399, + 74, + 249, + 185, + 137, + 53, + 247, + 334, + 18, + 112, + 162, + 387, + 227, + 7, + 326, + 132, + 22, + 26, + 314, + 359, + 72, + 194, + 148, + 393, + 160, + 49, + 275, + 120, + 346, + 164, + 97, + 317, + 267, + 212, + 297, + 201, + 350, + 332, + 350, + 329, + 223, + 385, + 24, + 167, + 279, + 374, + 128, + 392, + 117, + 41, + 143, + 38, + 312, + 226, + 313, + 78, + 209, + 351, + 320, + 194, + 192, + 333, + 242, + 254, + 340, + 290, + 72, + 359, + 370, + 220, + 241, + 48, + 197, + 31, + 297, + 282, + 375, + 181, + 97, + 70, + 87, + 363, + 63, + 286, + 166, + 114, + 344, + 332, + 31, + 167, + 278, + 75, + 340, + 138, + 83, + 189, + 263, + 221, + 243, + 366, + 190, + 336, + 79, + 235, + 338, + 290, + 128, + 100, + 80, + 347, + 341, + 351, + 160, + 328, + 183, + 351, + 361, + 157, + 91, + 95, + 217, + 365, + 124, + 325, + 293, + 212, + 170, + 376, + 296, + 178, + 140, + 127, + 86, + 200, + 216, + 23, + 239, + 385, + 134, + 316, + 187, + 391, + 71, + 19, + 9, + 286, + 46, + 42, + 172, + 292, + 58, + 67, + 84, + 4, + 159, + 110, + 66, + 213, + 3, + 320, + 40, + 23, + 97, + 86, + 102, + 83, + 119, + 237, + 242, + 171, + 320, + 268, + 377, + 53, + 65, + 133, + 144, + 389, + 275, + 215, + 100, + 134, + 185, + 94, + 213, + 307, + 297, + 250, + 321, + 252, + 106, + 400, + 265, + 266, + 176, + 141, + 14, + 201, + 250, + 295, + 202, + 287, + 301, + 179, + 133, + 68, + 347, + 113, + 181, + 148, + 346, + 356, + 258, + 69, + 130, + 84, + 244, + 85, + 109, + 139, + 268, + 83, + 367, + 129, + 52, + 287, + 217, + 164, + 123, + 202, + 122, + 163, + 79, + 321, + 202, + 302, + 93, + 256, + 29, + 16, + 209, + 348, + 315, + 282, + 391, + 51, + 247, + 184, + 351, + 40, + 96, + 60, + 39, + 278, + 108, + 81, + 389, + 344, + 149, + 176, + 64, + 344, + 165, + 262, + 40, + 75, + 263, + 46, + 392, + 266, + 47, + 8, + 278, + 262, + 192, + 260, + 329, + 332, + 25, + 314, + 15, + 22, + 146, + 101, + 343, + 245, + 238, + 354, + 222, + 69, + 259, + 139, + 352, + 73, + 46, + 223, + 294, + 122, + 292, + 312, + 382, + 338, + 260, + 334, + 165, + 341, + 62, + 108, + 227, + 232, + 208, + 40, + 342, + 281, + 120, + 62, + 185, + 165, + 348, + 114, + 26, + 65, + 146, + 33, + 34, + 340, + 156, + 275, + 68, + 187, + 396, + 205, + 366, + 26, + 298, + 64, + 220, + 73, + 192, + 303, + 57, + 382, + 273, + 313, + 385, + 134, + 261, + 327, + 307, + 325, + 108, + 386, + 251, + 305, + 114, + 392, + 114, + 147, + 72, + 312, + 108, + 264, + 378, + 316, + 398, + 169, + 217, + 39, + 58, + 46, + 12, + 265, + 7, + 187, + 105, + 53, + 133, + 44, + 244, + 115, + 129, + 282, + 22, + 340, + 200, + 121, + 90, + 209, + 97, + 388, + 133, + 345, + 113, + 289, + 298, + 312, + 284, + 72, + 98, + 259, + 201, + 111, + 357, + 337, + 369, + 286, + 346, + 206, + 159, + 20, + 266, + 177, + 386, + 114, + 16, + 334, + 132, + 277, + 214, + 375, + 229, + 29, + 124, + 19, + 95, + 169, + 65, + 318, + 120, + 245, + 31, + 301, + 306, + 197, + 261, + 102, + 290, + 156, + 69, + 330, + 346, + 139, + 159, + 287, + 284, + 126, + 301, + 57, + 274, + 386, + 106, + 147, + 19, + 344, + 11, + 276, + 31, + 252, + 87, + 133, + 73, + 259, + 20, + 85, + 334, + 311, + 352, + 197, + 282, + 348, + 359, + 120, + 18, + 250, + 389, + 233, + 6, + 75, + 395, + 191, + 51, + 156, + 387, + 377, + 155, + 355, + 343, + 49, + 270, + 308, + 95, + 41, + 66, + 380, + 335, + 224, + 162, + 198, + 366, + 44, + 259, + 232, + 170, + 177, + 251, + 256, + 10, + 337, + 175, + 82, + 230, + 54, + 275, + 34, + 113, + 228, + 288, + 151, + 199, + 361, + 244, + 221, + 336, + 336, + 30, + 105, + 228, + 317, + 356, + 227, + 251, + 58, + 6, + 165, + 150, + 400, + 271, + 48, + 343, + 383, + 48, + 144, + 289, + 270, + 147, + 18, + 131, + 302, + 191, + 249, + 143, + 32, + 279, + 245, + 350, + 176, + 154, + 103, + 355, + 359, + 167, + 239, + 121, + 361, + 10, + 217, + 78, + 207, + 391, + 309, + 16, + 65, + 309, + 185, + 299, + 299, + 372, + 86, + 146, + 316, + 207, + 96, + 196, + 97, + 28, + 28, + 128, + 234, + 123, + 108, + 88, + 359, + 124, + 27, + 76, + 377, + 318, + 155, + 251, + 231, + 148, + 352, + 378, + 3, + 93, + 400, + 34, + 235, + 299, + 360, + 118, + 211, + 22, + 282, + 57, + 270, + 295, + 150, + 283, + 204, + 12, + 357, + 231, + 119, + 20, + 173, + 55, + 129, + 61, + 286, + 382, + 303, + 135, + 89, + 249, + 384, + 77, + 379, + 142, + 333, + 178, + 295, + 198, + 293, + 338, + 150, + 10, + 17, + 354, + 177, + 157, + 76, + 38, + 293, + 236, + 205, + 98, + 169, + 265, + 109, + 91, + 172, + 218, + 125, + 298, + 50, + 339, + 115, + 168, + 165, + 26, + 53, + 84, + 236, + 13, + 97, + 400, + 387, + 37, + 243, + 172, + 180, + 285, + 94, + 209, + 125, + 353, + 67, + 257, + 34, + 168, + 360, + 78, + 251, + 320, + 278, + 376, + 317, + 148, + 263, + 32, + 356, + 160, + 208, + 289, + 235, + 249, + 357, + 318, + 55, + 155, + 283, + 134, + 60, + 156, + 21, + 295, + 20, + 65, + 46, + 215, + 321, + 39, + 12, + 346, + 108, + 321, + 270, + 156, + 136, + 334, + 364, + 318, + 168, + 365, + 79, + 90, + 123, + 325, + 330, + 189, + 52, + 123, + 310, + 267, + 231, + 289, + 133, + 293, + 32, + 346, + 288, + 313, + 108, + 398, + 62, + 321, + 25, + 362, + 268, + 313, + 123, + 280, + 353, + 129, + 100, + 170, + 54, + 13, + 348, + 167, + 82, + 167, + 176, + 41, + 235, + 45, + 400, + 216, + 211, + 233, + 297, + 310, + 240, + 193, + 248, + 242, + 375, + 371, + 170, + 342, + 197, + 190, + 367, + 43, + 71, + 249, + 251, + 299, + 317, + 291, + 345, + 69, + 60, + 333, + 21, + 312, + 194, + 6, + 285, + 320, + 201, + 8, + 218, + 286, + 127, + 388, + 183, + 27, + 181, + 263, + 102, + 246, + 134, + 37, + 236, + 262, + 196, + 186, + 157, + 281, + 266, + 263, + 219, + 345, + 120, + 22, + 210, + 246, + 72, + 29, + 121, + 299, + 240, + 167, + 270, + 47, + 229, + 84, + 226, + 26, + 70, + 85, + 197, + 218, + 198, + 278, + 232, + 36, + 1, + 298, + 144, + 130, + 2, + 240, + 86, + 216, + 288, + 135, + 98, + 68, + 41, + 142, + 192, + 301, + 169, + 114, + 261, + 11, + 322, + 148, + 66, + 196, + 358, + 280, + 347, + 15, + 9, + 212, + 383, + 394, + 127, + 194, + 277, + 135, + 231, + 223, + 84, + 284, + 98, + 286, + 367, + 28, + 299, + 74, + 187, + 260, + 273, + 300, + 206, + 23, + 244, + 291, + 364, + 21, + 12, + 52, + 362, + 20, + 353, + 38, + 370, + 188, + 64, + 320, + 226, + 103, + 206, + 25, + 197, + 35, + 348, + 213, + 182, + 364, + 249, + 118, + 352, + 286, + 166, + 101, + 375, + 292, + 258, + 62, + 372, + 102, + 149, + 250, + 223, + 97, + 180, + 129, + 394, + 184, + 132, + 29, + 88, + 104, + 180, + 50, + 97, + 192, + 339, + 166, + 234, + 374, + 219, + 233, + 141, + 337, + 317, + 274, + 44, + 165, + 189, + 112, + 363, + 156, + 291, + 44, + 288, + 142, + 391, + 289, + 17, + 341, + 335, + 6, + 177, + 219, + 285, + 224, + 62, + 20, + 258, + 270, + 91, + 254, + 334, + 124, + 185, + 120, + 8, + 13, + 339, + 306, + 333, + 255, + 41, + 7, + 316, + 236, + 80, + 145, + 247, + 368, + 312, + 124, + 346, + 116, + 1, + 108, + 9, + 126, + 303, + 357, + 5, + 223, + 83, + 172, + 205, + 242, + 77, + 61, + 159, + 121, + 268, + 256, + 331, + 203, + 70, + 217, + 122, + 310, + 142, + 156, + 108, + 379, + 321, + 289, + 379, + 63, + 264, + 372, + 395, + 261, + 190, + 11, + 291, + 148, + 72, + 215, + 259, + 304, + 381, + 38, + 216, + 134, + 62, + 211, + 279, + 213, + 125, + 27, + 254, + 81, + 43, + 150, + 256, + 371, + 295, + 219, + 335, + 230, + 79, + 177, + 159, + 241, + 304, + 63, + 247, + 107, + 143, + 400, + 262, + 369, + 242, + 90, + 82, + 105, + 229, + 162, + 222, + 383, + 363, + 223, + 211, + 114, + 134, + 162, + 245, + 371, + 95, + 329, + 124, + 216, + 201, + 195, + 157, + 85, + 309, + 271, + 384, + 143, + 51, + 366, + 183, + 326, + 170, + 49, + 326, + 351, + 107, + 141, + 334, + 102, + 323, + 286, + 12, + 215, + 4, + 228, + 322, + 255, + 256, + 323, + 69, + 168, + 274, + 148, + 237, + 194, + 331, + 203, + 132, + 151, + 238, + 215, + 46, + 106, + 35, + 225, + 360, + 124, + 386, + 37, + 111, + 331, + 340, + 12, + 181, + 143, + 249, + 348, + 165, + 10, + 282, + 18, + 359, + 346, + 371, + 267, + 355, + 15, + 212, + 68, + 382, + 222, + 110, + 54, + 270, + 53, + 245, + 213, + 152, + 80, + 323, + 6, + 264, + 149, + 360, + 388, + 323, + 284, + 315, + 125, + 119, + 95, + 243, + 218, + 360, + 394, + 383, + 221, + 289, + 113, + 294, + 359, + 140, + 113, + 292, + 48, + 266, + 386, + 30, + 186, + 65, + 384, + 351, + 228, + 31, + 144, + 359, + 352, + 50, + 362, + 362, + 202, + 27, + 294, + 9, + 68, + 164, + 105, + 37, + 137, + 251, + 394, + 20, + 306, + 145, + 176, + 74, + 229, + 235, + 211, + 174, + 14, + 221, + 165, + 116, + 374, + 198, + 136, + 148, + 198, + 271, + 222, + 48, + 143, + 19, + 399, + 386, + 125, + 378, + 40, + 140, + 183, + 78, + 100, + 26, + 66, + 233, + 114, + 122, + 23, + 183, + 115, + 338, + 357, + 255, + 71, + 230, + 65, + 115, + 75, + 86, + 110, + 100, + 90, + 389, + 159, + 318, + 397, + 40, + 70, + 41, + 106, + 55, + 49, + 181, + 344, + 381, + 132, + 26, + 52, + 306, + 172, + 323, + 197, + 116, + 126, + 39, + 154, + 77, + 256, + 48, + 39, + 317, + 384, + 347, + 66, + 178, + 266, + 1, + 110, + 162, + 153, + 2, + 86, + 192, + 145, + 245, + 193, + 396, + 366, + 205, + 369, + 88, + 158, + 160, + 217, + 58, + 287, + 384, + 110, + 345, + 369, + 36, + 366, + 71, + 233, + 246, + 213, + 300, + 68, + 291, + 245, + 208, + 356, + 303, + 212, + 152, + 181, + 292, + 67, + 379, + 354, + 388, + 372, + 30, + 304, + 135, + 123, + 118, + 281, + 380, + 344, + 20, + 53, + 107, + 3, + 216, + 381, + 22, + 363, + 271, + 269, + 196, + 97, + 40, + 399, + 115, + 361, + 219, + 128, + 340, + 15, + 308, + 186, + 8, + 292, + 183, + 63, + 42, + 8, + 273, + 45, + 195, + 108, + 140, + 324, + 230, + 306, + 159, + 324, + 172, + 72, + 109, + 203, + 188, + 329, + 186, + 61, + 174, + 362, + 143, + 10, + 388, + 66, + 211, + 227, + 13, + 239, + 201, + 198, + 96, + 208, + 26, + 345, + 336, + 21, + 145, + 1, + 206, + 393, + 81, + 251, + 303, + 195, + 11, + 68, + 205, + 341, + 144, + 178, + 256, + 348, + 70, + 12, + 6, + 385, + 201, + 108, + 92, + 284, + 140, + 43, + 51, + 106, + 172, + 148, + 195, + 218, + 370, + 73, + 335, + 189, + 138, + 13, + 227, + 227, + 208, + 338, + 137, + 379, + 68, + 308, + 236, + 258, + 293, + 287, + 13, + 129, + 132, + 60, + 174, + 126, + 319, + 185, + 189, + 318, + 232, + 359, + 275, + 364, + 46, + 256, + 179, + 172, + 368, + 45, + 68, + 132, + 201, + 21, + 285, + 99, + 338, + 340, + 140, + 300, + 270, + 208, + 380, + 187, + 188, + 22, + 112, + 304, + 55, + 39, + 198, + 20, + 355, + 257, + 298, + 91, + 235, + 18, + 235, + 58, + 77, + 397, + 232, + 51, + 277, + 284, + 292, + 360, + 369, + 188, + 350, + 158, + 125, + 158, + 49, + 160, + 111, + 64, + 21, + 368, + 390, + 287, + 279, + 104, + 291, + 246, + 294, + 196, + 400, + 161, + 133, + 319, + 310, + 62, + 118, + 205, + 320, + 164, + 44, + 81, + 10, + 270, + 51, + 23, + 265, + 121, + 184, + 389, + 120, + 355, + 221, + 167, + 105, + 289, + 147, + 174, + 133, + 185, + 225, + 228, + 309, + 218, + 320, + 233, + 115, + 126, + 22, + 383, + 356, + 254, + 36, + 19, + 95, + 80, + 327, + 107, + 42, + 327, + 70, + 107, + 45, + 119, + 323, + 83, + 81, + 68, + 261, + 195, + 76, + 45, + 172, + 6, + 154, + 305, + 108, + 263, + 249, + 146, + 120, + 112, + 298, + 207, + 382, + 231, + 371, + 102, + 87, + 155, + 168, + 387, + 309, + 70, + 166, + 95, + 12, + 343, + 302, + 266, + 113, + 41, + 173, + 268, + 350, + 224, + 42, + 70, + 353, + 6, + 319, + 39, + 144, + 223, + 240, + 68, + 11, + 36, + 326, + 364, + 31, + 7, + 329, + 295, + 392, + 147, + 250, + 192, + 24, + 334, + 27, + 272, + 21, + 49, + 398, + 222, + 150, + 255, + 326, + 100, + 149, + 33, + 357, + 143, + 15, + 246, + 30, + 72, + 101, + 398, + 120, + 398, + 87, + 210, + 355, + 354, + 364, + 244, + 360, + 81, + 293, + 140, + 384, + 197, + 371, + 357, + 157, + 139, + 73, + 198, + 151, + 253, + 79, + 155, + 184, + 24, + 99, + 121, + 66, + 330, + 351, + 279, + 280, + 284, + 362, + 384, + 294, + 262, + 80, + 232, + 62, + 15, + 395, + 102, + 287, + 147, + 20, + 380, + 37, + 211, + 292, + 53, + 265, + 159, + 17, + 141, + 22, + 348, + 311, + 224, + 372, + 116, + 138, + 360, + 170, + 210, + 118, + 208, + 367, + 248, + 267, + 194, + 273, + 162, + 124, + 128, + 45, + 30, + 353, + 258, + 204, + 329, + 49, + 101, + 232, + 133, + 95, + 371, + 186, + 128, + 214, + 318, + 233, + 20, + 37, + 253, + 291, + 152, + 223, + 254, + 321, + 277, + 224, + 68, + 346, + 395, + 89, + 23, + 5, + 136, + 52, + 369, + 158, + 2, + 48, + 34, + 102, + 187, + 101, + 117, + 344, + 301, + 294, + 302, + 349, + 272, + 148, + 169, + 82, + 108, + 10, + 302, + 9, + 81, + 124, + 209, + 327, + 371, + 247, + 270, + 26, + 337, + 109, + 128, + 13, + 53, + 148, + 73, + 162, + 390, + 89, + 173, + 86, + 156, + 114, + 394, + 90, + 105, + 61, + 388, + 24, + 318, + 366, + 260, + 34, + 340, + 159, + 293, + 205, + 266, + 87, + 142, + 370, + 355, + 57, + 69, + 369, + 385, + 136, + 379, + 59, + 298, + 141, + 199, + 274, + 137, + 241, + 109, + 253, + 159, + 384, + 180, + 174, + 263, + 302, + 350, + 371, + 273, + 292, + 298, + 184, + 215, + 279, + 60, + 103, + 137, + 50, + 317, + 154, + 380, + 360, + 284, + 68, + 178, + 4, + 125, + 165, + 196, + 36, + 151, + 392, + 99, + 59, + 236, + 197, + 107, + 98, + 207, + 231, + 369, + 240, + 213, + 313, + 36, + 259, + 151, + 189, + 387, + 348, + 392, + 69, + 350, + 214, + 17, + 228, + 29, + 215, + 243, + 216, + 17, + 55, + 113, + 200, + 347, + 217, + 132, + 52, + 57, + 109, + 253, + 288, + 377, + 258, + 281, + 251, + 230, + 298, + 98, + 252, + 347, + 232, + 50, + 157, + 213, + 288, + 381, + 142, + 192, + 142, + 156, + 161, + 24, + 257, + 344, + 160, + 242, + 294, + 214, + 151, + 290, + 274, + 142, + 383, + 219, + 309, + 227, + 110, + 137, + 256, + 127, + 299, + 319, + 34, + 153, + 164, + 168, + 341, + 143, + 200, + 205, + 324, + 225, + 216, + 149, + 237, + 89, + 280, + 244, + 256, + 159, + 394, + 135, + 394, + 99, + 267, + 309, + 159, + 176, + 110, + 393, + 268, + 291, + 55, + 102, + 68, + 85, + 158, + 11, + 224, + 84, + 150, + 272, + 342, + 152, + 7, + 67, + 237, + 202, + 286, + 361, + 179, + 52, + 118, + 182, + 121, + 319, + 92, + 216, + 312, + 163, + 100, + 162, + 53, + 244, + 369, + 307, + 64, + 282, + 354, + 135, + 255, + 5, + 97, + 147, + 384, + 290, + 115, + 83, + 17, + 249, + 308, + 129, + 279, + 199, + 162, + 304, + 392, + 331, + 185, + 305, + 333, + 298, + 243, + 124, + 120, + 231, + 378, + 74, + 311, + 85, + 40, + 43, + 14, + 266, + 169, + 175, + 342, + 133, + 151, + 329, + 186, + 295, + 35, + 324, + 291, + 124, + 187, + 11, + 135, + 195, + 341, + 255, + 281, + 255, + 362, + 329, + 274, + 338, + 182, + 52, + 172, + 219, + 141, + 14, + 64, + 87, + 105, + 132, + 156, + 69, + 106, + 6, + 117, + 249, + 297, + 113, + 123, + 388, + 17, + 164, + 348, + 278, + 93, + 86, + 199, + 385, + 283, + 237, + 80, + 30, + 352, + 51, + 58, + 133, + 127, + 100, + 128, + 234, + 380, + 234, + 42, + 310, + 304, + 32, + 18, + 300, + 215, + 391, + 169, + 107, + 324, + 49, + 157, + 207, + 317, + 282, + 90, + 48, + 145, + 339, + 349, + 120, + 226, + 174, + 64, + 397, + 274, + 295, + 261, + 341, + 157, + 165, + 263, + 186, + 194, + 56, + 128, + 3, + 284, + 57, + 88, + 304, + 151, + 43, + 65, + 86, + 350, + 9, + 203, + 31, + 126, + 249, + 387, + 377, + 298, + 43, + 236, + 310, + 247, + 102, + 143, + 14, + 114, + 262, + 156, + 182, + 108, + 398, + 372, + 100, + 393, + 329, + 359, + 285, + 388, + 59, + 184, + 221, + 303, + 327, + 145, + 124, + 144, + 9, + 107, + 142, + 18, + 56, + 36, + 313, + 329, + 98, + 54, + 367, + 201, + 102, + 325, + 37, + 205, + 123, + 299, + 241, + 84, + 112, + 235, + 46, + 357, + 214, + 361, + 392, + 220, + 171, + 3, + 240, + 388, + 167, + 7, + 293, + 4, + 194, + 269, + 197, + 125, + 78, + 162, + 301, + 222, + 157, + 248, + 74, + 278, + 110, + 156, + 273, + 239, + 161, + 290, + 117, + 27, + 356, + 377, + 328, + 80, + 152, + 302, + 193, + 180, + 256, + 365, + 237, + 194, + 354, + 178, + 199, + 248, + 154, + 336, + 249, + 267, + 315, + 356, + 200, + 379, + 224, + 215, + 104, + 51, + 146, + 28, + 77, + 232, + 346, + 22, + 43, + 16, + 12, + 212, + 120, + 209, + 268, + 213, + 159, + 193, + 260, + 232, + 298, + 153, + 278, + 129, + 109, + 375, + 121, + 151, + 34, + 256, + 7, + 260, + 139, + 255, + 384, + 376, + 130, + 108, + 215, + 103, + 179, + 181, + 24, + 328, + 385, + 213, + 20, + 41, + 74, + 8, + 365, + 195, + 56, + 23, + 310, + 325, + 235, + 307, + 322, + 320, + 218, + 26, + 363, + 220, + 181, + 353, + 369, + 315, + 366, + 78, + 125, + 138, + 177, + 333, + 164, + 54, + 128, + 315, + 1, + 173, + 254, + 259, + 33, + 302, + 219, + 248, + 235, + 72, + 279, + 97, + 389, + 79, + 313, + 198, + 301, + 324, + 338, + 293, + 378, + 124, + 270, + 325, + 170, + 375, + 118, + 224, + 254, + 78, + 117, + 103, + 180, + 303, + 94, + 259, + 54, + 375, + 147, + 399, + 299, + 128, + 122, + 364, + 23, + 330, + 288, + 314, + 71, + 162, + 398, + 96, + 176, + 371, + 30, + 12, + 21, + 130, + 190, + 205, + 52, + 20, + 102, + 262, + 268, + 122, + 23, + 354, + 104, + 221, + 191, + 129, + 33, + 51, + 339, + 198, + 111, + 159, + 395, + 295, + 93, + 272, + 124, + 114, + 254, + 116, + 127, + 272, + 41, + 210, + 384, + 83, + 34, + 393, + 84, + 359, + 137, + 355, + 228, + 316, + 175, + 75, + 280, + 221, + 98, + 43, + 68, + 197, + 194, + 40, + 242, + 50, + 123, + 149, + 206, + 331, + 158, + 224, + 142, + 88, + 201, + 250, + 251, + 186, + 42, + 191, + 317, + 282, + 3, + 250, + 137, + 139, + 305, + 110, + 165, + 269, + 333, + 378, + 360, + 292, + 183, + 370, + 78, + 100, + 344, + 186, + 137, + 120, + 220, + 14, + 302, + 303, + 55, + 381, + 234, + 382, + 93, + 342, + 168, + 213, + 155, + 180, + 201, + 191, + 386, + 296, + 303, + 82, + 131, + 218, + 299, + 360, + 282, + 253, + 49, + 215, + 225, + 67, + 378, + 23, + 109, + 398, + 48, + 15, + 235, + 138, + 373, + 270, + 366, + 7, + 150, + 92, + 372, + 110, + 123, + 57, + 66, + 98, + 210, + 164, + 338, + 341, + 171, + 92, + 277, + 20, + 33, + 280, + 214, + 28, + 363, + 79, + 291, + 256, + 161, + 252, + 322, + 372, + 134, + 203, + 108, + 54, + 127, + 392, + 128, + 180, + 185, + 99, + 7, + 75, + 141, + 188, + 37, + 309, + 1, + 316, + 377, + 345, + 177, + 229, + 133, + 160, + 312, + 294, + 198, + 130, + 363, + 118, + 72, + 52, + 198, + 375, + 52, + 306, + 336, + 300, + 140, + 130, + 395, + 386, + 205, + 263, + 30, + 155, + 301, + 389, + 59, + 47, + 162, + 120, + 360, + 311, + 281, + 102, + 41, + 197, + 46, + 271, + 36, + 179, + 303, + 106, + 316, + 253, + 283, + 292, + 103, + 218, + 199, + 158, + 144, + 54, + 127, + 53, + 293, + 36, + 215, + 168, + 110, + 233, + 192, + 377, + 1, + 170, + 245, + 225, + 363, + 172, + 56, + 110, + 165, + 134, + 139, + 248, + 325, + 84, + 340, + 53, + 78, + 395, + 9, + 288, + 223, + 105, + 165, + 230, + 317, + 189, + 72, + 252, + 296, + 169, + 214, + 75, + 179, + 256, + 60, + 178, + 30, + 138, + 376, + 327, + 98, + 191, + 48, + 14, + 320, + 39, + 172, + 183, + 229, + 291, + 88, + 110, + 400, + 12, + 238, + 159, + 309, + 256, + 170, + 26, + 348, + 191, + 296, + 236, + 275, + 314, + 280, + 126, + 231, + 185, + 263, + 306, + 35, + 35, + 378, + 198, + 162, + 49, + 212, + 224, + 66, + 40, + 47, + 24, + 154, + 226, + 198, + 98, + 193, + 398, + 51, + 130, + 64, + 73, + 378, + 189, + 71, + 158, + 314, + 47, + 209, + 339, + 197, + 372, + 201, + 116, + 33, + 215, + 169, + 211, + 155, + 378, + 11, + 226, + 125, + 188, + 182, + 341, + 102, + 318, + 81, + 359, + 388, + 11, + 174, + 241, + 179, + 367, + 368, + 311, + 232, + 9, + 131, + 174, + 384, + 45, + 355, + 209, + 289, + 372, + 339, + 86, + 40, + 385, + 79, + 15, + 161, + 386, + 386, + 124, + 368, + 305, + 299, + 301, + 384, + 315, + 389, + 378, + 95, + 249, + 394, + 393, + 174, + 291, + 259, + 290, + 268, + 373, + 340, + 39, + 253, + 294, + 254, + 212, + 222, + 164, + 27, + 379, + 39, + 50, + 70, + 153, + 191, + 292, + 21, + 9, + 254, + 100, + 115, + 80, + 117, + 387, + 389, + 236, + 257, + 226, + 292, + 169, + 238, + 92, + 36, + 190, + 73, + 177, + 301, + 24, + 173, + 168, + 242, + 208, + 91, + 366, + 87, + 206, + 247, + 161, + 340, + 105, + 151, + 108, + 26, + 124, + 228, + 268, + 371, + 176, + 360, + 334, + 164, + 190, + 10, + 59, + 63, + 67, + 2, + 135, + 334, + 166, + 266, + 350, + 153, + 142, + 32, + 261, + 107, + 389, + 170, + 1, + 27, + 19, + 331, + 288, + 190, + 311, + 189, + 82, + 34, + 369, + 89, + 127, + 217, + 344, + 248, + 312, + 233, + 215, + 86, + 5, + 203, + 362, + 54, + 278, + 33, + 310, + 342, + 154, + 168, + 376, + 378, + 16, + 140, + 285, + 336, + 237, + 185, + 303, + 222, + 10, + 120, + 341, + 110, + 125, + 16, + 180, + 211, + 362, + 344, + 244, + 199, + 168, + 146, + 114, + 55, + 347, + 242, + 318, + 392, + 298, + 316, + 230, + 109, + 23, + 271, + 289, + 169, + 26, + 96, + 47, + 114, + 159, + 119, + 320, + 367, + 10, + 36, + 171, + 349, + 270, + 384, + 245, + 15, + 393, + 192, + 43, + 356, + 247, + 68, + 320, + 215, + 21, + 366, + 58, + 186, + 335, + 131, + 321, + 7, + 280, + 239, + 224, + 159, + 237, + 271, + 13, + 129, + 231, + 396, + 221, + 359, + 14, + 372, + 253, + 267, + 349, + 375, + 290, + 361, + 243, + 252, + 1, + 261, + 397, + 60, + 375, + 393, + 234, + 105, + 342, + 301, + 380, + 143, + 393, + 282, + 6, + 279, + 321, + 308, + 148, + 143, + 358, + 114, + 192, + 206, + 220, + 382, + 343, + 207, + 186, + 194, + 395, + 144, + 77, + 264, + 19, + 251, + 336, + 60, + 57, + 182, + 363, + 19, + 225, + 226, + 241, + 333, + 260, + 267, + 380, + 375, + 234, + 340, + 27, + 132, + 335, + 379, + 143, + 225, + 50, + 8, + 209, + 306, + 223, + 122, + 127, + 302, + 244, + 194, + 301, + 251, + 393, + 326, + 239, + 50, + 98, 352, - 158, - 247, + 100, + 65, + 372, + 365, + 241, + 43, + 336, + 353, + 259, + 144, + 101, + 356, + 209, + 374, + 340, + 336, + 91, + 339, + 370, + 193, + 232, + 254, + 313, + 76, + 198, + 290, + 14, + 378, + 353, + 209, + 233, + 376, + 326, + 391, + 286, + 309, + 10, + 263, + 45, + 83, + 92, + 181, + 239, + 87, 82, - 368, - 24, - 41, - 307, + 171, + 217, + 52, + 127, + 323, + 157, + 270, + 21, + 114, + 172, + 51, + 290, + 276, + 308, + 47, + 296, + 84, + 122, + 365, + 373, + 324, + 104, + 100, + 6, + 382, + 211, + 363, + 210, + 308, + 291, + 128, + 282, + 225, + 218, + 333, + 13, + 377, + 400, + 33, + 348, + 232, + 364, + 276, + 350, + 187, + 47, + 147, + 345, + 198, + 146, + 395, + 294, + 32, + 300, + 322, + 128, + 352, + 334, + 343, + 169, + 355, + 336, + 71, + 15, + 213, + 131, + 25, + 389, + 125, + 107, + 156, + 68, + 111, + 126, + 320, + 276, + 360, + 73, + 92, + 310, + 12, + 346, + 25, + 110, + 396, + 52, + 234, + 348, + 94, + 20, + 250, + 377, + 226, + 10, + 372, + 193, + 108, + 83, + 360, + 322, + 303, + 396, + 94, + 316, + 160, + 102, + 388, + 212, + 357, + 1, + 142, + 63, + 131, + 166, + 221, + 115, + 172, + 375, + 108, + 293, + 210, + 222, + 226, + 137, + 260, + 166, + 260, + 199, + 19, + 344, + 166, + 381, + 304, + 325, + 344, + 343, + 122, + 282, + 16, + 71, + 257, + 306, + 323, + 54, + 366, + 47, + 264, + 262, + 8, + 213, + 64, + 186, + 6, + 222, + 389, + 122, + 178, + 176, + 337, + 380, + 315, + 359, + 169, + 305, + 77, + 30, + 113, + 291, + 341, + 317, 273, - 207, + 47, + 258, + 191, + 159, + 219, + 162, + 73, + 23, + 60, + 344, + 198, + 318, + 138, + 4, + 184, 16, - 121, 379, - 304, - 176, - 128, - 233, - 333, - 215, - 74, - 28, - 326, + 37, + 306, + 338, + 189, + 193, + 173, + 323, + 164, + 305, + 33, + 157, + 330, + 27, 16, - 252, + 335, + 339, + 352, + 191, + 10, + 36, + 222, + 77, + 307, + 103, + 358, + 196, + 333, + 169, + 386, + 308, + 152, + 34, + 75, + 348, + 219, + 343, + 48, + 11, + 2, + 23, + 367, + 365, + 294, + 275, + 39, + 338, + 154, + 335, + 245, + 313, + 264, + 107, + 223, + 304, + 61, + 306, + 186, + 108, + 147, + 236, + 283, + 147, + 397, + 343, + 111, + 184, + 313, + 264, + 132, + 398, + 49, + 298, + 325, + 370, + 400, + 208, + 146, + 381, + 43, + 153, + 188, + 309, + 212, + 243, + 278, + 184, + 388, + 222, + 46, + 32, 171, - 106, - 66, + 230, + 253, + 318, + 128, + 128, + 306, + 298, + 223, + 188, + 277, + 70, + 119, + 232, + 129, + 156, + 167, + 37, + 137, + 356, + 392, + 209, + 324, + 290, + 386, + 319, + 285, + 99, + 339, + 323, + 314, + 301, + 123, + 156, + 311, + 350, + 63, + 246, + 240, + 78, + 110, + 342, + 332, 374, + 286, + 20, + 253, + 332, + 340, + 37, + 210, + 174, + 324, + 236, + 243, + 395, + 375, + 134, 288, - 67, - 322, + 177, + 279, + 33, + 286, + 204, + 134, + 319, + 391, + 181, 211, + 355, + 32, + 312, + 62, + 69, + 124, + 297, + 38, + 388, + 37, + 350, + 53, + 2, + 129, + 24, + 234, + 372, + 394, + 231, + 168, + 367, + 139, + 345, + 46, + 279, + 180, + 147, + 89, + 364, + 168, + 153, + 94, + 63, + 62, + 127, + 110, + 245, + 229, + 4, + 298, + 352, + 262, + 41, + 269, + 121, + 129, + 40, + 228, + 254, + 114, + 128, + 118, + 73, + 261, + 375, + 65, + 14, + 175, + 128, + 367, + 110, + 50, + 366, + 65, + 59, + 170, + 260, + 58, + 12, + 224, + 246, + 87, + 210, + 12, + 130, + 354, + 123, + 122, + 299, + 143, + 311, + 187, + 298, + 372, + 201, + 159, + 395, + 356, + 15, + 142, + 352, + 212, + 302, + 212, + 213, + 58, + 265, + 209, + 156, + 392, + 261, + 313, + 323, + 293, + 302, + 299, + 171, + 258, + 353, + 382, 54, - 86, - 222, - 190, - 76, + 321, + 78, + 60, + 304, + 146, + 212, + 282, + 237, + 219, + 114, + 2, + 239, + 307, + 247, + 95, + 331, + 247, + 252, + 7, + 289, + 179, + 238, + 328, + 369, + 354, + 130, + 357, + 248, + 292, + 97, + 113, + 297, + 244, + 202, + 21, + 227, + 141, + 78, + 182, + 373, + 191, + 327, + 254, + 61, + 226, + 246, + 1, + 26, + 114, + 335, + 159, + 388, + 273, + 79, + 257, + 361, + 329, + 114, + 368, + 300, + 118, + 329, + 136, + 186, + 281, + 158, + 4, + 132, 30, + 396, + 361, + 154, + 118, + 151, + 380, + 178, + 238, + 315, + 195, + 179, + 207, + 341, + 231, + 47, + 78, + 37, + 389, + 115, + 329, + 191, + 169, + 217, + 367, + 116, + 61, + 113, + 12, + 21, + 123, + 213, + 128, + 184, + 321, + 260, + 131, + 119, + 34, + 15, + 178, + 58, + 117, + 54, + 35, + 292, + 92, + 271, + 181, + 62, + 168, + 82, + 72, + 310, 215, - 150, + 309, + 334, + 281, 72, + 351, + 333, + 171, + 207, + 85, + 221, 232, - 317, + 349, + 59, + 258, + 43, + 216, + 54, + 211, + 345, + 131, + 314, + 391, + 39, + 300, + 41, + 35, + 9, + 313, + 269, 86, - 267, - 232, - 249, - 352, - 373, - 162, - 245, - 140, - 149, + 239, + 189, 240, - 206, - 75, - 57, - 193, - 272, - 91, - 321, - 255, - 173, - 92, - 45, - 251, + 279, + 331, + 333, + 359, + 128, + 229, + 107, + 87, + 163, + 49, + 151, + 167, + 221, + 327, + 324, + 305, + 281, + 309, + 269, + 141, + 295, + 56, + 66, + 356, + 49, + 289, + 136, 139, - 263, - 400, - 280, + 117, 257, - 184, + 361, + 297, + 329, + 31, + 142, + 389, + 164, 32, - 396, - 182, - 355, - 300, - 339, + 96, + 210, + 149, + 145, + 106, + 51, + 273, + 80, + 211, + 61, + 60, + 106, + 99, + 216, + 309, + 175, + 314, + 370, + 204, + 236, + 148, + 395, + 283, + 55, + 159, + 343, + 292, + 375, + 39, + 237, + 347, + 126, + 192, + 356, + 188, + 357, + 346, + 280, + 308, + 188, + 186, + 159, + 121, + 33, + 52, + 217, + 14, + 191, + 90, + 373, + 5, + 147, + 291, + 332, + 191, + 100, + 27, 17, - 388, + 300, + 63, + 277, + 308, + 235, + 301, + 63, + 208, + 269, + 70, + 134, + 101, + 74, + 393, + 309, + 50, + 69, + 92, + 276, + 89, + 329, + 158, + 346, + 309, + 274, + 274, + 67, + 46, + 45, + 49, + 65, + 254, + 211, + 71, + 206, + 254, + 354, + 301, + 80, + 293, + 229, 156, - 186, - 286, - 360, - 342, - 143, - 248, - 135, - 394, - 353, - 366, - 150, + 139, + 155, + 37, + 189, + 159, + 213, + 359, + 284, + 341, + 118, + 307, + 223, + 267, + 345, + 310, + 22, + 136, + 211, + 329, + 209, + 117, + 199, + 164, + 47, + 255, + 281, + 170, + 22, + 313, + 17, + 327, + 304, + 147, 174, - 332, - 91, - 297, - 5 + 229, + 83, + 289, + 92, + 335, + 316, + 143, + 179, + 325, + 121, + 128, + 38, + 61, + 64, + 321, + 69, + 321, + 136, + 101, + 108 ] } From a22fdd007d3ab4226b4cf970c736ca80fc301760 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Sun, 26 Nov 2023 22:08:53 -0500 Subject: [PATCH 107/189] Simplify logic on static designs (#1775) * command line cycle limit parse * clippy * better static guard simplification * rewrite test * small change * small change * rewrite test * default to none --- .../src/passes/simplify_static_guards.rs | 36 +++++- calyx-opt/src/passes/static_promotion.rs | 119 ++++++++++++------ examples/futil/dot-product.expect | 4 +- .../passes/simplify-static-guards/basic.futil | 16 +-- .../simplify-static-guards/simplify-or.expect | 21 ++++ .../simplify-static-guards/simplify-or.futil | 24 ++++ .../static-promotion/no_promote_loop.expect | 27 ++-- .../static-promotion/no_promote_loop.futil | 2 +- 8 files changed, 188 insertions(+), 61 deletions(-) create mode 100644 tests/passes/simplify-static-guards/simplify-or.expect create mode 100644 tests/passes/simplify-static-guards/simplify-or.futil diff --git a/calyx-opt/src/passes/simplify_static_guards.rs b/calyx-opt/src/passes/simplify_static_guards.rs index e22d3c2da..3f8ac99b6 100644 --- a/calyx-opt/src/passes/simplify_static_guards.rs +++ b/calyx-opt/src/passes/simplify_static_guards.rs @@ -35,11 +35,6 @@ impl SimplifyStaticGuards { cur_anded_intervals: &mut Vec<(u64, u64)>, ) -> Option> { match g { - ir::Guard::Not(_) - | ir::Guard::Or(_, _) - | ir::Guard::True - | ir::Guard::CompOp(_, _, _) - | ir::Guard::Port(_) => Some(g), ir::Guard::And(g1, g2) => { // recursively call separate_anded_intervals on g1 and g2 let rest_g1 = @@ -65,6 +60,11 @@ impl SimplifyStaticGuards { cur_anded_intervals.push(static_timing_info.get_interval()); None } + ir::Guard::True + | ir::Guard::CompOp(_, _, _) + | ir::Guard::Not(_) + | ir::Guard::Or(_, _) + | ir::Guard::Port(_) => Some(g), } } @@ -75,7 +75,7 @@ impl SimplifyStaticGuards { /// For example: (port.out | !port1.out) & (port2.out == port3.out) & %[2:8] & %[5:10] ? /// becomes (port.out | !port1.out) & (port2.out == port3.out) & %[5:8] ? /// by "combining: %[2:8] & %[5:10] - fn simplify_guard( + fn simplify_anded_guards( guard: ir::Guard, group_latency: u64, ) -> ir::Guard { @@ -121,6 +121,30 @@ impl SimplifyStaticGuards { (Some(rg), Some(ig)) => ir::Guard::And(Box::new(rg), Box::new(ig)), } } + + fn simplify_guard( + guard: ir::Guard, + group_latency: u64, + ) -> ir::Guard { + match guard { + ir::Guard::Not(g) => ir::Guard::Not(Box::new( + Self::simplify_guard(*g, group_latency), + )), + ir::Guard::Or(g1, g2) => ir::Guard::Or( + Box::new(Self::simplify_guard(*g1, group_latency)), + Box::new(Self::simplify_guard(*g2, group_latency)), + ), + ir::Guard::And(_, _) => { + Self::simplify_anded_guards(guard, group_latency) + } + ir::Guard::Info(_) => { + Self::simplify_anded_guards(guard, group_latency) + } + ir::Guard::Port(_) + | ir::Guard::True + | ir::Guard::CompOp(_, _, _) => guard, + } + } } impl Visitor for SimplifyStaticGuards { diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 7e95df3cf..e5c3210d0 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -143,7 +143,7 @@ pub struct StaticPromotion { /// Threshold for promotion threshold: u64, /// Whether we should stop promoting when we see a loop. - stop_loop: bool, + cycle_limit: Option, } // Override constructor to build latency_data information from the primitives @@ -177,13 +177,13 @@ impl ConstructVisitor for StaticPromotion { } latency_data.insert(prim.name, GoDone::new(go_ports)); } - let (threshold, stop_loop) = Self::get_threshold(ctx); + let (threshold, cycle_limit) = Self::get_threshold(ctx); Ok(StaticPromotion { latency_data, static_group_name: HashMap::new(), static_component_latencies: HashMap::new(), threshold, - stop_loop, + cycle_limit, }) } @@ -206,7 +206,7 @@ impl Named for StaticPromotion { impl StaticPromotion { // Looks through ctx to get the given command line threshold. // Default threshold = 1 - fn get_threshold(ctx: &ir::Context) -> (u64, bool) + fn get_threshold(ctx: &ir::Context) -> (u64, Option) where Self: Named, { @@ -226,13 +226,24 @@ impl StaticPromotion { }) .collect(); - let mut stop_loop = false; - given_opts.iter().for_each(|arg| { - if *arg == "stop_loop" { - stop_loop = true + // searching for "-x static-promotion:cycle-limit=200" and getting back "200" + let cycle_limit_str: Option<&str> = given_opts.iter().find_map(|arg| { + let split: Vec<&str> = arg.split('=').collect(); + if let Some(str) = split.first() { + if str == &"cycle-limit" { + return Some(split[1]); + } } + None }); + // Default to None. There may be a more idiomatic way to do this. + let cycle_limit = match cycle_limit_str.unwrap_or("None").parse::() + { + Ok(n) => Some(n), + Err(_) => None, + }; + // searching for "-x static-promotion:threshold=1" and getting back "1" let threshold: Option<&str> = given_opts.iter().find_map(|arg| { let split: Vec<&str> = arg.split('=').collect(); @@ -246,9 +257,10 @@ impl StaticPromotion { // Need to convert string argument into int argument // Always default to threshold=1 + // Default cycle limit = 2^25 = 33554432 ( threshold.unwrap_or("1").parse::().unwrap_or(1), - stop_loop, + cycle_limit, ) } @@ -502,6 +514,13 @@ impl StaticPromotion { c.is_static() || c.has_attribute(ir::NumAttr::PromoteStatic) } + fn within_cycle_limit(&self, latency: u64) -> bool { + if self.cycle_limit.is_none() { + return true; + } + latency < self.cycle_limit.unwrap() + } + /// If we've already constructed the static group then use the already existing /// group. Otherwise construct `static group` and then return that. fn construct_static_group( @@ -743,18 +762,23 @@ impl StaticPromotion { v.iter().map(Self::approx_size).sum() } - /// First checks if the vec of control statements meets the self.threshold. + /// First checks if the vec of control statements satsifies the threshold + /// and cycle count threshold /// (That is, whether the combined approx_size of the static_vec is greater) - /// Than the threshold. + /// than the threshold and cycle count is less than cycle limit). /// If so, converts vec of control to a static seq, and returns a vec containing /// the static seq. /// Otherwise, just returns the vec without changing it. - fn convert_vec_seq_if_threshold( + fn convert_vec_seq_if_sat( &mut self, builder: &mut ir::Builder, control_vec: Vec, ) -> Vec { - if Self::approx_control_vec_size(&control_vec) <= self.threshold { + if Self::approx_control_vec_size(&control_vec) <= self.threshold + || !self.within_cycle_limit( + control_vec.iter().map(Self::get_inferred_latency).sum(), + ) + { // Return unchanged vec return control_vec; } @@ -768,16 +792,25 @@ impl StaticPromotion { vec![sseq] } - /// First checks if the vec of control statements meets the self.threshold. + /// First checks if the vec of control statements meets the self.threshold + /// and is within self.cycle_limit /// If so, converts vec of control to a static par, and returns a vec containing /// the static par. /// Otherwise, just returns the vec without changing it. - fn convert_vec_par_if_threshold( + fn convert_vec_par_if_sat( &mut self, builder: &mut ir::Builder, control_vec: Vec, ) -> Vec { - if Self::approx_control_vec_size(&control_vec) <= self.threshold { + if Self::approx_control_vec_size(&control_vec) <= self.threshold + || !self.within_cycle_limit( + control_vec + .iter() + .map(Self::get_inferred_latency) + .max() + .unwrap_or_else(|| unreachable!("Non Empty Par Block")), + ) + { // Return unchanged vec return control_vec; } @@ -933,17 +966,22 @@ impl Visitor for StaticPromotion { } else { // Accumualte cur_vec into a static seq if it meets threshold let possibly_promoted_stmts = - self.convert_vec_seq_if_threshold(&mut builder, cur_vec); + self.convert_vec_seq_if_sat(&mut builder, cur_vec); new_stmts.extend(possibly_promoted_stmts); - cur_vec = Vec::new(); // Add the current (non-promotable) stmt new_stmts.push(stmt); + // New cur_vec + cur_vec = Vec::new(); } } if new_stmts.is_empty() { // The entire seq can be promoted let approx_size: u64 = cur_vec.iter().map(Self::approx_size).sum(); - if approx_size > self.threshold { + if approx_size > self.threshold + && self.within_cycle_limit( + cur_vec.iter().map(Self::get_inferred_latency).sum(), + ) + { // Promote entire seq to a static seq let s_seq_stmts = self.convert_vec_to_static(&mut builder, cur_vec); @@ -970,7 +1008,7 @@ impl Visitor for StaticPromotion { // Entire seq is not static, so we're only promoting the last // bit of it if possible. let possibly_promoted_stmts = - self.convert_vec_seq_if_threshold(&mut builder, cur_vec); + self.convert_vec_seq_if_sat(&mut builder, cur_vec); new_stmts.extend(possibly_promoted_stmts); let new_seq = ir::Control::Seq(ir::Seq { @@ -997,7 +1035,15 @@ impl Visitor for StaticPromotion { }); if d_stmts.is_empty() { // Entire par block can be promoted to static - if Self::approx_control_vec_size(&s_stmts) > self.threshold { + if Self::approx_control_vec_size(&s_stmts) > self.threshold + && self.within_cycle_limit( + s_stmts + .iter() + .map(Self::get_inferred_latency) + .max() + .unwrap_or_else(|| unreachable!("Empty Par Block")), + ) + { // Promote entire par block to static let static_par_stmts = self.convert_vec_to_static(&mut builder, s_stmts); @@ -1025,7 +1071,7 @@ impl Visitor for StaticPromotion { } // Otherwise just promote the par threads that we can into a static par let s_stmts_possibly_promoted = - self.convert_vec_par_if_threshold(&mut builder, s_stmts); + self.convert_vec_par_if_sat(&mut builder, s_stmts); new_stmts.extend(s_stmts_possibly_promoted); new_stmts.extend(d_stmts); let new_par = ir::Control::Par(ir::Par { @@ -1050,16 +1096,18 @@ impl Visitor for StaticPromotion { let approx_size_if = Self::approx_size(&s.tbranch) + Self::approx_size(&s.fbranch) + APPROX_IF_SIZE; - if approx_size_if > self.threshold { + let latency = std::cmp::max( + Self::get_inferred_latency(&s.tbranch), + Self::get_inferred_latency(&s.fbranch), + ); + if approx_size_if > self.threshold + && self.within_cycle_limit(latency) + { // Meets size threshold so promote to static let static_tbranch = self.convert_to_static(&mut s.tbranch, &mut builder); let static_fbranch = self.convert_to_static(&mut s.fbranch, &mut builder); - let latency = std::cmp::max( - static_tbranch.get_latency(), - static_fbranch.get_latency(), - ); return Ok(Action::change(ir::Control::Static( ir::StaticControl::static_if( Rc::clone(&s.port), @@ -1090,9 +1138,6 @@ impl Visitor for StaticPromotion { sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if self.stop_loop { - return Ok(Action::Continue); - } let mut builder = ir::Builder::new(comp, sigs); // First check that while loop is bounded if let Some(num_repeats) = s.get_attributes().get(ir::NumAttr::Bound) { @@ -1100,11 +1145,13 @@ impl Visitor for StaticPromotion { if Self::can_be_promoted(&s.body) { let approx_size = Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; + let latency = Self::get_inferred_latency(&s.body) * num_repeats; // Then check that it reaches the threshold - if approx_size > self.threshold { + if approx_size > self.threshold + && self.within_cycle_limit(latency) + { // Turn repeat into static repeat let sc = self.convert_to_static(&mut s.body, &mut builder); - let latency = sc.get_latency() * num_repeats; let static_repeat = ir::StaticControl::repeat( num_repeats, latency, @@ -1134,18 +1181,16 @@ impl Visitor for StaticPromotion { sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if self.stop_loop { - return Ok(Action::Continue); - } let mut builder = ir::Builder::new(comp, sigs); if Self::can_be_promoted(&s.body) { // Body can be promoted let approx_size = Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; - if approx_size > self.threshold { + let latency = Self::get_inferred_latency(&s.body) * s.num_repeats; + if approx_size > self.threshold && self.within_cycle_limit(latency) + { // Meets size threshold, so turn repeat into static repeat let sc = self.convert_to_static(&mut s.body, &mut builder); - let latency = s.num_repeats * sc.get_latency(); let static_repeat = ir::StaticControl::repeat( s.num_repeats, latency, diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index c5f0d0db3..4021912c6 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -99,7 +99,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { B0.clk = clk; B0.addr0 = fsm.out == 4'd0 & early_reset_static_seq_go.out ? i0.out; B0.reset = reset; - B_read0_0.write_en = (fsm.out == 4'd0 & fsm.out < 4'd7 | fsm.out == 4'd5 & fsm.out < 4'd7) & early_reset_static_seq_go.out ? 1'd1; + B_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd5) & early_reset_static_seq_go.out ? 1'd1; B_read0_0.clk = clk; B_read0_0.reset = reset; B_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? B0.read_data; @@ -109,7 +109,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { early_reset_static_seq_done.in = ud0.out; tdcc_done.in = fsm0.out == 2'd3 ? 1'd1; while_wrapper_early_reset_static_seq_done.in = !comb_reg.out & fsm.out == 4'd0 ? 1'd1; - A_read0_0.write_en = (fsm.out == 4'd0 & fsm.out < 4'd7 | fsm.out == 4'd4 & fsm.out < 4'd7) & early_reset_static_seq_go.out ? 1'd1; + A_read0_0.write_en = (fsm.out == 4'd0 | fsm.out == 4'd4) & early_reset_static_seq_go.out ? 1'd1; A_read0_0.clk = clk; A_read0_0.reset = reset; A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; diff --git a/tests/passes/simplify-static-guards/basic.futil b/tests/passes/simplify-static-guards/basic.futil index 4c3dbeec6..4351d57eb 100644 --- a/tests/passes/simplify-static-guards/basic.futil +++ b/tests/passes/simplify-static-guards/basic.futil @@ -14,15 +14,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<10> group my_group { - a.write_en = (%[2:3] | lt.out) & %[1:5] ? 1'd1; // don't simplify - b.write_en = %[2:3] & (lt.out | gt.out) & %[1:5] ? 1'd1; // %[1:5] is redundant + a.write_en = (%[2:3] | lt.out) & %[1:5] ? 1'd1; // don't simplify + b.write_en = %[2:3] & (lt.out | gt.out) & %[1:5] ? 1'd1; // %[1:5] is redundant c.write_en = %[2:5] & (%[5:7] | lt.out) & %[3:7] & %[4:10] ? 1'd1; // %[5:7] shouldn't change, but can simplify rest to %[4:5] - d.write_en = %[2:5] & %[6:9] ? 1'd1; // assignment is false - e.write_en = %[0:10] & lt.out ? 1'd1; // no static timing necesary, since %[0:10] is same as group - a.in = 32'd1; - b.in = 32'd2; - c.in = 32'd3; - d.in = 32'd4; + d.write_en = %[2:5] & %[6:9] ? 1'd1; // assignment is false + e.write_en = %[0:10] & lt.out ? 1'd1; // no static timing necesary, since %[0:10] is same as group + a.in = 32'd1; + b.in = 32'd2; + c.in = 32'd3; + d.in = 32'd4; } } diff --git a/tests/passes/simplify-static-guards/simplify-or.expect b/tests/passes/simplify-static-guards/simplify-or.expect new file mode 100644 index 000000000..b126ad06c --- /dev/null +++ b/tests/passes/simplify-static-guards/simplify-or.expect @@ -0,0 +1,21 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(32); + b = std_reg(32); + c = std_reg(32); + d = std_reg(32); + e = std_reg(32); + lt = std_lt(32); + gt = std_lt(32); + } + wires { + static<10> group my_group { + a.write_en = %2 | %5 | lt.out & %7 ? 1'd1; + } + } + control { + my_group; + } +} diff --git a/tests/passes/simplify-static-guards/simplify-or.futil b/tests/passes/simplify-static-guards/simplify-or.futil new file mode 100644 index 000000000..a01944f16 --- /dev/null +++ b/tests/passes/simplify-static-guards/simplify-or.futil @@ -0,0 +1,24 @@ +// -p simplify-static-guards + +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(32); + b = std_reg(32); + c = std_reg(32); + d = std_reg(32); + e = std_reg(32); + lt = std_lt(32); + gt = std_lt(32); + } + wires { + static<10> group my_group { + a.write_en = (%[2:3] & %[2:9]) | (%[5:9] & %[5:6]) | (%[7:9] & %[7:8] & lt.out) ? 1'd1; // don't simplify + } + } + + control { + my_group; + } +} diff --git a/tests/passes/static-promotion/no_promote_loop.expect b/tests/passes/static-promotion/no_promote_loop.expect index 26a22869a..2aa38ac2b 100644 --- a/tests/passes/static-promotion/no_promote_loop.expect +++ b/tests/passes/static-promotion/no_promote_loop.expect @@ -6,6 +6,21 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c = std_reg(2); } wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group C<"promote_static"=1> { + c.in = 2'd2; + c.write_en = 1'd1; + C[done] = c.done; + } static<1> group A0 { a.in = 2'd0; a.write_en = 1'd1; @@ -20,8 +35,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - seq { - repeat 10 { + @promote_static(43) seq { + @promote_static(40) repeat 10 { @compactable static<4> seq { A0; B0; @@ -29,11 +44,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { C0; } } - @compactable static<3> seq { - A0; - B0; - C0; - } + @promote_static A; + @promote_static B; + @promote_static C; } } } diff --git a/tests/passes/static-promotion/no_promote_loop.futil b/tests/passes/static-promotion/no_promote_loop.futil index 36d9575ca..727917504 100644 --- a/tests/passes/static-promotion/no_promote_loop.futil +++ b/tests/passes/static-promotion/no_promote_loop.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:stop_loop +// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:cycle-limit=25 import "primitives/core.futil"; From 7d4f42c731b35c2495646f158d2d5cf02b389f20 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:06:42 -0500 Subject: [PATCH 108/189] Queues: more `if then else` (#1791) * FIFO without ifthenelse * More ITE, less seq in FIFO * PIFO futil unaltered * Fewer seqs * All but the big par * More ifthenelse in PIFO * PIFO tree with more ITE and less seqs * SDN with fewer seqs, more ITE * Static SDN with more ITE, fewer seqs * Unused groups * Revert FIFO and PIFO to get it to work * Some small changes that still work... * Another improvement * Another par bites the dust * Another one gone * Another one gone * Another seq bites the dust, yeah * Regerate all queue futils * Queues: more `par`s when possible (#1793) * Some seqs could have been pars * More opportunities in PIFO * Other files benefit without any change needed * Committing these was a bad idea * Regernate queue futils * Remove futil files --- calyx-py/calyx/queue_call.py | 56 +++--- calyx-py/test/correctness/fifo.py | 100 ++++++----- calyx-py/test/correctness/pifo.py | 271 +++++++++++++----------------- calyx-py/test/correctness/sdn.py | 58 +++---- 4 files changed, 217 insertions(+), 268 deletions(-) diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index e10d6539a..708980760 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -70,38 +70,34 @@ def insert_main(prog, queue): i_lt_max_cmds = main.lt_use(i.out, queue_util.MAX_CMDS) not_err = main.not_use(err.out) - main.control += [ - cb.while_with( - i_lt_max_cmds, # Run while i < MAX_CMDS - [ - read_cmd, - write_cmd_to_reg, # `cmd := commands[i]` - read_value, - write_value_to_reg, # `value := values[i]` - cb.invoke( # Invoke the queue. - queue, - in_cmd=cmd.out, - in_value=value.out, - ref_ans=ans, - ref_err=err, - ), + main.control += cb.while_with( + i_lt_max_cmds, # Run while i < MAX_CMDS + [ + read_cmd, + write_cmd_to_reg, # `cmd := commands[i]` + read_value, + write_value_to_reg, # `value := values[i]` + cb.invoke( # Invoke the queue. + queue, + in_cmd=cmd.out, + in_value=value.out, + ref_ans=ans, + ref_err=err, + ), + cb.if_with( + not_err, cb.if_with( - not_err, + cmd_le_1, # If the command was a pop or peek, [ - cb.if_with( - cmd_le_1, # If the command was a pop or peek, - [ - write_ans, # Write the answer to the answer list - incr_j, # And increment the answer index. - ], - ), + write_ans, # Write the answer to the answer list + incr_j, # And increment the answer index. ], ), - lower_err, # Lower the error flag - incr_i, # Increment the command index - ], - ), - ] + ), + lower_err, # Lower the error flag + incr_i, # Increment the command index + ], + ) return main @@ -206,8 +202,8 @@ def insert_runner(prog, queue, name, stats_component): [ cb.if_with( cmd_le_1, # If the command was a pop or peek - [raise_has_ans], # then raise the `has_ans` flag - [lower_has_ans], # else lower the `has_ans` flag + raise_has_ans, # then raise the `has_ans` flag + lower_has_ans, # else lower the `has_ans` flag ), ], ), diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/fifo.py index 5df6616ac..29c7d8726 100644 --- a/calyx-py/test/correctness/fifo.py +++ b/calyx-py/test/correctness/fifo.py @@ -64,63 +64,61 @@ def insert_fifo(prog, name): mem, ans, "read_payload_from_mem_phase2" ) - fifo.control += [ - cb.par( - # Was it a pop or a push? We can do both cases in parallel. + fifo.control += cb.par( + # Was it a pop or a push? We can do both cases in parallel. + cb.if_with( + # Did the user call pop? + cmd_eq_0, cb.if_with( - # Did the user call pop? - cmd_eq_0, - cb.if_with( - # Yes, the user called pop. But is the queue empty? - len_eq_0, - [raise_err, flash_ans], # The queue is empty: underflow. - [ # The queue is not empty. Proceed. - read_from_mem, # Read from the queue. - write_to_ans, # Write the answer to the answer register. - read_incr, # Increment the read pointer. - cb.if_with( - # Wrap around if necessary. - read_eq_max_queue_len, - flash_read, - ), - len_decr, # Decrement the length. - ], - ), + # Yes, the user called pop. But is the queue empty? + len_eq_0, + cb.par(raise_err, flash_ans), # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + read_from_mem, # Read from the queue. + write_to_ans, # Write the answer to the answer register. + read_incr, # Increment the read pointer. + cb.if_with( + # Wrap around if necessary. + read_eq_max_queue_len, + flash_read, + ), + len_decr, # Decrement the length. + ], ), - cb.if_with( - # Did the user call peek? - cmd_eq_1, - cb.if_with( # Yes, the user called peek. But is the queue empty? - len_eq_0, - [raise_err, flash_ans], # The queue is empty: underflow. - [ # The queue is not empty. Proceed. - read_from_mem, # Read from the queue. - write_to_ans, # Write the answer to the answer register. - # But don't increment the read pointer or change the length. - ], - ), + ), + cb.if_with( + # Did the user call peek? + cmd_eq_1, + cb.if_with( # Yes, the user called peek. But is the queue empty? + len_eq_0, + cb.par(raise_err, flash_ans), # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + read_from_mem, # Read from the queue. + write_to_ans, # Write the answer to the answer register. + # But don't increment the read pointer or change the length. + ], ), + ), + cb.if_with( + # Did the user call push? + cmd_eq_2, cb.if_with( - # Did the user call push? - cmd_eq_2, - cb.if_with( - # Yes, the user called push. But is the queue full? - len_eq_max_queue_len, - [raise_err, flash_ans], # The queue is full: overflow. - [ # The queue is not full. Proceed. - write_to_mem, # Write `value` to the queue. - write_incr, # Increment the write pointer. - cb.if_with( - # Wrap around if necessary. - write_eq_max_queue_len, - flash_write, - ), - len_incr, # Increment the length. - ], - ), + # Yes, the user called push. But is the queue full? + len_eq_max_queue_len, + cb.par(raise_err, flash_ans), # The queue is empty: underflow. + [ # The queue is not full. Proceed. + write_to_mem, # Write `value` to the queue. + write_incr, # Increment the write pointer. + cb.if_with( + # Wrap around if necessary. + write_eq_max_queue_len, + flash_write, + ), + len_incr, # Increment the length. + ], ), ), - ] + ) return fifo diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/pifo.py index ae868d1ac..aabcae0b9 100644 --- a/calyx-py/test/correctness/pifo.py +++ b/calyx-py/test/correctness/pifo.py @@ -117,9 +117,6 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None, static=False # Some equality checks. hot_eq_0 = pifo.eq_use(hot.out, 0) - hot_eq_1 = pifo.eq_use(hot.out, 1) - flow_eq_0 = pifo.eq_use(flow.out, 0) - flow_eq_1 = pifo.eq_use(flow.out, 1) len_eq_0 = pifo.eq_use(len.out, 0) len_eq_max_queue_len = pifo.eq_use(len.out, MAX_QUEUE_LEN) cmd_eq_0 = pifo.eq_use(cmd, 0) @@ -137,182 +134,144 @@ def insert_pifo(prog, name, queue_l, queue_r, boundary, stats=None, static=False len_decr = pifo.decr(len) # len-- # The main logic. - pifo.control += [ - cb.par( - # Was it a pop, peek, or a push? We can do all cases in parallel. + pifo.control += cb.par( + # Was it a pop, peek, or a push? We can do all cases in parallel. + cb.if_with( + # Did the user call pop? + cmd_eq_0, cb.if_with( - # Did the user call pop? - cmd_eq_0, - cb.if_with( - # Yes, the user called pop. But is the queue empty? - len_eq_0, - [raise_err, flash_ans], # The queue is empty: underflow. - [ # The queue is not empty. Proceed. - # We must check if `hot` is 0 or 1. - lower_err, - cb.par( # We'll check both cases in parallel. + # Yes, the user called pop. But is the queue empty? + len_eq_0, + cb.par(raise_err, flash_ans), # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + # We must check if `hot` is 0 or 1. + lower_err, + cb.if_with( + # Check if `hot` is 0. + hot_eq_0, + [ # `hot` is 0. We'll invoke `pop` on `queue_l`. + invoke_subqueue(queue_l, cmd, value, ans, err), + # Our next step depends on whether `queue_l` + # raised the error flag. + # We can check these cases in parallel. cb.if_with( - # Check if `hot` is 0. - hot_eq_0, - [ # `hot` is 0. We'll invoke `pop` on `queue_l`. - invoke_subqueue(queue_l, cmd, value, ans, err), - # Our next step depends on whether `queue_l` - # raised the error flag. - # We can check these cases in parallel. - cb.par( - cb.if_with( - err_neq_0, - [ # `queue_l` raised an error. - # We'll try to pop from `queue_r`. - # We'll pass it a lowered err - lower_err, - invoke_subqueue( - queue_r, cmd, value, ans, err - ), - ], - ), - cb.if_with( - err_eq_0, - [ # `queue_l` succeeded. - # Its answer is our answer. - flip_hot - # We'll just make `hot` point - # to the other sub-queue. - ], - ), - ), + err_neq_0, + [ # `queue_l` raised an error. + # We'll try to pop from `queue_r`. + # We'll pass it a lowered err + lower_err, + invoke_subqueue(queue_r, cmd, value, ans, err), ], + # `queue_l` succeeded. + # Its answer is our answer. + flip_hot + # We'll just make `hot` point + # to the other sub-queue. ), - # If `hot` is 1, we proceed symmetrically. + ], + [ # Else: `hot` is 1. Proceed symmetrically. + invoke_subqueue(queue_r, cmd, value, ans, err), cb.if_with( - hot_eq_1, + err_neq_0, [ - invoke_subqueue(queue_r, cmd, value, ans, err), - cb.par( - cb.if_with( - err_neq_0, - [ - lower_err, - invoke_subqueue( - queue_l, cmd, value, ans, err - ), - ], - ), - cb.if_with( - err_eq_0, - [flip_hot], - ), - ), + lower_err, + invoke_subqueue(queue_l, cmd, value, ans, err), ], + flip_hot, ), - ), - len_decr, # Decrement the length. - # It is possible that an irrecoverable error was raised above, - # in which case the length should _not_ in fact be decremented. - # However, in that case the PIFO's `err` flag would also - # have been raised, and no one will check this length anyway. - ], - ), + ], + ), + len_decr, # Decrement the length. + # It is possible that an irrecoverable error was raised above, + # in which case the length should _not_ in fact be decremented. + # However, in that case the PIFO's `err` flag would also + # have been raised, and no one will check this length anyway. + ], ), + ), + cb.if_with( + # Did the user call peek? + cmd_eq_1, cb.if_with( - # Did the user call peek? - cmd_eq_1, - cb.if_with( - # Yes, the user called peek. But is the queue empty? - len_eq_0, - [raise_err, flash_ans], # The queue is empty: underflow. - [ # The queue is not empty. Proceed. - # We must check if `hot` is 0 or 1. - lower_err, - cb.par( # We'll check both cases in parallel. + # Yes, the user called peek. But is the queue empty? + len_eq_0, + cb.par(raise_err, flash_ans), # The queue is empty: underflow. + [ # The queue is not empty. Proceed. + # We must check if `hot` is 0 or 1. + lower_err, + cb.if_with( + # Check if `hot` is 0. + hot_eq_0, + [ # `hot` is 0. We'll invoke `peek` on `queue_l`. + invoke_subqueue(queue_l, cmd, value, ans, err), + # Our next step depends on whether `queue_l` + # raised the error flag. cb.if_with( - # Check if `hot` is 0. - hot_eq_0, - [ # `hot` is 0. We'll invoke `peek` on `queue_l`. - invoke_subqueue(queue_l, cmd, value, ans, err), - # Our next step depends on whether `queue_l` - # raised the error flag. - cb.if_with( - err_neq_0, - [ # `queue_l` raised an error. - # We'll try to peek from `queue_r`. - # We'll pass it a lowered `err`. - lower_err, - invoke_subqueue( - queue_r, cmd, value, ans, err - ), - ], - ), - # Peeking does not affect `hot`. - # Peeking does not affect the length. + err_neq_0, + [ # `queue_l` raised an error. + # We'll try to peek from `queue_r`. + # We'll pass it a lowered `err`. + lower_err, + invoke_subqueue(queue_r, cmd, value, ans, err), ], ), - # If `hot` is 1, we proceed symmetrically. + # Peeking does not affect `hot`. + # Peeking does not affect the length. + ], + [ + invoke_subqueue(queue_r, cmd, value, ans, err), cb.if_with( - hot_eq_1, + err_neq_0, [ - invoke_subqueue(queue_r, cmd, value, ans, err), - cb.if_with( - err_neq_0, - [ - lower_err, - invoke_subqueue( - queue_l, cmd, value, ans, err - ), - ], - ), + lower_err, + invoke_subqueue(queue_l, cmd, value, ans, err), ], ), - ), - ], - ), + ], + ), + ], ), + ), + cb.if_with( + # Did the user call push? + cmd_eq_2, cb.if_with( - # Did the user call push? - cmd_eq_2, - cb.if_with( - # Yes, the user called push. But is the queue full? - len_eq_max_queue_len, - [raise_err, flash_ans], # The queue is full: overflow. - [ # The queue is not full. Proceed. - lower_err, - # We need to check which flow this value should be pushed to. - infer_flow, # Infer the flow and write it to `fifo_{flow}`. - cb.par( - cb.if_with( - flow_eq_0, - # This value should be pushed to queue_l. - invoke_subqueue(queue_l, cmd, value, ans, err), - ), - cb.if_with( - flow_eq_1, - # This value should be pushed to queue_r. - invoke_subqueue(queue_r, cmd, value, ans, err), + # Yes, the user called push. But is the queue full? + len_eq_max_queue_len, + cb.par(raise_err, flash_ans), # The queue is full: overflow. + [ # The queue is not full. Proceed. + lower_err, + # We need to check which flow this value should be pushed to. + infer_flow, # Infer the flow and write it to `flow`. + cb.if_( + flow.out, + # If flow = 1, value should be pushed to queue_r. + invoke_subqueue(queue_r, cmd, value, ans, err), + # If flow = 0, value should be pushed to queue_l. + invoke_subqueue(queue_l, cmd, value, ans, err), + ), + cb.if_with( + err_eq_0, + # If no stats component is provided, + # just increment the length. + len_incr + if not stats + else cb.par( + # If a stats component is provided, + # Increment the length and also + # tell the stats component what flow we pushed. + len_incr, + ( + cb.static_invoke(stats, in_flow=flow.out) + if static + else cb.invoke(stats, in_flow=flow.out) ), ), - cb.if_with( - err_eq_0, - # If no stats component is provided, - # just increment the length. - [len_incr] - if not stats - else [ - # If a stats component is provided, - # Increment the length and also - # tell the stats component what flow we pushed. - len_incr, - ( - cb.static_invoke(stats, in_flow=flow.out) - if static - else cb.invoke(stats, in_flow=flow.out) - ), - ], - ), - ], - ), + ), + ], ), ), - ] + ) return pifo diff --git a/calyx-py/test/correctness/sdn.py b/calyx-py/test/correctness/sdn.py index f87f95079..89aecd721 100644 --- a/calyx-py/test/correctness/sdn.py +++ b/calyx-py/test/correctness/sdn.py @@ -87,10 +87,8 @@ def insert_controller(prog, name, stats_component): get_data_locally.done = (count_0.done & count_1.done) @ 1 # The main logic. - controller.control += [ - get_data_locally, - # Great, now I have the data around locally. - ] + controller.control += get_data_locally + # Great, now I have the data around locally. return controller @@ -124,36 +122,34 @@ def insert_main(prog, dataplane, controller, stats_component): not_err = main.not_use(dataplane_err.out) - main.control += [ + main.control += cb.while_with( # We will run the dataplane and controller components in parallel, # in a while loop. The loop will terminate when the dataplane component # raises `dataplane_err`. - cb.while_with( - not_err, # While the dataplane component has not errored out. - [ - lower_has_ans, # Lower the has-ans flag. - cb.invoke( # Invoke the dataplane component. - dataplane, - ref_commands=commands, - ref_values=values, - ref_has_ans=has_ans, - ref_component_ans=dataplane_ans, - ref_component_err=dataplane_err, - ref_stats_runner=stats, - ), - # If the dataplane component has a nonzero answer, - # write it to the answer-list and increment the index `j`. - cb.if_( - has_ans.out, - cb.if_with(ans_neq_0, [write_ans, incr_j]), - ), - cb.invoke( # Invoke the controller component. - controller, - ref_stats_controller=stats, - ), - ], - ) - ] + not_err, # While the dataplane component has not errored out. + [ + lower_has_ans, # Lower the has-ans flag. + cb.invoke( # Invoke the dataplane component. + dataplane, + ref_commands=commands, + ref_values=values, + ref_has_ans=has_ans, + ref_component_ans=dataplane_ans, + ref_component_err=dataplane_err, + ref_stats_runner=stats, + ), + # If the dataplane component has a nonzero answer, + # write it to the answer-list and increment the index `j`. + cb.if_( + has_ans.out, + cb.if_with(ans_neq_0, [write_ans, incr_j]), + ), + cb.invoke( # Invoke the controller component. + controller, + ref_stats_controller=stats, + ), + ], + ) def build(static=False): From c5ff18b2dbcd580bae7deeeee48cf526e68c8aa5 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Mon, 4 Dec 2023 14:14:02 -0500 Subject: [PATCH 109/189] Add back the vscode settings (#1799) * add back the settings json and the rust config * leave a note --- .gitignore | 1 - .vscode/settings.json | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 750d98b8d..8a97d3c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,5 @@ __pycache__ tests/xilinx/cocotb/**/hdl -.vscode/settings.json !cider-dap/calyxDebug/package.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..f86c86fa6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + // Please only make changes to this file if they are useful/necessary for + // the whole project. For all other things use your own local settings. + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true, + }, +} From 6b0742ad5d0cb97d4d3c71b5585d29cd2fc8d6a3 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 4 Dec 2023 17:15:02 -0500 Subject: [PATCH 110/189] Fix pretty-printing for static invokes (#1795) (#1800) * Pretty printer: fix a closing parentheses Fixes #1795, which identified a problem with the closing parentheses in `static invoke` invocations. * Pretty printer: fix a stray semicolon A bonus fix, not directly discovered in #1795 but still obviously a problem. * Save expect files affected by #1795 --- calyx-ir/src/printer.rs | 6 +++--- tests/passes/static-promotion/invoke.expect | 3 +-- tests/passes/static-promotion/multi-static.expect | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/calyx-ir/src/printer.rs b/calyx-ir/src/printer.rs index 88c488f7b..7133eebf7 100644 --- a/calyx-ir/src/printer.rs +++ b/calyx-ir/src/printer.rs @@ -553,12 +553,12 @@ impl Printer { } if outputs.is_empty() { write!(f, ")")?; - } - if let Some(group) = comb_group { - writeln!(f, " with {};", group.borrow().name)?; } else { write!(f, "\n{})", " ".repeat(indent_level))?; } + if let Some(group) = comb_group { + write!(f, " with {}", group.borrow().name)?; + } writeln!(f, ";") } } diff --git a/tests/passes/static-promotion/invoke.expect b/tests/passes/static-promotion/invoke.expect index ccbd7e55a..e437c4e43 100644 --- a/tests/passes/static-promotion/invoke.expect +++ b/tests/passes/static-promotion/invoke.expect @@ -16,8 +16,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { static<2> invoke exp0( base = r.out, exp = r.out - )() - ); + )(); } } } diff --git a/tests/passes/static-promotion/multi-static.expect b/tests/passes/static-promotion/multi-static.expect index ee0ef2e7d..af49b1d0c 100644 --- a/tests/passes/static-promotion/multi-static.expect +++ b/tests/passes/static-promotion/multi-static.expect @@ -16,8 +16,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { static<2> invoke exp0( base = r.out, exp = r.out - )() - ); + )(); } } } From 91df50dcb8c1c404525495f078cc7542c2df477b Mon Sep 17 00:00:00 2001 From: Elias Castro <127804425+eliascxstro@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:18:02 -0500 Subject: [PATCH 111/189] Cider changes (#1798) * Added Disconnect Command * Added create threads and started two dummy threads, added pause command * Implemented StackTrace, Continue, Next, StepIn and StepOut * Corrected Disconnect, minor changes * PR revisions --------- Co-authored-by: root --- cider-dap/src/adapter.rs | 12 ++++ cider-dap/src/error.rs | 9 ++- cider-dap/src/main.rs | 124 +++++++++++++++++++++++++++++++++++---- 3 files changed, 133 insertions(+), 12 deletions(-) diff --git a/cider-dap/src/adapter.rs b/cider-dap/src/adapter.rs index 9b0837c35..a7af6d5e7 100644 --- a/cider-dap/src/adapter.rs +++ b/cider-dap/src/adapter.rs @@ -5,6 +5,7 @@ pub struct MyAdapter { file: File, breakpoints: Vec<(Source, i64)>, //This field is a placeholder break_count: Counter, + thread_count: Counter, threads: Vec, //This field is a placeholder } @@ -14,6 +15,7 @@ impl MyAdapter { file, breakpoints: Vec::new(), break_count: Counter::new(), + thread_count: Counter::new(), threads: Vec::new(), } } @@ -43,6 +45,16 @@ impl MyAdapter { out_vec } + ///Creates a thread using the parameter name. + pub fn create_thread(&mut self, name: String) -> Thread { + let thread = Thread { + id: self.thread_count.increment(), + name, + }; + self.threads.push(thread.clone()); + thread + } + /// Clone threads pub fn clone_threads(&self) -> Vec { self.threads.clone() diff --git a/cider-dap/src/error.rs b/cider-dap/src/error.rs index 81c2b41c0..2aff9b76e 100644 --- a/cider-dap/src/error.rs +++ b/cider-dap/src/error.rs @@ -2,7 +2,7 @@ use dap::errors::ServerError; use dap::requests::Command; #[allow(dead_code)] // remove this later -#[derive(thiserror::Error, Debug)] +#[derive(thiserror::Error)] pub enum MyAdapterError { /// Represents an unhandled command error. #[error("Unhandled command: {0:?}")] @@ -37,5 +37,12 @@ pub enum MyAdapterError { ServerError(#[from] ServerError), } +// Needed to properly display messages in output +impl std::fmt::Debug for MyAdapterError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self, f) + } +} + /// A type alias for the result returned by the adapter functions. pub type AdapterResult = Result; diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index 1681ec3c3..fc001530e 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -2,8 +2,10 @@ mod adapter; mod error; use adapter::MyAdapter; +use dap::events::{ExitedEventBody, StoppedEventBody, ThreadEventBody}; use dap::responses::{ - SetBreakpointsResponse, SetExceptionBreakpointsResponse, ThreadsResponse, + ContinueResponse, SetBreakpointsResponse, SetExceptionBreakpointsResponse, + StackTraceResponse, ThreadsResponse, }; use error::MyAdapterError; @@ -119,7 +121,23 @@ where let file = File::open(program_path)?; // Construct the adapter - let adapter = MyAdapter::new(file); + let mut adapter = MyAdapter::new(file); + + //Make two threads to make threads visible on call stack, subject to change. + let thread = &adapter.create_thread(String::from("Main")); + let thread2 = &adapter.create_thread(String::from("Thread 1")); + + // Notify server of first thread + server.send_event(Event::Thread(ThreadEventBody { + reason: types::ThreadEventReason::Started, + thread_id: thread.id, + }))?; + + //Notify server of second thread + server.send_event(Event::Thread(ThreadEventBody { + reason: types::ThreadEventReason::Started, + thread_id: thread2.id, + }))?; // Return the adapter instead of running the server Ok(adapter) @@ -142,12 +160,12 @@ fn run_server( } Command::SetBreakpoints(args) => { - //Add breakpoints + // Add breakpoints if let Some(breakpoint) = &args.breakpoints { let out = adapter.set_breakpoint(args.source.clone(), breakpoint); - //Success + // Success let rsp = req.success(ResponseBody::SetBreakpoints( SetBreakpointsResponse { breakpoints: (out) }, )); @@ -155,7 +173,7 @@ fn run_server( } } - //TODO: Implement this request fully when adapter becomes functional + // TODO: Implement this request fully when adapter becomes functional Command::SetExceptionBreakpoints(_) => { let rsp = req.success(ResponseBody::SetExceptionBreakpoints( SetExceptionBreakpointsResponse { @@ -164,18 +182,89 @@ fn run_server( )); server.respond(rsp)?; } - - //Retrieve a list of all threads + // Retrieve a list of all threads Command::Threads => { let rsp = req.success(ResponseBody::Threads(ThreadsResponse { threads: adapter.clone_threads(), })); server.respond(rsp)?; } - // Here, can add a match pattern for a disconnect or exit command - // to break out of the loop and close the server. - // Command::Disconnect(_) => break, - // ... + // Disconnect the server AND exit the debugger + Command::Disconnect(_) => { + let rsp = req.success(ResponseBody::Disconnect); + server.send_event(Event::Exited(ExitedEventBody { + exit_code: 0, + }))?; + server.respond(rsp)?; + + //Exit + eprintln!("exited debugger"); + return Ok(()); + } + // Send StackTrace, may be useful to make it more robust in the future + Command::StackTrace(_args) => { + let rsp = + req.success(ResponseBody::StackTrace(StackTraceResponse { + stack_frames: vec![], + total_frames: None, + })); + server.respond(rsp)?; + } + // Continue the debugger + Command::Continue(_args) => { + let rsp = + req.success(ResponseBody::Continue(ContinueResponse { + all_threads_continued: None, + })); + server.respond(rsp)?; + } + // Send a Stopped event with reason Pause + Command::Pause(args) => { + // Get ID before rsp takes ownership + let thread_id = args.thread_id; + let rsp = req.success(ResponseBody::Pause); + // Send response first + server.respond(rsp)?; + // Send event + let stopped = create_stopped(String::from("Paused"), thread_id); + server.send_event(stopped)?; + } + // Step over + Command::Next(args) => { + // Get ID before rsp takes ownership + let thread_id = args.thread_id; + let rsp = req.success(ResponseBody::Next); + // Send response first + server.respond(rsp)?; + // Send event + let stopped = + create_stopped(String::from("Continue"), thread_id); + server.send_event(stopped)?; + } + // Step in + Command::StepIn(args) => { + // Get ID before rsp takes ownership + let thread_id = args.thread_id; + // Send response first + let rsp = req.success(ResponseBody::StepIn); + server.respond(rsp)?; + // Send event + let stopped = + create_stopped(String::from("Paused on step"), thread_id); + server.send_event(stopped)?; + } + // Step out + Command::StepOut(args) => { + // Get ID before rsp takes ownership + let thread_id = args.thread_id; + // Send response first + let rsp = req.success(ResponseBody::StepOut); + server.respond(rsp)?; + // Send event + let stopped = + create_stopped(String::from("Paused on step"), thread_id); + server.send_event(stopped)?; + } unknown_command => { return Err(MyAdapterError::UnhandledCommandError( unknown_command.clone(), @@ -184,3 +273,16 @@ fn run_server( } } } + +/// Helper function used to create a Stopped event +fn create_stopped(reason: String, thread_id: i64) -> Event { + Event::Stopped(StoppedEventBody { + reason: types::StoppedEventReason::Step, + description: Some(reason), + thread_id: Some(thread_id), + preserve_focus_hint: None, + text: None, + all_threads_stopped: None, + hit_breakpoint_ids: None, + }) +} From 0f2a28c19c1fe97e66d4982aa38fd5872c8aa72e Mon Sep 17 00:00:00 2001 From: kadenlei <95266101+kadenlei@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:24:23 -0500 Subject: [PATCH 112/189] Implemented Single session (#1797) * Still working * Implemented single-session and configurations for session type * Finalizaing single-session * Resolved comments * Got rid of dead code --- .vscode/launch.json | 191 +++++++++++++----------------- cider-dap/README.md | 4 +- cider-dap/calyxDebug/extension.ts | 47 ++++++-- cider-dap/calyxDebug/package.json | 12 ++ cider-dap/src/main.rs | 12 +- 5 files changed, 135 insertions(+), 131 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4b303a6e4..f7eb3af4e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,108 +1,85 @@ { - "version": "0.2.0", - "configurations": [ - { - "type": "cider-dap", - "request": "launch", - "name": "Launch Program (Multi Session)", - "program": "${file}", - "stopOnEntry": true, - }, - { - "type": "cider-dap", - "request": "launch", - "name": "Launch Program", - "program": "${workspaceFolder}/Program" - }, - { - "name": "Python: Current File", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal", - "justMyCode": false - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug Compiler", - "args": [ - "${input:target}", - "-l", - "${workspaceFolder}", - "-p", - "${input:pass}", - "-b", - "${input:backend}", - ], - "program": "${workspaceFolder}/target/debug/calyx", - "cwd": "${workspaceFolder}", - "stopOnEntry": false, - "sourceLanguages": [ - "rust" - ], - "preLaunchTask": "Cargo Build", - "console": "integratedTerminal", - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug Interpreter", - "args": [ - "${input:target}", - "-l", - "${workspaceFolder}" - ], - "program": "${workspaceFolder}/target/debug/cider", - "windows": { - "program": "${workspaceFolder}/target/debug/cider.exe" - }, - "cwd": "${workspaceFolder}", - "stopOnEntry": false, - "sourceLanguages": [ - "rust" - ], - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug Interpreter on current file", - "args": [ - "${file}", - "-l", - "${workspaceFolder}" - ], - "program": "${workspaceFolder}/target/debug/cider", - "windows": { - "program": "${workspaceFolder}/target/debug/cider.exe" - }, - "cwd": "${workspaceFolder}", - "stopOnEntry": false, - "sourceLanguages": [ - "rust" - ], - } - ], - "inputs": [ - { - "id": "target", - "type": "promptString", - "description": "Target file" - }, - { - "id": "pass", - "type": "promptString", - "description": "Pass to be executed by the compiler (only one allowed)", - "default": "all" - }, - { - "id": "backend", - "type": "pickString", - "description": "Backend to be used by the compiler", - "options": [ - "verilog", - "calyx", - ], - } - ] -} \ No newline at end of file + "version": "0.2.0", + "configurations": [ + { + "type": "cider-dap", + "request": "launch", + "name": "Debug w/ Cider", + "program": "${file}", + "stopOnEntry": true + }, + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "justMyCode": false + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug Compiler", + "args": [ + "${input:target}", + "-l", + "${workspaceFolder}", + "-p", + "${input:pass}", + "-b", + "${input:backend}" + ], + "program": "${workspaceFolder}/target/debug/calyx", + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "sourceLanguages": ["rust"], + "preLaunchTask": "Cargo Build", + "console": "integratedTerminal" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug Interpreter", + "args": ["${input:target}", "-l", "${workspaceFolder}"], + "program": "${workspaceFolder}/target/debug/cider", + "windows": { + "program": "${workspaceFolder}/target/debug/cider.exe" + }, + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "sourceLanguages": ["rust"] + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug Interpreter on current file", + "args": ["${file}", "-l", "${workspaceFolder}"], + "program": "${workspaceFolder}/target/debug/cider", + "windows": { + "program": "${workspaceFolder}/target/debug/cider.exe" + }, + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "sourceLanguages": ["rust"] + } + ], + "inputs": [ + { + "id": "target", + "type": "promptString", + "description": "Target file" + }, + { + "id": "pass", + "type": "promptString", + "description": "Pass to be executed by the compiler (only one allowed)", + "default": "all" + }, + { + "id": "backend", + "type": "pickString", + "description": "Backend to be used by the compiler", + "options": ["verilog", "calyx"] + } + ] +} diff --git a/cider-dap/README.md b/cider-dap/README.md index 44b371a7a..5511e9574 100644 --- a/cider-dap/README.md +++ b/cider-dap/README.md @@ -19,7 +19,7 @@ the cider-dap binary somewhere on your path. From some directory on your PATH: ln -s /target/debug/cider-dap ``` -You will have to configure user settings of cider-dap in VSCode and input your cider binary path and port number. You can then launch the adapter with the Launch Program (Multi Session) action +You will have to configure user settings of cider-dap in VSCode and input your cider binary path, session type, and port number (if debug adapter is started as a server). You can then launch the adapter with the Launch Program (Multi Session) action. ## Known issues @@ -40,7 +40,7 @@ This project primarily leverages the Debug Adapter Protocol (DAP) for its functi         `adapter.rs`: Defines the primary adapter structure for the project and its associated functionalities. Not just any adapter, this file structures the fundamental protocols, handling the translation of high-level debugging commands into actionable, low-level instructions.
        `error.rs`: Contains custom error definitions and types for better error handling.
        `main.rs`: The entry point for the project, it integrates functionalities from the other source files and provides the main execution logic.
4. `calyxDebug` directory:
-        `extension.js`: JavaScript file for VSCode extension integration. It provides functions to interface between the VSCode environment and the Rust backend.
+        `extension.ts`: TypeScript file for VSCode extension integration. It provides functions to interface between the VSCode environment and the Rust backend.
### About main.rs: the Main File diff --git a/cider-dap/calyxDebug/extension.ts b/cider-dap/calyxDebug/extension.ts index 10fb8144e..94ba4e60f 100644 --- a/cider-dap/calyxDebug/extension.ts +++ b/cider-dap/calyxDebug/extension.ts @@ -35,7 +35,8 @@ async function getProgramName() { } } -class CiderDebugAdapterDescriptorFactory { +// Factory for multi-session +class CiderDebugAdapterDescriptorFactoryServer { adapter: CiderDebugAdapter; adapterPath: string; workspace: string; @@ -97,7 +98,7 @@ class CiderDebugAdapter { // Include the port as a command line argument this.adapterProcess = cp.spawn( this.adapterPath, - [programName, "--port", port, "--tcp"], + ["--port", port, "--tcp"], { cwd: this.cwd } ); @@ -128,15 +129,42 @@ class CiderDebugAdapter { } } +// Factory for single-session +class CiderDebugAdapterDescriptorFactoryExecutable { + createDebugAdapterDescriptor(_session) { + // Use the DebugAdapterExecutable as the debug adapter descriptor + console.log("inside adapter factory"); + console.log(vscode.workspace.getConfiguration("cider-dap").path); + + return new vscode.DebugAdapterExecutable( + vscode.workspace.getConfiguration("cider-dap").path, + [programName], + { cwd: vscode.workspace.rootPath } + ); + } +} + function activate(context) { logToPanel("Extension activated!"); - // Start the debug server explicitly - const factory = new CiderDebugAdapterDescriptorFactory( - vscode.workspace.getConfiguration("cider-dap").path, - vscode.workspace.rootPath, - outputChannel - ); + let factory: vscode.DebugAdapterDescriptorFactory; + + // Get session type (multi or single) from package.json configuration + switch (vscode.workspace.getConfiguration("cider-dap").sessionType) { + case "Multi-Session": + factory = new CiderDebugAdapterDescriptorFactoryServer( + vscode.workspace.getConfiguration("cider-dap").path, + vscode.workspace.rootPath, + outputChannel + ); + break; + + case "Single-Session": + default: + factory = new CiderDebugAdapterDescriptorFactoryExecutable(); + break; + } + context.subscriptions.push( vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory) ); @@ -144,9 +172,6 @@ function activate(context) { // Update the adapter path with the serverPort and use it for starting the debug adapter logToPanel("before startDebugging"); - /* context.subscriptions.push(vscode.commands.registerCommand('cider.startDebugging', startDebugging)); - context.subscriptions.push(vscode.commands.registerCommand('cider.stopDebugging', stopDebugging)); - */ logToPanel("Hello, your extension is now activated!"); } diff --git a/cider-dap/calyxDebug/package.json b/cider-dap/calyxDebug/package.json index dbc2c936e..b6bf43bd0 100644 --- a/cider-dap/calyxDebug/package.json +++ b/cider-dap/calyxDebug/package.json @@ -43,6 +43,18 @@ "scope": "machine", "default": 8888, "description": "Port number" + }, + "cider-dap.sessionType": { + "type": "string", + "default": "Single-Session", + "enum": [ + "Single-Session", + "Multi-Session" + ], + "enumDescriptions": [ + "Runs the debugger in single-session", + "Runs the debugger in multi-session" + ] } } } diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index fc001530e..2d4b24a23 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -14,14 +14,10 @@ use error::AdapterResult; use std::fs::File; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::net::TcpListener; -use std::path::PathBuf; #[derive(argh::FromArgs)] /// Positional arguments for file path struct Opts { - /// input file - #[argh(positional, from_str_fn(read_path))] - file: Option, #[argh(switch, long = "tcp")] /// runs in tcp mode is_multi_session: bool, @@ -29,13 +25,9 @@ struct Opts { /// port for the TCP server port: u16, } -fn read_path(path: &str) -> Result { - Ok(PathBuf::from(path)) -} fn main() -> Result<(), MyAdapterError> { let opts: Opts = argh::from_env(); - if opts.is_multi_session { eprintln!("running multi-session"); let listener = TcpListener::bind(("127.0.0.1", opts.port))?; @@ -52,13 +44,11 @@ fn main() -> Result<(), MyAdapterError> { // Run the server using the adapter run_server(&mut server, adapter)?; } else { - let path = opts.file.ok_or(MyAdapterError::MissingFile)?; - let file = File::open(path)?; - let adapter = MyAdapter::new(file); eprintln!("running single-session"); let write = BufWriter::new(stdout()); let read = BufReader::new(stdin()); let mut server = Server::new(read, write); + let adapter = multi_session_init(&mut server)?; run_server(&mut server, adapter)?; } eprintln!("exited run_Server"); From e13745908af5191c2ad986163efe79180b01a217 Mon Sep 17 00:00:00 2001 From: kadenlei <95266101+kadenlei@users.noreply.github.com> Date: Mon, 11 Dec 2023 13:56:07 -0500 Subject: [PATCH 113/189] Cider debugger logging (#1802) * Got logging to work * Still working * Got logging but found weird bug * Fixed bug -- working on finishing logging * Finished logging (except those outside of main) * Added tmp path for logger, passed logger in as args for other fns * Resolved comments (moved code and imported `slog::info`) --- Cargo.lock | 3 ++ cider-dap/Cargo.toml | 3 ++ cider-dap/README.md | 3 +- cider-dap/calyxDebug/extension.ts | 2 +- cider-dap/src/main.rs | 50 ++++++++++++++++++++++++------- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c535cebc..17bf05397 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,6 +343,9 @@ dependencies = [ "owo-colors", "serde", "serde_json", + "slog", + "slog-async", + "slog-term", "thiserror", ] diff --git a/cider-dap/Cargo.toml b/cider-dap/Cargo.toml index 0510e6924..296285448 100644 --- a/cider-dap/Cargo.toml +++ b/cider-dap/Cargo.toml @@ -12,6 +12,9 @@ serde_json = "1.0" serde.workspace= true owo-colors = "^3.5" argh = "0.1" +slog = "2.7.0" +slog-term = "2.8.0" +slog-async = "2.7.0" [[bin]] name = "cider-dap" diff --git a/cider-dap/README.md b/cider-dap/README.md index 5511e9574..187e9b5d0 100644 --- a/cider-dap/README.md +++ b/cider-dap/README.md @@ -19,7 +19,7 @@ the cider-dap binary somewhere on your path. From some directory on your PATH: ln -s /target/debug/cider-dap ``` -You will have to configure user settings of cider-dap in VSCode and input your cider binary path, session type, and port number (if debug adapter is started as a server). You can then launch the adapter with the Launch Program (Multi Session) action. +You will have to configure user settings of cider-dap in VSCode and input your cider binary path, session type, and port number (if debug adapter is started as a server). You can then launch the adapter with the Debug w/ Cider action. ## Known issues @@ -50,6 +50,7 @@ In `main.rs`, our program is set up to accommodate both single and multi-session At the start of the `main()` function: +- Initializes a logger to log to the terminal if in multi-session and a file in single-session. - The Opts struct captures command-line arguments. This struct contains an optional file path, a switch to determine if the application runs in multi-session mode, and a port number (with a default of 8080). - `argh::from_env()` processes the command-line arguments based on the defined struct. The use of argh simplifies command-line parsing, allowing you to focus on the main logic without getting bogged down in argument processing. diff --git a/cider-dap/calyxDebug/extension.ts b/cider-dap/calyxDebug/extension.ts index 94ba4e60f..62ffbf2a7 100644 --- a/cider-dap/calyxDebug/extension.ts +++ b/cider-dap/calyxDebug/extension.ts @@ -138,7 +138,7 @@ class CiderDebugAdapterDescriptorFactoryExecutable { return new vscode.DebugAdapterExecutable( vscode.workspace.getConfiguration("cider-dap").path, - [programName], + [], { cwd: vscode.workspace.rootPath } ); } diff --git a/cider-dap/src/main.rs b/cider-dap/src/main.rs index 2d4b24a23..7796bef79 100644 --- a/cider-dap/src/main.rs +++ b/cider-dap/src/main.rs @@ -11,7 +11,9 @@ use error::MyAdapterError; use dap::prelude::*; use error::AdapterResult; +use slog::{info, Drain}; use std::fs::File; +use std::fs::OpenOptions; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::net::TcpListener; @@ -28,35 +30,60 @@ struct Opts { fn main() -> Result<(), MyAdapterError> { let opts: Opts = argh::from_env(); + // Initializing logger + let log_path = "/tmp/output.log"; // Stores in tmp file for now, if testing, use a relative path + let file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(log_path) + .unwrap(); + + // Different decorators and drains for terminal and file logging -- async_drain picks the right one based on session + let async_drain = if opts.is_multi_session { + let term_decorator = slog_term::TermDecorator::new().build(); + let term_drain = + slog_term::FullFormat::new(term_decorator).build().fuse(); + slog_async::Async::new(term_drain).build().fuse() + } else { + let file_decorator = slog_term::PlainDecorator::new(file); + let file_drain = + slog_term::FullFormat::new(file_decorator).build().fuse(); + slog_async::Async::new(file_drain).build().fuse() + }; + let logger = slog::Logger::root(async_drain, slog::o!()); + + info!(logger, "Logging initialized"); if opts.is_multi_session { - eprintln!("running multi-session"); + info!(logger, "running multi-session"); let listener = TcpListener::bind(("127.0.0.1", opts.port))?; - eprintln!("bound on port: {} ", opts.port); + info!(logger, "bound on port: {} ", opts.port); let (stream, addr) = listener.accept()?; - eprintln!("Accepted client on: {}", addr); // changed to eprintln! + info!(logger, "Accepted client on: {}", addr); let read_stream = BufReader::new(stream.try_clone()?); let write_stream = BufWriter::new(stream); let mut server = Server::new(read_stream, write_stream); // Get the adapter from the init function - let adapter = multi_session_init(&mut server)?; + let adapter = multi_session_init(&mut server, &logger)?; // Run the server using the adapter - run_server(&mut server, adapter)?; + run_server(&mut server, adapter, &logger)?; } else { - eprintln!("running single-session"); + info!(logger, "running single-session"); let write = BufWriter::new(stdout()); let read = BufReader::new(stdin()); let mut server = Server::new(read, write); - let adapter = multi_session_init(&mut server)?; - run_server(&mut server, adapter)?; + let adapter = multi_session_init(&mut server, &logger)?; + run_server(&mut server, adapter, &logger)?; } - eprintln!("exited run_Server"); + info!(logger, "exited run_Server"); Ok(()) } fn multi_session_init( server: &mut Server, + logger: &slog::Logger, ) -> AdapterResult where R: Read, @@ -93,7 +120,7 @@ where let program_path = if let Command::Launch(params) = &req.command { if let Some(data) = ¶ms.additional_data { if let Some(program_path) = data.get("program") { - eprintln!("Program path: {}", program_path); + info!(logger, "Program path: {}", program_path); program_path .as_str() .ok_or(MyAdapterError::InvalidPathError)? @@ -136,6 +163,7 @@ where fn run_server( server: &mut Server, mut adapter: MyAdapter, + logger: &slog::Logger, ) -> AdapterResult<()> { loop { // Start looping here @@ -188,7 +216,7 @@ fn run_server( server.respond(rsp)?; //Exit - eprintln!("exited debugger"); + info!(logger, "exited debugger"); return Ok(()); } // Send StackTrace, may be useful to make it more robust in the future From 4c5a3dc3ff7908f7465443b1eaa8da874456f909 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Wed, 13 Dec 2023 10:31:09 -0500 Subject: [PATCH 114/189] Use runt version 0.4.0 (#1804) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9626465d9..9b1a1632c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,7 +58,7 @@ ADD . calyx WORKDIR /home/calyx RUN cargo build --all && \ cargo install vcdump && \ - cargo install runt --version 0.4.1 + cargo install runt --version 0.4.0 # Install fud WORKDIR /home/calyx/fud From bceade5d16374f79ec923bdd5238ed4982d1ef25 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Mon, 18 Dec 2023 17:12:39 -0500 Subject: [PATCH 115/189] bump rust version number (#1812) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9b1a1632c..0358b6dc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Use the official rust image as a parent image. -FROM rust:1.69 +FROM rust:1.70 # Connect to the Calux repository. LABEL org.opencontainers.image.source https://github.com/cucapra/calyx From 15d1b5cb2ed7832b09da6596bf34267936950174 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Mon, 18 Dec 2023 17:43:16 -0500 Subject: [PATCH 116/189] Initial code and tests for Calyx-to-FIRRTL backend (#1806) * Initial commit: added barebones firrtl.rs as a backend option. * Fix formatting errors and try to leverage VerilogBackend * Fix formatting * first pass on inputs and outputs * fix CI formatting issue * more CI formatting fixes * temporary commit before fixing up starter code * Clean up starter firrtl translation code * Fix CI errors * Barebones test containing input/output ports and single assignment * Fix test failure caused by whitespace * clean up unnecessary comments * Address PR comments * Add error message for ports that have groups as parents --- calyx-backend/src/backend_opt.rs | 3 + calyx-backend/src/firrtl.rs | 149 ++++++++++++++++++++++ calyx-backend/src/lib.rs | 2 + src/cmdline.rs | 8 +- tests/backend/firrtl/basic-program.expect | 12 ++ tests/backend/firrtl/basic-program.futil | 9 ++ 6 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 calyx-backend/src/firrtl.rs create mode 100644 tests/backend/firrtl/basic-program.expect create mode 100644 tests/backend/firrtl/basic-program.futil diff --git a/calyx-backend/src/backend_opt.rs b/calyx-backend/src/backend_opt.rs index f07df18a4..166189fb1 100644 --- a/calyx-backend/src/backend_opt.rs +++ b/calyx-backend/src/backend_opt.rs @@ -13,6 +13,7 @@ pub enum BackendOpt { Resources, Sexp, Yxi, + Firrtl, None, } @@ -28,6 +29,7 @@ fn backends() -> Vec<(&'static str, BackendOpt)> { ("resources", BackendOpt::Resources), ("sexp", BackendOpt::Sexp), ("yxi", BackendOpt::Yxi), + ("firrtl", BackendOpt::Firrtl), ("none", BackendOpt::None), ] } @@ -71,6 +73,7 @@ impl ToString for BackendOpt { Self::XilinxXml => "xilinx-xml", Self::Yxi => "yxi", Self::Calyx => "calyx", + Self::Firrtl => "firrtl", Self::None => "none", } .to_string() diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs new file mode 100644 index 000000000..06903f198 --- /dev/null +++ b/calyx-backend/src/firrtl.rs @@ -0,0 +1,149 @@ +//! FIRRTL backend for the Calyx compiler. +//! +//! Transforms an [`ir::Context`](crate::ir::Context) into a formatted string that represents a +//! valid FIRRTL program. + +use crate::{traits::Backend, VerilogBackend}; +use calyx_ir::{self as ir}; +use calyx_utils::{CalyxResult, OutputFile}; +use std::io; + +pub(super) const SPACING: &str = " "; + +/// Implements a simple FIRRTL backend. The backend only accepts Calyx programs with no control +/// and no groups. +#[derive(Default)] +pub struct FirrtlBackend; + +impl Backend for FirrtlBackend { + fn name(&self) -> &'static str { + "firrtl" + } + + fn link_externs( + _prog: &calyx_ir::Context, + _write: &mut calyx_utils::OutputFile, + ) -> calyx_utils::CalyxResult<()> { + Ok(()) // FIXME: Need to implement + } + + fn validate(prog: &calyx_ir::Context) -> calyx_utils::CalyxResult<()> { + VerilogBackend::validate(prog) // FIXME: would this work if we wanted to check for the same things? + } + + fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { + let out = &mut file.get_write(); + for comp in ctx.components.iter() { + emit_component(comp, out)? + } + Ok(()) + } +} + +// TODO: Ask about the other backend configurations in verilog.rs and see if I need any of it +fn emit_component( + comp: &ir::Component, + f: &mut F, +) -> io::Result<()> { + writeln!(f, "circuit {}:", comp.name)?; + writeln!(f, "{}module {}:", SPACING, comp.name)?; + + // Inputs and Outputs + let sig = comp.signature.borrow(); + for (_idx, port_ref) in sig.ports.iter().enumerate() { + let port = port_ref.borrow(); + let direction_string = + // NOTE: The signature port definitions are reversed inside the component. + match port.direction { + ir::Direction::Input => {"output"} + ir::Direction::Output => {"input"} + ir::Direction::Inout => { + panic!("Unexpected Inout port on Component: {}", port.name) + } + }; + if port.has_attribute(ir::BoolAttr::Clk) { + writeln!( + f, + "{}{} {}: Clock", + SPACING.repeat(2), + direction_string, + port.name + )?; + } else { + writeln!( + f, + "{}{} {}: UInt<{}>", + SPACING.repeat(2), + direction_string, + port.name, + port.width + )?; + } + } + + // Add a COMPONENT START: anchor before any code in the component + writeln!(f, "{}; COMPONENT START: {}", SPACING.repeat(2), comp.name)?; + + // TODO: Cells. NOTE: leaving this one for last + + for asgn in &comp.continuous_assignments { + // TODO: guards + match asgn.guard.as_ref() { + ir::Guard::Or(_, _) => todo!(), + ir::Guard::And(_, _) => todo!(), + ir::Guard::Not(_) => todo!(), + ir::Guard::True => { + // Simple assignment with no guard + let _ = write_assignment(asgn, f); + } + ir::Guard::CompOp(_, _, _) => todo!(), + ir::Guard::Port(_) => {} + ir::Guard::Info(_) => todo!(), + } + } + + // Add COMPONENT END: anchor + writeln!(f, "{}; COMPONENT END: {}", SPACING.repeat(2), comp.name)?; + + Ok(()) +} + +// Writes a FIRRTL assignment +fn write_assignment( + asgn: &ir::Assignment, + f: &mut F, +) -> CalyxResult<()> { + let dest_port = asgn.dst.borrow(); + let dest_string = get_port_string(&dest_port, true); + let source_port = asgn.src.borrow(); + let src_string = get_port_string(&source_port, false); + writeln!(f, "{}{} <= {}", SPACING.repeat(2), dest_string, src_string)?; + Ok(()) +} + +// returns the FIRRTL translation of a port. +// if is_dst is true, then the port is a destination of an assignment, and shouldn't be a constant. +fn get_port_string(port: &calyx_ir::Port, is_dst: bool) -> String { + match &port.parent { + ir::PortParent::Cell(cell) => { + let parent_ref = cell.upgrade(); + let parent = parent_ref.borrow(); + match parent.prototype { + ir::CellType::Constant { val, width: _ } => { + if !is_dst { + format!("UInt({})", val) + } else { + unreachable!() + } + } + ir::CellType::ThisComponent => String::from(port.name.as_ref()), + _ => { + format!("{}.{}", parent.name().as_ref(), port.name.as_ref()) + } + } + } + _ => { + unreachable!("Groups should not be parents as this backend takes place after compiler passes.") + } + } +} diff --git a/calyx-backend/src/lib.rs b/calyx-backend/src/lib.rs index 3d102da8c..2701920db 100644 --- a/calyx-backend/src/lib.rs +++ b/calyx-backend/src/lib.rs @@ -1,10 +1,12 @@ //! Backends for the Calyx compiler. mod backend_opt; +mod firrtl; mod traits; mod verilog; mod yxi; pub use backend_opt::BackendOpt; +pub use firrtl::FirrtlBackend; pub use traits::Backend; pub use verilog::VerilogBackend; pub use yxi::YxiBackend; diff --git a/src/cmdline.rs b/src/cmdline.rs index c15b14177..c65fdde41 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -4,8 +4,8 @@ use argh::FromArgs; use calyx_backend::SexpBackend; use calyx_backend::{ xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, - Backend, BackendOpt, MlirBackend, ResourcesBackend, VerilogBackend, - YxiBackend, + Backend, BackendOpt, FirrtlBackend, MlirBackend, ResourcesBackend, + VerilogBackend, YxiBackend, }; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; @@ -150,6 +150,10 @@ impl Opts { let backend = YxiBackend; backend.run(context, self.output) } + BackendOpt::Firrtl => { + let backend = FirrtlBackend; + backend.run(context, self.output) + } BackendOpt::Calyx => { ir::Printer::write_context( &context, diff --git a/tests/backend/firrtl/basic-program.expect b/tests/backend/firrtl/basic-program.expect new file mode 100644 index 000000000..73af9081f --- /dev/null +++ b/tests/backend/firrtl/basic-program.expect @@ -0,0 +1,12 @@ +circuit main: + module main: + input in: UInt<32> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out <= in + ; COMPONENT END: main diff --git a/tests/backend/firrtl/basic-program.futil b/tests/backend/firrtl/basic-program.futil new file mode 100644 index 000000000..e6d546ad3 --- /dev/null +++ b/tests/backend/firrtl/basic-program.futil @@ -0,0 +1,9 @@ +// -b firrtl +component main(in : 32) -> (out : 32) { + cells {} + wires { + out = in; + done = 1'd1; + } + control {} +} From 1deea042e9305bbfeb8842affce5c81c20a2a159 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:33:45 +0530 Subject: [PATCH 117/189] SDN correctness (#1796) * Three new flavors of SDN * Queues: tidy testing (#1808) * Move queues into their own folder * Delete old * SDN: single source of truth, tidying (#1809) * Nix the different flavors of SDN * SDN.py now takes a --static argument * Dedicated stanzas to capture ethe same file and run it differently' --- .../correctness/pifo_tree_pre_tangerine.data | 69 - .../test/correctness/{ => queues}/fifo.data | 0 .../test/correctness/{ => queues}/fifo.expect | 0 .../test/correctness/{ => queues}/fifo.py | 0 .../test/correctness/{ => queues}/pifo.data | 0 .../test/correctness/{ => queues}/pifo.expect | 0 .../test/correctness/{ => queues}/pifo.py | 0 .../correctness/{ => queues}/pifo_tree.data | 0 .../correctness/{ => queues}/pifo_tree.expect | 0 .../correctness/{ => queues}/pifo_tree.py | 0 .../test/correctness/{ => queues}/sdn.data | 0 .../test/correctness/{ => queues}/sdn.expect | 0 calyx-py/test/correctness/{ => queues}/sdn.py | 5 +- .../test/correctness/static/sdn_static.data | 60029 ---------------- .../test/correctness/static/sdn_static.expect | 60008 --------------- .../test/correctness/static/sdn_static.py | 9 - runt.toml | 57 +- 17 files changed, 58 insertions(+), 120119 deletions(-) delete mode 100644 calyx-py/test/correctness/pifo_tree_pre_tangerine.data rename calyx-py/test/correctness/{ => queues}/fifo.data (100%) rename calyx-py/test/correctness/{ => queues}/fifo.expect (100%) rename calyx-py/test/correctness/{ => queues}/fifo.py (100%) rename calyx-py/test/correctness/{ => queues}/pifo.data (100%) rename calyx-py/test/correctness/{ => queues}/pifo.expect (100%) rename calyx-py/test/correctness/{ => queues}/pifo.py (100%) rename calyx-py/test/correctness/{ => queues}/pifo_tree.data (100%) rename calyx-py/test/correctness/{ => queues}/pifo_tree.expect (100%) rename calyx-py/test/correctness/{ => queues}/pifo_tree.py (100%) rename calyx-py/test/correctness/{ => queues}/sdn.data (100%) rename calyx-py/test/correctness/{ => queues}/sdn.expect (100%) rename calyx-py/test/correctness/{ => queues}/sdn.py (96%) delete mode 100644 calyx-py/test/correctness/static/sdn_static.data delete mode 100644 calyx-py/test/correctness/static/sdn_static.expect delete mode 100644 calyx-py/test/correctness/static/sdn_static.py diff --git a/calyx-py/test/correctness/pifo_tree_pre_tangerine.data b/calyx-py/test/correctness/pifo_tree_pre_tangerine.data deleted file mode 100644 index 62b60a327..000000000 --- a/calyx-py/test/correctness/pifo_tree_pre_tangerine.data +++ /dev/null @@ -1,69 +0,0 @@ -{ - "commands": { - "data": [ - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 2 - } - }, - "values": { - "data": [ - 11, - 12, - 201, - 202, - 203, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 32 - } - }, - "ans_mem": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 32 - } - } -} \ No newline at end of file diff --git a/calyx-py/test/correctness/fifo.data b/calyx-py/test/correctness/queues/fifo.data similarity index 100% rename from calyx-py/test/correctness/fifo.data rename to calyx-py/test/correctness/queues/fifo.data diff --git a/calyx-py/test/correctness/fifo.expect b/calyx-py/test/correctness/queues/fifo.expect similarity index 100% rename from calyx-py/test/correctness/fifo.expect rename to calyx-py/test/correctness/queues/fifo.expect diff --git a/calyx-py/test/correctness/fifo.py b/calyx-py/test/correctness/queues/fifo.py similarity index 100% rename from calyx-py/test/correctness/fifo.py rename to calyx-py/test/correctness/queues/fifo.py diff --git a/calyx-py/test/correctness/pifo.data b/calyx-py/test/correctness/queues/pifo.data similarity index 100% rename from calyx-py/test/correctness/pifo.data rename to calyx-py/test/correctness/queues/pifo.data diff --git a/calyx-py/test/correctness/pifo.expect b/calyx-py/test/correctness/queues/pifo.expect similarity index 100% rename from calyx-py/test/correctness/pifo.expect rename to calyx-py/test/correctness/queues/pifo.expect diff --git a/calyx-py/test/correctness/pifo.py b/calyx-py/test/correctness/queues/pifo.py similarity index 100% rename from calyx-py/test/correctness/pifo.py rename to calyx-py/test/correctness/queues/pifo.py diff --git a/calyx-py/test/correctness/pifo_tree.data b/calyx-py/test/correctness/queues/pifo_tree.data similarity index 100% rename from calyx-py/test/correctness/pifo_tree.data rename to calyx-py/test/correctness/queues/pifo_tree.data diff --git a/calyx-py/test/correctness/pifo_tree.expect b/calyx-py/test/correctness/queues/pifo_tree.expect similarity index 100% rename from calyx-py/test/correctness/pifo_tree.expect rename to calyx-py/test/correctness/queues/pifo_tree.expect diff --git a/calyx-py/test/correctness/pifo_tree.py b/calyx-py/test/correctness/queues/pifo_tree.py similarity index 100% rename from calyx-py/test/correctness/pifo_tree.py rename to calyx-py/test/correctness/queues/pifo_tree.py diff --git a/calyx-py/test/correctness/sdn.data b/calyx-py/test/correctness/queues/sdn.data similarity index 100% rename from calyx-py/test/correctness/sdn.data rename to calyx-py/test/correctness/queues/sdn.data diff --git a/calyx-py/test/correctness/sdn.expect b/calyx-py/test/correctness/queues/sdn.expect similarity index 100% rename from calyx-py/test/correctness/sdn.expect rename to calyx-py/test/correctness/queues/sdn.expect diff --git a/calyx-py/test/correctness/sdn.py b/calyx-py/test/correctness/queues/sdn.py similarity index 96% rename from calyx-py/test/correctness/sdn.py rename to calyx-py/test/correctness/queues/sdn.py index 89aecd721..6dd19c5a0 100644 --- a/calyx-py/test/correctness/sdn.py +++ b/calyx-py/test/correctness/queues/sdn.py @@ -1,4 +1,5 @@ # pylint: disable=import-error +import sys import fifo import pifo import calyx.builder as cb @@ -172,5 +173,7 @@ def build(static=False): return prog.program +# We will have a command line argument to determine whether the program is static. if __name__ == "__main__": - build().emit() + static = sys.argv[1] == "--static" if len(sys.argv) > 1 else False + build(static=static).emit() diff --git a/calyx-py/test/correctness/static/sdn_static.data b/calyx-py/test/correctness/static/sdn_static.data deleted file mode 100644 index 3fbb87182..000000000 --- a/calyx-py/test/correctness/static/sdn_static.data +++ /dev/null @@ -1,60029 +0,0 @@ -{ - "commands": { - "data": [ - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 2 - } - }, - "values": { - "data": [ - 87, - 389, - 327, - 304, - 190, - 248, - 14, - 289, - 151, - 325, - 293, - 323, - 331, - 110, - 378, - 235, - 280, - 369, - 373, - 42, - 61, - 265, - 120, - 394, - 17, - 64, - 325, - 172, - 191, - 373, - 336, - 31, - 151, - 28, - 85, - 2, - 204, - 115, - 2, - 103, - 300, - 168, - 184, - 180, - 359, - 400, - 176, - 118, - 15, - 120, - 6, - 297, - 123, - 84, - 52, - 202, - 239, - 85, - 234, - 353, - 3, - 217, - 119, - 5, - 50, - 29, - 145, - 50, - 389, - 156, - 41, - 120, - 29, - 372, - 70, - 396, - 216, - 280, - 164, - 217, - 161, - 305, - 51, - 90, - 94, - 369, - 29, - 354, - 200, - 21, - 259, - 292, - 164, - 113, - 359, - 28, - 361, - 70, - 363, - 279, - 224, - 363, - 203, - 383, - 350, - 216, - 22, - 95, - 384, - 392, - 359, - 93, - 113, - 157, - 293, - 129, - 78, - 223, - 157, - 116, - 213, - 7, - 284, - 25, - 67, - 222, - 289, - 40, - 342, - 359, - 218, - 365, - 356, - 321, - 136, - 307, - 356, - 356, - 279, - 73, - 177, - 172, - 329, - 128, - 359, - 236, - 174, - 388, - 109, - 11, - 131, - 84, - 349, - 375, - 389, - 342, - 128, - 27, - 39, - 116, - 77, - 342, - 114, - 248, - 31, - 371, - 331, - 182, - 71, - 341, - 294, - 272, - 112, - 368, - 365, - 129, - 83, - 218, - 64, - 261, - 294, - 385, - 115, - 111, - 375, - 67, - 31, - 25, - 57, - 186, - 48, - 43, - 242, - 287, - 162, - 185, - 188, - 336, - 255, - 282, - 340, - 377, - 63, - 18, - 240, - 238, - 351, - 132, - 72, - 123, - 146, - 188, - 23, - 10, - 197, - 150, - 157, - 244, - 292, - 80, - 367, - 369, - 108, - 361, - 344, - 400, - 37, - 364, - 36, - 270, - 177, - 65, - 282, - 357, - 106, - 387, - 149, - 146, - 134, - 329, - 340, - 77, - 57, - 62, - 351, - 364, - 102, - 194, - 68, - 308, - 289, - 3, - 138, - 321, - 283, - 302, - 250, - 231, - 207, - 380, - 289, - 381, - 16, - 176, - 132, - 130, - 13, - 372, - 289, - 121, - 208, - 355, - 252, - 397, - 227, - 139, - 207, - 229, - 301, - 227, - 69, - 40, - 227, - 310, - 181, - 217, - 296, - 26, - 287, - 52, - 261, - 253, - 309, - 166, - 212, - 382, - 205, - 315, - 240, - 203, - 264, - 349, - 279, - 218, - 145, - 270, - 53, - 270, - 338, - 295, - 355, - 277, - 201, - 232, - 218, - 49, - 310, - 90, - 195, - 169, - 278, - 254, - 93, - 150, - 216, - 377, - 290, - 26, - 242, - 391, - 140, - 137, - 289, - 93, - 3, - 325, - 238, - 329, - 373, - 351, - 163, - 279, - 126, - 267, - 376, - 64, - 236, - 72, - 213, - 220, - 44, - 41, - 28, - 223, - 269, - 187, - 381, - 222, - 164, - 297, - 62, - 316, - 21, - 254, - 110, - 98, - 395, - 379, - 399, - 130, - 93, - 211, - 323, - 39, - 267, - 60, - 143, - 125, - 207, - 47, - 284, - 148, - 134, - 47, - 109, - 219, - 241, - 346, - 15, - 306, - 140, - 302, - 156, - 175, - 341, - 147, - 214, - 198, - 14, - 339, - 289, - 91, - 278, - 396, - 75, - 340, - 284, - 68, - 108, - 261, - 366, - 317, - 249, - 100, - 309, - 281, - 63, - 400, - 366, - 306, - 194, - 331, - 211, - 342, - 67, - 49, - 206, - 299, - 87, - 238, - 72, - 379, - 347, - 349, - 266, - 394, - 120, - 94, - 237, - 375, - 397, - 102, - 148, - 198, - 329, - 13, - 96, - 129, - 274, - 43, - 109, - 196, - 55, - 285, - 291, - 164, - 358, - 162, - 47, - 270, - 29, - 273, - 37, - 190, - 209, - 114, - 366, - 192, - 121, - 162, - 361, - 308, - 267, - 136, - 222, - 224, - 139, - 368, - 133, - 301, - 319, - 55, - 170, - 142, - 68, - 330, - 372, - 265, - 386, - 58, - 130, - 203, - 385, - 172, - 370, - 156, - 399, - 112, - 361, - 332, - 26, - 34, - 114, - 134, - 130, - 376, - 158, - 289, - 219, - 232, - 278, - 389, - 147, - 341, - 359, - 296, - 89, - 347, - 101, - 266, - 321, - 383, - 162, - 265, - 398, - 241, - 399, - 106, - 252, - 6, - 42, - 201, - 37, - 256, - 328, - 93, - 384, - 246, - 69, - 1, - 331, - 112, - 216, - 124, - 370, - 225, - 341, - 295, - 188, - 41, - 211, - 289, - 46, - 97, - 91, - 151, - 189, - 156, - 191, - 96, - 221, - 141, - 164, - 394, - 316, - 45, - 12, - 330, - 129, - 129, - 141, - 137, - 305, - 180, - 242, - 5, - 180, - 6, - 18, - 149, - 306, - 336, - 16, - 177, - 2, - 22, - 311, - 190, - 142, - 380, - 162, - 239, - 269, - 52, - 213, - 302, - 191, - 328, - 17, - 190, - 282, - 78, - 397, - 198, - 362, - 191, - 152, - 184, - 262, - 370, - 351, - 199, - 397, - 273, - 270, - 7, - 335, - 295, - 383, - 212, - 263, - 319, - 32, - 96, - 276, - 51, - 165, - 299, - 279, - 390, - 378, - 128, - 307, - 52, - 45, - 94, - 222, - 252, - 111, - 21, - 319, - 90, - 241, - 355, - 60, - 203, - 396, - 368, - 124, - 11, - 149, - 318, - 341, - 46, - 357, - 126, - 98, - 380, - 217, - 105, - 149, - 4, - 34, - 34, - 180, - 360, - 375, - 161, - 343, - 184, - 206, - 241, - 196, - 361, - 178, - 104, - 394, - 76, - 125, - 38, - 384, - 156, - 223, - 318, - 268, - 69, - 225, - 191, - 122, - 314, - 166, - 336, - 232, - 121, - 170, - 81, - 176, - 192, - 218, - 393, - 321, - 254, - 300, - 255, - 54, - 182, - 3, - 8, - 334, - 302, - 150, - 335, - 18, - 144, - 290, - 165, - 204, - 201, - 346, - 2, - 318, - 64, - 54, - 58, - 31, - 171, - 246, - 179, - 115, - 99, - 13, - 371, - 36, - 371, - 137, - 188, - 20, - 341, - 340, - 312, - 260, - 68, - 163, - 95, - 286, - 45, - 156, - 170, - 23, - 29, - 376, - 235, - 114, - 280, - 294, - 30, - 357, - 381, - 363, - 176, - 260, - 344, - 202, - 238, - 303, - 366, - 330, - 114, - 33, - 272, - 243, - 347, - 146, - 56, - 247, - 11, - 291, - 277, - 120, - 142, - 83, - 236, - 365, - 307, - 317, - 383, - 119, - 188, - 153, - 315, - 337, - 364, - 46, - 283, - 129, - 360, - 325, - 178, - 180, - 279, - 370, - 347, - 394, - 141, - 61, - 55, - 281, - 272, - 193, - 30, - 71, - 205, - 342, - 248, - 174, - 99, - 279, - 313, - 11, - 81, - 204, - 113, - 155, - 50, - 385, - 65, - 338, - 225, - 202, - 373, - 257, - 142, - 242, - 316, - 309, - 385, - 167, - 295, - 220, - 41, - 130, - 151, - 70, - 57, - 364, - 63, - 382, - 97, - 388, - 102, - 255, - 387, - 132, - 348, - 113, - 239, - 306, - 299, - 319, - 205, - 9, - 150, - 47, - 62, - 221, - 61, - 119, - 215, - 364, - 230, - 338, - 400, - 397, - 2, - 167, - 286, - 15, - 305, - 391, - 66, - 148, - 142, - 322, - 209, - 378, - 61, - 249, - 198, - 171, - 331, - 45, - 16, - 304, - 312, - 56, - 383, - 289, - 279, - 6, - 31, - 272, - 192, - 10, - 151, - 200, - 181, - 389, - 204, - 30, - 67, - 249, - 166, - 46, - 213, - 175, - 391, - 134, - 102, - 76, - 394, - 362, - 11, - 248, - 183, - 235, - 389, - 158, - 287, - 357, - 385, - 96, - 238, - 75, - 127, - 67, - 314, - 389, - 143, - 98, - 350, - 367, - 113, - 148, - 80, - 74, - 394, - 354, - 146, - 238, - 260, - 260, - 278, - 180, - 261, - 87, - 377, - 187, - 334, - 329, - 30, - 361, - 230, - 375, - 116, - 287, - 41, - 192, - 139, - 209, - 293, - 342, - 83, - 93, - 314, - 306, - 321, - 257, - 38, - 284, - 238, - 358, - 4, - 383, - 332, - 381, - 54, - 22, - 101, - 394, - 94, - 392, - 296, - 244, - 314, - 384, - 37, - 57, - 211, - 357, - 183, - 153, - 101, - 274, - 239, - 264, - 112, - 195, - 255, - 148, - 170, - 62, - 219, - 50, - 218, - 19, - 399, - 353, - 245, - 266, - 214, - 161, - 121, - 19, - 13, - 21, - 192, - 41, - 382, - 211, - 190, - 27, - 54, - 268, - 256, - 19, - 68, - 169, - 127, - 395, - 37, - 91, - 163, - 263, - 224, - 188, - 72, - 28, - 13, - 352, - 4, - 286, - 343, - 37, - 346, - 177, - 341, - 120, - 149, - 324, - 46, - 284, - 200, - 24, - 273, - 297, - 212, - 397, - 46, - 207, - 100, - 271, - 59, - 100, - 181, - 89, - 205, - 297, - 257, - 185, - 230, - 341, - 292, - 274, - 27, - 16, - 16, - 134, - 355, - 165, - 226, - 208, - 238, - 233, - 28, - 366, - 384, - 204, - 37, - 112, - 339, - 95, - 354, - 129, - 323, - 158, - 375, - 238, - 2, - 372, - 356, - 379, - 89, - 22, - 284, - 271, - 51, - 103, - 375, - 162, - 314, - 341, - 18, - 395, - 180, - 26, - 8, - 90, - 143, - 211, - 230, - 273, - 245, - 112, - 169, - 200, - 335, - 308, - 70, - 328, - 311, - 246, - 49, - 342, - 204, - 282, - 148, - 123, - 39, - 233, - 217, - 270, - 147, - 104, - 110, - 359, - 386, - 276, - 269, - 97, - 70, - 400, - 351, - 301, - 226, - 167, - 87, - 176, - 130, - 137, - 170, - 161, - 368, - 342, - 258, - 376, - 213, - 117, - 114, - 45, - 383, - 196, - 241, - 219, - 50, - 193, - 317, - 144, - 299, - 231, - 367, - 63, - 41, - 107, - 371, - 112, - 145, - 44, - 241, - 215, - 328, - 252, - 228, - 64, - 5, - 200, - 370, - 25, - 137, - 344, - 322, - 4, - 375, - 274, - 239, - 124, - 152, - 303, - 290, - 37, - 349, - 137, - 129, - 326, - 313, - 51, - 179, - 64, - 323, - 320, - 140, - 18, - 274, - 84, - 290, - 64, - 41, - 122, - 131, - 314, - 286, - 279, - 113, - 196, - 329, - 89, - 155, - 197, - 104, - 1, - 33, - 152, - 190, - 348, - 192, - 217, - 34, - 233, - 147, - 185, - 124, - 246, - 215, - 211, - 301, - 50, - 13, - 393, - 302, - 222, - 374, - 222, - 62, - 370, - 351, - 17, - 367, - 385, - 137, - 254, - 27, - 219, - 240, - 349, - 166, - 307, - 375, - 29, - 82, - 354, - 191, - 284, - 398, - 157, - 253, - 128, - 337, - 238, - 317, - 27, - 193, - 131, - 71, - 232, - 394, - 400, - 78, - 57, - 216, - 203, - 351, - 224, - 372, - 26, - 164, - 90, - 259, - 304, - 200, - 56, - 313, - 81, - 290, - 66, - 324, - 336, - 93, - 104, - 119, - 176, - 38, - 309, - 86, - 362, - 261, - 150, - 210, - 377, - 323, - 291, - 373, - 216, - 386, - 123, - 271, - 293, - 104, - 348, - 29, - 171, - 247, - 147, - 224, - 270, - 362, - 200, - 371, - 73, - 215, - 236, - 157, - 196, - 204, - 83, - 12, - 382, - 246, - 305, - 45, - 376, - 166, - 124, - 296, - 386, - 152, - 228, - 206, - 191, - 181, - 14, - 94, - 76, - 252, - 273, - 37, - 388, - 17, - 223, - 227, - 125, - 353, - 242, - 367, - 150, - 191, - 153, - 191, - 84, - 78, - 208, - 263, - 64, - 319, - 244, - 135, - 181, - 105, - 6, - 245, - 96, - 62, - 320, - 158, - 345, - 73, - 384, - 303, - 364, - 195, - 323, - 221, - 45, - 10, - 162, - 305, - 289, - 357, - 32, - 21, - 159, - 71, - 133, - 335, - 353, - 86, - 133, - 128, - 397, - 292, - 16, - 150, - 66, - 144, - 274, - 180, - 306, - 301, - 143, - 394, - 145, - 175, - 73, - 113, - 330, - 172, - 1, - 146, - 349, - 303, - 336, - 161, - 361, - 7, - 373, - 253, - 387, - 151, - 105, - 149, - 360, - 351, - 239, - 66, - 118, - 203, - 22, - 166, - 334, - 5, - 183, - 335, - 343, - 168, - 300, - 111, - 332, - 103, - 134, - 197, - 147, - 29, - 112, - 343, - 81, - 43, - 146, - 295, - 34, - 344, - 264, - 148, - 263, - 126, - 134, - 14, - 244, - 152, - 227, - 292, - 120, - 232, - 29, - 141, - 146, - 42, - 52, - 72, - 121, - 14, - 300, - 138, - 163, - 202, - 280, - 259, - 396, - 77, - 344, - 253, - 209, - 381, - 311, - 260, - 334, - 86, - 393, - 338, - 52, - 235, - 270, - 388, - 295, - 137, - 279, - 350, - 228, - 268, - 134, - 294, - 151, - 181, - 121, - 84, - 213, - 225, - 41, - 43, - 257, - 91, - 150, - 333, - 99, - 247, - 11, - 64, - 206, - 194, - 10, - 371, - 179, - 87, - 250, - 379, - 143, - 113, - 187, - 367, - 32, - 242, - 251, - 151, - 195, - 173, - 177, - 342, - 391, - 107, - 77, - 272, - 351, - 248, - 373, - 49, - 138, - 83, - 400, - 218, - 27, - 118, - 379, - 167, - 101, - 322, - 79, - 395, - 238, - 53, - 39, - 63, - 106, - 334, - 392, - 103, - 291, - 323, - 52, - 40, - 323, - 280, - 314, - 237, - 325, - 282, - 282, - 384, - 169, - 117, - 400, - 203, - 83, - 210, - 377, - 347, - 380, - 255, - 162, - 243, - 349, - 4, - 392, - 146, - 253, - 286, - 22, - 48, - 24, - 287, - 300, - 160, - 273, - 230, - 27, - 77, - 60, - 381, - 212, - 142, - 358, - 114, - 293, - 123, - 14, - 208, - 80, - 80, - 214, - 21, - 119, - 120, - 161, - 247, - 282, - 237, - 10, - 26, - 373, - 58, - 161, - 133, - 44, - 219, - 58, - 101, - 197, - 208, - 329, - 377, - 228, - 280, - 139, - 49, - 339, - 220, - 231, - 256, - 223, - 227, - 354, - 203, - 134, - 324, - 264, - 273, - 157, - 284, - 192, - 93, - 374, - 117, - 346, - 240, - 205, - 106, - 40, - 193, - 398, - 33, - 334, - 248, - 225, - 391, - 119, - 11, - 339, - 99, - 102, - 1, - 283, - 262, - 66, - 281, - 397, - 305, - 350, - 267, - 215, - 191, - 383, - 336, - 147, - 75, - 106, - 49, - 41, - 211, - 53, - 237, - 364, - 226, - 217, - 394, - 77, - 313, - 266, - 303, - 173, - 380, - 32, - 390, - 200, - 63, - 56, - 328, - 93, - 290, - 1, - 136, - 77, - 44, - 268, - 91, - 274, - 83, - 69, - 169, - 247, - 393, - 208, - 43, - 381, - 137, - 280, - 279, - 230, - 212, - 224, - 220, - 233, - 29, - 30, - 175, - 75, - 108, - 140, - 267, - 20, - 16, - 51, - 27, - 287, - 169, - 145, - 132, - 170, - 146, - 246, - 162, - 120, - 155, - 388, - 288, - 98, - 58, - 155, - 146, - 37, - 133, - 153, - 40, - 187, - 88, - 165, - 385, - 272, - 334, - 105, - 177, - 333, - 204, - 129, - 393, - 228, - 348, - 70, - 137, - 97, - 8, - 233, - 70, - 315, - 161, - 38, - 230, - 237, - 191, - 33, - 257, - 4, - 45, - 382, - 81, - 209, - 64, - 140, - 9, - 243, - 98, - 31, - 3, - 66, - 164, - 176, - 198, - 261, - 381, - 56, - 196, - 20, - 101, - 51, - 255, - 37, - 35, - 365, - 64, - 59, - 246, - 383, - 297, - 152, - 142, - 55, - 190, - 27, - 301, - 169, - 66, - 138, - 222, - 64, - 240, - 364, - 48, - 365, - 166, - 393, - 62, - 150, - 72, - 165, - 316, - 7, - 388, - 92, - 119, - 179, - 161, - 106, - 297, - 382, - 151, - 34, - 276, - 325, - 249, - 136, - 170, - 390, - 373, - 121, - 374, - 21, - 129, - 155, - 39, - 385, - 244, - 394, - 52, - 239, - 186, - 189, - 170, - 194, - 231, - 296, - 21, - 392, - 262, - 169, - 8, - 285, - 106, - 35, - 316, - 108, - 107, - 229, - 77, - 322, - 143, - 38, - 313, - 52, - 386, - 211, - 78, - 151, - 37, - 156, - 232, - 188, - 114, - 57, - 63, - 195, - 169, - 82, - 281, - 230, - 146, - 312, - 168, - 174, - 181, - 62, - 352, - 287, - 71, - 102, - 338, - 211, - 222, - 148, - 302, - 134, - 6, - 332, - 305, - 193, - 40, - 272, - 211, - 292, - 91, - 238, - 317, - 89, - 137, - 383, - 356, - 355, - 216, - 325, - 181, - 92, - 177, - 217, - 92, - 342, - 42, - 283, - 20, - 178, - 17, - 297, - 207, - 274, - 248, - 277, - 4, - 62, - 352, - 85, - 56, - 330, - 386, - 280, - 353, - 399, - 151, - 78, - 353, - 209, - 96, - 125, - 145, - 96, - 325, - 254, - 89, - 143, - 22, - 204, - 310, - 180, - 163, - 395, - 282, - 85, - 183, - 351, - 297, - 49, - 45, - 65, - 392, - 65, - 369, - 18, - 349, - 240, - 59, - 271, - 313, - 300, - 204, - 129, - 310, - 47, - 378, - 112, - 396, - 273, - 331, - 242, - 215, - 62, - 162, - 227, - 388, - 397, - 39, - 255, - 142, - 400, - 191, - 133, - 264, - 16, - 272, - 331, - 93, - 100, - 270, - 152, - 9, - 373, - 85, - 255, - 95, - 362, - 22, - 323, - 37, - 234, - 170, - 19, - 104, - 67, - 14, - 18, - 3, - 400, - 14, - 356, - 324, - 287, - 103, - 268, - 370, - 73, - 305, - 359, - 272, - 115, - 264, - 215, - 53, - 44, - 365, - 208, - 48, - 378, - 303, - 378, - 306, - 156, - 31, - 366, - 261, - 269, - 108, - 5, - 72, - 373, - 236, - 75, - 366, - 139, - 101, - 193, - 126, - 125, - 224, - 388, - 122, - 184, - 307, - 73, - 14, - 383, - 131, - 345, - 261, - 46, - 172, - 63, - 220, - 74, - 57, - 209, - 225, - 46, - 173, - 133, - 27, - 171, - 262, - 3, - 347, - 87, - 152, - 201, - 59, - 173, - 224, - 67, - 29, - 5, - 326, - 203, - 56, - 155, - 22, - 149, - 363, - 290, - 23, - 305, - 36, - 157, - 95, - 31, - 370, - 127, - 105, - 230, - 135, - 163, - 90, - 350, - 375, - 144, - 330, - 190, - 331, - 46, - 35, - 94, - 390, - 251, - 147, - 11, - 184, - 394, - 347, - 360, - 319, - 201, - 105, - 391, - 241, - 204, - 290, - 310, - 282, - 201, - 389, - 19, - 111, - 232, - 137, - 60, - 64, - 308, - 267, - 306, - 283, - 277, - 71, - 391, - 164, - 253, - 387, - 195, - 321, - 61, - 51, - 320, - 159, - 108, - 47, - 91, - 44, - 199, - 312, - 193, - 254, - 241, - 25, - 211, - 136, - 259, - 269, - 123, - 61, - 221, - 255, - 95, - 209, - 322, - 50, - 65, - 167, - 28, - 117, - 121, - 166, - 301, - 350, - 115, - 253, - 247, - 343, - 259, - 237, - 40, - 75, - 308, - 62, - 114, - 25, - 68, - 254, - 67, - 348, - 141, - 150, - 4, - 280, - 141, - 2, - 79, - 158, - 101, - 79, - 270, - 315, - 263, - 356, - 114, - 41, - 174, - 257, - 91, - 394, - 299, - 57, - 182, - 280, - 26, - 100, - 83, - 106, - 198, - 361, - 108, - 221, - 123, - 284, - 87, - 251, - 101, - 125, - 355, - 117, - 61, - 322, - 162, - 385, - 74, - 286, - 101, - 350, - 367, - 149, - 50, - 315, - 343, - 7, - 291, - 1, - 376, - 85, - 6, - 67, - 17, - 91, - 77, - 152, - 310, - 177, - 306, - 287, - 181, - 142, - 46, - 310, - 143, - 136, - 130, - 114, - 263, - 153, - 304, - 352, - 338, - 108, - 23, - 325, - 208, - 14, - 5, - 343, - 397, - 239, - 145, - 224, - 184, - 140, - 42, - 367, - 321, - 306, - 387, - 69, - 98, - 243, - 331, - 237, - 189, - 264, - 190, - 149, - 76, - 146, - 361, - 113, - 334, - 108, - 355, - 45, - 338, - 107, - 104, - 63, - 223, - 115, - 194, - 395, - 113, - 9, - 21, - 219, - 10, - 59, - 158, - 105, - 303, - 362, - 375, - 232, - 91, - 233, - 214, - 339, - 356, - 371, - 68, - 280, - 230, - 13, - 60, - 392, - 91, - 49, - 284, - 269, - 285, - 42, - 71, - 357, - 276, - 142, - 69, - 90, - 85, - 25, - 18, - 388, - 105, - 58, - 301, - 320, - 190, - 147, - 117, - 147, - 335, - 326, - 330, - 115, - 230, - 337, - 253, - 380, - 155, - 195, - 398, - 356, - 148, - 69, - 390, - 209, - 207, - 112, - 380, - 16, - 351, - 274, - 140, - 149, - 80, - 229, - 56, - 338, - 298, - 254, - 224, - 182, - 226, - 257, - 18, - 207, - 238, - 234, - 255, - 202, - 141, - 307, - 100, - 68, - 82, - 271, - 265, - 385, - 344, - 231, - 134, - 213, - 116, - 68, - 320, - 326, - 320, - 201, - 296, - 288, - 148, - 198, - 34, - 123, - 73, - 342, - 397, - 68, - 145, - 333, - 163, - 185, - 210, - 25, - 138, - 343, - 149, - 163, - 170, - 36, - 274, - 263, - 75, - 203, - 155, - 196, - 234, - 210, - 107, - 152, - 311, - 314, - 204, - 358, - 213, - 102, - 281, - 203, - 224, - 123, - 347, - 54, - 60, - 163, - 49, - 134, - 2, - 366, - 307, - 204, - 193, - 120, - 185, - 362, - 74, - 35, - 68, - 141, - 309, - 120, - 276, - 166, - 89, - 91, - 207, - 7, - 336, - 262, - 257, - 165, - 151, - 257, - 50, - 381, - 304, - 268, - 265, - 157, - 378, - 9, - 243, - 53, - 346, - 148, - 166, - 261, - 177, - 256, - 28, - 193, - 279, - 165, - 320, - 341, - 106, - 353, - 25, - 179, - 57, - 122, - 394, - 100, - 335, - 243, - 103, - 252, - 332, - 135, - 103, - 389, - 316, - 252, - 262, - 378, - 356, - 37, - 254, - 178, - 251, - 328, - 251, - 105, - 349, - 166, - 130, - 327, - 372, - 350, - 380, - 35, - 281, - 30, - 276, - 364, - 345, - 52, - 62, - 258, - 76, - 103, - 320, - 203, - 387, - 186, - 132, - 10, - 349, - 359, - 270, - 154, - 75, - 137, - 92, - 224, - 167, - 390, - 290, - 92, - 282, - 336, - 391, - 133, - 43, - 103, - 260, - 91, - 116, - 289, - 96, - 358, - 157, - 178, - 168, - 244, - 98, - 175, - 100, - 367, - 82, - 86, - 124, - 356, - 165, - 24, - 73, - 280, - 242, - 121, - 117, - 174, - 169, - 331, - 92, - 185, - 210, - 142, - 110, - 364, - 179, - 322, - 317, - 170, - 59, - 312, - 247, - 249, - 149, - 388, - 241, - 369, - 69, - 153, - 150, - 217, - 357, - 169, - 391, - 220, - 33, - 284, - 208, - 392, - 181, - 48, - 62, - 268, - 386, - 367, - 228, - 121, - 385, - 41, - 231, - 208, - 141, - 33, - 299, - 207, - 126, - 143, - 388, - 122, - 257, - 374, - 217, - 188, - 356, - 120, - 201, - 192, - 314, - 117, - 63, - 200, - 230, - 61, - 358, - 36, - 327, - 285, - 364, - 83, - 116, - 190, - 339, - 135, - 62, - 1, - 9, - 395, - 331, - 55, - 288, - 254, - 210, - 310, - 62, - 397, - 297, - 228, - 288, - 283, - 333, - 69, - 105, - 231, - 129, - 163, - 110, - 201, - 143, - 22, - 91, - 40, - 3, - 360, - 383, - 157, - 148, - 98, - 25, - 332, - 239, - 200, - 298, - 299, - 92, - 276, - 22, - 67, - 190, - 287, - 200, - 105, - 250, - 56, - 185, - 324, - 183, - 212, - 145, - 254, - 240, - 18, - 385, - 328, - 356, - 391, - 299, - 233, - 299, - 48, - 181, - 88, - 32, - 143, - 306, - 150, - 247, - 96, - 103, - 187, - 3, - 340, - 14, - 368, - 50, - 307, - 181, - 365, - 161, - 212, - 194, - 46, - 38, - 52, - 99, - 292, - 400, - 231, - 163, - 299, - 72, - 383, - 72, - 132, - 136, - 356, - 159, - 271, - 48, - 102, - 322, - 236, - 4, - 218, - 112, - 228, - 357, - 86, - 45, - 97, - 46, - 58, - 384, - 304, - 96, - 316, - 22, - 82, - 132, - 111, - 103, - 17, - 385, - 270, - 191, - 148, - 258, - 318, - 302, - 35, - 384, - 336, - 393, - 131, - 261, - 373, - 314, - 164, - 281, - 272, - 321, - 24, - 136, - 180, - 319, - 240, - 339, - 228, - 83, - 15, - 157, - 30, - 337, - 354, - 395, - 22, - 345, - 33, - 264, - 235, - 332, - 239, - 303, - 12, - 143, - 45, - 251, - 233, - 146, - 155, - 177, - 214, - 347, - 217, - 278, - 248, - 230, - 264, - 279, - 255, - 107, - 17, - 242, - 117, - 27, - 219, - 398, - 42, - 179, - 254, - 337, - 137, - 164, - 131, - 339, - 363, - 131, - 112, - 104, - 174, - 92, - 384, - 144, - 258, - 53, - 246, - 110, - 244, - 201, - 180, - 303, - 94, - 1, - 370, - 212, - 274, - 180, - 138, - 315, - 190, - 337, - 179, - 87, - 189, - 101, - 74, - 16, - 314, - 141, - 193, - 107, - 137, - 220, - 96, - 121, - 374, - 178, - 320, - 338, - 344, - 69, - 331, - 364, - 97, - 35, - 163, - 210, - 367, - 178, - 305, - 28, - 187, - 235, - 124, - 380, - 189, - 26, - 83, - 392, - 162, - 108, - 274, - 248, - 286, - 150, - 199, - 79, - 64, - 344, - 370, - 293, - 171, - 152, - 227, - 284, - 192, - 384, - 291, - 254, - 224, - 34, - 322, - 351, - 324, - 196, - 239, - 327, - 398, - 107, - 64, - 311, - 8, - 284, - 47, - 19, - 118, - 123, - 104, - 182, - 329, - 335, - 325, - 58, - 143, - 192, - 206, - 335, - 375, - 328, - 20, - 268, - 331, - 245, - 134, - 30, - 355, - 208, - 23, - 170, - 115, - 68, - 73, - 120, - 390, - 13, - 352, - 336, - 205, - 211, - 248, - 312, - 256, - 243, - 47, - 248, - 160, - 11, - 276, - 309, - 200, - 240, - 51, - 59, - 349, - 380, - 93, - 53, - 34, - 277, - 79, - 115, - 183, - 366, - 170, - 188, - 327, - 176, - 234, - 262, - 253, - 13, - 162, - 192, - 261, - 262, - 177, - 214, - 110, - 181, - 395, - 199, - 365, - 93, - 4, - 393, - 79, - 40, - 227, - 96, - 107, - 165, - 382, - 231, - 73, - 274, - 160, - 295, - 192, - 196, - 141, - 67, - 336, - 32, - 175, - 276, - 63, - 250, - 18, - 16, - 218, - 84, - 399, - 155, - 57, - 134, - 368, - 87, - 134, - 128, - 88, - 209, - 268, - 212, - 56, - 210, - 94, - 42, - 205, - 51, - 302, - 280, - 359, - 306, - 298, - 16, - 210, - 158, - 254, - 7, - 253, - 150, - 195, - 106, - 137, - 188, - 280, - 242, - 399, - 36, - 10, - 382, - 241, - 329, - 334, - 297, - 365, - 22, - 5, - 324, - 10, - 396, - 177, - 223, - 272, - 68, - 29, - 240, - 97, - 140, - 75, - 247, - 18, - 61, - 71, - 186, - 271, - 21, - 131, - 235, - 203, - 310, - 74, - 351, - 347, - 389, - 192, - 379, - 384, - 322, - 58, - 258, - 324, - 143, - 18, - 252, - 16, - 150, - 151, - 142, - 183, - 215, - 32, - 42, - 124, - 371, - 261, - 106, - 218, - 257, - 178, - 62, - 237, - 30, - 32, - 210, - 132, - 229, - 293, - 284, - 133, - 359, - 311, - 51, - 139, - 257, - 58, - 244, - 142, - 208, - 147, - 25, - 391, - 179, - 375, - 303, - 25, - 289, - 188, - 267, - 40, - 394, - 292, - 272, - 35, - 206, - 220, - 173, - 351, - 305, - 347, - 362, - 274, - 390, - 133, - 93, - 40, - 3, - 398, - 53, - 110, - 154, - 157, - 189, - 385, - 166, - 191, - 2, - 213, - 46, - 170, - 255, - 341, - 361, - 168, - 189, - 208, - 17, - 198, - 2, - 152, - 394, - 200, - 4, - 61, - 200, - 107, - 302, - 8, - 185, - 10, - 371, - 150, - 276, - 395, - 63, - 156, - 269, - 333, - 358, - 27, - 351, - 18, - 329, - 188, - 323, - 355, - 360, - 244, - 205, - 187, - 300, - 175, - 138, - 269, - 351, - 29, - 301, - 6, - 13, - 228, - 337, - 238, - 173, - 100, - 78, - 96, - 51, - 40, - 181, - 303, - 141, - 172, - 233, - 350, - 86, - 348, - 266, - 331, - 322, - 270, - 397, - 200, - 41, - 113, - 331, - 213, - 159, - 22, - 340, - 228, - 274, - 239, - 43, - 324, - 296, - 351, - 115, - 29, - 363, - 12, - 141, - 350, - 337, - 317, - 65, - 332, - 396, - 138, - 145, - 155, - 49, - 96, - 271, - 148, - 23, - 23, - 287, - 184, - 218, - 77, - 284, - 85, - 144, - 200, - 15, - 77, - 218, - 130, - 32, - 367, - 29, - 380, - 365, - 120, - 1, - 332, - 372, - 128, - 306, - 34, - 398, - 218, - 141, - 343, - 329, - 131, - 251, - 309, - 347, - 143, - 211, - 168, - 316, - 100, - 86, - 113, - 153, - 62, - 260, - 288, - 378, - 49, - 143, - 166, - 102, - 111, - 15, - 294, - 42, - 6, - 312, - 228, - 364, - 23, - 176, - 372, - 286, - 331, - 356, - 274, - 374, - 252, - 350, - 54, - 13, - 240, - 93, - 52, - 101, - 399, - 10, - 195, - 361, - 17, - 284, - 315, - 141, - 53, - 289, - 311, - 206, - 98, - 48, - 331, - 145, - 256, - 67, - 240, - 206, - 340, - 310, - 260, - 266, - 241, - 35, - 183, - 343, - 193, - 156, - 165, - 280, - 168, - 389, - 241, - 32, - 42, - 67, - 319, - 91, - 2, - 298, - 396, - 265, - 139, - 52, - 236, - 113, - 85, - 208, - 134, - 303, - 282, - 291, - 362, - 40, - 283, - 224, - 183, - 256, - 385, - 157, - 193, - 317, - 364, - 91, - 381, - 265, - 238, - 52, - 120, - 347, - 201, - 246, - 101, - 318, - 29, - 278, - 264, - 188, - 133, - 140, - 185, - 201, - 257, - 69, - 282, - 380, - 252, - 249, - 193, - 322, - 44, - 30, - 124, - 216, - 77, - 215, - 127, - 328, - 339, - 173, - 155, - 251, - 189, - 76, - 65, - 325, - 354, - 44, - 280, - 280, - 288, - 189, - 334, - 139, - 59, - 158, - 230, - 152, - 339, - 367, - 373, - 393, - 359, - 329, - 292, - 150, - 256, - 343, - 140, - 59, - 24, - 297, - 324, - 334, - 265, - 92, - 13, - 388, - 392, - 193, - 379, - 323, - 178, - 236, - 197, - 323, - 169, - 54, - 372, - 25, - 30, - 87, - 132, - 345, - 135, - 389, - 70, - 39, - 102, - 158, - 260, - 197, - 129, - 360, - 87, - 288, - 20, - 256, - 184, - 150, - 272, - 264, - 53, - 131, - 328, - 99, - 172, - 223, - 124, - 255, - 399, - 275, - 311, - 399, - 152, - 283, - 107, - 40, - 258, - 361, - 393, - 58, - 365, - 182, - 57, - 345, - 348, - 42, - 251, - 387, - 106, - 237, - 35, - 371, - 279, - 66, - 362, - 213, - 42, - 9, - 297, - 288, - 292, - 325, - 367, - 31, - 175, - 72, - 377, - 358, - 142, - 360, - 399, - 64, - 213, - 303, - 44, - 140, - 215, - 249, - 322, - 267, - 117, - 366, - 74, - 55, - 71, - 38, - 253, - 367, - 113, - 196, - 166, - 72, - 328, - 172, - 389, - 89, - 353, - 19, - 163, - 392, - 93, - 16, - 35, - 353, - 78, - 282, - 355, - 273, - 269, - 342, - 194, - 21, - 301, - 57, - 148, - 47, - 235, - 126, - 52, - 304, - 345, - 250, - 2, - 62, - 346, - 94, - 129, - 91, - 216, - 384, - 366, - 70, - 124, - 200, - 331, - 204, - 240, - 189, - 41, - 389, - 305, - 32, - 103, - 121, - 351, - 252, - 216, - 33, - 296, - 83, - 13, - 120, - 130, - 381, - 247, - 89, - 363, - 367, - 32, - 255, - 134, - 16, - 62, - 99, - 31, - 383, - 76, - 202, - 396, - 199, - 149, - 389, - 245, - 211, - 11, - 262, - 391, - 122, - 56, - 90, - 307, - 167, - 120, - 75, - 284, - 294, - 89, - 58, - 374, - 331, - 249, - 21, - 185, - 244, - 267, - 231, - 122, - 342, - 205, - 282, - 308, - 149, - 134, - 146, - 145, - 51, - 27, - 335, - 91, - 3, - 116, - 51, - 339, - 131, - 193, - 57, - 33, - 145, - 238, - 198, - 53, - 398, - 278, - 212, - 41, - 165, - 290, - 40, - 233, - 384, - 84, - 133, - 160, - 218, - 381, - 254, - 296, - 359, - 298, - 9, - 132, - 260, - 43, - 250, - 310, - 348, - 109, - 245, - 117, - 357, - 288, - 300, - 293, - 218, - 389, - 381, - 6, - 65, - 237, - 220, - 255, - 41, - 77, - 254, - 289, - 233, - 173, - 400, - 66, - 72, - 69, - 10, - 198, - 174, - 316, - 28, - 110, - 370, - 205, - 98, - 323, - 218, - 248, - 32, - 199, - 259, - 254, - 171, - 260, - 76, - 184, - 398, - 23, - 218, - 261, - 52, - 39, - 314, - 258, - 345, - 200, - 396, - 367, - 396, - 90, - 160, - 322, - 395, - 370, - 206, - 300, - 50, - 109, - 277, - 13, - 304, - 24, - 169, - 287, - 287, - 91, - 92, - 150, - 137, - 331, - 240, - 232, - 235, - 227, - 293, - 250, - 80, - 3, - 399, - 167, - 196, - 354, - 211, - 251, - 145, - 356, - 104, - 343, - 168, - 320, - 122, - 296, - 151, - 317, - 350, - 334, - 318, - 194, - 18, - 183, - 370, - 29, - 132, - 222, - 275, - 222, - 323, - 73, - 275, - 396, - 151, - 218, - 342, - 176, - 15, - 285, - 352, - 250, - 317, - 213, - 387, - 274, - 126, - 103, - 100, - 147, - 207, - 34, - 331, - 202, - 371, - 360, - 337, - 340, - 289, - 369, - 220, - 399, - 333, - 167, - 9, - 286, - 349, - 95, - 195, - 385, - 223, - 366, - 155, - 103, - 326, - 352, - 136, - 38, - 368, - 400, - 41, - 279, - 27, - 211, - 318, - 50, - 25, - 73, - 141, - 341, - 221, - 184, - 169, - 246, - 338, - 101, - 238, - 247, - 92, - 181, - 332, - 204, - 246, - 132, - 321, - 360, - 335, - 331, - 73, - 210, - 317, - 243, - 222, - 132, - 68, - 112, - 198, - 399, - 80, - 130, - 172, - 378, - 260, - 341, - 89, - 27, - 4, - 189, - 80, - 119, - 282, - 221, - 53, - 263, - 133, - 295, - 195, - 327, - 315, - 226, - 52, - 311, - 297, - 315, - 371, - 85, - 142, - 74, - 252, - 251, - 314, - 249, - 373, - 320, - 121, - 193, - 1, - 187, - 316, - 127, - 141, - 154, - 193, - 152, - 359, - 270, - 326, - 391, - 225, - 37, - 368, - 71, - 367, - 7, - 25, - 274, - 389, - 361, - 241, - 250, - 366, - 101, - 267, - 41, - 363, - 37, - 146, - 338, - 210, - 139, - 168, - 68, - 355, - 347, - 302, - 395, - 115, - 185, - 304, - 158, - 325, - 162, - 186, - 363, - 269, - 320, - 202, - 360, - 88, - 79, - 56, - 377, - 280, - 303, - 317, - 346, - 175, - 80, - 27, - 138, - 395, - 180, - 341, - 88, - 55, - 186, - 68, - 317, - 364, - 368, - 69, - 178, - 261, - 92, - 248, - 55, - 236, - 333, - 52, - 92, - 250, - 87, - 17, - 36, - 362, - 3, - 321, - 362, - 15, - 211, - 187, - 153, - 231, - 381, - 92, - 337, - 372, - 277, - 63, - 358, - 327, - 79, - 135, - 284, - 149, - 340, - 27, - 196, - 368, - 264, - 17, - 140, - 211, - 203, - 31, - 55, - 61, - 11, - 121, - 308, - 393, - 385, - 194, - 185, - 376, - 168, - 316, - 293, - 252, - 62, - 54, - 204, - 386, - 359, - 378, - 54, - 30, - 133, - 54, - 351, - 275, - 46, - 148, - 351, - 207, - 257, - 398, - 147, - 296, - 37, - 188, - 111, - 201, - 26, - 386, - 321, - 145, - 81, - 310, - 132, - 296, - 230, - 295, - 188, - 128, - 16, - 228, - 44, - 39, - 52, - 156, - 20, - 97, - 35, - 285, - 142, - 327, - 213, - 338, - 79, - 229, - 399, - 238, - 385, - 139, - 325, - 1, - 121, - 150, - 189, - 77, - 25, - 258, - 316, - 377, - 58, - 143, - 114, - 374, - 136, - 60, - 157, - 278, - 128, - 383, - 220, - 112, - 328, - 309, - 232, - 344, - 281, - 194, - 84, - 10, - 119, - 105, - 295, - 254, - 251, - 380, - 110, - 105, - 179, - 78, - 225, - 317, - 234, - 150, - 385, - 363, - 185, - 360, - 144, - 39, - 204, - 100, - 344, - 260, - 246, - 76, - 40, - 386, - 303, - 154, - 314, - 82, - 388, - 334, - 37, - 45, - 238, - 133, - 75, - 299, - 102, - 90, - 67, - 330, - 120, - 311, - 276, - 126, - 385, - 385, - 200, - 61, - 386, - 167, - 163, - 124, - 108, - 64, - 307, - 356, - 210, - 255, - 188, - 197, - 56, - 340, - 354, - 26, - 82, - 19, - 305, - 54, - 214, - 82, - 284, - 324, - 246, - 168, - 57, - 31, - 337, - 208, - 247, - 128, - 61, - 267, - 74, - 313, - 133, - 258, - 87, - 88, - 288, - 252, - 157, - 324, - 302, - 33, - 57, - 330, - 112, - 103, - 37, - 217, - 365, - 75, - 170, - 121, - 289, - 341, - 49, - 6, - 226, - 97, - 348, - 183, - 169, - 305, - 148, - 315, - 119, - 125, - 312, - 266, - 263, - 117, - 225, - 370, - 166, - 307, - 61, - 311, - 393, - 33, - 315, - 267, - 315, - 311, - 140, - 60, - 185, - 166, - 390, - 313, - 276, - 138, - 39, - 254, - 32, - 358, - 200, - 280, - 34, - 263, - 386, - 10, - 250, - 266, - 387, - 15, - 342, - 4, - 249, - 168, - 99, - 365, - 365, - 374, - 59, - 217, - 400, - 85, - 381, - 192, - 312, - 160, - 23, - 194, - 293, - 357, - 31, - 6, - 25, - 208, - 276, - 104, - 316, - 16, - 207, - 41, - 126, - 44, - 359, - 394, - 272, - 394, - 54, - 27, - 86, - 174, - 328, - 322, - 313, - 343, - 313, - 184, - 260, - 287, - 379, - 222, - 368, - 243, - 165, - 230, - 320, - 71, - 355, - 204, - 308, - 279, - 347, - 73, - 262, - 170, - 324, - 336, - 257, - 223, - 352, - 264, - 149, - 56, - 106, - 224, - 80, - 114, - 319, - 337, - 73, - 100, - 99, - 318, - 144, - 308, - 34, - 255, - 289, - 8, - 145, - 187, - 281, - 59, - 257, - 222, - 387, - 29, - 156, - 191, - 217, - 13, - 381, - 261, - 178, - 142, - 46, - 109, - 379, - 167, - 280, - 121, - 40, - 278, - 57, - 249, - 200, - 113, - 300, - 138, - 115, - 330, - 57, - 308, - 313, - 221, - 252, - 19, - 6, - 37, - 45, - 380, - 89, - 37, - 310, - 179, - 97, - 262, - 357, - 38, - 38, - 332, - 233, - 374, - 92, - 29, - 194, - 117, - 345, - 317, - 61, - 123, - 17, - 5, - 237, - 244, - 319, - 100, - 310, - 261, - 320, - 239, - 224, - 129, - 365, - 228, - 109, - 168, - 397, - 158, - 361, - 19, - 265, - 228, - 156, - 292, - 76, - 256, - 273, - 52, - 393, - 50, - 50, - 93, - 356, - 93, - 23, - 161, - 46, - 149, - 283, - 68, - 215, - 267, - 24, - 216, - 334, - 65, - 373, - 142, - 212, - 335, - 160, - 337, - 203, - 394, - 362, - 61, - 219, - 20, - 249, - 15, - 386, - 390, - 360, - 391, - 77, - 25, - 170, - 385, - 45, - 280, - 121, - 229, - 73, - 308, - 32, - 260, - 126, - 156, - 288, - 228, - 52, - 184, - 5, - 385, - 105, - 267, - 134, - 111, - 197, - 339, - 111, - 302, - 84, - 16, - 161, - 302, - 191, - 290, - 254, - 153, - 353, - 361, - 101, - 350, - 139, - 130, - 376, - 380, - 396, - 195, - 32, - 143, - 183, - 41, - 16, - 260, - 313, - 386, - 73, - 216, - 151, - 203, - 334, - 168, - 190, - 355, - 305, - 1, - 312, - 322, - 255, - 53, - 317, - 266, - 271, - 137, - 42, - 117, - 15, - 385, - 112, - 400, - 202, - 7, - 313, - 116, - 154, - 108, - 214, - 296, - 377, - 255, - 297, - 342, - 80, - 29, - 17, - 50, - 365, - 233, - 25, - 90, - 253, - 329, - 248, - 59, - 303, - 28, - 374, - 107, - 96, - 243, - 345, - 272, - 254, - 287, - 297, - 200, - 181, - 350, - 329, - 354, - 339, - 78, - 194, - 30, - 373, - 221, - 18, - 34, - 376, - 276, - 129, - 326, - 348, - 193, - 313, - 39, - 66, - 88, - 153, - 43, - 372, - 76, - 246, - 238, - 322, - 201, - 244, - 179, - 385, - 111, - 60, - 367, - 171, - 73, - 159, - 170, - 373, - 85, - 373, - 268, - 42, - 27, - 82, - 192, - 58, - 345, - 43, - 19, - 137, - 346, - 263, - 47, - 105, - 22, - 110, - 168, - 292, - 80, - 285, - 347, - 304, - 199, - 267, - 398, - 129, - 61, - 223, - 311, - 29, - 217, - 115, - 272, - 253, - 101, - 26, - 246, - 330, - 37, - 201, - 142, - 279, - 151, - 237, - 373, - 282, - 140, - 115, - 171, - 236, - 72, - 307, - 310, - 187, - 257, - 22, - 331, - 378, - 83, - 323, - 370, - 93, - 185, - 359, - 199, - 241, - 260, - 220, - 262, - 335, - 101, - 178, - 247, - 387, - 384, - 12, - 74, - 293, - 49, - 250, - 185, - 1, - 193, - 2, - 91, - 70, - 355, - 194, - 266, - 9, - 218, - 167, - 283, - 293, - 269, - 170, - 284, - 30, - 274, - 201, - 47, - 194, - 175, - 358, - 336, - 134, - 371, - 146, - 297, - 50, - 268, - 16, - 50, - 378, - 150, - 195, - 343, - 23, - 379, - 235, - 316, - 8, - 86, - 313, - 106, - 320, - 62, - 292, - 207, - 398, - 140, - 213, - 335, - 393, - 15, - 158, - 222, - 74, - 357, - 345, - 67, - 310, - 63, - 242, - 136, - 202, - 326, - 357, - 247, - 397, - 330, - 352, - 84, - 344, - 105, - 141, - 202, - 163, - 127, - 64, - 21, - 23, - 16, - 260, - 196, - 80, - 172, - 283, - 256, - 276, - 267, - 324, - 374, - 20, - 200, - 162, - 367, - 375, - 50, - 320, - 90, - 340, - 241, - 216, - 378, - 213, - 223, - 172, - 82, - 167, - 191, - 100, - 179, - 322, - 301, - 195, - 243, - 17, - 385, - 132, - 305, - 143, - 85, - 43, - 24, - 239, - 17, - 44, - 252, - 255, - 66, - 310, - 157, - 178, - 170, - 373, - 14, - 142, - 154, - 47, - 358, - 99, - 189, - 77, - 261, - 39, - 14, - 28, - 302, - 132, - 102, - 365, - 378, - 159, - 186, - 292, - 372, - 181, - 284, - 277, - 187, - 268, - 280, - 282, - 307, - 280, - 358, - 125, - 341, - 138, - 299, - 214, - 273, - 43, - 345, - 321, - 248, - 257, - 49, - 222, - 250, - 261, - 29, - 75, - 355, - 238, - 219, - 18, - 265, - 2, - 158, - 290, - 321, - 285, - 141, - 227, - 392, - 93, - 18, - 24, - 134, - 32, - 41, - 345, - 160, - 258, - 182, - 301, - 229, - 54, - 172, - 39, - 29, - 224, - 175, - 318, - 15, - 226, - 385, - 88, - 55, - 329, - 46, - 255, - 335, - 178, - 176, - 116, - 360, - 300, - 321, - 317, - 327, - 278, - 237, - 107, - 326, - 46, - 84, - 283, - 341, - 95, - 320, - 101, - 40, - 129, - 395, - 45, - 371, - 235, - 16, - 46, - 182, - 34, - 256, - 240, - 78, - 37, - 308, - 143, - 195, - 372, - 73, - 129, - 234, - 17, - 314, - 346, - 391, - 184, - 182, - 15, - 216, - 20, - 208, - 1, - 114, - 144, - 168, - 397, - 121, - 344, - 243, - 382, - 141, - 142, - 3, - 28, - 177, - 219, - 267, - 228, - 170, - 206, - 273, - 34, - 176, - 186, - 68, - 283, - 333, - 273, - 298, - 399, - 65, - 358, - 35, - 248, - 364, - 224, - 134, - 154, - 267, - 230, - 383, - 118, - 96, - 82, - 118, - 322, - 348, - 84, - 260, - 18, - 203, - 7, - 27, - 164, - 298, - 123, - 291, - 286, - 323, - 392, - 311, - 25, - 239, - 56, - 330, - 52, - 306, - 185, - 1, - 320, - 41, - 83, - 253, - 251, - 168, - 368, - 352, - 57, - 184, - 280, - 104, - 5, - 343, - 108, - 294, - 341, - 279, - 299, - 10, - 195, - 129, - 102, - 358, - 235, - 56, - 56, - 17, - 348, - 262, - 221, - 321, - 364, - 234, - 221, - 25, - 209, - 203, - 399, - 72, - 114, - 110, - 362, - 390, - 369, - 185, - 31, - 261, - 37, - 345, - 211, - 308, - 310, - 206, - 58, - 30, - 151, - 302, - 355, - 253, - 386, - 16, - 358, - 380, - 205, - 218, - 146, - 123, - 268, - 220, - 182, - 60, - 128, - 62, - 96, - 25, - 94, - 108, - 288, - 295, - 343, - 10, - 134, - 250, - 62, - 125, - 6, - 295, - 257, - 353, - 279, - 204, - 4, - 300, - 121, - 231, - 73, - 226, - 292, - 155, - 290, - 196, - 221, - 202, - 86, - 8, - 384, - 319, - 170, - 363, - 358, - 26, - 23, - 271, - 195, - 6, - 283, - 275, - 240, - 93, - 320, - 1, - 340, - 287, - 140, - 144, - 58, - 184, - 39, - 128, - 258, - 353, - 116, - 149, - 95, - 379, - 85, - 164, - 275, - 238, - 3, - 356, - 23, - 152, - 372, - 77, - 188, - 37, - 81, - 74, - 336, - 77, - 189, - 283, - 254, - 56, - 267, - 81, - 218, - 202, - 332, - 133, - 358, - 237, - 181, - 213, - 335, - 126, - 66, - 313, - 36, - 138, - 207, - 112, - 164, - 146, - 55, - 290, - 297, - 50, - 39, - 228, - 286, - 190, - 238, - 165, - 74, - 301, - 328, - 302, - 96, - 332, - 131, - 151, - 79, - 340, - 112, - 312, - 56, - 87, - 258, - 131, - 138, - 236, - 335, - 313, - 210, - 325, - 343, - 124, - 255, - 193, - 180, - 392, - 348, - 361, - 314, - 240, - 60, - 163, - 114, - 337, - 162, - 316, - 222, - 47, - 117, - 208, - 366, - 98, - 278, - 375, - 260, - 254, - 91, - 395, - 305, - 390, - 50, - 275, - 155, - 190, - 59, - 3, - 287, - 347, - 149, - 292, - 52, - 187, - 157, - 120, - 176, - 135, - 299, - 361, - 193, - 116, - 223, - 344, - 22, - 165, - 337, - 103, - 117, - 341, - 239, - 32, - 137, - 359, - 72, - 89, - 65, - 149, - 160, - 148, - 73, - 280, - 225, - 113, - 387, - 159, - 287, - 95, - 139, - 351, - 325, - 351, - 44, - 50, - 370, - 96, - 377, - 161, - 382, - 323, - 168, - 324, - 309, - 293, - 128, - 263, - 293, - 262, - 266, - 261, - 71, - 385, - 287, - 237, - 190, - 119, - 41, - 184, - 228, - 222, - 258, - 379, - 152, - 272, - 242, - 321, - 22, - 24, - 353, - 133, - 36, - 214, - 9, - 368, - 254, - 249, - 298, - 216, - 320, - 257, - 347, - 136, - 26, - 263, - 79, - 361, - 285, - 280, - 289, - 96, - 125, - 210, - 143, - 248, - 393, - 225, - 324, - 305, - 21, - 378, - 333, - 247, - 297, - 369, - 244, - 373, - 197, - 271, - 164, - 373, - 75, - 195, - 321, - 62, - 63, - 240, - 81, - 172, - 219, - 189, - 47, - 75, - 238, - 258, - 36, - 38, - 24, - 35, - 43, - 52, - 25, - 69, - 111, - 255, - 294, - 396, - 50, - 2, - 203, - 164, - 86, - 164, - 70, - 284, - 24, - 254, - 358, - 36, - 158, - 24, - 72, - 201, - 160, - 182, - 190, - 4, - 171, - 49, - 344, - 260, - 319, - 398, - 332, - 25, - 126, - 296, - 317, - 329, - 271, - 344, - 392, - 386, - 334, - 140, - 45, - 166, - 363, - 234, - 146, - 254, - 113, - 168, - 313, - 383, - 107, - 175, - 138, - 149, - 252, - 121, - 250, - 334, - 291, - 208, - 388, - 111, - 112, - 87, - 39, - 207, - 205, - 173, - 310, - 96, - 252, - 121, - 27, - 360, - 205, - 357, - 337, - 373, - 380, - 177, - 91, - 278, - 189, - 294, - 338, - 324, - 37, - 343, - 354, - 129, - 42, - 374, - 259, - 354, - 135, - 333, - 84, - 228, - 280, - 99, - 244, - 297, - 172, - 263, - 237, - 180, - 240, - 117, - 178, - 22, - 327, - 4, - 109, - 306, - 140, - 182, - 178, - 2, - 4, - 78, - 233, - 325, - 13, - 188, - 231, - 356, - 379, - 377, - 114, - 76, - 82, - 96, - 234, - 365, - 173, - 343, - 101, - 38, - 138, - 175, - 298, - 91, - 150, - 44, - 218, - 239, - 167, - 157, - 81, - 197, - 91, - 63, - 313, - 102, - 151, - 377, - 77, - 138, - 215, - 337, - 257, - 353, - 233, - 388, - 342, - 343, - 10, - 309, - 122, - 40, - 323, - 377, - 352, - 337, - 65, - 173, - 78, - 135, - 364, - 141, - 36, - 191, - 62, - 202, - 53, - 366, - 63, - 326, - 254, - 12, - 55, - 247, - 361, - 190, - 162, - 395, - 19, - 52, - 220, - 6, - 326, - 227, - 8, - 102, - 334, - 358, - 284, - 69, - 216, - 173, - 128, - 58, - 205, - 213, - 84, - 290, - 34, - 379, - 24, - 275, - 222, - 129, - 128, - 384, - 327, - 303, - 138, - 61, - 106, - 124, - 255, - 378, - 194, - 137, - 99, - 357, - 258, - 371, - 131, - 200, - 55, - 71, - 239, - 289, - 343, - 141, - 237, - 112, - 5, - 39, - 32, - 231, - 309, - 37, - 175, - 199, - 45, - 227, - 241, - 332, - 223, - 318, - 310, - 395, - 219, - 275, - 109, - 272, - 187, - 34, - 114, - 311, - 8, - 249, - 55, - 118, - 333, - 53, - 214, - 340, - 133, - 229, - 103, - 154, - 251, - 265, - 153, - 12, - 293, - 108, - 209, - 334, - 277, - 57, - 366, - 36, - 339, - 25, - 135, - 40, - 240, - 271, - 315, - 13, - 390, - 100, - 380, - 26, - 162, - 80, - 88, - 390, - 371, - 339, - 239, - 200, - 115, - 120, - 106, - 59, - 98, - 240, - 15, - 32, - 91, - 108, - 95, - 52, - 275, - 160, - 195, - 98, - 53, - 399, - 59, - 388, - 317, - 337, - 252, - 209, - 68, - 348, - 375, - 18, - 120, - 259, - 248, - 248, - 2, - 35, - 375, - 39, - 23, - 355, - 233, - 31, - 371, - 388, - 319, - 335, - 242, - 374, - 77, - 381, - 251, - 243, - 389, - 262, - 190, - 117, - 324, - 218, - 397, - 263, - 386, - 80, - 360, - 223, - 192, - 177, - 207, - 148, - 75, - 368, - 73, - 395, - 236, - 163, - 230, - 134, - 162, - 262, - 48, - 331, - 162, - 201, - 68, - 209, - 192, - 272, - 331, - 390, - 298, - 227, - 323, - 43, - 297, - 144, - 262, - 64, - 272, - 241, - 137, - 187, - 58, - 336, - 157, - 373, - 66, - 217, - 257, - 336, - 259, - 82, - 77, - 166, - 185, - 385, - 172, - 106, - 309, - 297, - 213, - 377, - 212, - 225, - 239, - 320, - 288, - 316, - 3, - 227, - 154, - 99, - 208, - 210, - 289, - 338, - 226, - 362, - 37, - 250, - 164, - 313, - 315, - 68, - 165, - 386, - 189, - 140, - 103, - 399, - 397, - 229, - 238, - 105, - 100, - 155, - 181, - 310, - 191, - 338, - 314, - 36, - 228, - 293, - 151, - 232, - 170, - 155, - 374, - 272, - 386, - 256, - 331, - 348, - 400, - 165, - 164, - 108, - 320, - 320, - 80, - 131, - 156, - 66, - 83, - 334, - 362, - 327, - 286, - 301, - 300, - 22, - 253, - 108, - 120, - 289, - 118, - 77, - 164, - 124, - 208, - 19, - 45, - 98, - 310, - 338, - 223, - 109, - 398, - 341, - 362, - 25, - 305, - 104, - 181, - 94, - 50, - 353, - 36, - 205, - 96, - 72, - 354, - 281, - 326, - 304, - 395, - 328, - 377, - 188, - 10, - 91, - 185, - 337, - 341, - 392, - 324, - 130, - 193, - 263, - 131, - 258, - 245, - 235, - 14, - 202, - 356, - 155, - 284, - 225, - 372, - 72, - 145, - 290, - 258, - 142, - 233, - 9, - 130, - 245, - 286, - 116, - 132, - 348, - 63, - 335, - 245, - 232, - 38, - 214, - 127, - 246, - 302, - 241, - 176, - 277, - 264, - 22, - 85, - 120, - 172, - 91, - 55, - 52, - 221, - 118, - 355, - 137, - 182, - 209, - 376, - 228, - 47, - 291, - 229, - 384, - 126, - 234, - 267, - 364, - 345, - 250, - 64, - 296, - 35, - 150, - 196, - 381, - 142, - 5, - 122, - 337, - 109, - 183, - 272, - 4, - 191, - 243, - 134, - 36, - 49, - 84, - 377, - 22, - 188, - 89, - 286, - 77, - 160, - 77, - 192, - 331, - 99, - 148, - 34, - 187, - 219, - 339, - 180, - 368, - 110, - 159, - 172, - 125, - 101, - 364, - 156, - 239, - 304, - 349, - 56, - 123, - 225, - 348, - 357, - 47, - 126, - 166, - 165, - 144, - 74, - 51, - 79, - 199, - 45, - 153, - 27, - 225, - 299, - 135, - 387, - 175, - 4, - 347, - 398, - 10, - 358, - 226, - 269, - 307, - 347, - 72, - 196, - 17, - 55, - 96, - 346, - 75, - 196, - 223, - 266, - 299, - 209, - 385, - 146, - 68, - 348, - 395, - 324, - 84, - 256, - 126, - 182, - 75, - 218, - 57, - 217, - 145, - 75, - 283, - 396, - 367, - 290, - 12, - 120, - 261, - 21, - 115, - 39, - 26, - 399, - 62, - 204, - 220, - 300, - 396, - 380, - 129, - 244, - 357, - 362, - 286, - 40, - 29, - 109, - 270, - 86, - 376, - 5, - 24, - 47, - 388, - 123, - 252, - 189, - 137, - 375, - 16, - 148, - 391, - 279, - 396, - 322, - 145, - 123, - 219, - 305, - 272, - 188, - 107, - 376, - 315, - 370, - 251, - 58, - 302, - 17, - 156, - 322, - 376, - 37, - 72, - 43, - 292, - 166, - 398, - 258, - 328, - 261, - 58, - 393, - 43, - 245, - 26, - 130, - 319, - 346, - 35, - 197, - 69, - 131, - 378, - 47, - 231, - 245, - 31, - 188, - 27, - 300, - 20, - 363, - 306, - 225, - 120, - 86, - 219, - 19, - 79, - 105, - 267, - 344, - 284, - 314, - 108, - 202, - 242, - 148, - 46, - 365, - 20, - 226, - 376, - 265, - 148, - 38, - 122, - 267, - 241, - 235, - 398, - 133, - 208, - 238, - 214, - 181, - 124, - 310, - 27, - 156, - 99, - 201, - 16, - 339, - 64, - 134, - 77, - 44, - 157, - 284, - 182, - 29, - 107, - 69, - 161, - 31, - 327, - 82, - 5, - 285, - 377, - 246, - 267, - 244, - 139, - 63, - 238, - 57, - 228, - 200, - 305, - 104, - 389, - 79, - 152, - 201, - 380, - 246, - 383, - 10, - 100, - 304, - 204, - 92, - 104, - 302, - 354, - 33, - 31, - 239, - 273, - 208, - 77, - 366, - 373, - 154, - 123, - 103, - 319, - 71, - 155, - 247, - 106, - 46, - 186, - 78, - 181, - 120, - 280, - 308, - 217, - 288, - 33, - 122, - 241, - 376, - 343, - 190, - 374, - 182, - 154, - 186, - 205, - 192, - 184, - 298, - 115, - 62, - 2, - 324, - 183, - 368, - 198, - 113, - 299, - 67, - 178, - 40, - 131, - 292, - 92, - 368, - 370, - 399, - 200, - 33, - 187, - 245, - 327, - 359, - 17, - 166, - 34, - 340, - 244, - 178, - 240, - 71, - 104, - 74, - 286, - 292, - 384, - 242, - 229, - 166, - 127, - 190, - 184, - 166, - 288, - 252, - 317, - 81, - 32, - 77, - 231, - 204, - 277, - 347, - 345, - 79, - 14, - 261, - 84, - 242, - 111, - 274, - 157, - 315, - 248, - 352, - 66, - 243, - 212, - 83, - 218, - 261, - 126, - 10, - 134, - 135, - 7, - 281, - 166, - 253, - 358, - 108, - 382, - 235, - 271, - 143, - 139, - 286, - 32, - 228, - 387, - 242, - 190, - 177, - 318, - 122, - 354, - 100, - 76, - 160, - 274, - 382, - 114, - 163, - 78, - 55, - 101, - 153, - 130, - 292, - 285, - 291, - 152, - 107, - 11, - 57, - 117, - 173, - 6, - 110, - 182, - 350, - 325, - 195, - 139, - 301, - 210, - 102, - 35, - 195, - 272, - 272, - 393, - 12, - 215, - 97, - 91, - 308, - 162, - 395, - 273, - 244, - 278, - 246, - 327, - 293, - 80, - 265, - 282, - 318, - 268, - 52, - 93, - 294, - 156, - 36, - 184, - 374, - 172, - 291, - 64, - 327, - 208, - 67, - 346, - 228, - 393, - 121, - 387, - 307, - 263, - 392, - 98, - 231, - 294, - 340, - 308, - 270, - 81, - 171, - 160, - 331, - 141, - 204, - 26, - 348, - 33, - 81, - 203, - 24, - 333, - 21, - 351, - 359, - 219, - 203, - 272, - 61, - 321, - 267, - 35, - 225, - 98, - 346, - 253, - 122, - 307, - 20, - 152, - 128, - 121, - 307, - 47, - 74, - 221, - 367, - 339, - 290, - 329, - 313, - 330, - 103, - 369, - 66, - 60, - 169, - 52, - 368, - 90, - 392, - 213, - 45, - 103, - 98, - 125, - 124, - 269, - 74, - 147, - 157, - 78, - 279, - 48, - 396, - 96, - 27, - 384, - 124, - 385, - 132, - 299, - 178, - 98, - 343, - 226, - 277, - 69, - 276, - 208, - 325, - 353, - 369, - 290, - 103, - 301, - 166, - 252, - 202, - 33, - 293, - 195, - 151, - 388, - 345, - 184, - 91, - 8, - 120, - 160, - 23, - 229, - 211, - 169, - 278, - 364, - 78, - 279, - 391, - 351, - 37, - 364, - 249, - 17, - 117, - 55, - 60, - 327, - 178, - 206, - 307, - 70, - 31, - 377, - 400, - 269, - 1, - 274, - 169, - 141, - 174, - 326, - 72, - 257, - 244, - 196, - 78, - 384, - 312, - 229, - 331, - 39, - 85, - 235, - 88, - 165, - 219, - 234, - 31, - 303, - 388, - 364, - 271, - 144, - 376, - 129, - 11, - 199, - 12, - 376, - 178, - 130, - 80, - 53, - 345, - 299, - 15, - 23, - 178, - 189, - 9, - 36, - 288, - 326, - 119, - 20, - 197, - 204, - 329, - 149, - 311, - 143, - 223, - 213, - 242, - 379, - 50, - 55, - 76, - 362, - 308, - 221, - 226, - 27, - 88, - 165, - 315, - 85, - 327, - 168, - 251, - 57, - 3, - 231, - 128, - 392, - 347, - 160, - 386, - 69, - 135, - 377, - 197, - 83, - 339, - 28, - 83, - 117, - 347, - 44, - 234, - 180, - 166, - 69, - 48, - 233, - 252, - 237, - 73, - 58, - 60, - 188, - 98, - 294, - 30, - 39, - 364, - 138, - 160, - 282, - 100, - 167, - 195, - 37, - 76, - 244, - 293, - 290, - 34, - 99, - 315, - 377, - 262, - 173, - 400, - 161, - 5, - 160, - 27, - 337, - 271, - 128, - 2, - 327, - 312, - 163, - 52, - 322, - 329, - 284, - 374, - 99, - 29, - 237, - 124, - 8, - 325, - 293, - 222, - 16, - 242, - 50, - 383, - 94, - 322, - 225, - 155, - 309, - 111, - 169, - 376, - 201, - 94, - 299, - 163, - 167, - 362, - 152, - 194, - 326, - 332, - 305, - 193, - 227, - 120, - 340, - 325, - 294, - 263, - 130, - 262, - 152, - 332, - 25, - 161, - 46, - 337, - 229, - 21, - 170, - 365, - 259, - 23, - 1, - 299, - 374, - 310, - 285, - 243, - 391, - 11, - 129, - 75, - 286, - 140, - 357, - 315, - 390, - 256, - 237, - 245, - 283, - 194, - 338, - 25, - 100, - 188, - 233, - 172, - 158, - 266, - 333, - 77, - 356, - 358, - 241, - 74, - 41, - 46, - 136, - 7, - 283, - 302, - 271, - 23, - 151, - 85, - 209, - 252, - 340, - 166, - 318, - 128, - 75, - 114, - 321, - 69, - 74, - 83, - 62, - 108, - 377, - 86, - 232, - 345, - 225, - 328, - 35, - 268, - 105, - 287, - 181, - 135, - 27, - 48, - 382, - 359, - 144, - 336, - 50, - 3, - 321, - 389, - 313, - 291, - 1, - 363, - 231, - 156, - 185, - 384, - 394, - 245, - 208, - 23, - 385, - 166, - 301, - 165, - 63, - 194, - 83, - 209, - 320, - 229, - 381, - 169, - 182, - 79, - 110, - 20, - 354, - 266, - 26, - 216, - 268, - 303, - 1, - 222, - 135, - 297, - 45, - 313, - 130, - 54, - 242, - 9, - 354, - 370, - 105, - 396, - 205, - 38, - 224, - 131, - 207, - 317, - 225, - 344, - 242, - 241, - 271, - 239, - 42, - 110, - 367, - 257, - 9, - 279, - 107, - 310, - 276, - 322, - 293, - 44, - 99, - 22, - 278, - 137, - 258, - 111, - 221, - 335, - 321, - 153, - 382, - 97, - 58, - 64, - 105, - 170, - 168, - 196, - 136, - 349, - 33, - 57, - 360, - 224, - 133, - 323, - 310, - 292, - 309, - 146, - 35, - 106, - 87, - 202, - 127, - 355, - 156, - 398, - 116, - 281, - 136, - 241, - 231, - 315, - 62, - 301, - 398, - 259, - 247, - 187, - 208, - 15, - 215, - 233, - 124, - 157, - 210, - 279, - 256, - 400, - 102, - 353, - 400, - 392, - 293, - 63, - 131, - 236, - 105, - 307, - 275, - 204, - 169, - 303, - 191, - 397, - 204, - 158, - 341, - 229, - 131, - 244, - 58, - 331, - 368, - 55, - 270, - 162, - 258, - 232, - 237, - 190, - 108, - 105, - 391, - 371, - 304, - 378, - 29, - 201, - 163, - 232, - 317, - 36, - 396, - 318, - 179, - 374, - 286, - 254, - 273, - 251, - 62, - 155, - 41, - 212, - 51, - 380, - 292, - 145, - 331, - 14, - 367, - 306, - 230, - 299, - 157, - 387, - 356, - 181, - 249, - 361, - 376, - 256, - 340, - 111, - 376, - 91, - 76, - 89, - 119, - 67, - 398, - 139, - 378, - 82, - 202, - 91, - 179, - 115, - 215, - 136, - 393, - 245, - 159, - 195, - 400, - 153, - 262, - 187, - 374, - 255, - 98, - 392, - 128, - 266, - 5, - 19, - 121, - 324, - 309, - 274, - 320, - 56, - 398, - 327, - 4, - 330, - 231, - 95, - 96, - 279, - 252, - 297, - 122, - 70, - 18, - 39, - 300, - 61, - 230, - 8, - 293, - 139, - 198, - 282, - 366, - 57, - 241, - 188, - 86, - 276, - 140, - 380, - 119, - 200, - 207, - 153, - 51, - 256, - 322, - 63, - 78, - 158, - 361, - 5, - 264, - 189, - 279, - 162, - 64, - 347, - 383, - 66, - 7, - 110, - 117, - 52, - 74, - 103, - 168, - 181, - 395, - 90, - 317, - 21, - 244, - 78, - 328, - 208, - 195, - 227, - 353, - 340, - 37, - 66, - 118, - 341, - 326, - 148, - 349, - 327, - 28, - 287, - 317, - 178, - 379, - 382, - 186, - 40, - 204, - 344, - 334, - 352, - 383, - 154, - 213, - 108, - 94, - 291, - 313, - 400, - 255, - 173, - 238, - 252, - 31, - 296, - 212, - 267, - 223, - 63, - 138, - 377, - 364, - 178, - 200, - 201, - 215, - 175, - 370, - 90, - 372, - 7, - 77, - 114, - 226, - 368, - 22, - 48, - 228, - 51, - 323, - 103, - 24, - 257, - 164, - 11, - 394, - 99, - 349, - 99, - 20, - 61, - 89, - 47, - 275, - 355, - 69, - 115, - 49, - 274, - 212, - 142, - 41, - 97, - 8, - 281, - 231, - 156, - 260, - 303, - 14, - 200, - 184, - 303, - 146, - 157, - 94, - 193, - 154, - 367, - 360, - 156, - 35, - 182, - 235, - 262, - 295, - 392, - 146, - 115, - 355, - 282, - 131, - 348, - 64, - 361, - 257, - 362, - 287, - 283, - 243, - 330, - 73, - 178, - 357, - 185, - 98, - 318, - 299, - 102, - 268, - 88, - 36, - 227, - 166, - 153, - 317, - 107, - 64, - 3, - 7, - 70, - 175, - 17, - 198, - 158, - 195, - 354, - 261, - 51, - 176, - 296, - 138, - 144, - 288, - 13, - 299, - 325, - 274, - 187, - 33, - 253, - 391, - 349, - 127, - 167, - 124, - 263, - 85, - 49, - 246, - 278, - 361, - 6, - 7, - 286, - 145, - 116, - 126, - 106, - 285, - 103, - 86, - 85, - 30, - 176, - 72, - 253, - 199, - 88, - 216, - 163, - 69, - 217, - 376, - 256, - 82, - 385, - 361, - 116, - 193, - 195, - 394, - 151, - 258, - 182, - 43, - 286, - 109, - 110, - 1, - 176, - 78, - 371, - 219, - 192, - 329, - 50, - 168, - 203, - 214, - 128, - 361, - 250, - 263, - 177, - 337, - 143, - 8, - 178, - 325, - 122, - 204, - 90, - 287, - 398, - 322, - 368, - 176, - 391, - 31, - 358, - 260, - 288, - 30, - 224, - 125, - 362, - 400, - 81, - 74, - 15, - 52, - 209, - 219, - 28, - 182, - 132, - 193, - 183, - 356, - 337, - 315, - 67, - 229, - 102, - 274, - 334, - 391, - 90, - 58, - 162, - 249, - 139, - 109, - 275, - 159, - 246, - 260, - 392, - 138, - 169, - 70, - 83, - 352, - 328, - 110, - 251, - 375, - 153, - 171, - 176, - 393, - 298, - 34, - 89, - 202, - 314, - 246, - 250, - 367, - 10, - 126, - 309, - 42, - 201, - 351, - 41, - 98, - 265, - 6, - 160, - 30, - 112, - 205, - 219, - 356, - 24, - 57, - 224, - 44, - 168, - 143, - 225, - 106, - 192, - 65, - 65, - 8, - 84, - 244, - 394, - 71, - 5, - 307, - 106, - 48, - 66, - 21, - 294, - 235, - 257, - 6, - 203, - 179, - 372, - 161, - 174, - 187, - 359, - 9, - 251, - 318, - 400, - 356, - 301, - 245, - 362, - 305, - 179, - 345, - 134, - 25, - 306, - 361, - 228, - 210, - 239, - 297, - 247, - 203, - 248, - 190, - 138, - 311, - 79, - 232, - 330, - 37, - 157, - 332, - 247, - 151, - 255, - 91, - 1, - 39, - 313, - 369, - 10, - 75, - 292, - 122, - 311, - 311, - 272, - 312, - 212, - 372, - 351, - 80, - 70, - 33, - 9, - 355, - 17, - 290, - 196, - 2, - 181, - 174, - 106, - 3, - 259, - 228, - 247, - 59, - 257, - 154, - 144, - 367, - 78, - 249, - 357, - 246, - 115, - 229, - 241, - 303, - 240, - 197, - 3, - 106, - 363, - 243, - 257, - 79, - 330, - 82, - 148, - 264, - 103, - 205, - 120, - 83, - 207, - 132, - 215, - 293, - 59, - 79, - 88, - 322, - 299, - 390, - 358, - 160, - 360, - 112, - 231, - 18, - 298, - 334, - 223, - 224, - 198, - 244, - 22, - 357, - 114, - 23, - 257, - 387, - 240, - 115, - 351, - 255, - 74, - 104, - 56, - 284, - 105, - 121, - 63, - 127, - 186, - 323, - 233, - 93, - 396, - 45, - 254, - 375, - 188, - 168, - 326, - 221, - 357, - 347, - 289, - 172, - 220, - 361, - 370, - 288, - 149, - 324, - 240, - 325, - 233, - 244, - 129, - 82, - 183, - 108, - 318, - 10, - 84, - 394, - 162, - 194, - 38, - 223, - 204, - 379, - 264, - 354, - 333, - 212, - 126, - 298, - 226, - 191, - 3, - 206, - 32, - 58, - 385, - 278, - 114, - 12, - 271, - 304, - 171, - 59, - 131, - 10, - 267, - 167, - 142, - 1, - 389, - 333, - 344, - 175, - 25, - 295, - 17, - 21, - 110, - 83, - 238, - 319, - 98, - 148, - 288, - 236, - 126, - 87, - 395, - 28, - 200, - 77, - 53, - 138, - 387, - 314, - 4, - 68, - 180, - 23, - 14, - 42, - 303, - 138, - 58, - 325, - 142, - 91, - 186, - 209, - 169, - 162, - 194, - 192, - 239, - 45, - 48, - 6, - 107, - 15, - 109, - 248, - 396, - 114, - 376, - 377, - 399, - 374, - 276, - 56, - 181, - 156, - 320, - 229, - 284, - 59, - 342, - 293, - 117, - 176, - 107, - 264, - 174, - 334, - 197, - 149, - 380, - 216, - 30, - 133, - 166, - 319, - 222, - 328, - 39, - 393, - 144, - 126, - 126, - 217, - 168, - 194, - 226, - 86, - 148, - 12, - 17, - 257, - 108, - 275, - 157, - 273, - 184, - 1, - 276, - 342, - 12, - 110, - 379, - 158, - 73, - 323, - 188, - 114, - 246, - 125, - 41, - 349, - 60, - 40, - 228, - 104, - 88, - 231, - 28, - 280, - 164, - 76, - 196, - 84, - 326, - 149, - 19, - 69, - 142, - 59, - 290, - 385, - 311, - 243, - 324, - 107, - 163, - 63, - 213, - 255, - 191, - 186, - 2, - 300, - 253, - 369, - 254, - 247, - 150, - 50, - 242, - 253, - 77, - 239, - 361, - 92, - 330, - 8, - 374, - 315, - 193, - 15, - 165, - 194, - 111, - 153, - 159, - 207, - 82, - 146, - 21, - 397, - 161, - 150, - 240, - 29, - 77, - 371, - 60, - 27, - 11, - 291, - 261, - 30, - 289, - 369, - 139, - 32, - 158, - 257, - 307, - 293, - 9, - 155, - 228, - 187, - 369, - 393, - 331, - 88, - 160, - 324, - 267, - 31, - 330, - 226, - 387, - 20, - 376, - 394, - 298, - 231, - 138, - 57, - 152, - 253, - 157, - 31, - 287, - 62, - 380, - 79, - 92, - 195, - 367, - 124, - 217, - 8, - 22, - 255, - 202, - 359, - 261, - 138, - 230, - 229, - 156, - 103, - 182, - 235, - 184, - 310, - 330, - 105, - 47, - 141, - 297, - 319, - 283, - 160, - 174, - 342, - 1, - 84, - 229, - 286, - 82, - 40, - 391, - 57, - 216, - 314, - 383, - 344, - 4, - 296, - 353, - 182, - 218, - 354, - 135, - 280, - 378, - 109, - 337, - 10, - 298, - 189, - 209, - 150, - 162, - 388, - 262, - 37, - 239, - 145, - 13, - 137, - 309, - 221, - 201, - 391, - 156, - 17, - 153, - 112, - 273, - 210, - 395, - 136, - 234, - 390, - 173, - 206, - 225, - 132, - 227, - 279, - 330, - 13, - 81, - 262, - 336, - 339, - 365, - 395, - 273, - 293, - 122, - 35, - 208, - 216, - 357, - 143, - 7, - 240, - 151, - 220, - 361, - 64, - 89, - 279, - 180, - 155, - 353, - 178, - 390, - 383, - 39, - 70, - 360, - 34, - 221, - 98, - 99, - 178, - 282, - 257, - 268, - 348, - 61, - 186, - 317, - 189, - 376, - 290, - 140, - 173, - 88, - 83, - 9, - 383, - 321, - 382, - 290, - 392, - 398, - 200, - 248, - 17, - 175, - 67, - 53, - 371, - 62, - 131, - 25, - 330, - 54, - 254, - 157, - 214, - 31, - 76, - 229, - 245, - 114, - 259, - 125, - 353, - 78, - 120, - 336, - 138, - 160, - 212, - 184, - 105, - 146, - 136, - 149, - 40, - 361, - 209, - 204, - 297, - 232, - 142, - 294, - 343, - 180, - 241, - 48, - 80, - 354, - 267, - 78, - 307, - 221, - 4, - 34, - 15, - 100, - 126, - 274, - 319, - 82, - 338, - 237, - 120, - 132, - 232, - 193, - 50, - 338, - 124, - 339, - 129, - 335, - 253, - 146, - 126, - 78, - 163, - 187, - 84, - 205, - 396, - 296, - 279, - 143, - 381, - 285, - 110, - 182, - 135, - 241, - 298, - 157, - 4, - 343, - 161, - 181, - 373, - 226, - 87, - 378, - 26, - 340, - 382, - 22, - 329, - 174, - 83, - 333, - 13, - 228, - 335, - 166, - 298, - 303, - 115, - 274, - 181, - 351, - 378, - 311, - 68, - 152, - 84, - 87, - 266, - 143, - 394, - 12, - 110, - 123, - 242, - 294, - 325, - 90, - 219, - 201, - 93, - 71, - 20, - 181, - 235, - 346, - 385, - 158, - 199, - 91, - 306, - 107, - 318, - 380, - 96, - 346, - 193, - 385, - 365, - 136, - 99, - 283, - 103, - 298, - 170, - 245, - 140, - 145, - 74, - 374, - 381, - 61, - 312, - 251, - 352, - 252, - 299, - 382, - 272, - 280, - 43, - 395, - 26, - 10, - 400, - 50, - 70, - 164, - 220, - 183, - 221, - 374, - 355, - 330, - 169, - 136, - 318, - 23, - 234, - 381, - 184, - 344, - 299, - 289, - 369, - 265, - 263, - 252, - 244, - 398, - 247, - 315, - 168, - 235, - 233, - 141, - 4, - 251, - 201, - 166, - 158, - 16, - 365, - 238, - 52, - 93, - 197, - 88, - 284, - 288, - 116, - 33, - 392, - 164, - 204, - 75, - 343, - 248, - 260, - 258, - 319, - 277, - 166, - 179, - 35, - 287, - 214, - 263, - 48, - 23, - 297, - 273, - 355, - 237, - 127, - 162, - 33, - 142, - 92, - 236, - 144, - 307, - 108, - 72, - 305, - 358, - 79, - 91, - 47, - 54, - 400, - 235, - 193, - 80, - 104, - 235, - 380, - 292, - 120, - 201, - 145, - 209, - 47, - 149, - 193, - 159, - 302, - 181, - 322, - 250, - 205, - 49, - 115, - 149, - 121, - 164, - 316, - 345, - 278, - 338, - 69, - 178, - 66, - 145, - 348, - 395, - 168, - 227, - 233, - 272, - 218, - 122, - 44, - 349, - 257, - 173, - 197, - 109, - 248, - 152, - 345, - 271, - 21, - 334, - 280, - 167, - 130, - 105, - 272, - 115, - 22, - 284, - 274, - 9, - 214, - 272, - 157, - 277, - 82, - 357, - 264, - 100, - 369, - 336, - 260, - 355, - 103, - 158, - 163, - 209, - 61, - 11, - 199, - 188, - 113, - 167, - 378, - 324, - 186, - 361, - 24, - 146, - 172, - 67, - 259, - 288, - 37, - 61, - 253, - 342, - 152, - 8, - 83, - 50, - 391, - 283, - 106, - 196, - 180, - 92, - 187, - 219, - 345, - 369, - 382, - 316, - 89, - 313, - 251, - 318, - 67, - 326, - 321, - 148, - 247, - 31, - 117, - 359, - 388, - 215, - 127, - 318, - 233, - 327, - 265, - 376, - 301, - 8, - 207, - 245, - 23, - 369, - 201, - 8, - 289, - 345, - 259, - 329, - 311, - 241, - 283, - 3, - 361, - 243, - 155, - 110, - 389, - 396, - 349, - 43, - 204, - 64, - 337, - 248, - 201, - 86, - 38, - 304, - 204, - 365, - 233, - 200, - 330, - 198, - 359, - 313, - 147, - 116, - 243, - 7, - 120, - 365, - 66, - 381, - 377, - 222, - 58, - 344, - 385, - 236, - 250, - 183, - 247, - 319, - 164, - 60, - 258, - 39, - 337, - 398, - 78, - 2, - 5, - 341, - 149, - 273, - 194, - 103, - 76, - 161, - 149, - 82, - 279, - 68, - 178, - 268, - 338, - 21, - 228, - 117, - 389, - 48, - 22, - 91, - 300, - 199, - 253, - 358, - 338, - 340, - 74, - 354, - 275, - 262, - 13, - 58, - 52, - 62, - 263, - 224, - 242, - 306, - 87, - 355, - 38, - 44, - 85, - 217, - 135, - 33, - 357, - 29, - 214, - 24, - 312, - 341, - 209, - 303, - 103, - 8, - 112, - 31, - 203, - 311, - 367, - 65, - 118, - 47, - 262, - 59, - 247, - 59, - 18, - 199, - 192, - 80, - 242, - 253, - 359, - 226, - 247, - 25, - 185, - 198, - 337, - 70, - 377, - 366, - 206, - 373, - 357, - 329, - 316, - 290, - 293, - 300, - 67, - 222, - 148, - 76, - 24, - 31, - 41, - 303, - 244, - 210, - 130, - 306, - 368, - 335, - 180, - 303, - 305, - 392, - 68, - 213, - 309, - 148, - 279, - 89, - 255, - 394, - 6, - 162, - 308, - 257, - 290, - 161, - 105, - 362, - 147, - 22, - 351, - 248, - 332, - 173, - 37, - 193, - 11, - 105, - 125, - 70, - 228, - 322, - 74, - 246, - 91, - 315, - 381, - 332, - 374, - 198, - 11, - 222, - 383, - 267, - 143, - 46, - 180, - 183, - 236, - 258, - 16, - 3, - 102, - 4, - 386, - 143, - 113, - 322, - 200, - 61, - 164, - 81, - 18, - 21, - 152, - 252, - 279, - 269, - 82, - 205, - 183, - 91, - 108, - 15, - 61, - 342, - 126, - 181, - 318, - 394, - 16, - 52, - 151, - 91, - 188, - 359, - 126, - 212, - 3, - 14, - 163, - 342, - 67, - 304, - 242, - 97, - 240, - 292, - 228, - 1, - 289, - 328, - 18, - 266, - 29, - 123, - 135, - 79, - 143, - 162, - 210, - 211, - 307, - 199, - 175, - 214, - 214, - 366, - 10, - 378, - 47, - 61, - 148, - 17, - 254, - 389, - 302, - 164, - 185, - 124, - 136, - 379, - 291, - 34, - 130, - 370, - 141, - 171, - 263, - 348, - 381, - 184, - 126, - 338, - 245, - 356, - 14, - 90, - 265, - 150, - 229, - 137, - 38, - 189, - 180, - 67, - 156, - 27, - 30, - 298, - 286, - 1, - 85, - 43, - 155, - 26, - 6, - 61, - 44, - 203, - 352, - 293, - 112, - 224, - 360, - 184, - 276, - 177, - 196, - 166, - 348, - 27, - 397, - 245, - 389, - 66, - 396, - 18, - 214, - 330, - 81, - 3, - 352, - 108, - 323, - 28, - 265, - 37, - 274, - 221, - 355, - 64, - 159, - 270, - 62, - 59, - 187, - 63, - 316, - 39, - 62, - 13, - 151, - 63, - 364, - 380, - 330, - 329, - 22, - 146, - 36, - 141, - 62, - 24, - 294, - 130, - 290, - 254, - 112, - 308, - 155, - 88, - 374, - 328, - 363, - 137, - 274, - 280, - 303, - 154, - 2, - 296, - 29, - 99, - 266, - 138, - 48, - 223, - 89, - 75, - 91, - 229, - 309, - 234, - 13, - 219, - 219, - 7, - 385, - 225, - 273, - 87, - 326, - 317, - 371, - 168, - 294, - 25, - 328, - 345, - 183, - 173, - 291, - 390, - 267, - 383, - 121, - 263, - 58, - 111, - 331, - 331, - 369, - 138, - 109, - 17, - 29, - 192, - 394, - 155, - 353, - 71, - 37, - 251, - 168, - 351, - 385, - 82, - 100, - 196, - 228, - 243, - 189, - 90, - 278, - 327, - 90, - 273, - 56, - 321, - 259, - 377, - 157, - 160, - 7, - 221, - 228, - 72, - 275, - 20, - 358, - 18, - 240, - 335, - 199, - 171, - 372, - 11, - 201, - 277, - 112, - 138, - 55, - 115, - 179, - 192, - 328, - 316, - 128, - 114, - 170, - 387, - 25, - 350, - 319, - 312, - 271, - 181, - 265, - 112, - 322, - 385, - 82, - 139, - 344, - 105, - 100, - 303, - 217, - 161, - 296, - 267, - 374, - 163, - 292, - 227, - 396, - 112, - 104, - 126, - 36, - 67, - 226, - 353, - 220, - 69, - 83, - 294, - 271, - 156, - 148, - 16, - 198, - 181, - 254, - 114, - 277, - 173, - 104, - 228, - 76, - 100, - 195, - 166, - 112, - 331, - 326, - 257, - 400, - 296, - 248, - 126, - 200, - 328, - 328, - 85, - 216, - 81, - 331, - 124, - 87, - 339, - 87, - 381, - 343, - 299, - 396, - 338, - 262, - 144, - 54, - 69, - 299, - 197, - 256, - 388, - 155, - 42, - 283, - 175, - 304, - 273, - 338, - 353, - 44, - 229, - 163, - 354, - 159, - 118, - 368, - 367, - 345, - 59, - 38, - 94, - 103, - 73, - 394, - 155, - 329, - 146, - 43, - 114, - 276, - 45, - 4, - 260, - 313, - 117, - 229, - 71, - 248, - 2, - 384, - 135, - 39, - 321, - 328, - 94, - 385, - 210, - 351, - 128, - 127, - 24, - 46, - 61, - 379, - 30, - 142, - 130, - 147, - 149, - 5, - 275, - 246, - 246, - 93, - 49, - 298, - 200, - 337, - 344, - 320, - 2, - 101, - 260, - 353, - 161, - 205, - 95, - 171, - 397, - 78, - 205, - 216, - 54, - 47, - 278, - 352, - 193, - 295, - 135, - 331, - 116, - 83, - 154, - 265, - 308, - 48, - 363, - 45, - 10, - 3, - 190, - 78, - 267, - 260, - 67, - 247, - 179, - 9, - 231, - 243, - 15, - 36, - 14, - 359, - 320, - 303, - 172, - 266, - 166, - 257, - 130, - 267, - 317, - 119, - 102, - 306, - 114, - 38, - 112, - 192, - 208, - 284, - 107, - 33, - 249, - 238, - 161, - 146, - 341, - 351, - 152, - 60, - 318, - 340, - 240, - 326, - 163, - 198, - 230, - 170, - 331, - 12, - 194, - 122, - 125, - 386, - 398, - 314, - 291, - 337, - 398, - 4, - 25, - 143, - 367, - 208, - 383, - 171, - 375, - 147, - 63, - 292, - 157, - 314, - 303, - 2, - 370, - 117, - 144, - 247, - 35, - 38, - 267, - 7, - 81, - 82, - 338, - 123, - 180, - 207, - 319, - 259, - 129, - 329, - 281, - 384, - 283, - 217, - 223, - 394, - 72, - 215, - 304, - 325, - 383, - 364, - 180, - 3, - 158, - 105, - 181, - 209, - 400, - 344, - 62, - 233, - 155, - 225, - 174, - 282, - 225, - 87, - 168, - 184, - 60, - 104, - 231, - 344, - 77, - 69, - 63, - 106, - 63, - 102, - 255, - 363, - 126, - 134, - 212, - 319, - 336, - 32, - 164, - 96, - 87, - 118, - 196, - 36, - 206, - 333, - 315, - 394, - 201, - 99, - 199, - 126, - 113, - 229, - 155, - 375, - 114, - 16, - 74, - 181, - 347, - 265, - 105, - 54, - 121, - 305, - 297, - 179, - 204, - 373, - 377, - 392, - 242, - 322, - 193, - 228, - 385, - 119, - 79, - 305, - 90, - 243, - 332, - 285, - 7, - 37, - 8, - 30, - 294, - 267, - 112, - 205, - 149, - 165, - 196, - 189, - 78, - 346, - 385, - 136, - 112, - 315, - 375, - 376, - 284, - 213, - 202, - 319, - 18, - 121, - 62, - 140, - 232, - 25, - 385, - 369, - 271, - 345, - 321, - 14, - 352, - 83, - 163, - 43, - 257, - 213, - 8, - 176, - 339, - 91, - 101, - 332, - 334, - 248, - 360, - 49, - 16, - 313, - 352, - 88, - 328, - 180, - 294, - 6, - 51, - 334, - 40, - 290, - 69, - 144, - 316, - 340, - 380, - 13, - 167, - 356, - 317, - 379, - 285, - 321, - 370, - 378, - 97, - 187, - 14, - 340, - 236, - 14, - 157, - 202, - 197, - 126, - 349, - 254, - 392, - 288, - 171, - 46, - 7, - 234, - 222, - 41, - 199, - 153, - 82, - 270, - 317, - 323, - 378, - 320, - 392, - 346, - 299, - 271, - 124, - 201, - 375, - 269, - 52, - 246, - 392, - 34, - 298, - 70, - 272, - 78, - 232, - 86, - 338, - 93, - 127, - 218, - 227, - 113, - 39, - 203, - 66, - 51, - 306, - 89, - 242, - 115, - 133, - 226, - 278, - 266, - 135, - 202, - 127, - 314, - 156, - 32, - 26, - 265, - 222, - 110, - 361, - 275, - 361, - 343, - 63, - 225, - 55, - 76, - 386, - 82, - 112, - 10, - 85, - 174, - 310, - 68, - 201, - 344, - 353, - 94, - 122, - 309, - 392, - 396, - 67, - 112, - 225, - 120, - 374, - 119, - 38, - 40, - 17, - 303, - 201, - 1, - 282, - 328, - 277, - 330, - 393, - 90, - 298, - 199, - 21, - 196, - 363, - 244, - 396, - 36, - 336, - 245, - 313, - 158, - 59, - 376, - 155, - 157, - 28, - 205, - 314, - 192, - 342, - 181, - 325, - 388, - 78, - 399, - 343, - 11, - 52, - 400, - 70, - 47, - 162, - 42, - 15, - 209, - 228, - 330, - 305, - 190, - 285, - 389, - 204, - 221, - 289, - 159, - 377, - 148, - 186, - 87, - 188, - 344, - 116, - 320, - 400, - 223, - 70, - 311, - 20, - 166, - 145, - 189, - 45, - 205, - 122, - 245, - 393, - 340, - 230, - 64, - 279, - 170, - 350, - 154, - 206, - 319, - 370, - 316, - 262, - 326, - 396, - 317, - 329, - 262, - 327, - 282, - 197, - 80, - 299, - 353, - 321, - 124, - 121, - 11, - 245, - 317, - 368, - 189, - 221, - 322, - 382, - 159, - 104, - 135, - 155, - 325, - 241, - 183, - 214, - 85, - 211, - 170, - 168, - 327, - 389, - 94, - 157, - 235, - 385, - 335, - 271, - 236, - 22, - 290, - 220, - 163, - 391, - 224, - 140, - 116, - 268, - 309, - 126, - 89, - 220, - 187, - 252, - 277, - 111, - 263, - 297, - 262, - 92, - 51, - 89, - 228, - 400, - 109, - 156, - 233, - 131, - 115, - 394, - 210, - 161, - 243, - 66, - 150, - 359, - 213, - 368, - 98, - 214, - 335, - 332, - 220, - 26, - 209, - 44, - 280, - 282, - 386, - 24, - 213, - 197, - 352, - 5, - 10, - 42, - 2, - 101, - 36, - 208, - 137, - 247, - 397, - 162, - 344, - 26, - 366, - 25, - 271, - 218, - 188, - 75, - 11, - 24, - 45, - 129, - 384, - 134, - 326, - 23, - 193, - 291, - 15, - 62, - 168, - 364, - 345, - 208, - 291, - 112, - 141, - 202, - 17, - 270, - 154, - 61, - 104, - 19, - 98, - 95, - 202, - 225, - 42, - 244, - 15, - 149, - 171, - 270, - 120, - 341, - 302, - 393, - 275, - 34, - 226, - 152, - 94, - 199, - 392, - 251, - 188, - 340, - 389, - 393, - 216, - 87, - 111, - 359, - 114, - 46, - 165, - 333, - 266, - 358, - 74, - 363, - 134, - 168, - 388, - 145, - 184, - 366, - 376, - 89, - 277, - 259, - 374, - 25, - 346, - 107, - 139, - 42, - 212, - 208, - 129, - 319, - 298, - 275, - 58, - 376, - 93, - 207, - 351, - 268, - 282, - 213, - 125, - 81, - 243, - 238, - 246, - 347, - 188, - 166, - 126, - 110, - 214, - 265, - 234, - 395, - 343, - 119, - 108, - 303, - 4, - 306, - 307, - 196, - 86, - 345, - 112, - 81, - 390, - 297, - 80, - 104, - 212, - 234, - 132, - 316, - 136, - 102, - 83, - 276, - 393, - 29, - 164, - 334, - 386, - 171, - 242, - 246, - 65, - 175, - 333, - 73, - 54, - 173, - 138, - 203, - 260, - 381, - 163, - 196, - 283, - 123, - 169, - 106, - 316, - 156, - 222, - 126, - 115, - 299, - 391, - 251, - 391, - 246, - 330, - 195, - 263, - 238, - 242, - 197, - 62, - 71, - 140, - 312, - 282, - 76, - 105, - 219, - 368, - 240, - 15, - 41, - 53, - 135, - 134, - 207, - 371, - 388, - 82, - 311, - 184, - 147, - 11, - 86, - 293, - 279, - 58, - 258, - 400, - 321, - 330, - 100, - 182, - 28, - 50, - 31, - 166, - 163, - 94, - 172, - 206, - 47, - 191, - 242, - 112, - 313, - 75, - 362, - 187, - 116, - 295, - 332, - 387, - 23, - 183, - 296, - 65, - 228, - 251, - 289, - 161, - 340, - 274, - 214, - 56, - 75, - 36, - 379, - 23, - 211, - 329, - 71, - 80, - 350, - 86, - 107, - 174, - 104, - 367, - 80, - 269, - 273, - 273, - 46, - 331, - 374, - 154, - 135, - 330, - 41, - 82, - 206, - 348, - 118, - 61, - 36, - 315, - 189, - 371, - 218, - 223, - 130, - 1, - 18, - 113, - 73, - 134, - 118, - 17, - 33, - 15, - 266, - 379, - 145, - 185, - 379, - 180, - 75, - 208, - 21, - 327, - 163, - 359, - 193, - 286, - 354, - 205, - 102, - 336, - 394, - 133, - 89, - 178, - 84, - 9, - 151, - 71, - 261, - 283, - 207, - 379, - 99, - 155, - 108, - 374, - 96, - 331, - 363, - 146, - 115, - 246, - 342, - 327, - 176, - 358, - 234, - 104, - 158, - 351, - 350, - 339, - 114, - 88, - 202, - 349, - 217, - 277, - 196, - 16, - 268, - 168, - 202, - 129, - 175, - 22, - 323, - 105, - 143, - 241, - 30, - 215, - 172, - 45, - 22, - 284, - 86, - 20, - 374, - 160, - 244, - 392, - 265, - 319, - 86, - 347, - 188, - 130, - 179, - 136, - 27, - 189, - 288, - 234, - 253, - 19, - 217, - 265, - 127, - 316, - 161, - 37, - 84, - 376, - 382, - 181, - 195, - 85, - 13, - 283, - 111, - 238, - 385, - 291, - 394, - 154, - 80, - 140, - 292, - 132, - 56, - 170, - 209, - 327, - 159, - 216, - 87, - 63, - 123, - 239, - 27, - 184, - 340, - 164, - 177, - 296, - 332, - 340, - 164, - 21, - 87, - 256, - 398, - 143, - 236, - 85, - 359, - 114, - 144, - 356, - 295, - 148, - 43, - 204, - 212, - 48, - 156, - 260, - 287, - 173, - 126, - 147, - 354, - 142, - 274, - 66, - 398, - 150, - 274, - 30, - 342, - 28, - 65, - 177, - 363, - 283, - 268, - 199, - 372, - 272, - 176, - 250, - 46, - 344, - 224, - 292, - 346, - 112, - 73, - 341, - 390, - 344, - 43, - 276, - 17, - 327, - 89, - 39, - 42, - 299, - 202, - 289, - 357, - 288, - 122, - 64, - 6, - 54, - 154, - 235, - 336, - 19, - 311, - 41, - 192, - 303, - 347, - 387, - 201, - 132, - 325, - 273, - 202, - 162, - 214, - 90, - 78, - 118, - 273, - 121, - 225, - 36, - 126, - 370, - 258, - 315, - 288, - 323, - 229, - 52, - 351, - 379, - 128, - 391, - 339, - 138, - 73, - 266, - 393, - 99, - 74, - 378, - 109, - 229, - 293, - 366, - 355, - 219, - 377, - 219, - 246, - 353, - 226, - 241, - 375, - 39, - 229, - 188, - 275, - 240, - 115, - 234, - 352, - 22, - 306, - 302, - 317, - 221, - 224, - 140, - 219, - 155, - 166, - 343, - 313, - 326, - 99, - 168, - 79, - 149, - 57, - 144, - 228, - 28, - 38, - 352, - 112, - 16, - 350, - 66, - 158, - 25, - 292, - 376, - 285, - 163, - 43, - 214, - 395, - 15, - 122, - 365, - 4, - 308, - 16, - 13, - 205, - 256, - 335, - 252, - 301, - 149, - 170, - 206, - 121, - 397, - 387, - 174, - 348, - 72, - 233, - 218, - 254, - 139, - 271, - 101, - 321, - 188, - 366, - 86, - 265, - 182, - 350, - 202, - 393, - 160, - 134, - 312, - 206, - 112, - 28, - 301, - 374, - 312, - 104, - 262, - 100, - 104, - 276, - 199, - 90, - 232, - 124, - 363, - 26, - 269, - 188, - 227, - 344, - 380, - 35, - 67, - 161, - 125, - 386, - 358, - 289, - 276, - 25, - 398, - 105, - 334, - 360, - 273, - 293, - 50, - 350, - 94, - 326, - 23, - 380, - 349, - 123, - 132, - 283, - 121, - 211, - 327, - 186, - 146, - 362, - 307, - 31, - 74, - 338, - 177, - 173, - 132, - 336, - 35, - 273, - 46, - 265, - 110, - 262, - 229, - 197, - 166, - 122, - 13, - 289, - 312, - 229, - 58, - 347, - 2, - 49, - 303, - 195, - 69, - 312, - 223, - 319, - 278, - 151, - 97, - 216, - 197, - 295, - 84, - 204, - 179, - 157, - 380, - 224, - 93, - 58, - 287, - 378, - 56, - 37, - 168, - 370, - 33, - 4, - 362, - 347, - 132, - 351, - 163, - 207, - 109, - 214, - 170, - 327, - 383, - 218, - 64, - 105, - 345, - 212, - 318, - 395, - 384, - 237, - 387, - 83, - 203, - 55, - 163, - 226, - 131, - 203, - 260, - 132, - 214, - 16, - 210, - 239, - 25, - 280, - 295, - 363, - 315, - 326, - 274, - 211, - 272, - 202, - 239, - 63, - 357, - 366, - 181, - 267, - 170, - 378, - 318, - 195, - 178, - 97, - 56, - 354, - 96, - 212, - 376, - 138, - 229, - 261, - 32, - 49, - 256, - 52, - 190, - 227, - 164, - 342, - 228, - 393, - 290, - 24, - 95, - 385, - 281, - 304, - 130, - 235, - 150, - 10, - 297, - 396, - 61, - 235, - 87, - 116, - 189, - 5, - 231, - 45, - 303, - 297, - 347, - 271, - 37, - 195, - 223, - 270, - 309, - 247, - 247, - 203, - 294, - 307, - 238, - 313, - 41, - 323, - 290, - 84, - 391, - 368, - 160, - 236, - 337, - 61, - 85, - 141, - 54, - 48, - 62, - 168, - 245, - 163, - 66, - 323, - 173, - 145, - 184, - 198, - 154, - 347, - 366, - 284, - 257, - 32, - 281, - 344, - 387, - 18, - 196, - 65, - 52, - 233, - 388, - 35, - 68, - 362, - 78, - 275, - 84, - 59, - 172, - 13, - 283, - 218, - 14, - 206, - 203, - 100, - 234, - 376, - 364, - 240, - 82, - 101, - 336, - 1, - 182, - 354, - 385, - 365, - 154, - 390, - 302, - 239, - 46, - 345, - 353, - 107, - 329, - 292, - 145, - 300, - 135, - 320, - 342, - 107, - 349, - 120, - 233, - 55, - 189, - 390, - 201, - 315, - 289, - 310, - 291, - 315, - 196, - 15, - 92, - 326, - 89, - 196, - 286, - 19, - 265, - 370, - 394, - 67, - 138, - 281, - 98, - 201, - 309, - 154, - 37, - 266, - 32, - 345, - 130, - 98, - 250, - 263, - 24, - 315, - 326, - 375, - 362, - 347, - 85, - 50, - 241, - 344, - 67, - 241, - 302, - 162, - 377, - 179, - 80, - 73, - 155, - 75, - 55, - 35, - 273, - 175, - 370, - 234, - 273, - 57, - 91, - 74, - 8, - 44, - 28, - 118, - 356, - 190, - 359, - 243, - 388, - 273, - 381, - 332, - 12, - 106, - 250, - 155, - 70, - 361, - 15, - 124, - 321, - 337, - 44, - 353, - 35, - 247, - 22, - 84, - 301, - 297, - 132, - 225, - 66, - 105, - 348, - 133, - 212, - 152, - 328, - 79, - 49, - 223, - 121, - 74, - 126, - 320, - 67, - 374, - 228, - 173, - 17, - 236, - 12, - 117, - 218, - 192, - 346, - 370, - 138, - 266, - 270, - 391, - 167, - 132, - 233, - 207, - 162, - 65, - 251, - 14, - 173, - 72, - 191, - 165, - 38, - 8, - 204, - 204, - 376, - 203, - 105, - 182, - 336, - 121, - 20, - 69, - 275, - 254, - 40, - 149, - 343, - 197, - 262, - 21, - 259, - 330, - 246, - 383, - 43, - 325, - 46, - 40, - 338, - 262, - 116, - 75, - 266, - 2, - 389, - 90, - 29, - 101, - 244, - 363, - 58, - 3, - 68, - 137, - 195, - 344, - 105, - 113, - 378, - 19, - 107, - 208, - 83, - 250, - 201, - 238, - 283, - 135, - 372, - 74, - 200, - 159, - 216, - 334, - 29, - 108, - 156, - 303, - 300, - 55, - 37, - 366, - 225, - 323, - 181, - 217, - 388, - 143, - 313, - 369, - 81, - 389, - 128, - 139, - 179, - 222, - 110, - 154, - 166, - 5, - 95, - 294, - 339, - 277, - 171, - 320, - 105, - 216, - 374, - 266, - 8, - 78, - 296, - 119, - 367, - 95, - 357, - 180, - 175, - 43, - 7, - 15, - 348, - 26, - 116, - 327, - 321, - 19, - 297, - 62, - 377, - 112, - 175, - 240, - 1, - 178, - 3, - 90, - 149, - 377, - 103, - 296, - 40, - 22, - 43, - 232, - 212, - 343, - 228, - 276, - 68, - 140, - 112, - 314, - 72, - 7, - 274, - 163, - 252, - 153, - 388, - 304, - 218, - 73, - 107, - 246, - 145, - 200, - 211, - 22, - 85, - 197, - 326, - 200, - 373, - 310, - 263, - 86, - 13, - 388, - 309, - 246, - 248, - 305, - 388, - 304, - 165, - 221, - 303, - 397, - 56, - 245, - 246, - 48, - 87, - 266, - 108, - 56, - 144, - 140, - 93, - 245, - 256, - 97, - 226, - 273, - 347, - 165, - 212, - 228, - 207, - 169, - 305, - 371, - 186, - 334, - 396, - 244, - 100, - 352, - 358, - 326, - 339, - 270, - 396, - 301, - 284, - 11, - 177, - 191, - 126, - 68, - 227, - 33, - 366, - 298, - 359, - 193, - 122, - 393, - 122, - 203, - 30, - 303, - 194, - 392, - 151, - 366, - 31, - 293, - 174, - 53, - 26, - 218, - 85, - 136, - 306, - 113, - 10, - 61, - 173, - 48, - 56, - 97, - 70, - 146, - 399, - 283, - 50, - 278, - 366, - 185, - 35, - 323, - 13, - 344, - 144, - 141, - 33, - 279, - 89, - 383, - 267, - 101, - 396, - 337, - 247, - 341, - 224, - 376, - 360, - 9, - 196, - 136, - 104, - 376, - 263, - 383, - 3, - 124, - 314, - 136, - 23, - 46, - 346, - 318, - 338, - 249, - 270, - 205, - 145, - 179, - 232, - 245, - 228, - 230, - 50, - 263, - 119, - 7, - 240, - 2, - 149, - 158, - 120, - 175, - 163, - 63, - 25, - 16, - 263, - 219, - 340, - 339, - 186, - 128, - 29, - 354, - 195, - 387, - 145, - 121, - 184, - 268, - 344, - 9, - 87, - 242, - 355, - 309, - 99, - 220, - 131, - 247, - 82, - 101, - 373, - 220, - 119, - 373, - 332, - 125, - 264, - 247, - 118, - 307, - 305, - 303, - 348, - 275, - 60, - 325, - 154, - 189, - 374, - 374, - 58, - 365, - 353, - 257, - 372, - 315, - 352, - 259, - 312, - 395, - 320, - 181, - 125, - 206, - 195, - 161, - 322, - 389, - 398, - 113, - 77, - 376, - 162, - 8, - 350, - 14, - 298, - 48, - 217, - 217, - 33, - 86, - 224, - 239, - 206, - 35, - 321, - 330, - 287, - 89, - 7, - 134, - 191, - 149, - 274, - 228, - 229, - 108, - 372, - 313, - 237, - 211, - 178, - 101, - 396, - 55, - 86, - 137, - 61, - 118, - 67, - 336, - 327, - 88, - 317, - 32, - 385, - 275, - 164, - 331, - 286, - 49, - 66, - 242, - 20, - 141, - 11, - 313, - 313, - 2, - 324, - 128, - 172, - 282, - 199, - 384, - 313, - 148, - 73, - 200, - 366, - 75, - 260, - 133, - 299, - 269, - 29, - 399, - 355, - 358, - 174, - 102, - 169, - 194, - 343, - 174, - 170, - 171, - 80, - 395, - 329, - 147, - 64, - 328, - 372, - 364, - 228, - 357, - 151, - 85, - 95, - 185, - 345, - 307, - 300, - 312, - 237, - 125, - 132, - 164, - 392, - 70, - 400, - 67, - 126, - 155, - 317, - 57, - 54, - 276, - 146, - 184, - 137, - 107, - 376, - 362, - 6, - 95, - 273, - 327, - 100, - 110, - 352, - 90, - 144, - 288, - 323, - 126, - 200, - 400, - 220, - 59, - 34, - 289, - 354, - 118, - 241, - 148, - 199, - 322, - 40, - 312, - 140, - 77, - 112, - 223, - 140, - 13, - 1, - 185, - 388, - 24, - 131, - 398, - 318, - 280, - 63, - 175, - 47, - 134, - 327, - 206, - 52, - 48, - 64, - 194, - 178, - 377, - 55, - 55, - 107, - 265, - 338, - 263, - 27, - 92, - 373, - 357, - 295, - 207, - 324, - 133, - 119, - 151, - 175, - 2, - 77, - 288, - 151, - 116, - 168, - 371, - 245, - 20, - 142, - 174, - 112, - 203, - 98, - 209, - 73, - 328, - 15, - 33, - 40, - 377, - 124, - 370, - 396, - 25, - 215, - 368, - 135, - 133, - 151, - 282, - 80, - 304, - 280, - 67, - 327, - 177, - 333, - 178, - 151, - 146, - 56, - 76, - 312, - 186, - 212, - 132, - 31, - 296, - 141, - 60, - 75, - 209, - 382, - 49, - 179, - 389, - 106, - 146, - 103, - 158, - 300, - 91, - 239, - 221, - 305, - 164, - 148, - 351, - 270, - 121, - 129, - 383, - 296, - 375, - 49, - 259, - 231, - 272, - 275, - 352, - 222, - 339, - 299, - 54, - 20, - 348, - 80, - 332, - 342, - 227, - 27, - 286, - 243, - 162, - 147, - 164, - 1, - 259, - 222, - 398, - 371, - 322, - 178, - 327, - 33, - 319, - 175, - 272, - 351, - 245, - 247, - 55, - 154, - 325, - 300, - 344, - 8, - 207, - 79, - 138, - 76, - 159, - 115, - 3, - 166, - 336, - 235, - 300, - 344, - 89, - 276, - 110, - 117, - 37, - 52, - 370, - 20, - 345, - 290, - 198, - 158, - 127, - 226, - 355, - 239, - 381, - 158, - 51, - 62, - 152, - 355, - 148, - 97, - 108, - 238, - 107, - 127, - 103, - 332, - 77, - 238, - 258, - 211, - 86, - 374, - 172, - 60, - 339, - 309, - 220, - 63, - 387, - 132, - 222, - 369, - 243, - 388, - 64, - 375, - 264, - 212, - 33, - 121, - 187, - 326, - 35, - 154, - 292, - 303, - 337, - 25, - 18, - 307, - 136, - 197, - 241, - 150, - 181, - 335, - 306, - 208, - 388, - 379, - 75, - 133, - 295, - 343, - 86, - 255, - 193, - 126, - 128, - 200, - 307, - 76, - 79, - 145, - 213, - 249, - 24, - 240, - 384, - 245, - 333, - 72, - 145, - 21, - 306, - 86, - 173, - 172, - 211, - 258, - 226, - 235, - 109, - 286, - 169, - 25, - 331, - 125, - 369, - 176, - 370, - 310, - 235, - 390, - 179, - 136, - 223, - 129, - 155, - 337, - 82, - 292, - 111, - 332, - 252, - 3, - 178, - 201, - 31, - 143, - 154, - 3, - 92, - 263, - 171, - 6, - 151, - 251, - 267, - 29, - 157, - 153, - 29, - 155, - 360, - 338, - 81, - 96, - 166, - 93, - 382, - 7, - 176, - 53, - 43, - 393, - 210, - 87, - 3, - 92, - 384, - 148, - 152, - 181, - 378, - 353, - 202, - 196, - 212, - 235, - 246, - 227, - 236, - 304, - 180, - 201, - 336, - 19, - 17, - 185, - 255, - 99, - 133, - 98, - 227, - 72, - 260, - 260, - 1, - 331, - 219, - 41, - 32, - 344, - 335, - 326, - 98, - 42, - 86, - 90, - 282, - 381, - 88, - 34, - 191, - 96, - 147, - 378, - 354, - 218, - 251, - 384, - 240, - 337, - 120, - 364, - 51, - 95, - 159, - 230, - 373, - 52, - 81, - 249, - 194, - 368, - 374, - 108, - 380, - 57, - 66, - 393, - 222, - 300, - 147, - 158, - 391, - 226, - 64, - 347, - 241, - 134, - 274, - 162, - 293, - 167, - 372, - 176, - 390, - 232, - 354, - 250, - 311, - 191, - 329, - 177, - 208, - 88, - 204, - 342, - 364, - 296, - 222, - 339, - 247, - 144, - 372, - 342, - 233, - 83, - 223, - 210, - 330, - 68, - 282, - 171, - 177, - 203, - 264, - 383, - 308, - 341, - 246, - 352, - 55, - 143, - 193, - 319, - 54, - 311, - 237, - 52, - 9, - 391, - 294, - 96, - 47, - 46, - 132, - 312, - 120, - 231, - 68, - 134, - 61, - 326, - 323, - 314, - 393, - 288, - 322, - 177, - 326, - 322, - 244, - 117, - 322, - 253, - 385, - 258, - 296, - 48, - 189, - 2, - 329, - 351, - 237, - 92, - 69, - 105, - 388, - 37, - 399, - 165, - 300, - 268, - 143, - 322, - 299, - 376, - 221, - 363, - 158, - 156, - 224, - 336, - 126, - 51, - 205, - 107, - 56, - 289, - 395, - 312, - 48, - 310, - 384, - 190, - 173, - 332, - 346, - 227, - 362, - 48, - 270, - 387, - 232, - 303, - 113, - 368, - 295, - 278, - 200, - 20, - 181, - 111, - 16, - 185, - 225, - 282, - 350, - 380, - 156, - 20, - 135, - 302, - 199, - 180, - 194, - 15, - 4, - 341, - 106, - 353, - 294, - 300, - 208, - 161, - 332, - 224, - 387, - 285, - 236, - 262, - 294, - 90, - 50, - 65, - 215, - 111, - 5, - 191, - 138, - 168, - 139, - 369, - 325, - 137, - 273, - 399, - 54, - 314, - 75, - 286, - 349, - 36, - 276, - 306, - 129, - 7, - 165, - 103, - 373, - 227, - 376, - 173, - 326, - 378, - 347, - 63, - 280, - 319, - 46, - 325, - 232, - 170, - 322, - 288, - 364, - 218, - 260, - 86, - 95, - 393, - 190, - 76, - 48, - 378, - 136, - 316, - 223, - 83, - 314, - 42, - 398, - 252, - 384, - 90, - 76, - 310, - 100, - 209, - 301, - 317, - 120, - 324, - 137, - 324, - 35, - 167, - 215, - 235, - 331, - 316, - 310, - 192, - 395, - 180, - 375, - 142, - 105, - 213, - 183, - 82, - 330, - 336, - 130, - 162, - 166, - 124, - 28, - 222, - 332, - 322, - 246, - 31, - 184, - 85, - 111, - 126, - 373, - 393, - 343, - 80, - 50, - 140, - 394, - 9, - 14, - 345, - 10, - 180, - 375, - 313, - 266, - 95, - 287, - 52, - 93, - 239, - 57, - 397, - 175, - 250, - 52, - 64, - 317, - 112, - 330, - 370, - 150, - 224, - 248, - 134, - 143, - 11, - 221, - 203, - 266, - 46, - 297, - 105, - 276, - 255, - 39, - 112, - 9, - 344, - 94, - 61, - 299, - 16, - 190, - 112, - 83, - 208, - 173, - 19, - 258, - 392, - 106, - 208, - 103, - 280, - 137, - 127, - 193, - 335, - 287, - 314, - 390, - 69, - 121, - 162, - 285, - 55, - 364, - 96, - 376, - 314, - 90, - 43, - 214, - 208, - 190, - 125, - 188, - 233, - 297, - 320, - 210, - 217, - 8, - 149, - 70, - 183, - 365, - 90, - 147, - 244, - 5, - 168, - 235, - 60, - 153, - 128, - 214, - 94, - 227, - 159, - 218, - 277, - 134, - 119, - 383, - 113, - 190, - 144, - 77, - 75, - 224, - 272, - 84, - 240, - 98, - 394, - 394, - 40, - 69, - 24, - 27, - 266, - 26, - 22, - 33, - 196, - 210, - 63, - 226, - 31, - 132, - 199, - 28, - 35, - 22, - 79, - 80, - 59, - 365, - 309, - 112, - 133, - 38, - 396, - 159, - 385, - 375, - 8, - 393, - 144, - 55, - 254, - 246, - 359, - 316, - 126, - 362, - 213, - 81, - 357, - 385, - 104, - 97, - 168, - 273, - 234, - 42, - 223, - 18, - 387, - 139, - 50, - 399, - 387, - 227, - 134, - 199, - 204, - 151, - 318, - 217, - 2, - 141, - 167, - 110, - 247, - 380, - 257, - 205, - 119, - 5, - 186, - 236, - 249, - 358, - 65, - 203, - 379, - 372, - 288, - 359, - 342, - 50, - 350, - 244, - 248, - 348, - 294, - 189, - 369, - 188, - 64, - 65, - 24, - 43, - 45, - 215, - 386, - 108, - 1, - 222, - 137, - 239, - 295, - 74, - 183, - 134, - 252, - 376, - 379, - 361, - 394, - 165, - 234, - 285, - 158, - 181, - 201, - 282, - 116, - 260, - 246, - 317, - 27, - 15, - 144, - 119, - 246, - 94, - 272, - 35, - 250, - 291, - 97, - 350, - 37, - 308, - 267, - 166, - 248, - 36, - 242, - 91, - 177, - 111, - 278, - 15, - 353, - 268, - 45, - 189, - 151, - 23, - 322, - 235, - 328, - 240, - 156, - 176, - 57, - 247, - 8, - 81, - 186, - 15, - 254, - 97, - 66, - 253, - 143, - 18, - 345, - 37, - 86, - 255, - 3, - 45, - 373, - 306, - 102, - 379, - 44, - 398, - 365, - 224, - 312, - 14, - 1, - 313, - 268, - 35, - 227, - 47, - 291, - 154, - 208, - 230, - 348, - 394, - 5, - 338, - 318, - 355, - 87, - 181, - 248, - 97, - 321, - 290, - 135, - 352, - 113, - 119, - 390, - 136, - 51, - 119, - 43, - 141, - 38, - 75, - 137, - 14, - 356, - 70, - 100, - 73, - 168, - 44, - 290, - 342, - 113, - 82, - 333, - 187, - 70, - 46, - 125, - 320, - 96, - 228, - 252, - 151, - 343, - 21, - 22, - 196, - 28, - 354, - 331, - 257, - 305, - 289, - 30, - 237, - 156, - 250, - 88, - 184, - 32, - 272, - 171, - 27, - 97, - 265, - 337, - 197, - 67, - 339, - 133, - 16, - 216, - 324, - 388, - 248, - 131, - 357, - 135, - 371, - 392, - 290, - 230, - 90, - 254, - 40, - 359, - 309, - 357, - 336, - 334, - 173, - 155, - 282, - 1, - 263, - 155, - 369, - 332, - 100, - 147, - 383, - 65, - 351, - 209, - 105, - 331, - 100, - 270, - 114, - 108, - 128, - 220, - 375, - 141, - 69, - 19, - 278, - 352, - 365, - 250, - 278, - 234, - 141, - 380, - 43, - 169, - 2, - 256, - 329, - 97, - 368, - 32, - 240, - 374, - 373, - 48, - 268, - 386, - 149, - 7, - 46, - 277, - 127, - 243, - 102, - 294, - 80, - 28, - 71, - 328, - 193, - 87, - 346, - 122, - 276, - 392, - 175, - 227, - 163, - 29, - 91, - 157, - 379, - 114, - 220, - 141, - 29, - 207, - 248, - 130, - 22, - 51, - 383, - 172, - 61, - 25, - 28, - 102, - 103, - 134, - 364, - 74, - 126, - 261, - 288, - 87, - 311, - 274, - 388, - 58, - 400, - 184, - 53, - 123, - 170, - 366, - 175, - 277, - 348, - 243, - 322, - 315, - 35, - 50, - 20, - 388, - 213, - 82, - 34, - 53, - 297, - 369, - 3, - 68, - 152, - 119, - 393, - 57, - 220, - 129, - 97, - 171, - 338, - 282, - 195, - 176, - 257, - 277, - 47, - 237, - 332, - 151, - 383, - 185, - 185, - 106, - 161, - 327, - 45, - 265, - 236, - 170, - 252, - 172, - 64, - 298, - 144, - 262, - 389, - 179, - 308, - 126, - 189, - 128, - 20, - 272, - 129, - 60, - 166, - 217, - 147, - 250, - 248, - 325, - 177, - 84, - 347, - 305, - 363, - 177, - 93, - 29, - 377, - 350, - 284, - 109, - 363, - 178, - 237, - 145, - 115, - 59, - 166, - 168, - 76, - 35, - 25, - 357, - 56, - 157, - 157, - 302, - 222, - 80, - 265, - 392, - 110, - 163, - 300, - 33, - 57, - 88, - 29, - 66, - 106, - 75, - 210, - 331, - 23, - 291, - 377, - 385, - 369, - 327, - 106, - 193, - 36, - 213, - 231, - 195, - 22, - 123, - 308, - 50, - 256, - 372, - 388, - 240, - 399, - 251, - 360, - 41, - 21, - 304, - 298, - 390, - 196, - 105, - 56, - 396, - 102, - 327, - 39, - 91, - 269, - 317, - 127, - 358, - 322, - 301, - 319, - 94, - 268, - 61, - 301, - 259, - 293, - 234, - 311, - 135, - 233, - 143, - 3, - 380, - 179, - 81, - 102, - 314, - 3, - 43, - 62, - 160, - 86, - 39, - 15, - 333, - 288, - 377, - 10, - 253, - 163, - 5, - 273, - 285, - 183, - 116, - 6, - 259, - 374, - 38, - 365, - 345, - 336, - 103, - 51, - 48, - 92, - 146, - 80, - 205, - 185, - 362, - 228, - 257, - 225, - 176, - 49, - 366, - 371, - 308, - 343, - 386, - 9, - 343, - 265, - 284, - 137, - 373, - 372, - 255, - 233, - 154, - 64, - 136, - 48, - 377, - 179, - 153, - 327, - 385, - 349, - 273, - 130, - 261, - 207, - 215, - 311, - 49, - 117, - 78, - 292, - 315, - 70, - 383, - 160, - 21, - 56, - 201, - 328, - 99, - 181, - 68, - 203, - 114, - 180, - 262, - 378, - 397, - 230, - 165, - 355, - 10, - 296, - 109, - 264, - 80, - 202, - 255, - 381, - 55, - 193, - 334, - 397, - 386, - 216, - 356, - 356, - 45, - 9, - 304, - 186, - 334, - 60, - 128, - 317, - 163, - 151, - 234, - 115, - 386, - 77, - 345, - 149, - 240, - 221, - 84, - 143, - 332, - 344, - 204, - 83, - 22, - 304, - 183, - 337, - 311, - 274, - 93, - 276, - 341, - 94, - 174, - 346, - 74, - 90, - 348, - 120, - 291, - 202, - 220, - 3, - 316, - 19, - 212, - 276, - 388, - 228, - 302, - 120, - 150, - 206, - 30, - 130, - 270, - 263, - 358, - 374, - 84, - 208, - 306, - 187, - 258, - 90, - 6, - 355, - 101, - 239, - 80, - 241, - 285, - 368, - 94, - 118, - 380, - 152, - 164, - 400, - 185, - 115, - 270, - 19, - 271, - 298, - 56, - 118, - 253, - 270, - 184, - 372, - 169, - 382, - 327, - 349, - 352, - 177, - 202, - 24, - 129, - 129, - 93, - 42, - 377, - 2, - 249, - 249, - 188, - 82, - 318, - 72, - 349, - 180, - 103, - 308, - 385, - 189, - 370, - 334, - 348, - 161, - 284, - 17, - 166, - 198, - 307, - 323, - 225, - 170, - 219, - 369, - 81, - 247, - 232, - 138, - 57, - 11, - 142, - 236, - 151, - 308, - 14, - 329, - 184, - 170, - 28, - 13, - 49, - 11, - 163, - 10, - 51, - 140, - 96, - 318, - 258, - 149, - 362, - 133, - 39, - 113, - 47, - 100, - 52, - 364, - 34, - 14, - 181, - 354, - 13, - 226, - 258, - 178, - 371, - 321, - 303, - 310, - 131, - 317, - 199, - 52, - 178, - 204, - 8, - 326, - 63, - 53, - 399, - 64, - 5, - 106, - 177, - 258, - 133, - 283, - 346, - 114, - 185, - 313, - 126, - 101, - 342, - 17, - 99, - 321, - 35, - 102, - 395, - 212, - 129, - 147, - 381, - 301, - 206, - 34, - 380, - 127, - 260, - 136, - 258, - 97, - 387, - 150, - 103, - 281, - 302, - 208, - 18, - 198, - 304, - 337, - 311, - 83, - 393, - 112, - 231, - 378, - 392, - 212, - 267, - 32, - 144, - 78, - 193, - 355, - 263, - 84, - 195, - 116, - 143, - 5, - 109, - 199, - 208, - 381, - 53, - 241, - 353, - 90, - 325, - 51, - 186, - 323, - 273, - 208, - 14, - 69, - 88, - 396, - 380, - 353, - 15, - 170, - 333, - 116, - 373, - 262, - 149, - 222, - 312, - 56, - 190, - 247, - 292, - 10, - 53, - 342, - 87, - 65, - 1, - 394, - 43, - 253, - 107, - 112, - 172, - 108, - 164, - 286, - 358, - 259, - 269, - 362, - 217, - 283, - 284, - 200, - 118, - 55, - 201, - 194, - 324, - 374, - 126, - 329, - 177, - 20, - 187, - 53, - 349, - 115, - 189, - 394, - 183, - 55, - 346, - 175, - 1, - 285, - 351, - 309, - 171, - 17, - 268, - 312, - 50, - 45, - 35, - 43, - 70, - 328, - 55, - 200, - 99, - 306, - 147, - 81, - 74, - 247, - 196, - 307, - 91, - 85, - 186, - 398, - 242, - 118, - 244, - 142, - 309, - 32, - 351, - 221, - 176, - 12, - 83, - 102, - 188, - 353, - 127, - 345, - 164, - 169, - 310, - 93, - 240, - 282, - 80, - 204, - 345, - 127, - 59, - 19, - 31, - 225, - 229, - 209, - 154, - 332, - 243, - 186, - 77, - 7, - 207, - 328, - 363, - 81, - 108, - 194, - 388, - 165, - 300, - 184, - 43, - 102, - 392, - 393, - 377, - 267, - 303, - 249, - 178, - 286, - 351, - 297, - 263, - 153, - 347, - 91, - 18, - 341, - 283, - 129, - 124, - 8, - 263, - 204, - 4, - 156, - 177, - 148, - 228, - 207, - 334, - 338, - 382, - 343, - 137, - 116, - 160, - 270, - 223, - 91, - 53, - 349, - 386, - 346, - 126, - 47, - 233, - 320, - 315, - 309, - 363, - 169, - 75, - 368, - 153, - 118, - 101, - 309, - 186, - 89, - 127, - 293, - 31, - 122, - 340, - 125, - 157, - 142, - 88, - 241, - 180, - 225, - 225, - 132, - 236, - 114, - 223, - 129, - 65, - 40, - 397, - 111, - 261, - 314, - 160, - 203, - 346, - 263, - 142, - 398, - 215, - 1, - 120, - 274, - 285, - 341, - 151, - 38, - 119, - 257, - 314, - 332, - 378, - 64, - 206, - 151, - 311, - 283, - 338, - 362, - 19, - 90, - 293, - 21, - 267, - 102, - 181, - 253, - 80, - 251, - 134, - 254, - 276, - 70, - 308, - 228, - 241, - 235, - 68, - 312, - 394, - 276, - 221, - 372, - 31, - 167, - 262, - 358, - 21, - 159, - 70, - 371, - 149, - 132, - 136, - 66, - 171, - 308, - 148, - 301, - 22, - 368, - 50, - 236, - 219, - 159, - 317, - 387, - 357, - 94, - 199, - 263, - 383, - 330, - 112, - 162, - 323, - 263, - 20, - 70, - 96, - 292, - 17, - 309, - 45, - 297, - 355, - 75, - 260, - 232, - 147, - 277, - 368, - 264, - 101, - 23, - 156, - 24, - 318, - 322, - 153, - 256, - 6, - 188, - 176, - 158, - 160, - 200, - 112, - 384, - 52, - 241, - 128, - 56, - 135, - 306, - 239, - 228, - 263, - 152, - 14, - 274, - 273, - 307, - 374, - 76, - 355, - 91, - 326, - 335, - 314, - 400, - 280, - 267, - 44, - 230, - 61, - 385, - 109, - 31, - 6, - 291, - 298, - 65, - 229, - 30, - 188, - 241, - 151, - 59, - 168, - 105, - 308, - 174, - 340, - 393, - 250, - 180, - 327, - 389, - 395, - 314, - 17, - 310, - 197, - 341, - 90, - 128, - 379, - 175, - 7, - 398, - 150, - 261, - 283, - 196, - 168, - 278, - 277, - 120, - 268, - 138, - 340, - 359, - 333, - 100, - 284, - 50, - 11, - 243, - 6, - 149, - 55, - 11, - 104, - 217, - 88, - 254, - 44, - 306, - 48, - 227, - 30, - 205, - 71, - 175, - 241, - 300, - 203, - 73, - 343, - 269, - 20, - 175, - 122, - 70, - 104, - 105, - 66, - 28, - 22, - 196, - 192, - 150, - 328, - 394, - 400, - 9, - 88, - 75, - 361, - 9, - 199, - 228, - 275, - 45, - 399, - 390, - 59, - 144, - 341, - 179, - 11, - 323, - 400, - 392, - 223, - 396, - 304, - 131, - 295, - 136, - 391, - 298, - 390, - 228, - 343, - 390, - 183, - 137, - 129, - 8, - 315, - 27, - 9, - 330, - 9, - 342, - 14, - 86, - 243, - 303, - 133, - 229, - 46, - 144, - 317, - 243, - 219, - 196, - 203, - 244, - 92, - 364, - 85, - 180, - 172, - 346, - 127, - 133, - 224, - 151, - 199, - 243, - 53, - 138, - 165, - 314, - 248, - 248, - 12, - 173, - 273, - 345, - 168, - 70, - 346, - 94, - 364, - 206, - 170, - 244, - 230, - 300, - 387, - 195, - 206, - 185, - 165, - 100, - 133, - 400, - 259, - 373, - 46, - 104, - 352, - 335, - 208, - 297, - 93, - 361, - 119, - 99, - 54, - 63, - 222, - 106, - 91, - 391, - 171, - 268, - 36, - 304, - 284, - 288, - 249, - 233, - 235, - 371, - 226, - 235, - 112, - 42, - 274, - 108, - 101, - 123, - 123, - 167, - 259, - 149, - 133, - 98, - 223, - 78, - 106, - 39, - 220, - 254, - 186, - 12, - 270, - 291, - 273, - 369, - 336, - 44, - 184, - 281, - 30, - 15, - 64, - 231, - 280, - 57, - 110, - 182, - 250, - 326, - 75, - 140, - 110, - 21, - 130, - 278, - 127, - 389, - 60, - 61, - 114, - 259, - 125, - 98, - 327, - 128, - 144, - 317, - 213, - 53, - 231, - 299, - 170, - 312, - 170, - 348, - 72, - 128, - 60, - 173, - 163, - 235, - 149, - 25, - 62, - 385, - 328, - 79, - 155, - 218, - 45, - 171, - 92, - 254, - 42, - 152, - 263, - 22, - 129, - 257, - 253, - 365, - 296, - 388, - 1, - 385, - 366, - 58, - 228, - 172, - 73, - 349, - 207, - 292, - 1, - 208, - 392, - 315, - 18, - 73, - 119, - 326, - 344, - 194, - 90, - 73, - 88, - 26, - 230, - 288, - 342, - 123, - 97, - 286, - 302, - 114, - 88, - 197, - 209, - 360, - 219, - 37, - 143, - 99, - 14, - 27, - 57, - 272, - 26, - 169, - 316, - 209, - 165, - 243, - 377, - 245, - 339, - 100, - 238, - 330, - 110, - 350, - 67, - 213, - 122, - 355, - 55, - 137, - 350, - 172, - 300, - 142, - 214, - 288, - 296, - 154, - 107, - 47, - 226, - 262, - 79, - 305, - 355, - 155, - 137, - 211, - 169, - 91, - 278, - 69, - 314, - 336, - 373, - 383, - 373, - 68, - 166, - 362, - 346, - 6, - 65, - 395, - 94, - 337, - 318, - 87, - 274, - 73, - 389, - 137, - 71, - 369, - 197, - 36, - 19, - 286, - 336, - 98, - 74, - 95, - 205, - 53, - 255, - 256, - 158, - 201, - 54, - 343, - 344, - 30, - 380, - 124, - 344, - 74, - 269, - 346, - 225, - 49, - 172, - 371, - 355, - 103, - 275, - 118, - 365, - 196, - 186, - 180, - 159, - 2, - 110, - 189, - 183, - 362, - 314, - 196, - 304, - 171, - 380, - 63, - 196, - 364, - 118, - 371, - 220, - 163, - 128, - 177, - 326, - 77, - 77, - 296, - 330, - 380, - 304, - 36, - 340, - 314, - 309, - 258, - 238, - 138, - 26, - 15, - 351, - 88, - 84, - 101, - 98, - 224, - 376, - 376, - 243, - 249, - 399, - 221, - 224, - 18, - 177, - 163, - 150, - 378, - 353, - 285, - 45, - 243, - 24, - 344, - 202, - 335, - 248, - 241, - 122, - 371, - 209, - 178, - 232, - 218, - 183, - 72, - 400, - 212, - 379, - 180, - 178, - 284, - 107, - 393, - 151, - 277, - 262, - 162, - 293, - 135, - 357, - 97, - 343, - 9, - 181, - 95, - 347, - 120, - 363, - 88, - 311, - 320, - 64, - 21, - 43, - 354, - 184, - 343, - 387, - 195, - 381, - 262, - 320, - 377, - 188, - 284, - 225, - 316, - 327, - 321, - 368, - 276, - 232, - 119, - 124, - 59, - 284, - 84, - 201, - 289, - 253, - 301, - 233, - 5, - 316, - 300, - 242, - 343, - 30, - 50, - 101, - 51, - 294, - 387, - 292, - 245, - 27, - 210, - 226, - 273, - 232, - 24, - 275, - 122, - 154, - 138, - 221, - 386, - 355, - 44, - 95, - 32, - 136, - 12, - 277, - 260, - 301, - 292, - 172, - 112, - 96, - 217, - 72, - 304, - 89, - 29, - 33, - 35, - 8, - 378, - 94, - 327, - 35, - 279, - 396, - 368, - 251, - 85, - 138, - 357, - 60, - 1, - 209, - 171, - 363, - 324, - 203, - 355, - 98, - 120, - 392, - 285, - 297, - 105, - 134, - 123, - 167, - 134, - 304, - 61, - 257, - 166, - 40, - 214, - 328, - 179, - 330, - 261, - 325, - 78, - 67, - 167, - 395, - 306, - 89, - 305, - 386, - 115, - 4, - 121, - 69, - 41, - 83, - 3, - 10, - 56, - 94, - 338, - 233, - 179, - 378, - 8, - 101, - 216, - 59, - 49, - 95, - 366, - 117, - 355, - 356, - 15, - 287, - 266, - 268, - 189, - 289, - 392, - 204, - 69, - 310, - 264, - 240, - 171, - 277, - 397, - 173, - 397, - 218, - 81, - 124, - 354, - 240, - 166, - 100, - 73, - 274, - 302, - 110, - 268, - 17, - 74, - 62, - 41, - 86, - 106, - 363, - 200, - 67, - 94, - 56, - 161, - 12, - 127, - 184, - 355, - 259, - 95, - 299, - 316, - 247, - 84, - 35, - 33, - 235, - 280, - 376, - 295, - 394, - 179, - 299, - 174, - 325, - 131, - 54, - 295, - 13, - 327, - 231, - 367, - 67, - 353, - 104, - 66, - 381, - 87, - 63, - 45, - 89, - 21, - 263, - 357, - 331, - 183, - 264, - 367, - 250, - 44, - 149, - 94, - 147, - 131, - 327, - 189, - 212, - 172, - 360, - 244, - 206, - 177, - 115, - 79, - 38, - 349, - 152, - 104, - 261, - 265, - 299, - 328, - 242, - 1, - 305, - 216, - 182, - 127, - 332, - 192, - 162, - 225, - 35, - 11, - 390, - 66, - 41, - 266, - 175, - 397, - 156, - 365, - 57, - 363, - 50, - 56, - 301, - 233, - 22, - 136, - 381, - 300, - 4, - 7, - 18, - 359, - 341, - 229, - 29, - 1, - 399, - 146, - 242, - 289, - 230, - 352, - 92, - 105, - 382, - 334, - 233, - 229, - 326, - 50, - 335, - 276, - 196, - 354, - 6, - 104, - 156, - 75, - 301, - 265, - 179, - 383, - 34, - 112, - 29, - 294, - 69, - 249, - 246, - 143, - 191, - 301, - 163, - 309, - 244, - 321, - 78, - 13, - 179, - 236, - 275, - 240, - 283, - 186, - 317, - 105, - 84, - 160, - 308, - 138, - 87, - 37, - 211, - 7, - 85, - 333, - 195, - 265, - 246, - 56, - 16, - 226, - 102, - 171, - 310, - 328, - 63, - 300, - 160, - 136, - 114, - 386, - 247, - 43, - 95, - 217, - 223, - 186, - 130, - 354, - 398, - 132, - 341, - 34, - 249, - 218, - 51, - 197, - 97, - 80, - 25, - 61, - 119, - 28, - 137, - 160, - 222, - 119, - 132, - 44, - 273, - 61, - 110, - 217, - 12, - 32, - 15, - 47, - 260, - 149, - 132, - 92, - 238, - 330, - 116, - 203, - 317, - 306, - 227, - 79, - 193, - 245, - 309, - 54, - 282, - 199, - 108, - 185, - 48, - 73, - 18, - 154, - 379, - 186, - 244, - 209, - 191, - 69, - 187, - 13, - 192, - 45, - 170, - 300, - 23, - 274, - 143, - 128, - 341, - 91, - 65, - 186, - 48, - 154, - 291, - 350, - 301, - 179, - 245, - 33, - 395, - 333, - 155, - 364, - 83, - 79, - 268, - 306, - 252, - 335, - 398, - 90, - 128, - 267, - 146, - 185, - 127, - 300, - 2, - 376, - 345, - 368, - 95, - 287, - 143, - 159, - 216, - 150, - 95, - 272, - 393, - 376, - 355, - 244, - 191, - 270, - 20, - 366, - 235, - 121, - 75, - 40, - 398, - 67, - 354, - 267, - 87, - 336, - 231, - 24, - 111, - 247, - 306, - 400, - 225, - 50, - 329, - 330, - 101, - 97, - 331, - 244, - 323, - 146, - 214, - 63, - 253, - 44, - 6, - 21, - 334, - 60, - 286, - 130, - 11, - 316, - 346, - 232, - 301, - 63, - 24, - 272, - 289, - 60, - 232, - 292, - 333, - 256, - 302, - 305, - 80, - 330, - 13, - 310, - 222, - 358, - 103, - 148, - 277, - 292, - 109, - 90, - 191, - 76, - 277, - 52, - 200, - 184, - 163, - 359, - 323, - 326, - 219, - 295, - 173, - 57, - 351, - 236, - 346, - 254, - 221, - 304, - 91, - 327, - 310, - 345, - 355, - 18, - 19, - 206, - 267, - 356, - 108, - 113, - 173, - 8, - 180, - 374, - 30, - 270, - 249, - 335, - 375, - 350, - 326, - 169, - 343, - 383, - 340, - 54, - 104, - 160, - 6, - 37, - 46, - 36, - 215, - 146, - 324, - 354, - 130, - 156, - 331, - 204, - 235, - 310, - 85, - 102, - 6, - 63, - 98, - 323, - 241, - 191, - 400, - 32, - 399, - 290, - 93, - 70, - 215, - 113, - 349, - 321, - 71, - 60, - 137, - 209, - 135, - 234, - 11, - 94, - 108, - 139, - 66, - 43, - 73, - 280, - 336, - 58, - 329, - 143, - 269, - 39, - 141, - 23, - 133, - 225, - 43, - 323, - 19, - 317, - 342, - 23, - 63, - 177, - 85, - 180, - 153, - 252, - 3, - 186, - 202, - 303, - 338, - 317, - 9, - 50, - 299, - 239, - 263, - 351, - 368, - 256, - 299, - 272, - 326, - 163, - 145, - 346, - 307, - 75, - 390, - 132, - 249, - 139, - 275, - 378, - 226, - 290, - 306, - 141, - 61, - 372, - 205, - 152, - 372, - 225, - 127, - 63, - 307, - 98, - 142, - 131, - 260, - 199, - 97, - 152, - 268, - 21, - 340, - 326, - 238, - 235, - 198, - 45, - 147, - 294, - 2, - 378, - 323, - 337, - 200, - 134, - 391, - 167, - 59, - 129, - 194, - 359, - 276, - 65, - 195, - 245, - 376, - 385, - 277, - 170, - 330, - 12, - 372, - 259, - 374, - 13, - 169, - 27, - 206, - 186, - 85, - 77, - 134, - 343, - 325, - 134, - 385, - 334, - 234, - 329, - 381, - 178, - 211, - 218, - 261, - 245, - 195, - 244, - 389, - 281, - 298, - 132, - 180, - 391, - 237, - 138, - 352, - 99, - 17, - 261, - 368, - 81, - 172, - 143, - 238, - 138, - 88, - 200, - 275, - 168, - 313, - 352, - 26, - 2, - 73, - 348, - 173, - 275, - 327, - 289, - 34, - 90, - 38, - 299, - 212, - 69, - 95, - 186, - 288, - 345, - 138, - 387, - 168, - 32, - 53, - 257, - 181, - 153, - 288, - 24, - 307, - 339, - 165, - 104, - 305, - 279, - 84, - 341, - 259, - 342, - 227, - 359, - 109, - 117, - 28, - 128, - 172, - 228, - 321, - 178, - 161, - 284, - 227, - 241, - 355, - 225, - 154, - 328, - 167, - 184, - 345, - 238, - 156, - 342, - 372, - 378, - 20, - 134, - 192, - 378, - 176, - 277, - 81, - 26, - 120, - 70, - 80, - 192, - 354, - 225, - 8, - 378, - 45, - 342, - 92, - 162, - 113, - 239, - 164, - 125, - 113, - 386, - 69, - 69, - 297, - 170, - 317, - 42, - 162, - 309, - 134, - 301, - 82, - 44, - 153, - 183, - 29, - 350, - 73, - 90, - 53, - 351, - 261, - 69, - 144, - 291, - 199, - 96, - 60, - 230, - 176, - 157, - 180, - 148, - 54, - 131, - 123, - 388, - 64, - 326, - 13, - 263, - 60, - 300, - 68, - 287, - 160, - 41, - 292, - 176, - 291, - 11, - 143, - 334, - 353, - 377, - 283, - 243, - 1, - 247, - 136, - 103, - 124, - 216, - 65, - 349, - 369, - 395, - 310, - 184, - 399, - 85, - 341, - 47, - 361, - 7, - 115, - 88, - 5, - 226, - 102, - 219, - 348, - 259, - 245, - 2, - 351, - 281, - 116, - 380, - 153, - 31, - 187, - 39, - 266, - 107, - 317, - 351, - 27, - 289, - 158, - 275, - 191, - 197, - 326, - 214, - 305, - 275, - 41, - 187, - 266, - 17, - 377, - 338, - 267, - 395, - 2, - 55, - 249, - 374, - 265, - 163, - 339, - 42, - 384, - 185, - 365, - 99, - 156, - 176, - 149, - 291, - 87, - 177, - 40, - 86, - 317, - 24, - 221, - 74, - 25, - 305, - 383, - 285, - 224, - 289, - 72, - 341, - 334, - 36, - 39, - 253, - 20, - 390, - 304, - 194, - 150, - 309, - 29, - 252, - 21, - 101, - 194, - 101, - 358, - 68, - 356, - 1, - 195, - 220, - 63, - 293, - 127, - 205, - 131, - 206, - 69, - 13, - 201, - 373, - 43, - 235, - 387, - 384, - 49, - 356, - 312, - 242, - 68, - 9, - 316, - 85, - 363, - 272, - 216, - 338, - 229, - 283, - 49, - 18, - 69, - 224, - 47, - 127, - 54, - 379, - 15, - 263, - 5, - 75, - 123, - 258, - 218, - 205, - 5, - 202, - 112, - 102, - 268, - 202, - 364, - 104, - 101, - 346, - 357, - 332, - 161, - 354, - 275, - 34, - 237, - 361, - 72, - 137, - 121, - 85, - 74, - 78, - 113, - 397, - 208, - 84, - 10, - 158, - 254, - 172, - 189, - 7, - 69, - 23, - 388, - 283, - 239, - 113, - 185, - 4, - 149, - 313, - 78, - 331, - 193, - 76, - 342, - 326, - 324, - 249, - 249, - 12, - 13, - 192, - 63, - 296, - 230, - 71, - 74, - 391, - 389, - 92, - 247, - 53, - 267, - 311, - 383, - 112, - 33, - 352, - 194, - 379, - 150, - 55, - 344, - 219, - 391, - 232, - 346, - 395, - 322, - 300, - 282, - 317, - 300, - 121, - 370, - 325, - 43, - 22, - 374, - 24, - 121, - 16, - 34, - 234, - 127, - 237, - 369, - 157, - 167, - 277, - 295, - 247, - 382, - 217, - 319, - 227, - 349, - 296, - 369, - 325, - 80, - 72, - 340, - 355, - 88, - 111, - 131, - 128, - 11, - 383, - 167, - 126, - 286, - 303, - 89, - 308, - 83, - 333, - 113, - 312, - 193, - 114, - 15, - 374, - 386, - 269, - 391, - 113, - 43, - 177, - 70, - 142, - 13, - 84, - 204, - 305, - 141, - 167, - 27, - 349, - 333, - 250, - 92, - 193, - 332, - 224, - 328, - 87, - 29, - 73, - 331, - 80, - 194, - 75, - 49, - 312, - 283, - 233, - 152, - 215, - 361, - 170, - 45, - 70, - 92, - 185, - 381, - 120, - 76, - 19, - 79, - 170, - 14, - 48, - 358, - 153, - 354, - 200, - 173, - 250, - 180, - 72, - 202, - 330, - 312, - 37, - 235, - 48, - 17, - 337, - 144, - 301, - 376, - 197, - 179, - 380, - 30, - 61, - 150, - 146, - 170, - 393, - 109, - 374, - 141, - 15, - 77, - 332, - 153, - 400, - 334, - 195, - 87, - 108, - 360, - 321, - 11, - 144, - 17, - 146, - 342, - 301, - 247, - 69, - 239, - 263, - 327, - 1, - 109, - 62, - 82, - 315, - 9, - 192, - 57, - 91, - 98, - 197, - 237, - 398, - 217, - 324, - 76, - 366, - 215, - 111, - 161, - 213, - 228, - 332, - 182, - 278, - 289, - 279, - 138, - 351, - 255, - 356, - 301, - 180, - 378, - 67, - 245, - 204, - 337, - 337, - 397, - 39, - 212, - 387, - 378, - 38, - 213, - 76, - 81, - 33, - 202, - 149, - 68, - 398, - 243, - 375, - 303, - 163, - 150, - 366, - 20, - 156, - 108, - 150, - 41, - 119, - 22, - 67, - 394, - 120, - 90, - 195, - 321, - 361, - 74, - 310, - 372, - 282, - 34, - 394, - 316, - 131, - 143, - 119, - 278, - 86, - 306, - 365, - 238, - 196, - 222, - 330, - 393, - 190, - 35, - 318, - 83, - 67, - 67, - 3, - 43, - 219, - 197, - 264, - 250, - 319, - 131, - 47, - 220, - 255, - 334, - 372, - 358, - 2, - 392, - 32, - 217, - 207, - 271, - 204, - 39, - 338, - 348, - 109, - 246, - 16, - 367, - 198, - 93, - 141, - 248, - 197, - 163, - 264, - 66, - 54, - 293, - 253, - 377, - 233, - 290, - 53, - 351, - 240, - 399, - 74, - 249, - 185, - 137, - 53, - 247, - 334, - 18, - 112, - 162, - 387, - 227, - 7, - 326, - 132, - 22, - 26, - 314, - 359, - 72, - 194, - 148, - 393, - 160, - 49, - 275, - 120, - 346, - 164, - 97, - 317, - 267, - 212, - 297, - 201, - 350, - 332, - 350, - 329, - 223, - 385, - 24, - 167, - 279, - 374, - 128, - 392, - 117, - 41, - 143, - 38, - 312, - 226, - 313, - 78, - 209, - 351, - 320, - 194, - 192, - 333, - 242, - 254, - 340, - 290, - 72, - 359, - 370, - 220, - 241, - 48, - 197, - 31, - 297, - 282, - 375, - 181, - 97, - 70, - 87, - 363, - 63, - 286, - 166, - 114, - 344, - 332, - 31, - 167, - 278, - 75, - 340, - 138, - 83, - 189, - 263, - 221, - 243, - 366, - 190, - 336, - 79, - 235, - 338, - 290, - 128, - 100, - 80, - 347, - 341, - 351, - 160, - 328, - 183, - 351, - 361, - 157, - 91, - 95, - 217, - 365, - 124, - 325, - 293, - 212, - 170, - 376, - 296, - 178, - 140, - 127, - 86, - 200, - 216, - 23, - 239, - 385, - 134, - 316, - 187, - 391, - 71, - 19, - 9, - 286, - 46, - 42, - 172, - 292, - 58, - 67, - 84, - 4, - 159, - 110, - 66, - 213, - 3, - 320, - 40, - 23, - 97, - 86, - 102, - 83, - 119, - 237, - 242, - 171, - 320, - 268, - 377, - 53, - 65, - 133, - 144, - 389, - 275, - 215, - 100, - 134, - 185, - 94, - 213, - 307, - 297, - 250, - 321, - 252, - 106, - 400, - 265, - 266, - 176, - 141, - 14, - 201, - 250, - 295, - 202, - 287, - 301, - 179, - 133, - 68, - 347, - 113, - 181, - 148, - 346, - 356, - 258, - 69, - 130, - 84, - 244, - 85, - 109, - 139, - 268, - 83, - 367, - 129, - 52, - 287, - 217, - 164, - 123, - 202, - 122, - 163, - 79, - 321, - 202, - 302, - 93, - 256, - 29, - 16, - 209, - 348, - 315, - 282, - 391, - 51, - 247, - 184, - 351, - 40, - 96, - 60, - 39, - 278, - 108, - 81, - 389, - 344, - 149, - 176, - 64, - 344, - 165, - 262, - 40, - 75, - 263, - 46, - 392, - 266, - 47, - 8, - 278, - 262, - 192, - 260, - 329, - 332, - 25, - 314, - 15, - 22, - 146, - 101, - 343, - 245, - 238, - 354, - 222, - 69, - 259, - 139, - 352, - 73, - 46, - 223, - 294, - 122, - 292, - 312, - 382, - 338, - 260, - 334, - 165, - 341, - 62, - 108, - 227, - 232, - 208, - 40, - 342, - 281, - 120, - 62, - 185, - 165, - 348, - 114, - 26, - 65, - 146, - 33, - 34, - 340, - 156, - 275, - 68, - 187, - 396, - 205, - 366, - 26, - 298, - 64, - 220, - 73, - 192, - 303, - 57, - 382, - 273, - 313, - 385, - 134, - 261, - 327, - 307, - 325, - 108, - 386, - 251, - 305, - 114, - 392, - 114, - 147, - 72, - 312, - 108, - 264, - 378, - 316, - 398, - 169, - 217, - 39, - 58, - 46, - 12, - 265, - 7, - 187, - 105, - 53, - 133, - 44, - 244, - 115, - 129, - 282, - 22, - 340, - 200, - 121, - 90, - 209, - 97, - 388, - 133, - 345, - 113, - 289, - 298, - 312, - 284, - 72, - 98, - 259, - 201, - 111, - 357, - 337, - 369, - 286, - 346, - 206, - 159, - 20, - 266, - 177, - 386, - 114, - 16, - 334, - 132, - 277, - 214, - 375, - 229, - 29, - 124, - 19, - 95, - 169, - 65, - 318, - 120, - 245, - 31, - 301, - 306, - 197, - 261, - 102, - 290, - 156, - 69, - 330, - 346, - 139, - 159, - 287, - 284, - 126, - 301, - 57, - 274, - 386, - 106, - 147, - 19, - 344, - 11, - 276, - 31, - 252, - 87, - 133, - 73, - 259, - 20, - 85, - 334, - 311, - 352, - 197, - 282, - 348, - 359, - 120, - 18, - 250, - 389, - 233, - 6, - 75, - 395, - 191, - 51, - 156, - 387, - 377, - 155, - 355, - 343, - 49, - 270, - 308, - 95, - 41, - 66, - 380, - 335, - 224, - 162, - 198, - 366, - 44, - 259, - 232, - 170, - 177, - 251, - 256, - 10, - 337, - 175, - 82, - 230, - 54, - 275, - 34, - 113, - 228, - 288, - 151, - 199, - 361, - 244, - 221, - 336, - 336, - 30, - 105, - 228, - 317, - 356, - 227, - 251, - 58, - 6, - 165, - 150, - 400, - 271, - 48, - 343, - 383, - 48, - 144, - 289, - 270, - 147, - 18, - 131, - 302, - 191, - 249, - 143, - 32, - 279, - 245, - 350, - 176, - 154, - 103, - 355, - 359, - 167, - 239, - 121, - 361, - 10, - 217, - 78, - 207, - 391, - 309, - 16, - 65, - 309, - 185, - 299, - 299, - 372, - 86, - 146, - 316, - 207, - 96, - 196, - 97, - 28, - 28, - 128, - 234, - 123, - 108, - 88, - 359, - 124, - 27, - 76, - 377, - 318, - 155, - 251, - 231, - 148, - 352, - 378, - 3, - 93, - 400, - 34, - 235, - 299, - 360, - 118, - 211, - 22, - 282, - 57, - 270, - 295, - 150, - 283, - 204, - 12, - 357, - 231, - 119, - 20, - 173, - 55, - 129, - 61, - 286, - 382, - 303, - 135, - 89, - 249, - 384, - 77, - 379, - 142, - 333, - 178, - 295, - 198, - 293, - 338, - 150, - 10, - 17, - 354, - 177, - 157, - 76, - 38, - 293, - 236, - 205, - 98, - 169, - 265, - 109, - 91, - 172, - 218, - 125, - 298, - 50, - 339, - 115, - 168, - 165, - 26, - 53, - 84, - 236, - 13, - 97, - 400, - 387, - 37, - 243, - 172, - 180, - 285, - 94, - 209, - 125, - 353, - 67, - 257, - 34, - 168, - 360, - 78, - 251, - 320, - 278, - 376, - 317, - 148, - 263, - 32, - 356, - 160, - 208, - 289, - 235, - 249, - 357, - 318, - 55, - 155, - 283, - 134, - 60, - 156, - 21, - 295, - 20, - 65, - 46, - 215, - 321, - 39, - 12, - 346, - 108, - 321, - 270, - 156, - 136, - 334, - 364, - 318, - 168, - 365, - 79, - 90, - 123, - 325, - 330, - 189, - 52, - 123, - 310, - 267, - 231, - 289, - 133, - 293, - 32, - 346, - 288, - 313, - 108, - 398, - 62, - 321, - 25, - 362, - 268, - 313, - 123, - 280, - 353, - 129, - 100, - 170, - 54, - 13, - 348, - 167, - 82, - 167, - 176, - 41, - 235, - 45, - 400, - 216, - 211, - 233, - 297, - 310, - 240, - 193, - 248, - 242, - 375, - 371, - 170, - 342, - 197, - 190, - 367, - 43, - 71, - 249, - 251, - 299, - 317, - 291, - 345, - 69, - 60, - 333, - 21, - 312, - 194, - 6, - 285, - 320, - 201, - 8, - 218, - 286, - 127, - 388, - 183, - 27, - 181, - 263, - 102, - 246, - 134, - 37, - 236, - 262, - 196, - 186, - 157, - 281, - 266, - 263, - 219, - 345, - 120, - 22, - 210, - 246, - 72, - 29, - 121, - 299, - 240, - 167, - 270, - 47, - 229, - 84, - 226, - 26, - 70, - 85, - 197, - 218, - 198, - 278, - 232, - 36, - 1, - 298, - 144, - 130, - 2, - 240, - 86, - 216, - 288, - 135, - 98, - 68, - 41, - 142, - 192, - 301, - 169, - 114, - 261, - 11, - 322, - 148, - 66, - 196, - 358, - 280, - 347, - 15, - 9, - 212, - 383, - 394, - 127, - 194, - 277, - 135, - 231, - 223, - 84, - 284, - 98, - 286, - 367, - 28, - 299, - 74, - 187, - 260, - 273, - 300, - 206, - 23, - 244, - 291, - 364, - 21, - 12, - 52, - 362, - 20, - 353, - 38, - 370, - 188, - 64, - 320, - 226, - 103, - 206, - 25, - 197, - 35, - 348, - 213, - 182, - 364, - 249, - 118, - 352, - 286, - 166, - 101, - 375, - 292, - 258, - 62, - 372, - 102, - 149, - 250, - 223, - 97, - 180, - 129, - 394, - 184, - 132, - 29, - 88, - 104, - 180, - 50, - 97, - 192, - 339, - 166, - 234, - 374, - 219, - 233, - 141, - 337, - 317, - 274, - 44, - 165, - 189, - 112, - 363, - 156, - 291, - 44, - 288, - 142, - 391, - 289, - 17, - 341, - 335, - 6, - 177, - 219, - 285, - 224, - 62, - 20, - 258, - 270, - 91, - 254, - 334, - 124, - 185, - 120, - 8, - 13, - 339, - 306, - 333, - 255, - 41, - 7, - 316, - 236, - 80, - 145, - 247, - 368, - 312, - 124, - 346, - 116, - 1, - 108, - 9, - 126, - 303, - 357, - 5, - 223, - 83, - 172, - 205, - 242, - 77, - 61, - 159, - 121, - 268, - 256, - 331, - 203, - 70, - 217, - 122, - 310, - 142, - 156, - 108, - 379, - 321, - 289, - 379, - 63, - 264, - 372, - 395, - 261, - 190, - 11, - 291, - 148, - 72, - 215, - 259, - 304, - 381, - 38, - 216, - 134, - 62, - 211, - 279, - 213, - 125, - 27, - 254, - 81, - 43, - 150, - 256, - 371, - 295, - 219, - 335, - 230, - 79, - 177, - 159, - 241, - 304, - 63, - 247, - 107, - 143, - 400, - 262, - 369, - 242, - 90, - 82, - 105, - 229, - 162, - 222, - 383, - 363, - 223, - 211, - 114, - 134, - 162, - 245, - 371, - 95, - 329, - 124, - 216, - 201, - 195, - 157, - 85, - 309, - 271, - 384, - 143, - 51, - 366, - 183, - 326, - 170, - 49, - 326, - 351, - 107, - 141, - 334, - 102, - 323, - 286, - 12, - 215, - 4, - 228, - 322, - 255, - 256, - 323, - 69, - 168, - 274, - 148, - 237, - 194, - 331, - 203, - 132, - 151, - 238, - 215, - 46, - 106, - 35, - 225, - 360, - 124, - 386, - 37, - 111, - 331, - 340, - 12, - 181, - 143, - 249, - 348, - 165, - 10, - 282, - 18, - 359, - 346, - 371, - 267, - 355, - 15, - 212, - 68, - 382, - 222, - 110, - 54, - 270, - 53, - 245, - 213, - 152, - 80, - 323, - 6, - 264, - 149, - 360, - 388, - 323, - 284, - 315, - 125, - 119, - 95, - 243, - 218, - 360, - 394, - 383, - 221, - 289, - 113, - 294, - 359, - 140, - 113, - 292, - 48, - 266, - 386, - 30, - 186, - 65, - 384, - 351, - 228, - 31, - 144, - 359, - 352, - 50, - 362, - 362, - 202, - 27, - 294, - 9, - 68, - 164, - 105, - 37, - 137, - 251, - 394, - 20, - 306, - 145, - 176, - 74, - 229, - 235, - 211, - 174, - 14, - 221, - 165, - 116, - 374, - 198, - 136, - 148, - 198, - 271, - 222, - 48, - 143, - 19, - 399, - 386, - 125, - 378, - 40, - 140, - 183, - 78, - 100, - 26, - 66, - 233, - 114, - 122, - 23, - 183, - 115, - 338, - 357, - 255, - 71, - 230, - 65, - 115, - 75, - 86, - 110, - 100, - 90, - 389, - 159, - 318, - 397, - 40, - 70, - 41, - 106, - 55, - 49, - 181, - 344, - 381, - 132, - 26, - 52, - 306, - 172, - 323, - 197, - 116, - 126, - 39, - 154, - 77, - 256, - 48, - 39, - 317, - 384, - 347, - 66, - 178, - 266, - 1, - 110, - 162, - 153, - 2, - 86, - 192, - 145, - 245, - 193, - 396, - 366, - 205, - 369, - 88, - 158, - 160, - 217, - 58, - 287, - 384, - 110, - 345, - 369, - 36, - 366, - 71, - 233, - 246, - 213, - 300, - 68, - 291, - 245, - 208, - 356, - 303, - 212, - 152, - 181, - 292, - 67, - 379, - 354, - 388, - 372, - 30, - 304, - 135, - 123, - 118, - 281, - 380, - 344, - 20, - 53, - 107, - 3, - 216, - 381, - 22, - 363, - 271, - 269, - 196, - 97, - 40, - 399, - 115, - 361, - 219, - 128, - 340, - 15, - 308, - 186, - 8, - 292, - 183, - 63, - 42, - 8, - 273, - 45, - 195, - 108, - 140, - 324, - 230, - 306, - 159, - 324, - 172, - 72, - 109, - 203, - 188, - 329, - 186, - 61, - 174, - 362, - 143, - 10, - 388, - 66, - 211, - 227, - 13, - 239, - 201, - 198, - 96, - 208, - 26, - 345, - 336, - 21, - 145, - 1, - 206, - 393, - 81, - 251, - 303, - 195, - 11, - 68, - 205, - 341, - 144, - 178, - 256, - 348, - 70, - 12, - 6, - 385, - 201, - 108, - 92, - 284, - 140, - 43, - 51, - 106, - 172, - 148, - 195, - 218, - 370, - 73, - 335, - 189, - 138, - 13, - 227, - 227, - 208, - 338, - 137, - 379, - 68, - 308, - 236, - 258, - 293, - 287, - 13, - 129, - 132, - 60, - 174, - 126, - 319, - 185, - 189, - 318, - 232, - 359, - 275, - 364, - 46, - 256, - 179, - 172, - 368, - 45, - 68, - 132, - 201, - 21, - 285, - 99, - 338, - 340, - 140, - 300, - 270, - 208, - 380, - 187, - 188, - 22, - 112, - 304, - 55, - 39, - 198, - 20, - 355, - 257, - 298, - 91, - 235, - 18, - 235, - 58, - 77, - 397, - 232, - 51, - 277, - 284, - 292, - 360, - 369, - 188, - 350, - 158, - 125, - 158, - 49, - 160, - 111, - 64, - 21, - 368, - 390, - 287, - 279, - 104, - 291, - 246, - 294, - 196, - 400, - 161, - 133, - 319, - 310, - 62, - 118, - 205, - 320, - 164, - 44, - 81, - 10, - 270, - 51, - 23, - 265, - 121, - 184, - 389, - 120, - 355, - 221, - 167, - 105, - 289, - 147, - 174, - 133, - 185, - 225, - 228, - 309, - 218, - 320, - 233, - 115, - 126, - 22, - 383, - 356, - 254, - 36, - 19, - 95, - 80, - 327, - 107, - 42, - 327, - 70, - 107, - 45, - 119, - 323, - 83, - 81, - 68, - 261, - 195, - 76, - 45, - 172, - 6, - 154, - 305, - 108, - 263, - 249, - 146, - 120, - 112, - 298, - 207, - 382, - 231, - 371, - 102, - 87, - 155, - 168, - 387, - 309, - 70, - 166, - 95, - 12, - 343, - 302, - 266, - 113, - 41, - 173, - 268, - 350, - 224, - 42, - 70, - 353, - 6, - 319, - 39, - 144, - 223, - 240, - 68, - 11, - 36, - 326, - 364, - 31, - 7, - 329, - 295, - 392, - 147, - 250, - 192, - 24, - 334, - 27, - 272, - 21, - 49, - 398, - 222, - 150, - 255, - 326, - 100, - 149, - 33, - 357, - 143, - 15, - 246, - 30, - 72, - 101, - 398, - 120, - 398, - 87, - 210, - 355, - 354, - 364, - 244, - 360, - 81, - 293, - 140, - 384, - 197, - 371, - 357, - 157, - 139, - 73, - 198, - 151, - 253, - 79, - 155, - 184, - 24, - 99, - 121, - 66, - 330, - 351, - 279, - 280, - 284, - 362, - 384, - 294, - 262, - 80, - 232, - 62, - 15, - 395, - 102, - 287, - 147, - 20, - 380, - 37, - 211, - 292, - 53, - 265, - 159, - 17, - 141, - 22, - 348, - 311, - 224, - 372, - 116, - 138, - 360, - 170, - 210, - 118, - 208, - 367, - 248, - 267, - 194, - 273, - 162, - 124, - 128, - 45, - 30, - 353, - 258, - 204, - 329, - 49, - 101, - 232, - 133, - 95, - 371, - 186, - 128, - 214, - 318, - 233, - 20, - 37, - 253, - 291, - 152, - 223, - 254, - 321, - 277, - 224, - 68, - 346, - 395, - 89, - 23, - 5, - 136, - 52, - 369, - 158, - 2, - 48, - 34, - 102, - 187, - 101, - 117, - 344, - 301, - 294, - 302, - 349, - 272, - 148, - 169, - 82, - 108, - 10, - 302, - 9, - 81, - 124, - 209, - 327, - 371, - 247, - 270, - 26, - 337, - 109, - 128, - 13, - 53, - 148, - 73, - 162, - 390, - 89, - 173, - 86, - 156, - 114, - 394, - 90, - 105, - 61, - 388, - 24, - 318, - 366, - 260, - 34, - 340, - 159, - 293, - 205, - 266, - 87, - 142, - 370, - 355, - 57, - 69, - 369, - 385, - 136, - 379, - 59, - 298, - 141, - 199, - 274, - 137, - 241, - 109, - 253, - 159, - 384, - 180, - 174, - 263, - 302, - 350, - 371, - 273, - 292, - 298, - 184, - 215, - 279, - 60, - 103, - 137, - 50, - 317, - 154, - 380, - 360, - 284, - 68, - 178, - 4, - 125, - 165, - 196, - 36, - 151, - 392, - 99, - 59, - 236, - 197, - 107, - 98, - 207, - 231, - 369, - 240, - 213, - 313, - 36, - 259, - 151, - 189, - 387, - 348, - 392, - 69, - 350, - 214, - 17, - 228, - 29, - 215, - 243, - 216, - 17, - 55, - 113, - 200, - 347, - 217, - 132, - 52, - 57, - 109, - 253, - 288, - 377, - 258, - 281, - 251, - 230, - 298, - 98, - 252, - 347, - 232, - 50, - 157, - 213, - 288, - 381, - 142, - 192, - 142, - 156, - 161, - 24, - 257, - 344, - 160, - 242, - 294, - 214, - 151, - 290, - 274, - 142, - 383, - 219, - 309, - 227, - 110, - 137, - 256, - 127, - 299, - 319, - 34, - 153, - 164, - 168, - 341, - 143, - 200, - 205, - 324, - 225, - 216, - 149, - 237, - 89, - 280, - 244, - 256, - 159, - 394, - 135, - 394, - 99, - 267, - 309, - 159, - 176, - 110, - 393, - 268, - 291, - 55, - 102, - 68, - 85, - 158, - 11, - 224, - 84, - 150, - 272, - 342, - 152, - 7, - 67, - 237, - 202, - 286, - 361, - 179, - 52, - 118, - 182, - 121, - 319, - 92, - 216, - 312, - 163, - 100, - 162, - 53, - 244, - 369, - 307, - 64, - 282, - 354, - 135, - 255, - 5, - 97, - 147, - 384, - 290, - 115, - 83, - 17, - 249, - 308, - 129, - 279, - 199, - 162, - 304, - 392, - 331, - 185, - 305, - 333, - 298, - 243, - 124, - 120, - 231, - 378, - 74, - 311, - 85, - 40, - 43, - 14, - 266, - 169, - 175, - 342, - 133, - 151, - 329, - 186, - 295, - 35, - 324, - 291, - 124, - 187, - 11, - 135, - 195, - 341, - 255, - 281, - 255, - 362, - 329, - 274, - 338, - 182, - 52, - 172, - 219, - 141, - 14, - 64, - 87, - 105, - 132, - 156, - 69, - 106, - 6, - 117, - 249, - 297, - 113, - 123, - 388, - 17, - 164, - 348, - 278, - 93, - 86, - 199, - 385, - 283, - 237, - 80, - 30, - 352, - 51, - 58, - 133, - 127, - 100, - 128, - 234, - 380, - 234, - 42, - 310, - 304, - 32, - 18, - 300, - 215, - 391, - 169, - 107, - 324, - 49, - 157, - 207, - 317, - 282, - 90, - 48, - 145, - 339, - 349, - 120, - 226, - 174, - 64, - 397, - 274, - 295, - 261, - 341, - 157, - 165, - 263, - 186, - 194, - 56, - 128, - 3, - 284, - 57, - 88, - 304, - 151, - 43, - 65, - 86, - 350, - 9, - 203, - 31, - 126, - 249, - 387, - 377, - 298, - 43, - 236, - 310, - 247, - 102, - 143, - 14, - 114, - 262, - 156, - 182, - 108, - 398, - 372, - 100, - 393, - 329, - 359, - 285, - 388, - 59, - 184, - 221, - 303, - 327, - 145, - 124, - 144, - 9, - 107, - 142, - 18, - 56, - 36, - 313, - 329, - 98, - 54, - 367, - 201, - 102, - 325, - 37, - 205, - 123, - 299, - 241, - 84, - 112, - 235, - 46, - 357, - 214, - 361, - 392, - 220, - 171, - 3, - 240, - 388, - 167, - 7, - 293, - 4, - 194, - 269, - 197, - 125, - 78, - 162, - 301, - 222, - 157, - 248, - 74, - 278, - 110, - 156, - 273, - 239, - 161, - 290, - 117, - 27, - 356, - 377, - 328, - 80, - 152, - 302, - 193, - 180, - 256, - 365, - 237, - 194, - 354, - 178, - 199, - 248, - 154, - 336, - 249, - 267, - 315, - 356, - 200, - 379, - 224, - 215, - 104, - 51, - 146, - 28, - 77, - 232, - 346, - 22, - 43, - 16, - 12, - 212, - 120, - 209, - 268, - 213, - 159, - 193, - 260, - 232, - 298, - 153, - 278, - 129, - 109, - 375, - 121, - 151, - 34, - 256, - 7, - 260, - 139, - 255, - 384, - 376, - 130, - 108, - 215, - 103, - 179, - 181, - 24, - 328, - 385, - 213, - 20, - 41, - 74, - 8, - 365, - 195, - 56, - 23, - 310, - 325, - 235, - 307, - 322, - 320, - 218, - 26, - 363, - 220, - 181, - 353, - 369, - 315, - 366, - 78, - 125, - 138, - 177, - 333, - 164, - 54, - 128, - 315, - 1, - 173, - 254, - 259, - 33, - 302, - 219, - 248, - 235, - 72, - 279, - 97, - 389, - 79, - 313, - 198, - 301, - 324, - 338, - 293, - 378, - 124, - 270, - 325, - 170, - 375, - 118, - 224, - 254, - 78, - 117, - 103, - 180, - 303, - 94, - 259, - 54, - 375, - 147, - 399, - 299, - 128, - 122, - 364, - 23, - 330, - 288, - 314, - 71, - 162, - 398, - 96, - 176, - 371, - 30, - 12, - 21, - 130, - 190, - 205, - 52, - 20, - 102, - 262, - 268, - 122, - 23, - 354, - 104, - 221, - 191, - 129, - 33, - 51, - 339, - 198, - 111, - 159, - 395, - 295, - 93, - 272, - 124, - 114, - 254, - 116, - 127, - 272, - 41, - 210, - 384, - 83, - 34, - 393, - 84, - 359, - 137, - 355, - 228, - 316, - 175, - 75, - 280, - 221, - 98, - 43, - 68, - 197, - 194, - 40, - 242, - 50, - 123, - 149, - 206, - 331, - 158, - 224, - 142, - 88, - 201, - 250, - 251, - 186, - 42, - 191, - 317, - 282, - 3, - 250, - 137, - 139, - 305, - 110, - 165, - 269, - 333, - 378, - 360, - 292, - 183, - 370, - 78, - 100, - 344, - 186, - 137, - 120, - 220, - 14, - 302, - 303, - 55, - 381, - 234, - 382, - 93, - 342, - 168, - 213, - 155, - 180, - 201, - 191, - 386, - 296, - 303, - 82, - 131, - 218, - 299, - 360, - 282, - 253, - 49, - 215, - 225, - 67, - 378, - 23, - 109, - 398, - 48, - 15, - 235, - 138, - 373, - 270, - 366, - 7, - 150, - 92, - 372, - 110, - 123, - 57, - 66, - 98, - 210, - 164, - 338, - 341, - 171, - 92, - 277, - 20, - 33, - 280, - 214, - 28, - 363, - 79, - 291, - 256, - 161, - 252, - 322, - 372, - 134, - 203, - 108, - 54, - 127, - 392, - 128, - 180, - 185, - 99, - 7, - 75, - 141, - 188, - 37, - 309, - 1, - 316, - 377, - 345, - 177, - 229, - 133, - 160, - 312, - 294, - 198, - 130, - 363, - 118, - 72, - 52, - 198, - 375, - 52, - 306, - 336, - 300, - 140, - 130, - 395, - 386, - 205, - 263, - 30, - 155, - 301, - 389, - 59, - 47, - 162, - 120, - 360, - 311, - 281, - 102, - 41, - 197, - 46, - 271, - 36, - 179, - 303, - 106, - 316, - 253, - 283, - 292, - 103, - 218, - 199, - 158, - 144, - 54, - 127, - 53, - 293, - 36, - 215, - 168, - 110, - 233, - 192, - 377, - 1, - 170, - 245, - 225, - 363, - 172, - 56, - 110, - 165, - 134, - 139, - 248, - 325, - 84, - 340, - 53, - 78, - 395, - 9, - 288, - 223, - 105, - 165, - 230, - 317, - 189, - 72, - 252, - 296, - 169, - 214, - 75, - 179, - 256, - 60, - 178, - 30, - 138, - 376, - 327, - 98, - 191, - 48, - 14, - 320, - 39, - 172, - 183, - 229, - 291, - 88, - 110, - 400, - 12, - 238, - 159, - 309, - 256, - 170, - 26, - 348, - 191, - 296, - 236, - 275, - 314, - 280, - 126, - 231, - 185, - 263, - 306, - 35, - 35, - 378, - 198, - 162, - 49, - 212, - 224, - 66, - 40, - 47, - 24, - 154, - 226, - 198, - 98, - 193, - 398, - 51, - 130, - 64, - 73, - 378, - 189, - 71, - 158, - 314, - 47, - 209, - 339, - 197, - 372, - 201, - 116, - 33, - 215, - 169, - 211, - 155, - 378, - 11, - 226, - 125, - 188, - 182, - 341, - 102, - 318, - 81, - 359, - 388, - 11, - 174, - 241, - 179, - 367, - 368, - 311, - 232, - 9, - 131, - 174, - 384, - 45, - 355, - 209, - 289, - 372, - 339, - 86, - 40, - 385, - 79, - 15, - 161, - 386, - 386, - 124, - 368, - 305, - 299, - 301, - 384, - 315, - 389, - 378, - 95, - 249, - 394, - 393, - 174, - 291, - 259, - 290, - 268, - 373, - 340, - 39, - 253, - 294, - 254, - 212, - 222, - 164, - 27, - 379, - 39, - 50, - 70, - 153, - 191, - 292, - 21, - 9, - 254, - 100, - 115, - 80, - 117, - 387, - 389, - 236, - 257, - 226, - 292, - 169, - 238, - 92, - 36, - 190, - 73, - 177, - 301, - 24, - 173, - 168, - 242, - 208, - 91, - 366, - 87, - 206, - 247, - 161, - 340, - 105, - 151, - 108, - 26, - 124, - 228, - 268, - 371, - 176, - 360, - 334, - 164, - 190, - 10, - 59, - 63, - 67, - 2, - 135, - 334, - 166, - 266, - 350, - 153, - 142, - 32, - 261, - 107, - 389, - 170, - 1, - 27, - 19, - 331, - 288, - 190, - 311, - 189, - 82, - 34, - 369, - 89, - 127, - 217, - 344, - 248, - 312, - 233, - 215, - 86, - 5, - 203, - 362, - 54, - 278, - 33, - 310, - 342, - 154, - 168, - 376, - 378, - 16, - 140, - 285, - 336, - 237, - 185, - 303, - 222, - 10, - 120, - 341, - 110, - 125, - 16, - 180, - 211, - 362, - 344, - 244, - 199, - 168, - 146, - 114, - 55, - 347, - 242, - 318, - 392, - 298, - 316, - 230, - 109, - 23, - 271, - 289, - 169, - 26, - 96, - 47, - 114, - 159, - 119, - 320, - 367, - 10, - 36, - 171, - 349, - 270, - 384, - 245, - 15, - 393, - 192, - 43, - 356, - 247, - 68, - 320, - 215, - 21, - 366, - 58, - 186, - 335, - 131, - 321, - 7, - 280, - 239, - 224, - 159, - 237, - 271, - 13, - 129, - 231, - 396, - 221, - 359, - 14, - 372, - 253, - 267, - 349, - 375, - 290, - 361, - 243, - 252, - 1, - 261, - 397, - 60, - 375, - 393, - 234, - 105, - 342, - 301, - 380, - 143, - 393, - 282, - 6, - 279, - 321, - 308, - 148, - 143, - 358, - 114, - 192, - 206, - 220, - 382, - 343, - 207, - 186, - 194, - 395, - 144, - 77, - 264, - 19, - 251, - 336, - 60, - 57, - 182, - 363, - 19, - 225, - 226, - 241, - 333, - 260, - 267, - 380, - 375, - 234, - 340, - 27, - 132, - 335, - 379, - 143, - 225, - 50, - 8, - 209, - 306, - 223, - 122, - 127, - 302, - 244, - 194, - 301, - 251, - 393, - 326, - 239, - 50, - 98, - 352, - 100, - 65, - 372, - 365, - 241, - 43, - 336, - 353, - 259, - 144, - 101, - 356, - 209, - 374, - 340, - 336, - 91, - 339, - 370, - 193, - 232, - 254, - 313, - 76, - 198, - 290, - 14, - 378, - 353, - 209, - 233, - 376, - 326, - 391, - 286, - 309, - 10, - 263, - 45, - 83, - 92, - 181, - 239, - 87, - 82, - 171, - 217, - 52, - 127, - 323, - 157, - 270, - 21, - 114, - 172, - 51, - 290, - 276, - 308, - 47, - 296, - 84, - 122, - 365, - 373, - 324, - 104, - 100, - 6, - 382, - 211, - 363, - 210, - 308, - 291, - 128, - 282, - 225, - 218, - 333, - 13, - 377, - 400, - 33, - 348, - 232, - 364, - 276, - 350, - 187, - 47, - 147, - 345, - 198, - 146, - 395, - 294, - 32, - 300, - 322, - 128, - 352, - 334, - 343, - 169, - 355, - 336, - 71, - 15, - 213, - 131, - 25, - 389, - 125, - 107, - 156, - 68, - 111, - 126, - 320, - 276, - 360, - 73, - 92, - 310, - 12, - 346, - 25, - 110, - 396, - 52, - 234, - 348, - 94, - 20, - 250, - 377, - 226, - 10, - 372, - 193, - 108, - 83, - 360, - 322, - 303, - 396, - 94, - 316, - 160, - 102, - 388, - 212, - 357, - 1, - 142, - 63, - 131, - 166, - 221, - 115, - 172, - 375, - 108, - 293, - 210, - 222, - 226, - 137, - 260, - 166, - 260, - 199, - 19, - 344, - 166, - 381, - 304, - 325, - 344, - 343, - 122, - 282, - 16, - 71, - 257, - 306, - 323, - 54, - 366, - 47, - 264, - 262, - 8, - 213, - 64, - 186, - 6, - 222, - 389, - 122, - 178, - 176, - 337, - 380, - 315, - 359, - 169, - 305, - 77, - 30, - 113, - 291, - 341, - 317, - 273, - 47, - 258, - 191, - 159, - 219, - 162, - 73, - 23, - 60, - 344, - 198, - 318, - 138, - 4, - 184, - 16, - 379, - 37, - 306, - 338, - 189, - 193, - 173, - 323, - 164, - 305, - 33, - 157, - 330, - 27, - 16, - 335, - 339, - 352, - 191, - 10, - 36, - 222, - 77, - 307, - 103, - 358, - 196, - 333, - 169, - 386, - 308, - 152, - 34, - 75, - 348, - 219, - 343, - 48, - 11, - 2, - 23, - 367, - 365, - 294, - 275, - 39, - 338, - 154, - 335, - 245, - 313, - 264, - 107, - 223, - 304, - 61, - 306, - 186, - 108, - 147, - 236, - 283, - 147, - 397, - 343, - 111, - 184, - 313, - 264, - 132, - 398, - 49, - 298, - 325, - 370, - 400, - 208, - 146, - 381, - 43, - 153, - 188, - 309, - 212, - 243, - 278, - 184, - 388, - 222, - 46, - 32, - 171, - 230, - 253, - 318, - 128, - 128, - 306, - 298, - 223, - 188, - 277, - 70, - 119, - 232, - 129, - 156, - 167, - 37, - 137, - 356, - 392, - 209, - 324, - 290, - 386, - 319, - 285, - 99, - 339, - 323, - 314, - 301, - 123, - 156, - 311, - 350, - 63, - 246, - 240, - 78, - 110, - 342, - 332, - 374, - 286, - 20, - 253, - 332, - 340, - 37, - 210, - 174, - 324, - 236, - 243, - 395, - 375, - 134, - 288, - 177, - 279, - 33, - 286, - 204, - 134, - 319, - 391, - 181, - 211, - 355, - 32, - 312, - 62, - 69, - 124, - 297, - 38, - 388, - 37, - 350, - 53, - 2, - 129, - 24, - 234, - 372, - 394, - 231, - 168, - 367, - 139, - 345, - 46, - 279, - 180, - 147, - 89, - 364, - 168, - 153, - 94, - 63, - 62, - 127, - 110, - 245, - 229, - 4, - 298, - 352, - 262, - 41, - 269, - 121, - 129, - 40, - 228, - 254, - 114, - 128, - 118, - 73, - 261, - 375, - 65, - 14, - 175, - 128, - 367, - 110, - 50, - 366, - 65, - 59, - 170, - 260, - 58, - 12, - 224, - 246, - 87, - 210, - 12, - 130, - 354, - 123, - 122, - 299, - 143, - 311, - 187, - 298, - 372, - 201, - 159, - 395, - 356, - 15, - 142, - 352, - 212, - 302, - 212, - 213, - 58, - 265, - 209, - 156, - 392, - 261, - 313, - 323, - 293, - 302, - 299, - 171, - 258, - 353, - 382, - 54, - 321, - 78, - 60, - 304, - 146, - 212, - 282, - 237, - 219, - 114, - 2, - 239, - 307, - 247, - 95, - 331, - 247, - 252, - 7, - 289, - 179, - 238, - 328, - 369, - 354, - 130, - 357, - 248, - 292, - 97, - 113, - 297, - 244, - 202, - 21, - 227, - 141, - 78, - 182, - 373, - 191, - 327, - 254, - 61, - 226, - 246, - 1, - 26, - 114, - 335, - 159, - 388, - 273, - 79, - 257, - 361, - 329, - 114, - 368, - 300, - 118, - 329, - 136, - 186, - 281, - 158, - 4, - 132, - 30, - 396, - 361, - 154, - 118, - 151, - 380, - 178, - 238, - 315, - 195, - 179, - 207, - 341, - 231, - 47, - 78, - 37, - 389, - 115, - 329, - 191, - 169, - 217, - 367, - 116, - 61, - 113, - 12, - 21, - 123, - 213, - 128, - 184, - 321, - 260, - 131, - 119, - 34, - 15, - 178, - 58, - 117, - 54, - 35, - 292, - 92, - 271, - 181, - 62, - 168, - 82, - 72, - 310, - 215, - 309, - 334, - 281, - 72, - 351, - 333, - 171, - 207, - 85, - 221, - 232, - 349, - 59, - 258, - 43, - 216, - 54, - 211, - 345, - 131, - 314, - 391, - 39, - 300, - 41, - 35, - 9, - 313, - 269, - 86, - 239, - 189, - 240, - 279, - 331, - 333, - 359, - 128, - 229, - 107, - 87, - 163, - 49, - 151, - 167, - 221, - 327, - 324, - 305, - 281, - 309, - 269, - 141, - 295, - 56, - 66, - 356, - 49, - 289, - 136, - 139, - 117, - 257, - 361, - 297, - 329, - 31, - 142, - 389, - 164, - 32, - 96, - 210, - 149, - 145, - 106, - 51, - 273, - 80, - 211, - 61, - 60, - 106, - 99, - 216, - 309, - 175, - 314, - 370, - 204, - 236, - 148, - 395, - 283, - 55, - 159, - 343, - 292, - 375, - 39, - 237, - 347, - 126, - 192, - 356, - 188, - 357, - 346, - 280, - 308, - 188, - 186, - 159, - 121, - 33, - 52, - 217, - 14, - 191, - 90, - 373, - 5, - 147, - 291, - 332, - 191, - 100, - 27, - 17, - 300, - 63, - 277, - 308, - 235, - 301, - 63, - 208, - 269, - 70, - 134, - 101, - 74, - 393, - 309, - 50, - 69, - 92, - 276, - 89, - 329, - 158, - 346, - 309, - 274, - 274, - 67, - 46, - 45, - 49, - 65, - 254, - 211, - 71, - 206, - 254, - 354, - 301, - 80, - 293, - 229, - 156, - 139, - 155, - 37, - 189, - 159, - 213, - 359, - 284, - 341, - 118, - 307, - 223, - 267, - 345, - 310, - 22, - 136, - 211, - 329, - 209, - 117, - 199, - 164, - 47, - 255, - 281, - 170, - 22, - 313, - 17, - 327, - 304, - 147, - 174, - 229, - 83, - 289, - 92, - 335, - 316, - 143, - 179, - 325, - 121, - 128, - 38, - 61, - 64, - 321, - 69, - 321, - 136, - 101, - 108 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 32 - } - }, - "ans_mem": { - "data": [ - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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 - ], - "format": { - "is_signed": false, - "numeric_type": "bitnum", - "width": 32 - } - } -} diff --git a/calyx-py/test/correctness/static/sdn_static.expect b/calyx-py/test/correctness/static/sdn_static.expect deleted file mode 100644 index f84dae9ac..000000000 --- a/calyx-py/test/correctness/static/sdn_static.expect +++ /dev/null @@ -1,60008 +0,0 @@ -{ - "ans_mem": [ - 87, - 327, - 190, - 248, - 14, - 289, - 110, - 293, - 61, - 331, - 120, - 378, - 17, - 235, - 172, - 373, - 64, - 265, - 115, - 325, - 31, - 373, - 180, - 300, - 85, - 359, - 176, - 297, - 2, - 217, - 120, - 85, - 145, - 3, - 5, - 41, - 372, - 29, - 396, - 70, - 216, - 51, - 369, - 200, - 354, - 94, - 292, - 359, - 361, - 363, - 279, - 224, - 95, - 383, - 350, - 216, - 157, - 384, - 129, - 293, - 25, - 213, - 157, - 284, - 40, - 289, - 116, - 218, - 356, - 279, - 177, - 329, - 172, - 359, - 109, - 388, - 349, - 389, - 128, - 39, - 77, - 248, - 114, - 331, - 71, - 294, - 112, - 365, - 83, - 64, - 294, - 115, - 385, - 31, - 57, - 48, - 242, - 162, - 287, - 63, - 336, - 188, - 255, - 18, - 282, - 132, - 377, - 80, - 240, - 123, - 238, - 37, - 244, - 150, - 344, - 36, - 357, - 157, - 149, - 329, - 134, - 351, - 57, - 102, - 289, - 62, - 68, - 283, - 302, - 207, - 289, - 381, - 132, - 372, - 13, - 208, - 252, - 139, - 227, - 69, - 229, - 227, - 227, - 26, - 217, - 287, - 253, - 212, - 205, - 315, - 240, - 279, - 218, - 53, - 270, - 338, - 295, - 201, - 232, - 218, - 278, - 254, - 216, - 290, - 242, - 140, - 289, - 137, - 238, - 163, - 373, - 126, - 351, - 72, - 267, - 187, - 376, - 44, - 223, - 164, - 269, - 41, - 297, - 28, - 254, - 143, - 399, - 62, - 211, - 134, - 219, - 21, - 346, - 140, - 306, - 98, - 341, - 175, - 339, - 93, - 289, - 39, - 278, - 47, - 396, - 14, - 340, - 75, - 249, - 68, - 281, - 100, - 366, - 63, - 306, - 211, - 342, - 206, - 94, - 347, - 102, - 237, - 13, - 375, - 148, - 329, - 96, - 198, - 55, - 129, - 273, - 29, - 209, - 190, - 361, - 37, - 267, - 121, - 222, - 224, - 55, - 368, - 170, - 330, - 372, - 130, - 203, - 172, - 385, - 26, - 370, - 156, - 399, - 130, - 289, - 158, - 219, - 101, - 232, - 162, - 278, - 6, - 341, - 296, - 266, - 321, - 265, - 112, - 398, - 1, - 399, - 188, - 252, - 41, - 256, - 97, - 328, - 96, - 331, - 45, - 216, - 129, - 370, - 225, - 180, - 289, - 6, - 221, - 180, - 394, - 2, - 316, - 149, - 305, - 22, - 242, - 177, - 336, - 52, - 380, - 142, - 302, - 17, - 370, - 191, - 351, - 7, - 335, - 190, - 295, - 51, - 383, - 198, - 212, - 52, - 319, - 191, - 279, - 45, - 378, - 184, - 355, - 94, - 368, - 165, - 341, - 21, - 380, - 111, - 217, - 46, - 149, - 206, - 98, - 149, - 4, - 184, - 34, - 196, - 34, - 318, - 104, - 268, - 38, - 314, - 125, - 232, - 69, - 218, - 122, - 393, - 8, - 254, - 166, - 300, - 170, - 255, - 182, - 290, - 64, - 201, - 144, - 346, - 54, - 371, - 179, - 341, - 58, - 340, - 188, - 312, - 99, - 156, - 13, - 235, - 170, - 280, - 36, - 294, - 176, - 260, - 95, - 344, - 30, - 238, - 33, - 303, - 11, - 366, - 142, - 347, - 83, - 277, - 188, - 236, - 46, - 307, - 180, - 383, - 55, - 315, - 141, - 337, - 30, - 283, - 99, - 360, - 113, - 370, - 50, - 347, - 394, - 142, - 272, - 342, - 167, - 248, - 41, - 313, - 130, - 385, - 57, - 202, - 102, - 373, - 242, - 113, - 382, - 255, - 47, - 306, - 150, - 299, - 205, - 221, - 2, - 215, - 167, - 230, - 15, - 338, - 171, - 286, - 66, - 391, - 61, - 209, - 45, - 378, - 56, - 249, - 181, - 312, - 6, - 383, - 175, - 389, - 31, - 249, - 102, - 394, - 30, - 235, - 183, - 389, - 46, - 287, - 127, - 357, - 96, - 367, - 113, - 394, - 75, - 260, - 146, - 261, - 67, - 377, - 180, - 334, - 98, - 209, - 192, - 293, - 80, - 306, - 74, - 321, - 41, - 257, - 101, - 238, - 83, - 383, - 93, - 332, - 38, - 296, - 183, - 244, - 101, - 357, - 148, - 274, - 264, - 19, - 219, - 121, - 218, - 353, - 245, - 266, - 214, - 382, - 54, - 211, - 19, - 68, - 395, - 37, - 263, - 91, - 224, - 72, - 352, - 177, - 286, - 13, - 346, - 120, - 341, - 149, - 324, - 200, - 273, - 271, - 89, - 205, - 297, - 230, - 16, - 292, - 274, - 165, - 226, - 208, - 233, - 384, - 204, - 95, - 354, - 129, - 238, - 2, - 372, - 22, - 271, - 103, - 314, - 51, - 395, - 162, - 18, - 273, - 143, - 26, - 112, - 308, - 70, - 328, - 148, - 246, - 49, - 342, - 147, - 204, - 110, - 233, - 70, - 217, - 167, - 276, - 130, - 400, - 117, - 351, - 114, - 301, - 196, - 226, - 342, - 258, - 376, - 383, - 219, - 112, - 231, - 64, - 371, - 145, - 241, - 5, - 328, - 137, - 252, - 124, - 228, - 152, - 322, - 239, - 51, - 303, - 326, - 140, - 320, - 84, - 274, - 41, - 290, - 279, - 196, - 329, - 89, - 197, - 348, - 34, - 217, - 152, - 233, - 13, - 246, - 190, - 301, - 147, - 393, - 27, - 302, - 185, - 222, - 82, - 370, - 166, - 351, - 128, - 385, - 193, - 254, - 78, - 240, - 131, - 307, - 26, - 375, - 90, - 253, - 200, - 238, - 56, - 317, - 119, - 232, - 81, - 394, - 93, - 216, - 351, - 290, - 123, - 309, - 104, - 362, - 171, - 261, - 147, - 323, - 200, - 291, - 83, - 386, - 196, - 271, - 12, - 224, - 124, - 270, - 371, - 236, - 14, - 228, - 94, - 206, - 125, - 252, - 17, - 273, - 191, - 388, - 84, - 367, - 153, - 263, - 6, - 244, - 191, - 245, - 62, - 303, - 158, - 364, - 10, - 221, - 305, - 32, - 159, - 335, - 71, - 353, - 397, - 16, - 144, - 66, - 306, - 143, - 301, - 175, - 330, - 1, - 303, - 172, - 361, - 7, - 373, - 146, - 253, - 161, - 360, - 351, - 203, - 183, - 335, - 111, - 300, - 332, - 29, - 147, - 81, - 295, - 146, - 264, - 148, - 263, - 134, - 227, - 292, - 29, - 146, - 42, - 138, - 280, - 52, - 163, - 344, - 72, - 253, - 14, - 209, - 52, - 381, - 134, - 260, - 84, - 393, - 151, - 338, - 181, - 388, - 279, - 11, - 350, - 228, - 179, - 268, - 87, - 257, - 187, - 333, - 32, - 247, - 151, - 206, - 77, - 371, - 195, - 379, - 83, - 251, - 173, - 391, - 27, - 272, - 118, - 379, - 79, - 395, - 167, - 334, - 53, - 314, - 101, - 237, - 63, - 282, - 103, - 400, - 52, - 203, - 169, - 243, - 83, - 392, - 162, - 286, - 4, - 300, - 146, - 381, - 48, - 212, - 142, - 358, - 24, - 208, - 161, - 282, - 27, - 237, - 21, - 373, - 133, - 219, - 58, - 197, - 228, - 139, - 339, - 220, - 231, - 157, - 223, - 93, - 227, - 192, - 354, - 117, - 203, - 106, - 264, - 11, - 273, - 99, - 374, - 1, - 205, - 334, - 248, - 283, - 262, - 305, - 49, - 350, - 53, - 215, - 336, - 364, - 226, - 217, - 313, - 200, - 303, - 56, - 380, - 93, - 328, - 77, - 290, - 44, - 274, - 137, - 393, - 83, - 208, - 280, - 279, - 75, - 220, - 233, - 267, - 51, - 287, - 145, - 246, - 132, - 146, - 98, - 162, - 58, - 155, - 37, - 155, - 40, - 146, - 165, - 105, - 393, - 177, - 348, - 97, - 233, - 161, - 315, - 70, - 230, - 33, - 237, - 45, - 257, - 64, - 382, - 164, - 9, - 381, - 31, - 56, - 51, - 37, - 365, - 64, - 383, - 152, - 55, - 190, - 27, - 240, - 169, - 66, - 138, - 48, - 316, - 166, - 388, - 62, - 150, - 106, - 382, - 34, - 249, - 151, - 136, - 121, - 21, - 155, - 244, - 39, - 239, - 186, - 231, - 189, - 296, - 35, - 262, - 170, - 316, - 169, - 229, - 106, - 322, - 143, - 151, - 156, - 188, - 57, - 281, - 195, - 82, - 169, - 62, - 146, - 168, - 338, - 102, - 211, - 40, - 222, - 134, - 302, - 193, - 305, - 137, - 211, - 92, - 292, - 238, - 178, - 317, - 17, - 356, - 4, - 355, - 216, - 217, - 342, - 274, - 248, - 352, - 353, - 125, - 209, - 96, - 325, - 145, - 22, - 395, - 180, - 282, - 85, - 351, - 163, - 297, - 49, - 369, - 183, - 349, - 59, - 240, - 112, - 300, - 310, - 378, - 396, - 273, - 16, - 242, - 133, - 215, - 93, - 255, - 152, - 400, - 100, - 264, - 9, - 272, - 85, - 323, - 22, - 400, - 37, - 356, - 115, - 324, - 67, - 370, - 3, - 359, - 156, - 272, - 14, - 264, - 108, - 303, - 53, - 261, - 101, - 236, - 48, - 224, - 193, - 388, - 72, - 383, - 125, - 345, - 75, - 209, - 172, - 225, - 73, - 262, - 152, - 46, - 74, - 27, - 3, - 326, - 67, - 155, - 22, - 290, - 157, - 305, - 36, - 230, - 127, - 350, - 31, - 375, - 105, - 331, - 135, - 394, - 11, - 360, - 163, - 319, - 147, - 391, - 184, - 282, - 19, - 232, - 60, - 308, - 306, - 71, - 283, - 391, - 387, - 61, - 159, - 51, - 47, - 44, - 254, - 193, - 211, - 25, - 259, - 136, - 269, - 95, - 209, - 167, - 301, - 50, - 253, - 117, - 259, - 65, - 237, - 121, - 308, - 62, - 280, - 115, - 315, - 68, - 263, - 114, - 2, - 141, - 150, - 57, - 280, - 141, - 26, - 158, - 221, - 100, - 284, - 174, - 251, - 61, - 198, - 385, - 74, - 117, - 101, - 50, - 343, - 291, - 85, - 376, - 67, - 152, - 77, - 306, - 287, - 46, - 143, - 136, - 304, - 130, - 338, - 14, - 208, - 153, - 397, - 108, - 224, - 42, - 306, - 145, - 387, - 76, - 331, - 189, - 237, - 190, - 264, - 149, - 338, - 63, - 223, - 104, - 395, - 9, - 219, - 113, - 362, - 21, - 232, - 59, - 214, - 91, - 356, - 91, - 371, - 142, - 280, - 49, - 230, - 25, - 392, - 190, - 284, - 147, - 285, - 117, - 357, - 147, - 276, - 69, - 301, - 115, - 320, - 16, - 330, - 148, - 337, - 56, - 380, - 112, - 398, - 149, - 351, - 182, - 229, - 338, - 82, - 254, - 207, - 134, - 238, - 202, - 271, - 148, - 231, - 73, - 213, - 198, - 326, - 68, - 320, - 123, - 201, - 25, - 288, - 149, - 342, - 163, - 210, - 170, - 263, - 152, - 234, - 210, - 314, - 204, - 347, - 60, - 163, - 366, - 134, - 204, - 185, - 74, - 68, - 309, - 276, - 89, - 207, - 7, - 336, - 151, - 381, - 50, - 304, - 157, - 268, - 148, - 243, - 166, - 256, - 177, - 341, - 25, - 165, - 394, - 106, - 335, - 122, - 243, - 37, - 252, - 135, - 389, - 105, - 316, - 166, - 252, - 30, - 262, - 130, - 378, - 76, - 251, - 251, - 327, - 380, - 276, - 345, - 137, - 258, - 75, - 349, - 167, - 359, - 92, - 270, - 133, - 224, - 96, - 290, - 282, - 98, - 289, - 100, - 244, - 82, - 165, - 280, - 24, - 121, - 174, - 169, - 185, - 364, - 110, - 179, - 312, - 59, - 247, - 153, - 249, - 150, - 241, - 33, - 369, - 169, - 391, - 48, - 284, - 181, - 208, - 62, - 268, - 121, - 228, - 41, - 299, - 141, - 207, - 143, - 217, - 61, - 356, - 122, - 358, - 36, - 327, - 120, - 285, - 83, - 339, - 117, - 331, - 9, - 210, - 135, - 397, - 55, - 297, - 129, - 288, - 69, - 333, - 157, - 383, - 91, - 239, - 200, - 276, - 3, - 200, - 324, - 98, - 105, - 25, - 183, - 385, - 67, - 356, - 56, - 391, - 143, - 299, - 88, - 233, - 150, - 299, - 96, - 247, - 103, - 340, - 50, - 307, - 187, - 212, - 46, - 292, - 161, - 322, - 52, - 236, - 163, - 72, - 132, - 48, - 384, - 159, - 97, - 102, - 58, - 270, - 132, - 258, - 96, - 318, - 111, - 302, - 82, - 393, - 131, - 373, - 17, - 281, - 164, - 272, - 83, - 321, - 15, - 319, - 30, - 240, - 264, - 143, - 239, - 12, - 251, - 146, - 217, - 155, - 248, - 177, - 230, - 117, - 264, - 179, - 255, - 137, - 219, - 131, - 398, - 131, - 337, - 94, - 384, - 112, - 258, - 104, - 201, - 174, - 274, - 74, - 337, - 144, - 314, - 96, - 220, - 110, - 374, - 180, - 344, - 180, - 331, - 138, - 364, - 28, - 305, - 101, - 235, - 141, - 392, - 107, - 189, - 248, - 150, - 199, - 344, - 171, - 293, - 152, - 384, - 291, - 254, - 322, - 351, - 239, - 64, - 398, - 8, - 118, - 329, - 47, - 335, - 123, - 335, - 58, - 375, - 104, - 328, - 20, - 268, - 170, - 245, - 23, - 355, - 68, - 390, - 73, - 352, - 200, - 336, - 11, - 205, - 59, - 248, - 53, - 256, - 188, - 248, - 79, - 240, - 176, - 349, - 13, - 277, - 162, - 262, - 93, - 253, - 181, - 261, - 79, - 214, - 107, - 395, - 73, - 393, - 175, - 227, - 63, - 231, - 155, - 295, - 18, - 336, - 16, - 218, - 56, - 368, - 42, - 209, - 268, - 16, - 210, - 205, - 7, - 359, - 195, - 298, - 137, - 242, - 36, - 399, - 382, - 5, - 241, - 329, - 297, - 396, - 29, - 272, - 75, - 240, - 186, - 247, - 18, - 271, - 71, - 203, - 74, - 351, - 143, - 347, - 58, - 379, - 151, - 384, - 18, - 258, - 124, - 252, - 16, - 215, - 106, - 218, - 32, - 257, - 133, - 237, - 51, - 284, - 139, - 257, - 25, - 244, - 142, - 208, - 35, - 391, - 147, - 303, - 188, - 292, - 40, - 272, - 110, - 220, - 3, - 351, - 157, - 362, - 53, - 398, - 170, - 385, - 2, - 213, - 168, - 394, - 17, - 302, - 189, - 8, - 333, - 200, - 358, - 10, - 323, - 200, - 355, - 63, - 360, - 185, - 205, - 27, - 351, - 188, - 228, - 29, - 238, - 187, - 303, - 6, - 348, - 175, - 266, - 96, - 331, - 181, - 270, - 51, - 340, - 172, - 239, - 43, - 296, - 159, - 337, - 29, - 317, - 115, - 332, - 12, - 271, - 138, - 65, - 218, - 148, - 380, - 49, - 184, - 96, - 200, - 306, - 23, - 398, - 120, - 218, - 85, - 343, - 131, - 211, - 15, - 316, - 143, - 288, - 32, - 113, - 29, - 228, - 143, - 372, - 34, - 356, - 166, - 274, - 100, - 350, - 111, - 62, - 101, - 361, - 42, - 195, - 23, - 52, - 206, - 17, - 331, - 53, - 240, - 67, - 340, - 183, - 260, - 35, - 266, - 193, - 280, - 67, - 389, - 156, - 241, - 91, - 298, - 168, - 396, - 2, - 303, - 134, - 282, - 40, - 291, - 183, - 362, - 52, - 283, - 157, - 317, - 188, - 364, - 69, - 381, - 133, - 318, - 44, - 278, - 193, - 264, - 30, - 257, - 127, - 252, - 77, - 322, - 173, - 216, - 44, - 354, - 155, - 280, - 189, - 288, - 139, - 367, - 373, - 140, - 343, - 297, - 334, - 92, - 388, - 193, - 13, - 236, - 197, - 169, - 25, - 345, - 30, - 87, - 102, - 39, - 288, - 158, - 256, - 87, - 272, - 197, - 264, - 20, - 399, - 129, - 283, - 53, - 131, - 393, - 99, - 124, - 58, - 152, - 251, - 42, - 237, - 35, - 362, - 66, - 213, - 297, - 288, - 292, - 325, - 142, - 358, - 44, - 360, - 140, - 213, - 117, - 303, - 71, - 249, - 38, - 366, - 72, - 253, - 89, - 353, - 163, - 392, - 16, - 353, - 78, - 282, - 126, - 355, - 47, - 273, - 129, - 342, - 2, - 301, - 91, - 235, - 70, - 304, - 345, - 346, - 121, - 216, - 83, - 204, - 120, - 389, - 130, - 305, - 32, - 252, - 134, - 216, - 16, - 296, - 31, - 255, - 11, - 202, - 167, - 396, - 90, - 389, - 120, - 245, - 75, - 262, - 185, - 307, - 89, - 374, - 134, - 331, - 51, - 342, - 145, - 205, - 27, - 282, - 145, - 57, - 398, - 165, - 212, - 33, - 290, - 160, - 384, - 53, - 218, - 132, - 381, - 41, - 298, - 40, - 260, - 348, - 300, - 218, - 6, - 381, - 65, - 220, - 41, - 255, - 174, - 289, - 77, - 400, - 110, - 316, - 66, - 248, - 69, - 254, - 10, - 398, - 28, - 261, - 98, - 314, - 76, - 396, - 39, - 322, - 160, - 395, - 206, - 13, - 300, - 169, - 304, - 92, - 287, - 150, - 240, - 293, - 80, - 399, - 167, - 354, - 196, - 211, - 168, - 251, - 356, - 18, - 343, - 194, - 350, - 132, - 318, - 222, - 323, - 151, - 218, - 126, - 342, - 103, - 285, - 147, - 352, - 250, - 317, - 167, - 213, - 387, - 195, - 274, - 103, - 331, - 337, - 289, - 369, - 399, - 333, - 286, - 385, - 366, - 400, - 25, - 341, - 141, - 221, - 73, - 246, - 184, - 338, - 92, - 332, - 101, - 204, - 181, - 321, - 132, - 360, - 4, - 331, - 112, - 210, - 53, - 243, - 189, - 399, - 52, - 378, - 119, - 260, - 85, - 341, - 193, - 263, - 74, - 295, - 127, - 311, - 154, - 315, - 37, - 371, - 152, - 251, - 25, - 249, - 320, - 41, - 316, - 37, - 225, - 368, - 68, - 367, - 389, - 361, - 250, - 338, - 355, - 186, - 347, - 325, - 202, - 88, - 377, - 175, - 303, - 79, - 317, - 138, - 346, - 80, - 317, - 186, - 364, - 88, - 248, - 68, - 362, - 69, - 92, - 211, - 55, - 231, - 92, - 337, - 87, - 277, - 17, - 358, - 15, - 327, - 196, - 264, - 92, - 211, - 140, - 203, - 17, - 393, - 185, - 385, - 316, - 54, - 293, - 252, - 386, - 359, - 54, - 351, - 148, - 351, - 207, - 37, - 257, - 188, - 386, - 81, - 321, - 132, - 310, - 44, - 296, - 188, - 228, - 39, - 338, - 156, - 229, - 52, - 385, - 142, - 97, - 139, - 258, - 77, - 316, - 189, - 114, - 136, - 278, - 128, - 328, - 84, - 309, - 112, - 232, - 194, - 344, - 119, - 281, - 105, - 295, - 105, - 251, - 39, - 317, - 179, - 360, - 100, - 260, - 76, - 386, - 37, - 334, - 238, - 299, - 90, - 330, - 311, - 126, - 385, - 61, - 385, - 200, - 356, - 64, - 167, - 56, - 108, - 305, - 26, - 214, - 82, - 284, - 19, - 324, - 54, - 246, - 133, - 247, - 57, - 258, - 157, - 302, - 74, - 330, - 103, - 365, - 87, - 121, - 226, - 88, - 348, - 57, - 305, - 37, - 315, - 97, - 312, - 266, - 307, - 33, - 311, - 393, - 315, - 311, - 166, - 390, - 138, - 313, - 34, - 358, - 200, - 280, - 15, - 386, - 168, - 266, - 4, - 249, - 192, - 365, - 99, - 365, - 59, - 400, - 25, - 381, - 104, - 357, - 16, - 359, - 126, - 394, - 54, - 86, - 322, - 343, - 313, - 260, - 222, - 165, - 243, - 230, - 355, - 73, - 204, - 279, - 324, - 149, - 223, - 352, - 80, - 264, - 114, - 319, - 73, - 318, - 145, - 255, - 99, - 289, - 187, - 281, - 8, - 381, - 178, - 261, - 29, - 142, - 46, - 109, - 121, - 300, - 113, - 308, - 57, - 313, - 138, - 221, - 37, - 380, - 89, - 310, - 38, - 357, - 38, - 332, - 117, - 345, - 29, - 319, - 123, - 320, - 61, - 239, - 109, - 224, - 5, - 228, - 168, - 228, - 100, - 156, - 52, - 50, - 356, - 50, - 161, - 283, - 149, - 215, - 65, - 267, - 142, - 216, - 20, - 334, - 160, - 373, - 77, - 203, - 170, - 362, - 73, - 219, - 156, - 249, - 52, - 386, - 105, - 360, - 84, - 385, - 111, - 229, - 197, - 308, - 111, - 385, - 191, - 267, - 153, - 302, - 32, - 302, - 130, - 361, - 143, - 260, - 183, - 313, - 168, - 386, - 53, - 355, - 190, - 305, - 42, - 255, - 112, - 317, - 116, - 271, - 80, - 202, - 154, - 214, - 50, - 296, - 25, - 377, - 28, - 255, - 96, - 297, - 181, - 342, - 78, - 365, - 253, - 374, - 243, - 345, - 254, - 297, - 354, - 373, - 276, - 313, - 88, - 43, - 246, - 76, - 201, - 179, - 385, - 60, - 367, - 111, - 373, - 85, - 373, - 171, - 268, - 42, - 292, - 159, - 285, - 58, - 267, - 192, - 223, - 19, - 110, - 246, - 47, - 330, - 168, - 201, - 22, - 282, - 199, - 236, - 61, - 307, - 115, - 310, - 29, - 331, - 115, - 378, - 26, - 241, - 171, - 260, - 83, - 262, - 101, - 335, - 74, - 293, - 178, - 355, - 49, - 218, - 167, - 283, - 2, - 293, - 9, - 269, - 30, - 284, - 47, - 274, - 16, - 336, - 371, - 378, - 343, - 379, - 235, - 316, - 62, - 292, - 207, - 213, - 335, - 393, - 136, - 357, - 67, - 345, - 63, - 310, - 105, - 242, - 84, - 202, - 163, - 326, - 64, - 344, - 80, - 256, - 267, - 374, - 200, - 367, - 50, - 320, - 340, - 172, - 241, - 100, - 378, - 191, - 223, - 322, - 132, - 385, - 43, - 305, - 24, - 239, - 157, - 252, - 47, - 255, - 178, - 261, - 99, - 302, - 170, - 378, - 28, - 292, - 142, - 277, - 154, - 282, - 189, - 307, - 43, - 280, - 102, - 299, - 159, - 273, - 186, - 321, - 181, - 257, - 125, - 222, - 158, - 238, - 141, - 265, - 18, - 285, - 134, - 345, - 24, - 258, - 160, - 301, - 32, - 182, - 175, - 55, - 46, - 335, - 178, - 360, - 116, - 300, - 46, - 321, - 107, - 317, - 95, - 237, - 101, - 40, - 182, - 16, - 46, - 34, - 78, - 372, - 37, - 234, - 314, - 182, - 346, - 20, - 391, - 114, - 397, - 3, - 344, - 144, - 243, - 168, - 267, - 34, - 273, - 121, - 273, - 68, - 298, - 141, - 399, - 96, - 358, - 177, - 248, - 84, - 364, - 176, - 224, - 18, - 383, - 154, - 291, - 25, - 323, - 123, - 392, - 52, - 311, - 185, - 330, - 41, - 320, - 168, - 368, - 83, - 343, - 129, - 294, - 5, - 279, - 102, - 299, - 235, - 262, - 25, - 234, - 221, - 203, - 185, - 399, - 37, - 362, - 390, - 369, - 58, - 310, - 30, - 302, - 355, - 253, - 380, - 205, - 182, - 220, - 62, - 288, - 108, - 295, - 96, - 343, - 125, - 257, - 25, - 279, - 62, - 300, - 6, - 221, - 196, - 202, - 4, - 319, - 170, - 363, - 73, - 271, - 195, - 240, - 86, - 144, - 26, - 6, - 128, - 353, - 95, - 379, - 116, - 238, - 85, - 149, - 77, - 188, - 336, - 74, - 283, - 254, - 81, - 202, - 332, - 358, - 237, - 213, - 335, - 313, - 112, - 55, - 146, - 50, - 228, - 190, - 286, - 96, - 238, - 131, - 328, - 56, - 302, - 151, - 332, - 112, - 312, - 131, - 236, - 138, - 335, - 325, - 60, - 343, - 337, - 47, - 316, - 222, - 91, - 208, - 50, - 278, - 375, - 260, - 254, - 149, - 390, - 275, - 157, - 347, - 176, - 361, - 116, - 344, - 165, - 337, - 103, - 239, - 359, - 89, - 149, - 65, - 160, - 113, - 287, - 95, - 159, - 351, - 50, - 96, - 382, - 161, - 323, - 293, - 263, - 293, - 262, - 266, - 41, - 261, - 190, - 228, - 119, - 222, - 22, - 272, - 184, - 353, - 36, - 368, - 133, - 254, - 9, - 249, - 136, - 257, - 125, - 285, - 143, - 280, - 289, - 164, - 210, - 195, - 248, - 63, - 393, - 172, - 378, - 81, - 333, - 47, - 297, - 36, - 369, - 52, - 373, - 25, - 271, - 164, - 219, - 69, - 258, - 158, - 294, - 2, - 396, - 160, - 203, - 70, - 260, - 182, - 319, - 24, - 317, - 190, - 329, - 4, - 271, - 146, - 386, - 49, - 334, - 113, - 254, - 25, - 313, - 107, - 252, - 45, - 250, - 138, - 208, - 87, - 388, - 121, - 310, - 39, - 360, - 27, - 357, - 42, - 278, - 135, - 294, - 84, - 324, - 343, - 172, - 354, - 180, - 374, - 22, - 259, - 117, - 263, - 4, - 327, - 109, - 182, - 188, - 356, - 76, - 379, - 377, - 173, - 234, - 38, - 298, - 175, - 218, - 91, - 239, - 81, - 313, - 102, - 377, - 91, - 215, - 151, - 257, - 77, - 388, - 122, - 343, - 10, - 323, - 141, - 377, - 40, - 364, - 190, - 202, - 65, - 326, - 36, - 254, - 53, - 395, - 128, - 220, - 63, - 326, - 55, - 334, - 128, - 284, - 19, - 216, - 138, - 205, - 8, - 290, - 34, - 222, - 24, - 303, - 200, - 255, - 99, - 239, - 55, - 289, - 71, - 237, - 199, - 231, - 32, - 309, - 45, - 223, - 109, - 318, - 34, - 310, - 118, - 311, - 8, - 333, - 103, - 214, - 55, - 229, - 154, - 209, - 53, - 271, - 108, - 390, - 57, - 135, - 36, - 371, - 162, - 25, - 115, - 40, - 13, - 240, - 80, - 108, - 275, - 59, - 32, - 399, - 52, - 317, - 98, - 337, - 120, - 252, - 59, - 209, - 18, - 259, - 2, - 248, - 35, - 375, - 31, - 233, - 190, - 242, - 251, - 243, - 80, - 218, - 192, - 263, - 148, - 223, - 368, - 163, - 230, - 48, - 262, - 134, - 331, - 68, - 272, - 390, - 298, - 323, - 262, - 272, - 187, - 336, - 66, - 373, - 166, - 217, - 82, - 257, - 259, - 297, - 213, - 225, - 320, - 288, - 154, - 227, - 99, - 210, - 164, - 289, - 165, - 226, - 189, - 250, - 313, - 105, - 386, - 399, - 191, - 310, - 338, - 314, - 155, - 228, - 232, - 386, - 165, - 256, - 331, - 80, - 320, - 131, - 334, - 327, - 286, - 22, - 253, - 108, - 289, - 77, - 208, - 118, - 310, - 45, - 398, - 164, - 341, - 50, - 362, - 109, - 353, - 36, - 205, - 181, - 326, - 91, - 304, - 188, - 395, - 131, - 328, - 337, - 392, - 145, - 263, - 258, - 245, - 130, - 284, - 372, - 233, - 286, - 348, - 38, - 335, - 214, - 241, - 277, - 85, - 264, - 172, - 55, - 355, - 118, - 376, - 47, - 228, - 182, - 291, - 35, - 229, - 126, - 384, - 5, - 234, - 109, - 296, - 4, - 272, - 134, - 84, - 286, - 188, - 22, - 192, - 89, - 187, - 339, - 77, - 180, - 77, - 239, - 110, - 349, - 172, - 225, - 74, - 348, - 125, - 357, - 79, - 225, - 101, - 387, - 4, - 398, - 123, - 226, - 166, - 347, - 55, - 165, - 96, - 299, - 144, - 209, - 75, - 385, - 153, - 348, - 68, - 324, - 135, - 217, - 75, - 367, - 146, - 261, - 12, - 399, - 126, - 220, - 62, - 300, - 120, - 286, - 40, - 270, - 86, - 24, - 388, - 189, - 252, - 137, - 279, - 148, - 145, - 219, - 107, - 305, - 272, - 58, - 370, - 156, - 302, - 17, - 292, - 37, - 398, - 72, - 261, - 130, - 319, - 26, - 346, - 35, - 69, - 188, - 300, - 31, - 306, - 120, - 225, - 86, - 267, - 105, - 344, - 19, - 314, - 148, - 365, - 46, - 376, - 148, - 265, - 20, - 267, - 181, - 235, - 27, - 208, - 124, - 238, - 64, - 339, - 156, - 284, - 29, - 327, - 161, - 285, - 31, - 377, - 5, - 267, - 238, - 305, - 389, - 10, - 380, - 104, - 204, - 92, - 354, - 154, - 239, - 33, - 273, - 155, - 366, - 71, - 373, - 186, - 319, - 46, - 247, - 120, - 217, - 78, - 343, - 122, - 205, - 190, - 2, - 368, - 183, - 67, - 292, - 198, - 368, - 40, - 245, - 113, - 359, - 33, - 244, - 187, - 240, - 34, - 286, - 178, - 292, - 71, - 384, - 166, - 288, - 81, - 317, - 190, - 32, - 261, - 111, - 242, - 14, - 248, - 157, - 212, - 84, - 218, - 66, - 261, - 143, - 253, - 83, - 358, - 139, - 382, - 7, - 235, - 160, - 271, - 100, - 286, - 114, - 318, - 76, - 354, - 101, - 292, - 78, - 285, - 182, - 291, - 55, - 350, - 195, - 325, - 6, - 301, - 195, - 210, - 35, - 215, - 12, - 308, - 97, - 273, - 156, - 278, - 80, - 246, - 184, - 268, - 67, - 294, - 172, - 374, - 98, - 228, - 171, - 307, - 81, - 392, - 33, - 231, - 21, - 294, - 308, - 348, - 203, - 333, - 351, - 219, - 272, - 267, - 225, - 152, - 307, - 47, - 221, - 128, - 339, - 313, - 66, - 369, - 60, - 368, - 52, - 103, - 125, - 269, - 78, - 147, - 157, - 96, - 384, - 124, - 385, - 132, - 299, - 103, - 277, - 166, - 276, - 208, - 325, - 91, - 353, - 184, - 369, - 8, - 290, - 169, - 202, - 23, - 293, - 78, - 388, - 178, - 229, - 37, - 278, - 169, - 391, - 60, - 206, - 174, - 377, - 70, - 400, - 196, - 257, - 31, - 384, - 1, - 312, - 39, - 219, - 199, - 376, - 85, - 345, - 178, - 88, - 31, - 11, - 80, - 53, - 119, - 204, - 15, - 329, - 197, - 213, - 50, - 379, - 149, - 221, - 76, - 226, - 143, - 85, - 57, - 3, - 392, - 160, - 69, - 135, - 339, - 83, - 347, - 197, - 180, - 69, - 48, - 237, - 73, - 58, - 294, - 138, - 364, - 39, - 282, - 100, - 244, - 161, - 293, - 37, - 315, - 160, - 377, - 76, - 262, - 34, - 327, - 99, - 329, - 27, - 284, - 52, - 374, - 155, - 325, - 99, - 242, - 111, - 383, - 29, - 322, - 120, - 225, - 50, - 376, - 130, - 299, - 46, - 362, - 21, - 326, - 332, - 305, - 227, - 325, - 129, - 262, - 11, - 332, - 229, - 365, - 374, - 25, - 310, - 172, - 391, - 100, - 286, - 357, - 315, - 283, - 338, - 136, - 233, - 23, - 356, - 166, - 283, - 302, - 271, - 209, - 340, - 74, - 377, - 108, - 345, - 83, - 328, - 181, - 287, - 86, - 382, - 144, - 359, - 50, - 336, - 185, - 321, - 3, - 313, - 166, - 363, - 1, - 231, - 165, - 384, - 23, - 385, - 194, - 381, - 79, - 354, - 182, - 266, - 26, - 216, - 135, - 313, - 130, - 370, - 105, - 396, - 131, - 205, - 42, - 207, - 9, - 271, - 367, - 257, - 322, - 137, - 278, - 99, - 258, - 22, - 221, - 321, - 105, - 168, - 349, - 196, - 360, - 133, - 323, - 35, - 310, - 106, - 292, - 87, - 309, - 127, - 202, - 187, - 355, - 398, - 281, - 157, - 241, - 259, - 247, - 279, - 256, - 131, - 400, - 105, - 400, - 169, - 307, - 158, - 204, - 131, - 303, - 162, - 397, - 190, - 204, - 105, - 341, - 163, - 244, - 179, - 331, - 62, - 270, - 232, - 304, - 378, - 145, - 317, - 318, - 374, - 254, - 212, - 331, - 367, - 306, - 91, - 230, - 119, - 387, - 139, - 249, - 361, - 91, - 256, - 179, - 393, - 115, - 245, - 195, - 374, - 255, - 128, - 266, - 121, - 324, - 4, - 274, - 320, - 398, - 327, - 330, - 231, - 39, - 297, - 139, - 230, - 61, - 293, - 198, - 282, - 51, - 366, - 188, - 276, - 78, - 380, - 140, - 361, - 64, - 279, - 200, - 347, - 66, - 395, - 153, - 7, - 103, - 52, - 227, - 181, - 353, - 21, - 326, - 195, - 327, - 37, - 287, - 118, - 317, - 28, - 379, - 186, - 382, - 40, - 352, - 173, - 383, - 94, - 213, - 178, - 313, - 200, - 400, - 7, - 252, - 114, - 296, - 48, - 377, - 103, - 201, - 215, - 372, - 368, - 257, - 61, - 349, - 115, - 274, - 89, - 212, - 47, - 231, - 200, - 260, - 69, - 303, - 146, - 303, - 49, - 360, - 157, - 235, - 97, - 193, - 156, - 348, - 64, - 257, - 115, - 362, - 73, - 243, - 178, - 330, - 102, - 36, - 166, - 153, - 64, - 175, - 7, - 198, - 70, - 296, - 195, - 51, - 176, - 274, - 138, - 253, - 144, - 263, - 127, - 246, - 6, - 278, - 167, - 361, - 7, - 124, - 86, - 103, - 216, - 85, - 376, - 176, - 72, - 88, - 69, - 82, - 394, - 151, - 258, - 43, - 371, - 109, - 329, - 1, - 203, - 110, - 361, - 78, - 250, - 177, - 325, - 50, - 398, - 8, - 322, - 90, - 391, - 31, - 358, - 30, - 260, - 81, - 224, - 132, - 219, - 52, - 337, - 193, - 229, - 90, - 274, - 162, - 109, - 246, - 159, - 260, - 70, - 352, - 110, - 328, - 83, - 375, - 171, - 298, - 10, - 314, - 126, - 246, - 42, - 250, - 160, - 201, - 6, - 205, - 57, - 44, - 143, - 65, - 106, - 65, - 192, - 71, - 307, - 106, - 294, - 48, - 257, - 174, - 203, - 66, - 372, - 179, - 251, - 21, - 356, - 134, - 301, - 6, - 245, - 190, - 362, - 79, - 305, - 138, - 210, - 1, - 239, - 39, - 203, - 75, - 311, - 80, - 330, - 9, - 332, - 196, - 247, - 2, - 369, - 174, - 292, - 311, - 154, - 272, - 78, - 212, - 355, - 257, - 249, - 197, - 357, - 79, - 241, - 106, - 363, - 82, - 243, - 103, - 257, - 79, - 330, - 132, - 205, - 18, - 293, - 322, - 299, - 198, - 231, - 22, - 357, - 114, - 240, - 23, - 351, - 105, - 323, - 74, - 233, - 121, - 127, - 186, - 326, - 168, - 221, - 357, - 347, - 149, - 370, - 82, - 324, - 108, - 325, - 38, - 233, - 162, - 244, - 194, - 394, - 3, - 223, - 191, - 204, - 32, - 379, - 114, - 264, - 212, - 385, - 1, - 278, - 175, - 267, - 25, - 344, - 110, - 238, - 21, - 288, - 148, - 236, - 98, - 126, - 28, - 138, - 53, - 180, - 209, - 68, - 142, - 23, - 169, - 14, - 162, - 248, - 42, - 107, - 377, - 58, - 399, - 181, - 276, - 6, - 284, - 117, - 293, - 264, - 197, - 334, - 30, - 380, - 39, - 216, - 126, - 222, - 12, - 328, - 126, - 217, - 17, - 226, - 168, - 257, - 148, - 275, - 157, - 276, - 114, - 342, - 40, - 379, - 125, - 228, - 28, - 280, - 84, - 149, - 19, - 59, - 385, - 107, - 243, - 2, - 324, - 191, - 213, - 186, - 255, - 92, - 300, - 150, - 254, - 8, - 242, - 193, - 253, - 82, - 361, - 165, - 330, - 21, - 374, - 153, - 240, - 77, - 261, - 159, - 257, - 27, - 293, - 161, - 228, - 31, - 369, - 139, - 324, - 20, - 330, - 155, - 226, - 79, - 394, - 187, - 298, - 92, - 253, - 160, - 287, - 152, - 217, - 157, - 202, - 124, - 359, - 138, - 230, - 1, - 330, - 156, - 319, - 82, - 283, - 182, - 342, - 184, - 229, - 141, - 314, - 135, - 383, - 344, - 296, - 162, - 353, - 37, - 218, - 156, - 209, - 17, - 262, - 136, - 239, - 309, - 132, - 221, - 201, - 81, - 391, - 395, - 390, - 206, - 227, - 395, - 35, - 208, - 357, - 151, - 240, - 89, - 220, - 155, - 279, - 383, - 70, - 221, - 34, - 282, - 99, - 268, - 186, - 376, - 61, - 290, - 189, - 382, - 88, - 173, - 248, - 9, - 175, - 17, - 330, - 67, - 254, - 25, - 245, - 54, - 125, - 76, - 78, - 212, - 138, - 361, - 40, - 209, - 160, - 232, - 184, - 343, - 78, - 354, - 105, - 221, - 15, - 319, - 146, - 100, - 232, - 142, - 180, - 120, - 339, - 132, - 335, - 84, - 396, - 146, - 296, - 126, - 279, - 163, - 241, - 187, - 373, - 143, - 226, - 22, - 382, - 110, - 329, - 13, - 333, - 182, - 274, - 161, - 181, - 266, - 84, - 394, - 174, - 294, - 87, - 219, - 166, - 201, - 90, - 235, - 181, - 346, - 93, - 385, - 152, - 385, - 91, - 283, - 110, - 298, - 74, - 245, - 199, - 374, - 107, - 312, - 10, - 251, - 136, - 252, - 170, - 382, - 140, - 280, - 183, - 395, - 374, - 330, - 234, - 381, - 344, - 369, - 263, - 244, - 141, - 398, - 247, - 235, - 16, - 238, - 158, - 284, - 52, - 288, - 197, - 392, - 75, - 204, - 166, - 260, - 35, - 258, - 23, - 319, - 277, - 162, - 273, - 33, - 144, - 92, - 358, - 72, - 235, - 79, - 91, - 47, - 380, - 120, - 201, - 47, - 193, - 302, - 181, - 250, - 49, - 115, - 121, - 278, - 69, - 348, - 178, - 395, - 145, - 218, - 44, - 349, - 168, - 248, - 109, - 345, - 167, - 271, - 115, - 334, - 157, - 272, - 100, - 274, - 103, - 214, - 61, - 272, - 163, - 277, - 24, - 264, - 199, - 369, - 37, - 336, - 186, - 260, - 61, - 378, - 146, - 324, - 83, - 288, - 180, - 283, - 50, - 369, - 148, - 382, - 92, - 316, - 127, - 251, - 89, - 321, - 67, - 359, - 31, - 318, - 23, - 327, - 376, - 245, - 369, - 311, - 283, - 43, - 361, - 243, - 396, - 38, - 204, - 201, - 200, - 365, - 330, - 147, - 243, - 120, - 66, - 377, - 183, - 222, - 58, - 344, - 39, - 385, - 194, - 236, - 5, - 250, - 103, - 247, - 68, - 258, - 21, - 337, - 341, - 273, - 389, - 199, - 300, - 74, - 253, - 13, - 358, - 58, - 354, - 224, - 87, - 355, - 44, - 217, - 85, - 214, - 24, - 341, - 103, - 303, - 31, - 203, - 47, - 311, - 199, - 367, - 59, - 262, - 192, - 242, - 59, - 253, - 198, - 359, - 25, - 226, - 70, - 366, - 67, - 357, - 24, - 329, - 180, - 290, - 41, - 222, - 148, - 244, - 89, - 306, - 105, - 305, - 147, - 213, - 37, - 309, - 173, - 279, - 11, - 394, - 193, - 308, - 74, - 257, - 198, - 322, - 46, - 246, - 3, - 315, - 113, - 381, - 332, - 383, - 18, - 267, - 21, - 236, - 258, - 386, - 15, - 279, - 61, - 269, - 151, - 205, - 16, - 318, - 188, - 359, - 52, - 212, - 97, - 242, - 240, - 289, - 328, - 266, - 135, - 143, - 210, - 199, - 307, - 214, - 10, - 47, - 148, - 254, - 389, - 185, - 379, - 124, - 291, - 136, - 370, - 14, - 263, - 130, - 348, - 27, - 338, - 171, - 229, - 1, - 298, - 184, - 43, - 293, - 126, - 224, - 6, - 276, - 150, - 397, - 61, - 396, - 189, - 330, - 27, - 323, - 180, - 66, - 270, - 156, - 18, - 166, - 3, - 108, - 28, - 159, - 364, - 37, - 380, - 146, - 64, - 141, - 290, - 39, - 130, - 63, - 374, - 155, - 328, - 24, - 274, - 138, - 280, - 29, - 303, - 99, - 296, - 89, - 223, - 75, - 229, - 13, - 309, - 7, - 219, - 87, - 273, - 111, - 317, - 25, - 328, - 109, - 345, - 17, - 291, - 168, - 267, - 29, - 383, - 189, - 263, - 37, - 251, - 90, - 351, - 385, - 7, - 228, - 20, - 278, - 199, - 273, - 18, - 377, - 171, - 221, - 11, - 228, - 138, - 335, - 179, - 201, - 192, - 277, - 170, - 316, - 112, - 387, - 100, - 350, - 161, - 312, - 112, - 385, - 69, - 303, - 126, - 217, - 16, - 374, - 156, - 227, - 181, - 396, - 114, - 226, - 353, - 220, - 294, - 331, - 257, - 126, - 248, - 85, - 328, - 200, - 331, - 81, - 339, - 124, - 381, - 87, - 343, - 144, - 396, - 197, - 338, - 155, - 283, - 159, - 273, - 59, - 229, - 118, - 367, - 38, - 345, - 146, - 329, - 94, - 260, - 114, - 313, - 4, - 248, - 117, - 328, - 94, - 210, - 46, - 351, - 130, - 379, - 30, - 275, - 149, - 298, - 93, - 337, - 49, - 344, - 353, - 171, - 397, - 54, - 205, - 47, - 216, - 278, - 331, - 265, - 48, - 363, - 3, - 78, - 260, - 179, - 247, - 67, - 243, - 9, - 320, - 166, - 257, - 36, - 317, - 130, - 208, - 38, - 102, - 33, - 192, - 161, - 351, - 60, - 318, - 326, - 198, - 170, - 12, - 122, - 386, - 398, - 25, - 314, - 143, - 291, - 63, - 398, - 157, - 367, - 35, - 375, - 314, - 123, - 303, - 82, - 370, - 180, - 247, - 72, - 267, - 129, - 338, - 180, - 259, - 62, - 329, - 158, - 281, - 87, - 283, - 181, - 223, - 60, - 304, - 155, - 383, - 77, - 400, - 184, - 282, - 69, - 255, - 102, - 333, - 63, - 315, - 126, - 394, - 32, - 201, - 164, - 229, - 96, - 347, - 118, - 305, - 16, - 204, - 199, - 377, - 155, - 392, - 181, - 322, - 7, - 385, - 121, - 205, - 37, - 193, - 8, - 112, - 189, - 315, - 136, - 375, - 112, - 376, - 213, - 140, - 385, - 25, - 271, - 163, - 352, - 14, - 257, - 101, - 213, - 83, - 248, - 91, - 313, - 352, - 180, - 6, - 51, - 290, - 144, - 316, - 13, - 340, - 356, - 379, - 97, - 378, - 14, - 340, - 157, - 126, - 254, - 288, - 46, - 234, - 7, - 222, - 270, - 323, - 320, - 346, - 271, - 201, - 269, - 246, - 34, - 298, - 127, - 272, - 70, - 232, - 113, - 218, - 86, - 242, - 115, - 278, - 93, - 266, - 156, - 314, - 26, - 222, - 110, - 361, - 361, - 76, - 112, - 82, - 10, - 344, - 85, - 309, - 122, - 392, - 68, - 374, - 112, - 303, - 38, - 201, - 120, - 282, - 40, - 277, - 119, - 393, - 90, - 396, - 196, - 21, - 155, - 342, - 36, - 325, - 59, - 399, - 28, - 78, - 47, - 42, - 209, - 228, - 330, - 159, - 285, - 87, - 389, - 148, - 204, - 70, - 289, - 166, - 344, - 20, - 320, - 122, - 223, - 64, - 205, - 154, - 245, - 393, - 279, - 80, - 319, - 370, - 121, - 316, - 11, - 396, - 317, - 104, - 329, - 85, - 353, - 135, - 245, - 168, - 322, - 382, - 325, - 241, - 214, - 327, - 389, - 140, - 335, - 126, - 271, - 187, - 236, - 309, - 220, - 263, - 51, - 228, - 109, - 400, - 89, - 233, - 66, - 243, - 359, - 213, - 335, - 220, - 209, - 280, - 24, - 282, - 5, - 352, - 2, - 208, - 137, - 247, - 36, - 344, - 188, - 271, - 26, - 129, - 45, - 326, - 193, - 291, - 168, - 364, - 345, - 17, - 208, - 154, - 202, - 19, - 225, - 171, - 244, - 98, - 341, - 120, - 302, - 42, - 275, - 152, - 251, - 15, - 340, - 188, - 393, - 87, - 359, - 111, - 333, - 46, - 388, - 114, - 376, - 89, - 277, - 134, - 259, - 42, - 346, - 184, - 298, - 93, - 275, - 107, - 268, - 81, - 282, - 129, - 213, - 4, - 246, - 188, - 234, - 81, - 395, - 166, - 303, - 110, - 306, - 112, - 345, - 83, - 316, - 29, - 334, - 65, - 386, - 73, - 242, - 333, - 203, - 196, - 381, - 169, - 222, - 106, - 391, - 156, - 251, - 126, - 391, - 195, - 246, - 197, - 330, - 263, - 53, - 242, - 134, - 312, - 219, - 184, - 368, - 11, - 388, - 86, - 279, - 182, - 258, - 58, - 321, - 172, - 28, - 242, - 112, - 362, - 50, - 295, - 116, - 332, - 23, - 228, - 183, - 289, - 65, - 274, - 161, - 214, - 56, - 379, - 107, - 211, - 36, - 374, - 174, - 330, - 80, - 371, - 104, - 218, - 80, - 154, - 46, - 266, - 118, - 82, - 379, - 118, - 327, - 61, - 359, - 180, - 286, - 36, - 354, - 102, - 394, - 1, - 151, - 207, - 73, - 379, - 155, - 374, - 17, - 331, - 15, - 246, - 75, - 327, - 9, - 234, - 339, - 88, - 349, - 277, - 16, - 268, - 202, - 105, - 323, - 22, - 241, - 172, - 284, - 30, - 374, - 188, - 392, - 86, - 319, - 136, - 234, - 20, - 253, - 127, - 265, - 86, - 382, - 161, - 283, - 19, - 385, - 195, - 394, - 37, - 327, - 111, - 239, - 13, - 340, - 140, - 296, - 80, - 332, - 132, - 256, - 63, - 398, - 170, - 359, - 27, - 356, - 123, - 295, - 85, - 260, - 144, - 354, - 43, - 398, - 126, - 274, - 66, - 342, - 147, - 268, - 65, - 272, - 142, - 224, - 46, - 292, - 112, - 341, - 73, - 390, - 122, - 202, - 43, - 311, - 154, - 17, - 192, - 325, - 89, - 202, - 42, - 214, - 121, - 225, - 6, - 54, - 41, - 288, - 78, - 351, - 52, - 391, - 138, - 339, - 73, - 378, - 109, - 293, - 366, - 355, - 188, - 219, - 22, - 377, - 115, - 219, - 353, - 226, - 241, - 234, - 352, - 57, - 306, - 149, - 221, - 28, - 219, - 158, - 343, - 16, - 313, - 163, - 326, - 66, - 350, - 122, - 292, - 25, - 395, - 149, - 256, - 15, - 335, - 170, - 233, - 4, - 218, - 121, - 271, - 16, - 366, - 188, - 265, - 72, - 202, - 182, - 206, - 100, - 301, - 112, - 374, - 26, - 312, - 262, - 35, - 227, - 67, - 358, - 25, - 289, - 50, - 276, - 398, - 123, - 334, - 23, - 293, - 380, - 146, - 349, - 31, - 283, - 177, - 307, - 46, - 273, - 173, - 132, - 110, - 122, - 312, - 58, - 347, - 195, - 303, - 2, - 278, - 151, - 216, - 49, - 204, - 69, - 380, - 97, - 224, - 132, - 287, - 84, - 370, - 56, - 214, - 105, - 383, - 37, - 218, - 163, - 345, - 33, - 318, - 4, - 395, - 83, - 384, - 16, - 237, - 226, - 260, - 295, - 315, - 326, - 202, - 181, - 267, - 195, - 318, - 178, - 212, - 96, - 229, - 138, - 261, - 49, - 227, - 190, - 228, - 24, - 393, - 164, - 385, - 10, - 281, - 130, - 231, - 87, - 116, - 347, - 37, - 271, - 195, - 223, - 41, - 247, - 294, - 238, - 313, - 323, - 290, - 141, - 391, - 54, - 163, - 48, - 347, - 184, - 62, - 198, - 344, - 66, - 154, - 32, - 233, - 52, - 362, - 172, - 275, - 68, - 283, - 78, - 203, - 101, - 240, - 84, - 336, - 154, - 354, - 59, - 239, - 145, - 345, - 13, - 292, - 135, - 320, - 100, - 349, - 189, - 233, - 82, - 390, - 196, - 289, - 1, - 310, - 46, - 315, - 19, - 326, - 130, - 286, - 67, - 394, - 32, - 281, - 98, - 201, - 162, - 345, - 24, - 375, - 179, - 347, - 85, - 344, - 155, - 241, - 50, - 273, - 175, - 234, - 35, - 356, - 155, - 243, - 57, - 332, - 8, - 250, - 28, - 337, - 12, - 15, - 35, - 22, - 348, - 133, - 212, - 84, - 328, - 152, - 223, - 66, - 320, - 121, - 228, - 79, - 236, - 126, - 218, - 14, - 346, - 117, - 370, - 72, - 266, - 132, - 391, - 69, - 207, - 165, - 251, - 182, - 376, - 21, - 336, - 121, - 262, - 43, - 330, - 116, - 246, - 46, - 383, - 40, - 266, - 2, - 389, - 195, - 344, - 19, - 378, - 113, - 208, - 83, - 250, - 159, - 201, - 29, - 372, - 108, - 303, - 55, - 225, - 143, - 369, - 37, - 139, - 222, - 81, - 110, - 294, - 95, - 339, - 171, - 277, - 78, - 320, - 119, - 374, - 95, - 296, - 180, - 367, - 19, - 327, - 112, - 321, - 62, - 297, - 240, - 377, - 22, - 296, - 43, - 232, - 68, - 314, - 112, - 252, - 72, - 388, - 153, - 304, - 7, - 211, - 200, - 326, - 73, - 197, - 22, - 246, - 13, - 305, - 304, - 56, - 221, - 397, - 245, - 144, - 246, - 93, - 266, - 140, - 256, - 97, - 273, - 165, - 347, - 186, - 212, - 11, - 228, - 177, - 305, - 68, - 334, - 126, - 244, - 33, - 326, - 193, - 396, - 30, - 284, - 122, - 298, - 31, - 366, - 113, - 293, - 53, - 173, - 26, - 56, - 97, - 50, - 35, - 344, - 144, - 13, - 383, - 141, - 337, - 101, - 341, - 376, - 360, - 104, - 263, - 3, - 314, - 124, - 346, - 23, - 318, - 46, - 338, - 50, - 249, - 270, - 205, - 232, - 175, - 263, - 63, - 340, - 163, - 354, - 25, - 387, - 186, - 242, - 16, - 355, - 128, - 309, - 87, - 195, - 99, - 332, - 184, - 131, - 125, - 305, - 60, - 303, - 154, - 348, - 58, - 374, - 257, - 372, - 315, - 312, - 125, - 195, - 322, - 113, - 389, - 162, - 350, - 14, - 217, - 48, - 224, - 33, - 239, - 191, - 206, - 35, - 330, - 178, - 287, - 86, - 228, - 101, - 372, - 61, - 313, - 67, - 237, - 32, - 211, - 141, - 396, - 49, - 385, - 128, - 331, - 66, - 286, - 148, - 324, - 11, - 282, - 200, - 313, - 2, - 299, - 174, - 269, - 75, - 399, - 102, - 395, - 80, - 329, - 194, - 328, - 147, - 364, - 67, - 357, - 125, - 345, - 57, - 307, - 132, - 312, - 6, - 400, - 126, - 327, - 90, - 352, - 155, - 288, - 146, - 220, - 144, - 289, - 200, - 354, - 77, - 241, - 118, - 312, - 13, - 223, - 131, - 388, - 1, - 318, - 134, - 280, - 63, - 206, - 55, - 377, - 338, - 27, - 373, - 357, - 133, - 324, - 2, - 288, - 151, - 371, - 77, - 245, - 151, - 203, - 98, - 328, - 142, - 377, - 33, - 304, - 174, - 327, - 40, - 124, - 25, - 133, - 80, - 151, - 151, - 212, - 31, - 141, - 60, - 75, - 179, - 106, - 103, - 300, - 164, - 239, - 121, - 221, - 305, - 351, - 296, - 375, - 231, - 222, - 299, - 20, - 348, - 80, - 332, - 286, - 147, - 259, - 1, - 371, - 178, - 327, - 319, - 272, - 245, - 247, - 300, - 344, - 138, - 207, - 3, - 235, - 159, - 300, - 52, - 276, - 115, - 370, - 166, - 345, - 62, - 290, - 110, - 355, - 198, - 239, - 77, - 238, - 158, - 332, - 63, - 238, - 158, - 258, - 64, - 374, - 107, - 309, - 127, - 222, - 172, - 212, - 132, - 292, - 187, - 307, - 154, - 306, - 75, - 208, - 136, - 388, - 86, - 379, - 197, - 255, - 79, - 150, - 24, - 193, - 72, - 126, - 128, - 145, - 211, - 173, - 258, - 286, - 25, - 125, - 370, - 176, - 235, - 129, - 390, - 155, - 223, - 3, - 337, - 178, - 292, - 3, - 201, - 151, - 263, - 92, - 251, - 155, - 267, - 29, - 360, - 81, - 382, - 7, - 384, - 148, - 43, - 152, - 212, - 87, - 246, - 181, - 227, - 92, - 304, - 180, - 201, - 185, - 260, - 72, - 331, - 41, - 344, - 98, - 326, - 86, - 282, - 191, - 354, - 88, - 251, - 147, - 364, - 34, - 230, - 120, - 249, - 51, - 368, - 194, - 374, - 95, - 380, - 108, - 393, - 64, - 222, - 147, - 300, - 134, - 391, - 274, - 293, - 390, - 232, - 354, - 311, - 329, - 208, - 204, - 364, - 339, - 247, - 342, - 233, - 55, - 330, - 143, - 264, - 383, - 9, - 341, - 96, - 246, - 237, - 120, - 312, - 68, - 326, - 134, - 323, - 314, - 393, - 288, - 48, - 322, - 189, - 326, - 322, - 69, - 258, - 37, - 300, - 165, - 322, - 299, - 376, - 156, - 224, - 51, - 126, - 289, - 48, - 395, - 173, - 312, - 48, - 346, - 227, - 270, - 200, - 387, - 295, - 278, - 185, - 225, - 20, - 350, - 135, - 380, - 4, - 353, - 180, - 332, - 194, - 224, - 106, - 285, - 90, - 215, - 161, - 369, - 50, - 325, - 168, - 273, - 65, - 349, - 137, - 306, - 5, - 227, - 129, - 36, - 165, - 280, - 173, - 325, - 170, - 288, - 218, - 86, - 393, - 190, - 378, - 95, - 223, - 136, - 314, - 76, - 398, - 137, - 384, - 90, - 317, - 76, - 324, - 100, - 324, - 105, - 215, - 35, - 331, - 130, - 395, - 330, - 336, - 332, - 322, - 85, - 126, - 393, - 80, - 394, - 140, - 345, - 50, - 180, - 239, - 9, - 175, - 14, - 95, - 317, - 52, - 330, - 150, - 134, - 221, - 46, - 266, - 143, - 297, - 39, - 276, - 105, - 344, - 94, - 299, - 112, - 258, - 83, - 335, - 190, - 390, - 69, - 285, - 112, - 364, - 43, - 376, - 173, - 214, - 8, - 217, - 106, - 137, - 127, - 5, - 121, - 60, - 214, - 190, - 94, - 277, - 188, - 149, - 183, - 128, - 224, - 119, - 272, - 40, - 240, - 113, - 394, - 27, - 144, - 22, - 226, - 132, - 33, - 31, - 35, - 309, - 112, - 385, - 79, - 393, - 159, - 246, - 80, - 359, - 144, - 316, - 38, - 234, - 168, - 223, - 8, - 387, - 134, - 204, - 55, - 217, - 199, - 81, - 257, - 119, - 205, - 97, - 236, - 186, - 358, - 18, - 288, - 50, - 244, - 189, - 248, - 2, - 348, - 5, - 215, - 65, - 222, - 24, - 239, - 45, - 252, - 376, - 158, - 379, - 27, - 361, - 181, - 394, - 35, - 234, - 116, - 201, - 97, - 282, - 177, - 317, - 37, - 246, - 36, - 272, - 45, - 291, - 308, - 176, - 248, - 57, - 353, - 8, - 322, - 81, - 235, - 15, - 240, - 97, - 247, - 37, - 253, - 86, - 379, - 3, - 398, - 35, - 365, - 47, - 313, - 5, - 268, - 181, - 291, - 135, - 208, - 113, - 348, - 119, - 355, - 38, - 290, - 136, - 14, - 119, - 70, - 137, - 100, - 320, - 168, - 73, - 125, - 82, - 46, - 22, - 354, - 28, - 257, - 156, - 305, - 30, - 237, - 184, - 265, - 88, - 197, - 216, - 32, - 324, - 135, - 388, - 97, - 357, - 40, - 371, - 173, - 290, - 155, - 357, - 100, - 336, - 147, - 334, - 105, - 332, - 114, - 351, - 108, - 331, - 375, - 278, - 352, - 250, - 43, - 278, - 169, - 329, - 32, - 368, - 149, - 240, - 7, - 374, - 102, - 268, - 46, - 386, - 80, - 277, - 71, - 294, - 392, - 157, - 379, - 141, - 207, - 130, - 51, - 172, - 61, - 102, - 364, - 74, - 288, - 134, - 274, - 58, - 126, - 123, - 366, - 277, - 348, - 315, - 50, - 213, - 20, - 34, - 369, - 3, - 393, - 68, - 129, - 97, - 282, - 195, - 257, - 151, - 277, - 237, - 106, - 327, - 265, - 236, - 64, - 252, - 144, - 298, - 20, - 389, - 179, - 217, - 189, - 128, - 347, - 93, - 305, - 129, - 363, - 166, - 377, - 59, - 350, - 147, - 357, - 76, - 302, - 177, - 222, - 25, - 392, - 178, - 300, - 56, - 331, - 157, - 291, - 80, - 106, - 33, - 57, - 213, - 195, - 231, - 123, - 308, - 21, - 256, - 196, - 372, - 388, - 39, - 240, - 251, - 94, - 360, - 61, - 396, - 327, - 269, - 358, - 322, - 179, - 301, - 81, - 319, - 62, - 301, - 86, - 234, - 15, - 311, - 183, - 333, - 10, - 288, - 116, - 273, - 5, - 285, - 146, - 345, - 6, - 362, - 185, - 48, - 371, - 80, - 343, - 343, - 137, - 284, - 373, - 255, - 48, - 233, - 153, - 327, - 273, - 261, - 215, - 49, - 292, - 117, - 315, - 78, - 383, - 70, - 328, - 180, - 203, - 68, - 230, - 10, - 296, - 264, - 202, - 255, - 334, - 397, - 45, - 356, - 186, - 356, - 60, - 317, - 151, - 386, - 149, - 345, - 240, - 221, - 83, - 204, - 22, - 304, - 174, - 337, - 93, - 311, - 120, - 274, - 74, - 276, - 291, - 202, - 212, - 388, - 206, - 270, - 263, - 358, - 374, - 306, - 6, - 355, - 80, - 285, - 118, - 380, - 94, - 152, - 19, - 185, - 115, - 253, - 184, - 382, - 24, - 327, - 169, - 349, - 352, - 2, - 202, - 249, - 318, - 349, - 103, - 385, - 370, - 161, - 348, - 166, - 284, - 307, - 219, - 369, - 138, - 232, - 11, - 236, - 151, - 14, - 28, - 49, - 163, - 51, - 318, - 149, - 362, - 96, - 364, - 133, - 47, - 113, - 371, - 100, - 310, - 181, - 317, - 34, - 204, - 199, - 326, - 14, - 399, - 106, - 8, - 346, - 185, - 126, - 342, - 17, - 321, - 395, - 129, - 381, - 34, - 301, - 127, - 380, - 136, - 260, - 258, - 387, - 281, - 83, - 208, - 393, - 392, - 212, - 144, - 193, - 263, - 195, - 208, - 53, - 381, - 116, - 241, - 51, - 353, - 143, - 273, - 14, - 396, - 109, - 353, - 69, - 333, - 199, - 373, - 56, - 222, - 186, - 247, - 10, - 342, - 149, - 253, - 1, - 358, - 108, - 362, - 43, - 217, - 164, - 283, - 20, - 201, - 118, - 374, - 53, - 329, - 194, - 346, - 17, - 285, - 115, - 309, - 45, - 312, - 175, - 306, - 35, - 307, - 147, - 244, - 99, - 118, - 81, - 142, - 85, - 176, - 353, - 32, - 310, - 164, - 282, - 169, - 204, - 59, - 225, - 19, - 229, - 31, - 209, - 108, - 332, - 243, - 207, - 363, - 388, - 392, - 377, - 267, - 249, - 286, - 153, - 351, - 91, - 283, - 129, - 18, - 124, - 8, - 207, - 177, - 334, - 137, - 116, - 160, - 349, - 53, - 126, - 233, - 315, - 363, - 75, - 368, - 101, - 186, - 127, - 31, - 122, - 157, - 241, - 88, - 225, - 132, - 65, - 397, - 114, - 261, - 129, - 314, - 1, - 203, - 142, - 346, - 120, - 263, - 274, - 285, - 257, - 206, - 338, - 19, - 293, - 102, - 267, - 181, - 254, - 134, - 308, - 68, - 241, - 167, - 235, - 21, - 312, - 159, - 394, - 66, - 276, - 149, - 372, - 22, - 308, - 132, - 236, - 50, - 219, - 148, - 387, - 70, - 330, - 159, - 292, - 96, - 297, - 199, - 355, - 24, - 277, - 112, - 264, - 162, - 256, - 101, - 156, - 241, - 56, - 306, - 176, - 228, - 158, - 263, - 76, - 273, - 160, - 374, - 61, - 326, - 128, - 335, - 31, - 314, - 30, - 280, - 105, - 267, - 59, - 230, - 174, - 385, - 197, - 298, - 128, - 340, - 175, - 393, - 150, - 327, - 196, - 395, - 314, - 11, - 310, - 341, - 55, - 278, - 11, - 277, - 88, - 268, - 44, - 359, - 71, - 333, - 284, - 175, - 217, - 20, - 241, - 105, - 203, - 70, - 269, - 192, - 400, - 22, - 361, - 75, - 275, - 399, - 144, - 390, - 179, - 400, - 223, - 136, - 396, - 304, - 295, - 137, - 390, - 27, - 228, - 129, - 343, - 9, - 315, - 133, - 330, - 14, - 342, - 180, - 229, - 86, - 317, - 172, - 219, - 85, - 203, - 127, - 224, - 70, - 243, - 199, - 314, - 138, - 248, - 195, - 273, - 206, - 244, - 230, - 259, - 46, - 352, - 119, - 335, - 93, - 208, - 171, - 361, - 91, - 222, - 391, - 268, - 304, - 108, - 284, - 288, - 249, - 235, - 133, - 274, - 39, - 259, - 106, - 223, - 12, - 273, - 186, - 369, - 44, - 336, - 110, - 30, - 182, - 64, - 110, - 57, - 21, - 60, - 114, - 98, - 125, - 144, - 213, - 53, - 312, - 170, - 348, - 72, - 235, - 170, - 385, - 62, - 263, - 128, - 257, - 79, - 365, - 173, - 388, - 45, - 385, - 163, - 349, - 92, - 208, - 149, - 42, - 326, - 129, - 344, - 58, - 194, - 18, - 123, - 209, - 90, - 114, - 73, - 197, - 26, - 88, - 99, - 316, - 169, - 243, - 27, - 377, - 165, - 245, - 339, - 55, - 350, - 213, - 350, - 214, - 154, - 288, - 79, - 226, - 262, - 137, - 211, - 91, - 278, - 169, - 336, - 373, - 383, - 65, - 94, - 318, - 73, - 274, - 389, - 197, - 19, - 336, - 98, - 205, - 158, - 201, - 74, - 53, - 380, - 74, - 344, - 103, - 269, - 346, - 196, - 225, - 2, - 371, - 159, - 355, - 110, - 362, - 196, - 380, - 196, - 371, - 128, - 220, - 326, - 330, - 304, - 340, - 138, - 309, - 258, - 88, - 238, - 101, - 224, - 376, - 243, - 399, - 177, - 163, - 150, - 243, - 45, - 344, - 248, - 122, - 371, - 178, - 209, - 183, - 379, - 180, - 284, - 151, - 277, - 162, - 97, - 135, - 181, - 347, - 88, - 311, - 120, - 320, - 21, - 387, - 184, - 381, - 43, - 377, - 195, - 321, - 59, - 276, - 188, - 232, - 84, - 284, - 124, - 201, - 5, - 289, - 101, - 301, - 122, - 300, - 343, - 44, - 294, - 387, - 12, - 245, - 210, - 275, - 96, - 386, - 72, - 355, - 29, - 277, - 8, - 260, - 35, - 304, - 378, - 138, - 357, - 209, - 363, - 203, - 98, - 392, - 297, - 134, - 304, - 123, - 257, - 134, - 214, - 179, - 330, - 67, - 395, - 89, - 305, - 115, - 69, - 83, - 10, - 56, - 233, - 179, - 216, - 59, - 101, - 49, - 117, - 15, - 268, - 69, - 289, - 171, - 392, - 81, - 204, - 124, - 310, - 100, - 264, - 166, - 277, - 74, - 218, - 106, - 354, - 62, - 274, - 41, - 259, - 86, - 316, - 179, - 247, - 94, - 280, - 131, - 394, - 12, - 325, - 104, - 295, - 95, - 327, - 84, - 263, - 35, - 357, - 33, - 250, - 67, - 147, - 327, - 66, - 212, - 189, - 244, - 44, - 206, - 172, - 349, - 79, - 261, - 104, - 265, - 182, - 305, - 11, - 225, - 127, - 266, - 66, - 365, - 156, - 233, - 57, - 300, - 56, - 359, - 22, - 229, - 146, - 4, - 230, - 105, - 382, - 92, - 233, - 196, - 229, - 75, - 326, - 104, - 335, - 112, - 301, - 69, - 249, - 143, - 301, - 78, - 309, - 179, - 244, - 275, - 317, - 84, - 160, - 87, - 37, - 85, - 265, - 195, - 246, - 56, - 226, - 102, - 310, - 16, - 300, - 136, - 386, - 63, - 223, - 114, - 354, - 80, - 249, - 186, - 218, - 61, - 130, - 132, - 119, - 137, - 32, - 132, - 260, - 92, - 238, - 132, - 203, - 116, - 317, - 54, - 306, - 193, - 48, - 199, - 154, - 209, - 186, - 191, - 187, - 300, - 170, - 143, - 91, - 128, - 48, - 186, - 301, - 33, - 245, - 179, - 395, - 83, - 333, - 128, - 268, - 79, - 306, - 185, - 252, - 2, - 398, - 159, - 267, - 95, - 345, - 95, - 287, - 75, - 393, - 111, - 376, - 40, - 244, - 67, - 270, - 101, - 366, - 24, - 267, - 50, - 306, - 130, - 331, - 44, - 244, - 21, - 323, - 11, - 214, - 60, - 334, - 13, - 316, - 103, - 232, - 90, - 272, - 148, - 232, - 76, - 333, - 109, - 256, - 191, - 222, - 184, - 359, - 91, - 351, - 18, - 254, - 113, - 221, - 304, - 327, - 310, - 345, - 355, - 206, - 356, - 375, - 350, - 6, - 326, - 146, - 343, - 46, - 383, - 340, - 85, - 215, - 191, - 354, - 6, - 235, - 113, - 310, - 63, - 323, - 137, - 241, - 98, - 215, - 135, - 234, - 93, - 280, - 139, - 60, - 323, - 143, - 342, - 11, - 141, - 66, - 252, - 133, - 202, - 73, - 239, - 153, - 263, - 58, - 351, - 186, - 256, - 85, - 346, - 163, - 275, - 3, - 378, - 145, - 372, - 9, - 225, - 139, - 307, - 50, - 260, - 152, - 75, - 127, - 294, - 63, - 378, - 152, - 323, - 98, - 337, - 198, - 359, - 97, - 276, - 147, - 376, - 45, - 385, - 194, - 372, - 195, - 206, - 77, - 343, - 186, - 325, - 178, - 334, - 195, - 234, - 132, - 381, - 99, - 218, - 138, - 261, - 17, - 245, - 172, - 244, - 81, - 281, - 143, - 237, - 26, - 275, - 138, - 348, - 73, - 327, - 168, - 289, - 38, - 299, - 186, - 345, - 69, - 257, - 168, - 288, - 24, - 279, - 104, - 259, - 84, - 342, - 117, - 227, - 128, - 359, - 178, - 284, - 20, - 355, - 161, - 342, - 70, - 372, - 167, - 378, - 92, - 378, - 134, - 277, - 69, - 225, - 192, - 378, - 42, - 239, - 120, - 386, - 82, - 317, - 192, - 301, - 44, - 261, - 125, - 291, - 29, - 113, - 96, - 326, - 144, - 60, - 300, - 199, - 292, - 54, - 291, - 176, - 334, - 64, - 353, - 131, - 377, - 41, - 160, - 11, - 310, - 136, - 399, - 47, - 103, - 7, - 226, - 184, - 219, - 348, - 259, - 31, - 245, - 187, - 281, - 380, - 27, - 275, - 158, - 326, - 305, - 41, - 266, - 377, - 338, - 55, - 267, - 163, - 374, - 185, - 384, - 99, - 291, - 176, - 87, - 177, - 40, - 383, - 24, - 285, - 25, - 224, - 194, - 390, - 72, - 304, - 150, - 252, - 36, - 358, - 101, - 220, - 20, - 293, - 194, - 205, - 68, - 206, - 101, - 235, - 13, - 384, - 195, - 312, - 43, - 316, - 49, - 216, - 18, - 229, - 15, - 283, - 224, - 379, - 112, - 205, - 102, - 202, - 268, - 161, - 364, - 346, - 237, - 85, - 361, - 137, - 208, - 74, - 254, - 121, - 78, - 113, - 239, - 158, - 172, - 149, - 331, - 78, - 342, - 193, - 326, - 63, - 324, - 71, - 249, - 74, - 391, - 53, - 247, - 112, - 352, - 33, - 219, - 194, - 391, - 322, - 121, - 300, - 22, - 282, - 121, - 317, - 370, - 325, - 157, - 237, - 167, - 295, - 382, - 217, - 227, - 349, - 340, - 88, - 131, - 383, - 11, - 286, - 303, - 83, - 333, - 193, - 15, - 269, - 114, - 391, - 113, - 142, - 204, - 27, - 349, - 141, - 333, - 29, - 250, - 167, - 224, - 80, - 328, - 193, - 283, - 75, - 233, - 152, - 361, - 45, - 354, - 120, - 76, - 202, - 170, - 330, - 19, - 337, - 153, - 301, - 79, - 380, - 200, - 374, - 72, - 144, - 17, - 197, - 146, - 334, - 170, - 109, - 195, - 11, - 144, - 17, - 146, - 239, - 1, - 263, - 192, - 315, - 62, - 82, - 9, - 324, - 111, - 366, - 98, - 332, - 182, - 76, - 138, - 255, - 180, - 301, - 67, - 204, - 337, - 337, - 397, - 212, - 81, - 202, - 149, - 243, - 375, - 20, - 303, - 150, - 366, - 41, - 394, - 22, - 321, - 67, - 372, - 34, - 316, - 131, - 119, - 306, - 196, - 365, - 190, - 393, - 318, - 67, - 219, - 43, - 264, - 131, - 220, - 334, - 358, - 32, - 392, - 217, - 16, - 207, - 198, - 271, - 93, - 204, - 163, - 338, - 348, - 293, - 253, - 351, - 399, - 249, - 53, - 247, - 137, - 18, - 326, - 112, - 26, - 162, - 72, - 194, - 275, - 49, - 346, - 148, - 317, - 120, - 212, - 164, - 201, - 350, - 350, - 385, - 41, - 279, - 312, - 226, - 194, - 209, - 351, - 320, - 72, - 254, - 197, - 290, - 48, - 359, - 220, - 70, - 282, - 363, - 166, - 114, - 31, - 167, - 340, - 83, - 263, - 243, - 190, - 336, - 235, - 100, - 347, - 128, - 341, - 91, - 328, - 183, - 351, - 95, - 365, - 157, - 325, - 86, - 212, - 124, - 296, - 23, - 140, - 286, - 71, - 292, - 200, - 213, - 19, - 172, - 46, - 110, - 58, - 84, - 320, - 4, - 3, - 389, - 144, - 215, - 23, - 134, - 97, - 250, - 185, - 321, - 86, - 252, - 106, - 265, - 83, - 266, - 179, - 250, - 53, - 295, - 113, - 301, - 65, - 244, - 130, - 14, - 139, - 68, - 321, - 129, - 302, - 69, - 256, - 123, - 315, - 84, - 282, - 122, - 351, - 85, - 163, - 83, - 108, - 344, - 79, - 149, - 51, - 165, - 263, - 60, - 75, - 278, - 192, - 46, - 332, - 47, - 146, - 245, - 15, - 354, - 101, - 222, - 22, - 223, - 139, - 294, - 73, - 260, - 122, - 232, - 46, - 342, - 108, - 62, - 120, - 348, - 26, - 146, - 275, - 33, - 156, - 34, - 366, - 26, - 298, - 64, - 220, - 57, - 273, - 261, - 108, - 307, - 325, - 114, - 72, - 114, - 147, - 378, - 39, - 398, - 169, - 217, - 58, - 244, - 105, - 46, - 133, - 44, - 200, - 209, - 90, - 345, - 133, - 289, - 97, - 259, - 98, - 357, - 369, - 20, - 286, - 346, - 206, - 266, - 386, - 29, - 277, - 214, - 169, - 375, - 120, - 31, - 306, - 197, - 290, - 156, - 330, - 139, - 346, - 159, - 284, - 19, - 301, - 106, - 344, - 31, - 252, - 73, - 20, - 85, - 282, - 359, - 18, - 250, - 233, - 395, - 156, - 51, - 355, - 155, - 308, - 49, - 95, - 66, - 162, - 366, - 44, - 170, - 251, - 256, - 337, - 230, - 275, - 113, - 228, - 151, - 288, - 199, - 244, - 58, - 221, - 105, - 336, - 6, - 228, - 165, - 227, - 48, - 400, - 144, - 383, - 18, - 289, - 176, - 270, - 154, - 279, - 10, - 245, - 103, - 361, - 78, - 217, - 196, - 207, - 16, - 309, - 123, - 299, - 86, - 299, - 108, - 207, - 96, - 234, - 148, - 377, - 88, - 231, - 76, - 378, - 3, - 299, - 22, - 211, - 270, - 12, - 231, - 20, - 55, - 286, - 61, - 382, - 142, - 249, - 77, - 384, - 150, - 379, - 17, - 333, - 177, - 293, - 98, - 338, - 157, - 91, - 109, - 172, - 125, - 26, - 115, - 400, - 53, - 285, - 165, - 209, - 84, - 353, - 172, - 360, - 13, - 320, - 180, - 278, - 37, - 263, - 168, - 356, - 67, - 318, - 155, - 134, - 156, - 295, - 20, - 65, - 46, - 346, - 108, - 321, - 79, - 334, - 168, - 364, - 52, - 318, - 123, - 365, - 189, - 325, - 123, - 293, - 62, - 398, - 108, - 321, - 25, - 268, - 123, - 313, - 100, - 235, - 129, - 400, - 54, - 211, - 167, - 297, - 193, - 240, - 43, - 248, - 170, - 371, - 71, - 342, - 194, - 251, - 60, - 299, - 183, - 317, - 21, - 291, - 181, - 345, - 37, - 320, - 102, - 201, - 22, - 286, - 134, - 281, - 72, - 263, - 196, - 345, - 29, - 270, - 186, - 226, - 36, - 218, - 121, - 232, - 167, - 240, - 68, - 216, - 198, - 301, - 41, - 322, - 130, - 358, - 11, - 280, - 135, - 66, - 192, - 169, - 194, - 223, - 284, - 286, - 28, - 260, - 187, - 273, - 74, - 300, - 23, - 206, - 12, - 52, - 38, - 320, - 103, - 206, - 197, - 348, - 182, - 249, - 286, - 101, - 375, - 258, - 102, - 250, - 97, - 394, - 129, - 29, - 184, - 50, - 339, - 97, - 234, - 141, - 374, - 44, - 337, - 165, - 317, - 189, - 291, - 142, - 391, - 341, - 335, - 224, - 20, - 258, - 124, - 270, - 8, - 254, - 185, - 306, - 13, - 316, - 120, - 236, - 7, - 247, - 116, - 368, - 9, - 312, - 5, - 357, - 223, - 121, - 256, - 203, - 217, - 142, - 310, - 379, - 321, - 289, - 264, - 261, - 11, - 148, - 259, - 72, - 304, - 38, - 381, - 62, - 213, - 27, - 254, - 43, - 256, - 230, - 177, - 241, - 63, - 107, - 143, - 369, - 90, - 242, - 162, - 383, - 363, - 162, - 223, - 95, - 211, - 124, - 329, - 85, - 216, - 195, - 201, - 51, - 309, - 157, - 366, - 12, - 183, - 107, - 102, - 255, - 69, - 323, - 168, - 274, - 194, - 203, - 238, - 106, - 225, - 124, - 360, - 386, - 181, - 331, - 10, - 249, - 348, - 359, - 267, - 15, - 382, - 68, - 270, - 54, - 213, - 152, - 264, - 80, - 149, - 284, - 95, - 315, - 119, - 394, - 221, - 289, - 140, - 294, - 48, - 266, - 186, - 384, - 30, - 228, - 65, - 352, - 50, - 362, - 27, - 137, - 394, - 9, - 306, - 145, - 229, - 68, - 211, - 174, - 221, - 20, - 374, - 136, - 386, - 14, - 378, - 148, - 40, - 233, - 198, - 78, - 122, - 338, - 100, - 357, - 115, - 230, - 71, - 110, - 65, - 397, - 70, - 41, - 55, - 344, - 381, - 52, - 172, - 197, - 39, - 126, - 77, - 39, - 384, - 66, - 266, - 162, - 1, - 153, - 245, - 145, - 396, - 88, - 366, - 158, - 205, - 58, - 384, - 71, - 366, - 233, - 246, - 213, - 208, - 152, - 356, - 30, - 292, - 181, - 379, - 123, - 354, - 53, - 388, - 3, - 372, - 344, - 196, - 269, - 399, - 15, - 361, - 128, - 219, - 63, - 340, - 183, - 308, - 42, - 292, - 195, - 324, - 159, - 230, - 172, - 329, - 10, - 211, - 109, - 13, - 208, - 186, - 96, - 143, - 198, - 206, - 145, - 251, - 195, - 303, - 341, - 178, - 256, - 12, - 385, - 92, - 201, - 43, - 284, - 148, - 218, - 370, - 189, - 13, - 227, - 68, - 208, - 338, - 379, - 13, - 287, - 132, - 319, - 60, - 318, - 126, - 364, - 46, - 189, - 45, - 132, - 21, - 338, - 140, - 340, - 99, - 187, - 22, - 304, - 55, - 39, - 257, - 298, - 18, - 58, - 397, - 51, - 277, - 188, - 292, - 49, - 360, - 125, - 368, - 64, - 390, - 158, - 279, - 62, - 291, - 160, - 294, - 44, - 400, - 196, - 310, - 10, - 320, - 133, - 355, - 23, - 228, - 118, - 309, - 22, - 320, - 120, - 383, - 167, - 356, - 105, - 147, - 327, - 70, - 133, - 323, - 83, - 185, - 68, - 195, - 172, - 305, - 108, - 263, - 120, - 249, - 87, - 382, - 168, - 231, - 95, - 371, - 12, - 387, - 173, - 268, - 41, - 224, - 42, - 353, - 6, - 319, - 147, - 223, - 39, - 326, - 68, - 364, - 150, - 295, - 36, - 250, - 143, - 398, - 7, - 357, - 101, - 398, - 24, - 354, - 27, - 293, - 140, - 21, - 197, - 100, - 157, - 253, - 15, - 198, - 72, - 121, - 351, - 87, - 79, - 24, - 384, - 80, - 294, - 62, - 287, - 102, - 380, - 211, - 53, - 265, - 141, - 348, - 17, - 224, - 116, - 360, - 170, - 210, - 45, - 248, - 118, - 273, - 30, - 329, - 194, - 371, - 49, - 214, - 162, - 233, - 95, - 291, - 124, - 223, - 37, - 277, - 133, - 346, - 68, - 369, - 186, - 301, - 23, - 302, - 102, - 349, - 52, - 371, - 101, - 247, - 2, - 148, - 48, - 108, - 10, - 124, - 394, - 9, - 148, - 13, - 162, - 260, - 73, - 340, - 156, - 205, - 89, - 370, - 114, - 355, - 90, - 369, - 159, - 274, - 61, - 241, - 142, - 253, - 69, - 384, - 136, - 302, - 59, - 350, - 137, - 273, - 50, - 292, - 137, - 215, - 4, - 279, - 178, - 284, - 36, - 236, - 197, - 369, - 99, - 213, - 107, - 313, - 59, - 387, - 36, - 348, - 113, - 214, - 69, - 243, - 200, - 17, - 258, - 132, - 281, - 17, - 251, - 157, - 230, - 52, - 347, - 156, - 213, - 98, - 381, - 160, - 257, - 50, - 344, - 151, - 274, - 34, - 219, - 110, - 309, - 164, - 227, - 89, - 299, - 143, - 319, - 159, - 205, - 324, - 225, - 394, - 394, - 393, - 55, - 291, - 158, - 224, - 68, - 272, - 152, - 342, - 85, - 202, - 179, - 361, - 7, - 319, - 182, - 244, - 53, - 369, - 162, - 307, - 64, - 255, - 147, - 290, - 83, - 279, - 115, - 304, - 129, - 331, - 298, - 124, - 231, - 120, - 266, - 85, - 342, - 175, - 40, - 186, - 324, - 43, - 14, - 11, - 195, - 255, - 281, - 255, - 182, - 362, - 219, - 14, - 105, - 87, - 156, - 249, - 6, - 117, - 17, - 123, - 278, - 93, - 385, - 199, - 86, - 30, - 133, - 234, - 127, - 380, - 32, - 310, - 128, - 215, - 18, - 391, - 107, - 324, - 90, - 317, - 145, - 349, - 48, - 274, - 64, - 295, - 186, - 3, - 194, - 88, - 128, - 65, - 350, - 151, - 249, - 31, - 387, - 126, - 298, - 43, - 247, - 143, - 398, - 14, - 372, - 108, - 329, - 100, - 359, - 145, - 303, - 9, - 327, - 142, - 313, - 18, - 201, - 102, - 98, - 299, - 123, - 241, - 84, - 235, - 46, - 214, - 3, - 240, - 194, - 388, - 7, - 293, - 197, - 222, - 74, - 248, - 278, - 161, - 290, - 356, - 152, - 377, - 328, - 302, - 365, - 237, - 199, - 248, - 154, - 336, - 200, - 249, - 51, - 356, - 104, - 346, - 77, - 146, - 268, - 16, - 260, - 120, - 232, - 159, - 193, - 129, - 7, - 121, - 151, - 376, - 139, - 215, - 24, - 108, - 103, - 20, - 74, - 195, - 8, - 310, - 235, - 307, - 320, - 363, - 181, - 369, - 78, - 366, - 138, - 333, - 54, - 254, - 177, - 219, - 1, - 279, - 128, - 389, - 173, - 301, - 124, - 338, - 293, - 378, - 270, - 224, - 117, - 180, - 259, - 94, - 147, - 299, - 122, - 364, - 288, - 71, - 162, - 96, - 130, - 30, - 190, - 262, - 12, - 21, - 52, - 221, - 23, - 33, - 339, - 198, - 295, - 159, - 124, - 114, - 272, - 127, - 210, - 34, - 384, - 137, - 359, - 75, - 355, - 197, - 280, - 43, - 221, - 123, - 331, - 40, - 224, - 158, - 201, - 88, - 251, - 142, - 317, - 186, - 250, - 137, - 305, - 78, - 333, - 137, - 370, - 100, - 344, - 120, - 302, - 14, - 382, - 155, - 55, - 296, - 180, - 218, - 131, - 282, - 49, - 253, - 225, - 378, - 15, - 398, - 138, - 270, - 150, - 372, - 57, - 210, - 123, - 338, - 98, - 171, - 214, - 92, - 291, - 33, - 256, - 79, - 203, - 134, - 392, - 99, - 127, - 75, - 309, - 128, - 316, - 185, - 377, - 141, - 177, - 160, - 363, - 72, - 198, - 52, - 336, - 140, - 386, - 130, - 30, - 155, - 59, - 47, - 360, - 281, - 41, - 46, - 36, - 303, - 106, - 316, - 199, - 253, - 127, - 283, - 36, - 292, - 192, - 293, - 215, - 172, - 377, - 245, - 134, - 363, - 84, - 248, - 165, - 340, - 53, - 395, - 189, - 288, - 78, - 230, - 178, - 317, - 9, - 252, - 172, - 214, - 98, - 256, - 183, - 376, - 48, - 327, - 110, - 291, - 14, - 296, - 159, - 236, - 26, - 275, - 170, - 280, - 35, - 263, - 126, - 212, - 24, - 398, - 198, - 98, - 162, - 314, - 71, - 209, - 198, - 47, - 193, - 211, - 11, - 378, - 189, - 116, - 359, - 81, - 388, - 169, - 155, - 125, - 232, - 9, - 384, - 182, - 355, - 174, - 209, - 79, - 372, - 174, - 386, - 161, - 299, - 384, - 315, - 378, - 394, - 174, - 291, - 39, - 259, - 290, - 373, - 294, - 50, - 254, - 70, - 212, - 379, - 292, - 115, - 389, - 80, - 226, - 117, - 292, - 169, - 73, - 301, - 168, - 24, - 366, - 91, - 206, - 105, - 247, - 26, - 268, - 151, - 360, - 176, - 59, - 164, - 334, - 67, - 350, - 135, - 261, - 32, - 153, - 27, - 331, - 190, - 82, - 189, - 89, - 127, - 248, - 233, - 215, - 54, - 203, - 168, - 362, - 16, - 278, - 140, - 310, - 10, - 342, - 185, - 376, - 125, - 336, - 180, - 303, - 55, - 222, - 168, - 341, - 23, - 347, - 169, - 316, - 47, - 230, - 159, - 271, - 119, - 289, - 349, - 43, - 384, - 192, - 245, - 68, - 247, - 186, - 320, - 7, - 366, - 131, - 335, - 14, - 321, - 159, - 224, - 129, - 237, - 359, - 267, - 375, - 290, - 143, - 261, - 6, - 397, - 143, - 375, - 192, - 393, - 234, - 380, - 77, - 393, - 144, - 321, - 308, - 358, - 182, - 343, - 207, - 363, - 226, - 241, - 333, - 132, - 267, - 340, - 225, - 8, - 306, - 122, - 302, - 194, - 251, - 50, - 393, - 100, - 326, - 372, - 241, - 353, - 259, - 356, - 374, - 193, - 336, - 91, - 339, - 76, - 370, - 313, - 290, - 376, - 391, - 10, - 286, - 45, - 239, - 181, - 171, - 52, - 323, - 270, - 114, - 51, - 276, - 122, - 296, - 47, - 324, - 104, - 382, - 84, - 210, - 6, - 308, - 13, - 218, - 333, - 232, - 187, - 364, - 147, - 276, - 32, - 294, - 198, - 352, - 343, - 71, - 355, - 15, - 336, - 389, - 156, - 68, - 276, - 126, - 73, - 346, - 12, - 396, - 94, - 234, - 20, - 348, - 193, - 250, - 83, - 226, - 102, - 360, - 94, - 322, - 142, - 303, - 63, - 396, - 166, - 316, - 19, - 212, - 172, - 375, - 166, - 210, - 71, - 260, - 166, - 381, - 54, - 304, - 186, - 325, - 47, - 282, - 122, - 257, - 8, - 323, - 113, - 222, - 77, - 389, - 191, - 380, - 159, - 291, - 162, - 273, - 4, - 258, - 138, - 318, - 16, - 306, - 173, - 338, - 33, - 323, - 164, - 352, - 36, - 191, - 77, - 358, - 196, - 386, - 169, - 75, - 219, - 48, - 343, - 2, - 294, - 39, - 338, - 335, - 245, - 223, - 61, - 306, - 147, - 283, - 111, - 397, - 184, - 343, - 132, - 398, - 298, - 188, - 325, - 184, - 400, - 208, - 381, - 171, - 309, - 128, - 212, - 230, - 188, - 306, - 70, - 119, - 129, - 167, - 392, - 324, - 99, - 290, - 319, - 156, - 285, - 63, - 339, - 110, - 301, - 246, - 332, - 37, - 286, - 253, - 332, - 243, - 134, - 395, - 33, - 288, - 177, - 319, - 181, - 312, - 32, - 388, - 129, - 350, - 62, - 372, - 69, - 394, - 180, - 231, - 38, - 367, - 147, - 279, - 53, - 364, - 153, - 245, - 2, - 229, - 129, - 352, - 24, - 41, - 118, - 261, - 375, - 175, - 367, - 50, - 366, - 110, - 260, - 65, - 246, - 170, - 210, - 12, - 123, - 372, - 122, - 201, - 15, - 356, - 143, - 302, - 142, - 212, - 265, - 209, - 171, - 261, - 302, - 54, - 299, - 146, - 321, - 78, - 282, - 114, - 247, - 60, - 331, - 130, - 252, - 2, - 289, - 97, - 238, - 141, - 328, - 78, - 369, - 1, - 354, - 114, - 292, - 297, - 114, - 244, - 373, - 327, - 158, - 254, - 30, - 226, - 118, - 335, - 388, - 257, - 329, - 300, - 179, - 329, - 47, - 281, - 78, - 396, - 191, - 341, - 21, - 231, - 169, - 217, - 113, - 367, - 34, - 213, - 184, - 271, - 15, - 178, - 58, - 117, - 334, - 54, - 281, - 168, - 351, - 62, - 333, - 82, - 207, - 72, - 232, - 85, - 345, - 59, - 300, - 54, - 313, - 189, - 240, - 41, - 279, - 128, - 333, - 87, - 359, - 107, - 324, - 49, - 305, - 163, - 269, - 56, - 356, - 167, - 289, - 66, - 297, - 139, - 210, - 32, - 164, - 80, - 309, - 149, - 314, - 99, - 370, - 145, - 395, - 39, - 283, - 106, - 343, - 126, - 292, - 192, - 237, - 33, - 347, - 188, - 308, - 14, - 217, - 188, - 373, - 100, - 300, - 191, - 277, - 63, - 308, - 191, - 301, - 63, - 208, - 70, - 309, - 50, - 276, - 92, - 309, - 46, - 254, - 45, - 211, - 139, - 254, - 49, - 301, - 229, - 359, - 284, - 22, - 341, - 199, - 223, - 47, - 267, - 22, - 345, - 174, - 310, - 211, - 329, - 209, - 143, - 255, - 313, - 327, - 61, - 316, - 325, - 321, - 101, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 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, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ], - "commands": [ - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 2, - 0, - 0, - 2, - 2, - 2, - 2, - 2, - 0, - 2, - 2, - 2, - 0, - 2, - 0, - 2, - 2, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 2, - 0, - 0, - 0, - 0, - 0, - 2, - 2, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 0, - 0, - 2, - 0, - 2, - 0 - ], - "values": [ - 87, - 389, - 327, - 304, - 190, - 248, - 14, - 289, - 151, - 325, - 293, - 323, - 331, - 110, - 378, - 235, - 280, - 369, - 373, - 42, - 61, - 265, - 120, - 394, - 17, - 64, - 325, - 172, - 191, - 373, - 336, - 31, - 151, - 28, - 85, - 2, - 204, - 115, - 2, - 103, - 300, - 168, - 184, - 180, - 359, - 400, - 176, - 118, - 15, - 120, - 6, - 297, - 123, - 84, - 52, - 202, - 239, - 85, - 234, - 353, - 3, - 217, - 119, - 5, - 50, - 29, - 145, - 50, - 389, - 156, - 41, - 120, - 29, - 372, - 70, - 396, - 216, - 280, - 164, - 217, - 161, - 305, - 51, - 90, - 94, - 369, - 29, - 354, - 200, - 21, - 259, - 292, - 164, - 113, - 359, - 28, - 361, - 70, - 363, - 279, - 224, - 363, - 203, - 383, - 350, - 216, - 22, - 95, - 384, - 392, - 359, - 93, - 113, - 157, - 293, - 129, - 78, - 223, - 157, - 116, - 213, - 7, - 284, - 25, - 67, - 222, - 289, - 40, - 342, - 359, - 218, - 365, - 356, - 321, - 136, - 307, - 356, - 356, - 279, - 73, - 177, - 172, - 329, - 128, - 359, - 236, - 174, - 388, - 109, - 11, - 131, - 84, - 349, - 375, - 389, - 342, - 128, - 27, - 39, - 116, - 77, - 342, - 114, - 248, - 31, - 371, - 331, - 182, - 71, - 341, - 294, - 272, - 112, - 368, - 365, - 129, - 83, - 218, - 64, - 261, - 294, - 385, - 115, - 111, - 375, - 67, - 31, - 25, - 57, - 186, - 48, - 43, - 242, - 287, - 162, - 185, - 188, - 336, - 255, - 282, - 340, - 377, - 63, - 18, - 240, - 238, - 351, - 132, - 72, - 123, - 146, - 188, - 23, - 10, - 197, - 150, - 157, - 244, - 292, - 80, - 367, - 369, - 108, - 361, - 344, - 400, - 37, - 364, - 36, - 270, - 177, - 65, - 282, - 357, - 106, - 387, - 149, - 146, - 134, - 329, - 340, - 77, - 57, - 62, - 351, - 364, - 102, - 194, - 68, - 308, - 289, - 3, - 138, - 321, - 283, - 302, - 250, - 231, - 207, - 380, - 289, - 381, - 16, - 176, - 132, - 130, - 13, - 372, - 289, - 121, - 208, - 355, - 252, - 397, - 227, - 139, - 207, - 229, - 301, - 227, - 69, - 40, - 227, - 310, - 181, - 217, - 296, - 26, - 287, - 52, - 261, - 253, - 309, - 166, - 212, - 382, - 205, - 315, - 240, - 203, - 264, - 349, - 279, - 218, - 145, - 270, - 53, - 270, - 338, - 295, - 355, - 277, - 201, - 232, - 218, - 49, - 310, - 90, - 195, - 169, - 278, - 254, - 93, - 150, - 216, - 377, - 290, - 26, - 242, - 391, - 140, - 137, - 289, - 93, - 3, - 325, - 238, - 329, - 373, - 351, - 163, - 279, - 126, - 267, - 376, - 64, - 236, - 72, - 213, - 220, - 44, - 41, - 28, - 223, - 269, - 187, - 381, - 222, - 164, - 297, - 62, - 316, - 21, - 254, - 110, - 98, - 395, - 379, - 399, - 130, - 93, - 211, - 323, - 39, - 267, - 60, - 143, - 125, - 207, - 47, - 284, - 148, - 134, - 47, - 109, - 219, - 241, - 346, - 15, - 306, - 140, - 302, - 156, - 175, - 341, - 147, - 214, - 198, - 14, - 339, - 289, - 91, - 278, - 396, - 75, - 340, - 284, - 68, - 108, - 261, - 366, - 317, - 249, - 100, - 309, - 281, - 63, - 400, - 366, - 306, - 194, - 331, - 211, - 342, - 67, - 49, - 206, - 299, - 87, - 238, - 72, - 379, - 347, - 349, - 266, - 394, - 120, - 94, - 237, - 375, - 397, - 102, - 148, - 198, - 329, - 13, - 96, - 129, - 274, - 43, - 109, - 196, - 55, - 285, - 291, - 164, - 358, - 162, - 47, - 270, - 29, - 273, - 37, - 190, - 209, - 114, - 366, - 192, - 121, - 162, - 361, - 308, - 267, - 136, - 222, - 224, - 139, - 368, - 133, - 301, - 319, - 55, - 170, - 142, - 68, - 330, - 372, - 265, - 386, - 58, - 130, - 203, - 385, - 172, - 370, - 156, - 399, - 112, - 361, - 332, - 26, - 34, - 114, - 134, - 130, - 376, - 158, - 289, - 219, - 232, - 278, - 389, - 147, - 341, - 359, - 296, - 89, - 347, - 101, - 266, - 321, - 383, - 162, - 265, - 398, - 241, - 399, - 106, - 252, - 6, - 42, - 201, - 37, - 256, - 328, - 93, - 384, - 246, - 69, - 1, - 331, - 112, - 216, - 124, - 370, - 225, - 341, - 295, - 188, - 41, - 211, - 289, - 46, - 97, - 91, - 151, - 189, - 156, - 191, - 96, - 221, - 141, - 164, - 394, - 316, - 45, - 12, - 330, - 129, - 129, - 141, - 137, - 305, - 180, - 242, - 5, - 180, - 6, - 18, - 149, - 306, - 336, - 16, - 177, - 2, - 22, - 311, - 190, - 142, - 380, - 162, - 239, - 269, - 52, - 213, - 302, - 191, - 328, - 17, - 190, - 282, - 78, - 397, - 198, - 362, - 191, - 152, - 184, - 262, - 370, - 351, - 199, - 397, - 273, - 270, - 7, - 335, - 295, - 383, - 212, - 263, - 319, - 32, - 96, - 276, - 51, - 165, - 299, - 279, - 390, - 378, - 128, - 307, - 52, - 45, - 94, - 222, - 252, - 111, - 21, - 319, - 90, - 241, - 355, - 60, - 203, - 396, - 368, - 124, - 11, - 149, - 318, - 341, - 46, - 357, - 126, - 98, - 380, - 217, - 105, - 149, - 4, - 34, - 34, - 180, - 360, - 375, - 161, - 343, - 184, - 206, - 241, - 196, - 361, - 178, - 104, - 394, - 76, - 125, - 38, - 384, - 156, - 223, - 318, - 268, - 69, - 225, - 191, - 122, - 314, - 166, - 336, - 232, - 121, - 170, - 81, - 176, - 192, - 218, - 393, - 321, - 254, - 300, - 255, - 54, - 182, - 3, - 8, - 334, - 302, - 150, - 335, - 18, - 144, - 290, - 165, - 204, - 201, - 346, - 2, - 318, - 64, - 54, - 58, - 31, - 171, - 246, - 179, - 115, - 99, - 13, - 371, - 36, - 371, - 137, - 188, - 20, - 341, - 340, - 312, - 260, - 68, - 163, - 95, - 286, - 45, - 156, - 170, - 23, - 29, - 376, - 235, - 114, - 280, - 294, - 30, - 357, - 381, - 363, - 176, - 260, - 344, - 202, - 238, - 303, - 366, - 330, - 114, - 33, - 272, - 243, - 347, - 146, - 56, - 247, - 11, - 291, - 277, - 120, - 142, - 83, - 236, - 365, - 307, - 317, - 383, - 119, - 188, - 153, - 315, - 337, - 364, - 46, - 283, - 129, - 360, - 325, - 178, - 180, - 279, - 370, - 347, - 394, - 141, - 61, - 55, - 281, - 272, - 193, - 30, - 71, - 205, - 342, - 248, - 174, - 99, - 279, - 313, - 11, - 81, - 204, - 113, - 155, - 50, - 385, - 65, - 338, - 225, - 202, - 373, - 257, - 142, - 242, - 316, - 309, - 385, - 167, - 295, - 220, - 41, - 130, - 151, - 70, - 57, - 364, - 63, - 382, - 97, - 388, - 102, - 255, - 387, - 132, - 348, - 113, - 239, - 306, - 299, - 319, - 205, - 9, - 150, - 47, - 62, - 221, - 61, - 119, - 215, - 364, - 230, - 338, - 400, - 397, - 2, - 167, - 286, - 15, - 305, - 391, - 66, - 148, - 142, - 322, - 209, - 378, - 61, - 249, - 198, - 171, - 331, - 45, - 16, - 304, - 312, - 56, - 383, - 289, - 279, - 6, - 31, - 272, - 192, - 10, - 151, - 200, - 181, - 389, - 204, - 30, - 67, - 249, - 166, - 46, - 213, - 175, - 391, - 134, - 102, - 76, - 394, - 362, - 11, - 248, - 183, - 235, - 389, - 158, - 287, - 357, - 385, - 96, - 238, - 75, - 127, - 67, - 314, - 389, - 143, - 98, - 350, - 367, - 113, - 148, - 80, - 74, - 394, - 354, - 146, - 238, - 260, - 260, - 278, - 180, - 261, - 87, - 377, - 187, - 334, - 329, - 30, - 361, - 230, - 375, - 116, - 287, - 41, - 192, - 139, - 209, - 293, - 342, - 83, - 93, - 314, - 306, - 321, - 257, - 38, - 284, - 238, - 358, - 4, - 383, - 332, - 381, - 54, - 22, - 101, - 394, - 94, - 392, - 296, - 244, - 314, - 384, - 37, - 57, - 211, - 357, - 183, - 153, - 101, - 274, - 239, - 264, - 112, - 195, - 255, - 148, - 170, - 62, - 219, - 50, - 218, - 19, - 399, - 353, - 245, - 266, - 214, - 161, - 121, - 19, - 13, - 21, - 192, - 41, - 382, - 211, - 190, - 27, - 54, - 268, - 256, - 19, - 68, - 169, - 127, - 395, - 37, - 91, - 163, - 263, - 224, - 188, - 72, - 28, - 13, - 352, - 4, - 286, - 343, - 37, - 346, - 177, - 341, - 120, - 149, - 324, - 46, - 284, - 200, - 24, - 273, - 297, - 212, - 397, - 46, - 207, - 100, - 271, - 59, - 100, - 181, - 89, - 205, - 297, - 257, - 185, - 230, - 341, - 292, - 274, - 27, - 16, - 16, - 134, - 355, - 165, - 226, - 208, - 238, - 233, - 28, - 366, - 384, - 204, - 37, - 112, - 339, - 95, - 354, - 129, - 323, - 158, - 375, - 238, - 2, - 372, - 356, - 379, - 89, - 22, - 284, - 271, - 51, - 103, - 375, - 162, - 314, - 341, - 18, - 395, - 180, - 26, - 8, - 90, - 143, - 211, - 230, - 273, - 245, - 112, - 169, - 200, - 335, - 308, - 70, - 328, - 311, - 246, - 49, - 342, - 204, - 282, - 148, - 123, - 39, - 233, - 217, - 270, - 147, - 104, - 110, - 359, - 386, - 276, - 269, - 97, - 70, - 400, - 351, - 301, - 226, - 167, - 87, - 176, - 130, - 137, - 170, - 161, - 368, - 342, - 258, - 376, - 213, - 117, - 114, - 45, - 383, - 196, - 241, - 219, - 50, - 193, - 317, - 144, - 299, - 231, - 367, - 63, - 41, - 107, - 371, - 112, - 145, - 44, - 241, - 215, - 328, - 252, - 228, - 64, - 5, - 200, - 370, - 25, - 137, - 344, - 322, - 4, - 375, - 274, - 239, - 124, - 152, - 303, - 290, - 37, - 349, - 137, - 129, - 326, - 313, - 51, - 179, - 64, - 323, - 320, - 140, - 18, - 274, - 84, - 290, - 64, - 41, - 122, - 131, - 314, - 286, - 279, - 113, - 196, - 329, - 89, - 155, - 197, - 104, - 1, - 33, - 152, - 190, - 348, - 192, - 217, - 34, - 233, - 147, - 185, - 124, - 246, - 215, - 211, - 301, - 50, - 13, - 393, - 302, - 222, - 374, - 222, - 62, - 370, - 351, - 17, - 367, - 385, - 137, - 254, - 27, - 219, - 240, - 349, - 166, - 307, - 375, - 29, - 82, - 354, - 191, - 284, - 398, - 157, - 253, - 128, - 337, - 238, - 317, - 27, - 193, - 131, - 71, - 232, - 394, - 400, - 78, - 57, - 216, - 203, - 351, - 224, - 372, - 26, - 164, - 90, - 259, - 304, - 200, - 56, - 313, - 81, - 290, - 66, - 324, - 336, - 93, - 104, - 119, - 176, - 38, - 309, - 86, - 362, - 261, - 150, - 210, - 377, - 323, - 291, - 373, - 216, - 386, - 123, - 271, - 293, - 104, - 348, - 29, - 171, - 247, - 147, - 224, - 270, - 362, - 200, - 371, - 73, - 215, - 236, - 157, - 196, - 204, - 83, - 12, - 382, - 246, - 305, - 45, - 376, - 166, - 124, - 296, - 386, - 152, - 228, - 206, - 191, - 181, - 14, - 94, - 76, - 252, - 273, - 37, - 388, - 17, - 223, - 227, - 125, - 353, - 242, - 367, - 150, - 191, - 153, - 191, - 84, - 78, - 208, - 263, - 64, - 319, - 244, - 135, - 181, - 105, - 6, - 245, - 96, - 62, - 320, - 158, - 345, - 73, - 384, - 303, - 364, - 195, - 323, - 221, - 45, - 10, - 162, - 305, - 289, - 357, - 32, - 21, - 159, - 71, - 133, - 335, - 353, - 86, - 133, - 128, - 397, - 292, - 16, - 150, - 66, - 144, - 274, - 180, - 306, - 301, - 143, - 394, - 145, - 175, - 73, - 113, - 330, - 172, - 1, - 146, - 349, - 303, - 336, - 161, - 361, - 7, - 373, - 253, - 387, - 151, - 105, - 149, - 360, - 351, - 239, - 66, - 118, - 203, - 22, - 166, - 334, - 5, - 183, - 335, - 343, - 168, - 300, - 111, - 332, - 103, - 134, - 197, - 147, - 29, - 112, - 343, - 81, - 43, - 146, - 295, - 34, - 344, - 264, - 148, - 263, - 126, - 134, - 14, - 244, - 152, - 227, - 292, - 120, - 232, - 29, - 141, - 146, - 42, - 52, - 72, - 121, - 14, - 300, - 138, - 163, - 202, - 280, - 259, - 396, - 77, - 344, - 253, - 209, - 381, - 311, - 260, - 334, - 86, - 393, - 338, - 52, - 235, - 270, - 388, - 295, - 137, - 279, - 350, - 228, - 268, - 134, - 294, - 151, - 181, - 121, - 84, - 213, - 225, - 41, - 43, - 257, - 91, - 150, - 333, - 99, - 247, - 11, - 64, - 206, - 194, - 10, - 371, - 179, - 87, - 250, - 379, - 143, - 113, - 187, - 367, - 32, - 242, - 251, - 151, - 195, - 173, - 177, - 342, - 391, - 107, - 77, - 272, - 351, - 248, - 373, - 49, - 138, - 83, - 400, - 218, - 27, - 118, - 379, - 167, - 101, - 322, - 79, - 395, - 238, - 53, - 39, - 63, - 106, - 334, - 392, - 103, - 291, - 323, - 52, - 40, - 323, - 280, - 314, - 237, - 325, - 282, - 282, - 384, - 169, - 117, - 400, - 203, - 83, - 210, - 377, - 347, - 380, - 255, - 162, - 243, - 349, - 4, - 392, - 146, - 253, - 286, - 22, - 48, - 24, - 287, - 300, - 160, - 273, - 230, - 27, - 77, - 60, - 381, - 212, - 142, - 358, - 114, - 293, - 123, - 14, - 208, - 80, - 80, - 214, - 21, - 119, - 120, - 161, - 247, - 282, - 237, - 10, - 26, - 373, - 58, - 161, - 133, - 44, - 219, - 58, - 101, - 197, - 208, - 329, - 377, - 228, - 280, - 139, - 49, - 339, - 220, - 231, - 256, - 223, - 227, - 354, - 203, - 134, - 324, - 264, - 273, - 157, - 284, - 192, - 93, - 374, - 117, - 346, - 240, - 205, - 106, - 40, - 193, - 398, - 33, - 334, - 248, - 225, - 391, - 119, - 11, - 339, - 99, - 102, - 1, - 283, - 262, - 66, - 281, - 397, - 305, - 350, - 267, - 215, - 191, - 383, - 336, - 147, - 75, - 106, - 49, - 41, - 211, - 53, - 237, - 364, - 226, - 217, - 394, - 77, - 313, - 266, - 303, - 173, - 380, - 32, - 390, - 200, - 63, - 56, - 328, - 93, - 290, - 1, - 136, - 77, - 44, - 268, - 91, - 274, - 83, - 69, - 169, - 247, - 393, - 208, - 43, - 381, - 137, - 280, - 279, - 230, - 212, - 224, - 220, - 233, - 29, - 30, - 175, - 75, - 108, - 140, - 267, - 20, - 16, - 51, - 27, - 287, - 169, - 145, - 132, - 170, - 146, - 246, - 162, - 120, - 155, - 388, - 288, - 98, - 58, - 155, - 146, - 37, - 133, - 153, - 40, - 187, - 88, - 165, - 385, - 272, - 334, - 105, - 177, - 333, - 204, - 129, - 393, - 228, - 348, - 70, - 137, - 97, - 8, - 233, - 70, - 315, - 161, - 38, - 230, - 237, - 191, - 33, - 257, - 4, - 45, - 382, - 81, - 209, - 64, - 140, - 9, - 243, - 98, - 31, - 3, - 66, - 164, - 176, - 198, - 261, - 381, - 56, - 196, - 20, - 101, - 51, - 255, - 37, - 35, - 365, - 64, - 59, - 246, - 383, - 297, - 152, - 142, - 55, - 190, - 27, - 301, - 169, - 66, - 138, - 222, - 64, - 240, - 364, - 48, - 365, - 166, - 393, - 62, - 150, - 72, - 165, - 316, - 7, - 388, - 92, - 119, - 179, - 161, - 106, - 297, - 382, - 151, - 34, - 276, - 325, - 249, - 136, - 170, - 390, - 373, - 121, - 374, - 21, - 129, - 155, - 39, - 385, - 244, - 394, - 52, - 239, - 186, - 189, - 170, - 194, - 231, - 296, - 21, - 392, - 262, - 169, - 8, - 285, - 106, - 35, - 316, - 108, - 107, - 229, - 77, - 322, - 143, - 38, - 313, - 52, - 386, - 211, - 78, - 151, - 37, - 156, - 232, - 188, - 114, - 57, - 63, - 195, - 169, - 82, - 281, - 230, - 146, - 312, - 168, - 174, - 181, - 62, - 352, - 287, - 71, - 102, - 338, - 211, - 222, - 148, - 302, - 134, - 6, - 332, - 305, - 193, - 40, - 272, - 211, - 292, - 91, - 238, - 317, - 89, - 137, - 383, - 356, - 355, - 216, - 325, - 181, - 92, - 177, - 217, - 92, - 342, - 42, - 283, - 20, - 178, - 17, - 297, - 207, - 274, - 248, - 277, - 4, - 62, - 352, - 85, - 56, - 330, - 386, - 280, - 353, - 399, - 151, - 78, - 353, - 209, - 96, - 125, - 145, - 96, - 325, - 254, - 89, - 143, - 22, - 204, - 310, - 180, - 163, - 395, - 282, - 85, - 183, - 351, - 297, - 49, - 45, - 65, - 392, - 65, - 369, - 18, - 349, - 240, - 59, - 271, - 313, - 300, - 204, - 129, - 310, - 47, - 378, - 112, - 396, - 273, - 331, - 242, - 215, - 62, - 162, - 227, - 388, - 397, - 39, - 255, - 142, - 400, - 191, - 133, - 264, - 16, - 272, - 331, - 93, - 100, - 270, - 152, - 9, - 373, - 85, - 255, - 95, - 362, - 22, - 323, - 37, - 234, - 170, - 19, - 104, - 67, - 14, - 18, - 3, - 400, - 14, - 356, - 324, - 287, - 103, - 268, - 370, - 73, - 305, - 359, - 272, - 115, - 264, - 215, - 53, - 44, - 365, - 208, - 48, - 378, - 303, - 378, - 306, - 156, - 31, - 366, - 261, - 269, - 108, - 5, - 72, - 373, - 236, - 75, - 366, - 139, - 101, - 193, - 126, - 125, - 224, - 388, - 122, - 184, - 307, - 73, - 14, - 383, - 131, - 345, - 261, - 46, - 172, - 63, - 220, - 74, - 57, - 209, - 225, - 46, - 173, - 133, - 27, - 171, - 262, - 3, - 347, - 87, - 152, - 201, - 59, - 173, - 224, - 67, - 29, - 5, - 326, - 203, - 56, - 155, - 22, - 149, - 363, - 290, - 23, - 305, - 36, - 157, - 95, - 31, - 370, - 127, - 105, - 230, - 135, - 163, - 90, - 350, - 375, - 144, - 330, - 190, - 331, - 46, - 35, - 94, - 390, - 251, - 147, - 11, - 184, - 394, - 347, - 360, - 319, - 201, - 105, - 391, - 241, - 204, - 290, - 310, - 282, - 201, - 389, - 19, - 111, - 232, - 137, - 60, - 64, - 308, - 267, - 306, - 283, - 277, - 71, - 391, - 164, - 253, - 387, - 195, - 321, - 61, - 51, - 320, - 159, - 108, - 47, - 91, - 44, - 199, - 312, - 193, - 254, - 241, - 25, - 211, - 136, - 259, - 269, - 123, - 61, - 221, - 255, - 95, - 209, - 322, - 50, - 65, - 167, - 28, - 117, - 121, - 166, - 301, - 350, - 115, - 253, - 247, - 343, - 259, - 237, - 40, - 75, - 308, - 62, - 114, - 25, - 68, - 254, - 67, - 348, - 141, - 150, - 4, - 280, - 141, - 2, - 79, - 158, - 101, - 79, - 270, - 315, - 263, - 356, - 114, - 41, - 174, - 257, - 91, - 394, - 299, - 57, - 182, - 280, - 26, - 100, - 83, - 106, - 198, - 361, - 108, - 221, - 123, - 284, - 87, - 251, - 101, - 125, - 355, - 117, - 61, - 322, - 162, - 385, - 74, - 286, - 101, - 350, - 367, - 149, - 50, - 315, - 343, - 7, - 291, - 1, - 376, - 85, - 6, - 67, - 17, - 91, - 77, - 152, - 310, - 177, - 306, - 287, - 181, - 142, - 46, - 310, - 143, - 136, - 130, - 114, - 263, - 153, - 304, - 352, - 338, - 108, - 23, - 325, - 208, - 14, - 5, - 343, - 397, - 239, - 145, - 224, - 184, - 140, - 42, - 367, - 321, - 306, - 387, - 69, - 98, - 243, - 331, - 237, - 189, - 264, - 190, - 149, - 76, - 146, - 361, - 113, - 334, - 108, - 355, - 45, - 338, - 107, - 104, - 63, - 223, - 115, - 194, - 395, - 113, - 9, - 21, - 219, - 10, - 59, - 158, - 105, - 303, - 362, - 375, - 232, - 91, - 233, - 214, - 339, - 356, - 371, - 68, - 280, - 230, - 13, - 60, - 392, - 91, - 49, - 284, - 269, - 285, - 42, - 71, - 357, - 276, - 142, - 69, - 90, - 85, - 25, - 18, - 388, - 105, - 58, - 301, - 320, - 190, - 147, - 117, - 147, - 335, - 326, - 330, - 115, - 230, - 337, - 253, - 380, - 155, - 195, - 398, - 356, - 148, - 69, - 390, - 209, - 207, - 112, - 380, - 16, - 351, - 274, - 140, - 149, - 80, - 229, - 56, - 338, - 298, - 254, - 224, - 182, - 226, - 257, - 18, - 207, - 238, - 234, - 255, - 202, - 141, - 307, - 100, - 68, - 82, - 271, - 265, - 385, - 344, - 231, - 134, - 213, - 116, - 68, - 320, - 326, - 320, - 201, - 296, - 288, - 148, - 198, - 34, - 123, - 73, - 342, - 397, - 68, - 145, - 333, - 163, - 185, - 210, - 25, - 138, - 343, - 149, - 163, - 170, - 36, - 274, - 263, - 75, - 203, - 155, - 196, - 234, - 210, - 107, - 152, - 311, - 314, - 204, - 358, - 213, - 102, - 281, - 203, - 224, - 123, - 347, - 54, - 60, - 163, - 49, - 134, - 2, - 366, - 307, - 204, - 193, - 120, - 185, - 362, - 74, - 35, - 68, - 141, - 309, - 120, - 276, - 166, - 89, - 91, - 207, - 7, - 336, - 262, - 257, - 165, - 151, - 257, - 50, - 381, - 304, - 268, - 265, - 157, - 378, - 9, - 243, - 53, - 346, - 148, - 166, - 261, - 177, - 256, - 28, - 193, - 279, - 165, - 320, - 341, - 106, - 353, - 25, - 179, - 57, - 122, - 394, - 100, - 335, - 243, - 103, - 252, - 332, - 135, - 103, - 389, - 316, - 252, - 262, - 378, - 356, - 37, - 254, - 178, - 251, - 328, - 251, - 105, - 349, - 166, - 130, - 327, - 372, - 350, - 380, - 35, - 281, - 30, - 276, - 364, - 345, - 52, - 62, - 258, - 76, - 103, - 320, - 203, - 387, - 186, - 132, - 10, - 349, - 359, - 270, - 154, - 75, - 137, - 92, - 224, - 167, - 390, - 290, - 92, - 282, - 336, - 391, - 133, - 43, - 103, - 260, - 91, - 116, - 289, - 96, - 358, - 157, - 178, - 168, - 244, - 98, - 175, - 100, - 367, - 82, - 86, - 124, - 356, - 165, - 24, - 73, - 280, - 242, - 121, - 117, - 174, - 169, - 331, - 92, - 185, - 210, - 142, - 110, - 364, - 179, - 322, - 317, - 170, - 59, - 312, - 247, - 249, - 149, - 388, - 241, - 369, - 69, - 153, - 150, - 217, - 357, - 169, - 391, - 220, - 33, - 284, - 208, - 392, - 181, - 48, - 62, - 268, - 386, - 367, - 228, - 121, - 385, - 41, - 231, - 208, - 141, - 33, - 299, - 207, - 126, - 143, - 388, - 122, - 257, - 374, - 217, - 188, - 356, - 120, - 201, - 192, - 314, - 117, - 63, - 200, - 230, - 61, - 358, - 36, - 327, - 285, - 364, - 83, - 116, - 190, - 339, - 135, - 62, - 1, - 9, - 395, - 331, - 55, - 288, - 254, - 210, - 310, - 62, - 397, - 297, - 228, - 288, - 283, - 333, - 69, - 105, - 231, - 129, - 163, - 110, - 201, - 143, - 22, - 91, - 40, - 3, - 360, - 383, - 157, - 148, - 98, - 25, - 332, - 239, - 200, - 298, - 299, - 92, - 276, - 22, - 67, - 190, - 287, - 200, - 105, - 250, - 56, - 185, - 324, - 183, - 212, - 145, - 254, - 240, - 18, - 385, - 328, - 356, - 391, - 299, - 233, - 299, - 48, - 181, - 88, - 32, - 143, - 306, - 150, - 247, - 96, - 103, - 187, - 3, - 340, - 14, - 368, - 50, - 307, - 181, - 365, - 161, - 212, - 194, - 46, - 38, - 52, - 99, - 292, - 400, - 231, - 163, - 299, - 72, - 383, - 72, - 132, - 136, - 356, - 159, - 271, - 48, - 102, - 322, - 236, - 4, - 218, - 112, - 228, - 357, - 86, - 45, - 97, - 46, - 58, - 384, - 304, - 96, - 316, - 22, - 82, - 132, - 111, - 103, - 17, - 385, - 270, - 191, - 148, - 258, - 318, - 302, - 35, - 384, - 336, - 393, - 131, - 261, - 373, - 314, - 164, - 281, - 272, - 321, - 24, - 136, - 180, - 319, - 240, - 339, - 228, - 83, - 15, - 157, - 30, - 337, - 354, - 395, - 22, - 345, - 33, - 264, - 235, - 332, - 239, - 303, - 12, - 143, - 45, - 251, - 233, - 146, - 155, - 177, - 214, - 347, - 217, - 278, - 248, - 230, - 264, - 279, - 255, - 107, - 17, - 242, - 117, - 27, - 219, - 398, - 42, - 179, - 254, - 337, - 137, - 164, - 131, - 339, - 363, - 131, - 112, - 104, - 174, - 92, - 384, - 144, - 258, - 53, - 246, - 110, - 244, - 201, - 180, - 303, - 94, - 1, - 370, - 212, - 274, - 180, - 138, - 315, - 190, - 337, - 179, - 87, - 189, - 101, - 74, - 16, - 314, - 141, - 193, - 107, - 137, - 220, - 96, - 121, - 374, - 178, - 320, - 338, - 344, - 69, - 331, - 364, - 97, - 35, - 163, - 210, - 367, - 178, - 305, - 28, - 187, - 235, - 124, - 380, - 189, - 26, - 83, - 392, - 162, - 108, - 274, - 248, - 286, - 150, - 199, - 79, - 64, - 344, - 370, - 293, - 171, - 152, - 227, - 284, - 192, - 384, - 291, - 254, - 224, - 34, - 322, - 351, - 324, - 196, - 239, - 327, - 398, - 107, - 64, - 311, - 8, - 284, - 47, - 19, - 118, - 123, - 104, - 182, - 329, - 335, - 325, - 58, - 143, - 192, - 206, - 335, - 375, - 328, - 20, - 268, - 331, - 245, - 134, - 30, - 355, - 208, - 23, - 170, - 115, - 68, - 73, - 120, - 390, - 13, - 352, - 336, - 205, - 211, - 248, - 312, - 256, - 243, - 47, - 248, - 160, - 11, - 276, - 309, - 200, - 240, - 51, - 59, - 349, - 380, - 93, - 53, - 34, - 277, - 79, - 115, - 183, - 366, - 170, - 188, - 327, - 176, - 234, - 262, - 253, - 13, - 162, - 192, - 261, - 262, - 177, - 214, - 110, - 181, - 395, - 199, - 365, - 93, - 4, - 393, - 79, - 40, - 227, - 96, - 107, - 165, - 382, - 231, - 73, - 274, - 160, - 295, - 192, - 196, - 141, - 67, - 336, - 32, - 175, - 276, - 63, - 250, - 18, - 16, - 218, - 84, - 399, - 155, - 57, - 134, - 368, - 87, - 134, - 128, - 88, - 209, - 268, - 212, - 56, - 210, - 94, - 42, - 205, - 51, - 302, - 280, - 359, - 306, - 298, - 16, - 210, - 158, - 254, - 7, - 253, - 150, - 195, - 106, - 137, - 188, - 280, - 242, - 399, - 36, - 10, - 382, - 241, - 329, - 334, - 297, - 365, - 22, - 5, - 324, - 10, - 396, - 177, - 223, - 272, - 68, - 29, - 240, - 97, - 140, - 75, - 247, - 18, - 61, - 71, - 186, - 271, - 21, - 131, - 235, - 203, - 310, - 74, - 351, - 347, - 389, - 192, - 379, - 384, - 322, - 58, - 258, - 324, - 143, - 18, - 252, - 16, - 150, - 151, - 142, - 183, - 215, - 32, - 42, - 124, - 371, - 261, - 106, - 218, - 257, - 178, - 62, - 237, - 30, - 32, - 210, - 132, - 229, - 293, - 284, - 133, - 359, - 311, - 51, - 139, - 257, - 58, - 244, - 142, - 208, - 147, - 25, - 391, - 179, - 375, - 303, - 25, - 289, - 188, - 267, - 40, - 394, - 292, - 272, - 35, - 206, - 220, - 173, - 351, - 305, - 347, - 362, - 274, - 390, - 133, - 93, - 40, - 3, - 398, - 53, - 110, - 154, - 157, - 189, - 385, - 166, - 191, - 2, - 213, - 46, - 170, - 255, - 341, - 361, - 168, - 189, - 208, - 17, - 198, - 2, - 152, - 394, - 200, - 4, - 61, - 200, - 107, - 302, - 8, - 185, - 10, - 371, - 150, - 276, - 395, - 63, - 156, - 269, - 333, - 358, - 27, - 351, - 18, - 329, - 188, - 323, - 355, - 360, - 244, - 205, - 187, - 300, - 175, - 138, - 269, - 351, - 29, - 301, - 6, - 13, - 228, - 337, - 238, - 173, - 100, - 78, - 96, - 51, - 40, - 181, - 303, - 141, - 172, - 233, - 350, - 86, - 348, - 266, - 331, - 322, - 270, - 397, - 200, - 41, - 113, - 331, - 213, - 159, - 22, - 340, - 228, - 274, - 239, - 43, - 324, - 296, - 351, - 115, - 29, - 363, - 12, - 141, - 350, - 337, - 317, - 65, - 332, - 396, - 138, - 145, - 155, - 49, - 96, - 271, - 148, - 23, - 23, - 287, - 184, - 218, - 77, - 284, - 85, - 144, - 200, - 15, - 77, - 218, - 130, - 32, - 367, - 29, - 380, - 365, - 120, - 1, - 332, - 372, - 128, - 306, - 34, - 398, - 218, - 141, - 343, - 329, - 131, - 251, - 309, - 347, - 143, - 211, - 168, - 316, - 100, - 86, - 113, - 153, - 62, - 260, - 288, - 378, - 49, - 143, - 166, - 102, - 111, - 15, - 294, - 42, - 6, - 312, - 228, - 364, - 23, - 176, - 372, - 286, - 331, - 356, - 274, - 374, - 252, - 350, - 54, - 13, - 240, - 93, - 52, - 101, - 399, - 10, - 195, - 361, - 17, - 284, - 315, - 141, - 53, - 289, - 311, - 206, - 98, - 48, - 331, - 145, - 256, - 67, - 240, - 206, - 340, - 310, - 260, - 266, - 241, - 35, - 183, - 343, - 193, - 156, - 165, - 280, - 168, - 389, - 241, - 32, - 42, - 67, - 319, - 91, - 2, - 298, - 396, - 265, - 139, - 52, - 236, - 113, - 85, - 208, - 134, - 303, - 282, - 291, - 362, - 40, - 283, - 224, - 183, - 256, - 385, - 157, - 193, - 317, - 364, - 91, - 381, - 265, - 238, - 52, - 120, - 347, - 201, - 246, - 101, - 318, - 29, - 278, - 264, - 188, - 133, - 140, - 185, - 201, - 257, - 69, - 282, - 380, - 252, - 249, - 193, - 322, - 44, - 30, - 124, - 216, - 77, - 215, - 127, - 328, - 339, - 173, - 155, - 251, - 189, - 76, - 65, - 325, - 354, - 44, - 280, - 280, - 288, - 189, - 334, - 139, - 59, - 158, - 230, - 152, - 339, - 367, - 373, - 393, - 359, - 329, - 292, - 150, - 256, - 343, - 140, - 59, - 24, - 297, - 324, - 334, - 265, - 92, - 13, - 388, - 392, - 193, - 379, - 323, - 178, - 236, - 197, - 323, - 169, - 54, - 372, - 25, - 30, - 87, - 132, - 345, - 135, - 389, - 70, - 39, - 102, - 158, - 260, - 197, - 129, - 360, - 87, - 288, - 20, - 256, - 184, - 150, - 272, - 264, - 53, - 131, - 328, - 99, - 172, - 223, - 124, - 255, - 399, - 275, - 311, - 399, - 152, - 283, - 107, - 40, - 258, - 361, - 393, - 58, - 365, - 182, - 57, - 345, - 348, - 42, - 251, - 387, - 106, - 237, - 35, - 371, - 279, - 66, - 362, - 213, - 42, - 9, - 297, - 288, - 292, - 325, - 367, - 31, - 175, - 72, - 377, - 358, - 142, - 360, - 399, - 64, - 213, - 303, - 44, - 140, - 215, - 249, - 322, - 267, - 117, - 366, - 74, - 55, - 71, - 38, - 253, - 367, - 113, - 196, - 166, - 72, - 328, - 172, - 389, - 89, - 353, - 19, - 163, - 392, - 93, - 16, - 35, - 353, - 78, - 282, - 355, - 273, - 269, - 342, - 194, - 21, - 301, - 57, - 148, - 47, - 235, - 126, - 52, - 304, - 345, - 250, - 2, - 62, - 346, - 94, - 129, - 91, - 216, - 384, - 366, - 70, - 124, - 200, - 331, - 204, - 240, - 189, - 41, - 389, - 305, - 32, - 103, - 121, - 351, - 252, - 216, - 33, - 296, - 83, - 13, - 120, - 130, - 381, - 247, - 89, - 363, - 367, - 32, - 255, - 134, - 16, - 62, - 99, - 31, - 383, - 76, - 202, - 396, - 199, - 149, - 389, - 245, - 211, - 11, - 262, - 391, - 122, - 56, - 90, - 307, - 167, - 120, - 75, - 284, - 294, - 89, - 58, - 374, - 331, - 249, - 21, - 185, - 244, - 267, - 231, - 122, - 342, - 205, - 282, - 308, - 149, - 134, - 146, - 145, - 51, - 27, - 335, - 91, - 3, - 116, - 51, - 339, - 131, - 193, - 57, - 33, - 145, - 238, - 198, - 53, - 398, - 278, - 212, - 41, - 165, - 290, - 40, - 233, - 384, - 84, - 133, - 160, - 218, - 381, - 254, - 296, - 359, - 298, - 9, - 132, - 260, - 43, - 250, - 310, - 348, - 109, - 245, - 117, - 357, - 288, - 300, - 293, - 218, - 389, - 381, - 6, - 65, - 237, - 220, - 255, - 41, - 77, - 254, - 289, - 233, - 173, - 400, - 66, - 72, - 69, - 10, - 198, - 174, - 316, - 28, - 110, - 370, - 205, - 98, - 323, - 218, - 248, - 32, - 199, - 259, - 254, - 171, - 260, - 76, - 184, - 398, - 23, - 218, - 261, - 52, - 39, - 314, - 258, - 345, - 200, - 396, - 367, - 396, - 90, - 160, - 322, - 395, - 370, - 206, - 300, - 50, - 109, - 277, - 13, - 304, - 24, - 169, - 287, - 287, - 91, - 92, - 150, - 137, - 331, - 240, - 232, - 235, - 227, - 293, - 250, - 80, - 3, - 399, - 167, - 196, - 354, - 211, - 251, - 145, - 356, - 104, - 343, - 168, - 320, - 122, - 296, - 151, - 317, - 350, - 334, - 318, - 194, - 18, - 183, - 370, - 29, - 132, - 222, - 275, - 222, - 323, - 73, - 275, - 396, - 151, - 218, - 342, - 176, - 15, - 285, - 352, - 250, - 317, - 213, - 387, - 274, - 126, - 103, - 100, - 147, - 207, - 34, - 331, - 202, - 371, - 360, - 337, - 340, - 289, - 369, - 220, - 399, - 333, - 167, - 9, - 286, - 349, - 95, - 195, - 385, - 223, - 366, - 155, - 103, - 326, - 352, - 136, - 38, - 368, - 400, - 41, - 279, - 27, - 211, - 318, - 50, - 25, - 73, - 141, - 341, - 221, - 184, - 169, - 246, - 338, - 101, - 238, - 247, - 92, - 181, - 332, - 204, - 246, - 132, - 321, - 360, - 335, - 331, - 73, - 210, - 317, - 243, - 222, - 132, - 68, - 112, - 198, - 399, - 80, - 130, - 172, - 378, - 260, - 341, - 89, - 27, - 4, - 189, - 80, - 119, - 282, - 221, - 53, - 263, - 133, - 295, - 195, - 327, - 315, - 226, - 52, - 311, - 297, - 315, - 371, - 85, - 142, - 74, - 252, - 251, - 314, - 249, - 373, - 320, - 121, - 193, - 1, - 187, - 316, - 127, - 141, - 154, - 193, - 152, - 359, - 270, - 326, - 391, - 225, - 37, - 368, - 71, - 367, - 7, - 25, - 274, - 389, - 361, - 241, - 250, - 366, - 101, - 267, - 41, - 363, - 37, - 146, - 338, - 210, - 139, - 168, - 68, - 355, - 347, - 302, - 395, - 115, - 185, - 304, - 158, - 325, - 162, - 186, - 363, - 269, - 320, - 202, - 360, - 88, - 79, - 56, - 377, - 280, - 303, - 317, - 346, - 175, - 80, - 27, - 138, - 395, - 180, - 341, - 88, - 55, - 186, - 68, - 317, - 364, - 368, - 69, - 178, - 261, - 92, - 248, - 55, - 236, - 333, - 52, - 92, - 250, - 87, - 17, - 36, - 362, - 3, - 321, - 362, - 15, - 211, - 187, - 153, - 231, - 381, - 92, - 337, - 372, - 277, - 63, - 358, - 327, - 79, - 135, - 284, - 149, - 340, - 27, - 196, - 368, - 264, - 17, - 140, - 211, - 203, - 31, - 55, - 61, - 11, - 121, - 308, - 393, - 385, - 194, - 185, - 376, - 168, - 316, - 293, - 252, - 62, - 54, - 204, - 386, - 359, - 378, - 54, - 30, - 133, - 54, - 351, - 275, - 46, - 148, - 351, - 207, - 257, - 398, - 147, - 296, - 37, - 188, - 111, - 201, - 26, - 386, - 321, - 145, - 81, - 310, - 132, - 296, - 230, - 295, - 188, - 128, - 16, - 228, - 44, - 39, - 52, - 156, - 20, - 97, - 35, - 285, - 142, - 327, - 213, - 338, - 79, - 229, - 399, - 238, - 385, - 139, - 325, - 1, - 121, - 150, - 189, - 77, - 25, - 258, - 316, - 377, - 58, - 143, - 114, - 374, - 136, - 60, - 157, - 278, - 128, - 383, - 220, - 112, - 328, - 309, - 232, - 344, - 281, - 194, - 84, - 10, - 119, - 105, - 295, - 254, - 251, - 380, - 110, - 105, - 179, - 78, - 225, - 317, - 234, - 150, - 385, - 363, - 185, - 360, - 144, - 39, - 204, - 100, - 344, - 260, - 246, - 76, - 40, - 386, - 303, - 154, - 314, - 82, - 388, - 334, - 37, - 45, - 238, - 133, - 75, - 299, - 102, - 90, - 67, - 330, - 120, - 311, - 276, - 126, - 385, - 385, - 200, - 61, - 386, - 167, - 163, - 124, - 108, - 64, - 307, - 356, - 210, - 255, - 188, - 197, - 56, - 340, - 354, - 26, - 82, - 19, - 305, - 54, - 214, - 82, - 284, - 324, - 246, - 168, - 57, - 31, - 337, - 208, - 247, - 128, - 61, - 267, - 74, - 313, - 133, - 258, - 87, - 88, - 288, - 252, - 157, - 324, - 302, - 33, - 57, - 330, - 112, - 103, - 37, - 217, - 365, - 75, - 170, - 121, - 289, - 341, - 49, - 6, - 226, - 97, - 348, - 183, - 169, - 305, - 148, - 315, - 119, - 125, - 312, - 266, - 263, - 117, - 225, - 370, - 166, - 307, - 61, - 311, - 393, - 33, - 315, - 267, - 315, - 311, - 140, - 60, - 185, - 166, - 390, - 313, - 276, - 138, - 39, - 254, - 32, - 358, - 200, - 280, - 34, - 263, - 386, - 10, - 250, - 266, - 387, - 15, - 342, - 4, - 249, - 168, - 99, - 365, - 365, - 374, - 59, - 217, - 400, - 85, - 381, - 192, - 312, - 160, - 23, - 194, - 293, - 357, - 31, - 6, - 25, - 208, - 276, - 104, - 316, - 16, - 207, - 41, - 126, - 44, - 359, - 394, - 272, - 394, - 54, - 27, - 86, - 174, - 328, - 322, - 313, - 343, - 313, - 184, - 260, - 287, - 379, - 222, - 368, - 243, - 165, - 230, - 320, - 71, - 355, - 204, - 308, - 279, - 347, - 73, - 262, - 170, - 324, - 336, - 257, - 223, - 352, - 264, - 149, - 56, - 106, - 224, - 80, - 114, - 319, - 337, - 73, - 100, - 99, - 318, - 144, - 308, - 34, - 255, - 289, - 8, - 145, - 187, - 281, - 59, - 257, - 222, - 387, - 29, - 156, - 191, - 217, - 13, - 381, - 261, - 178, - 142, - 46, - 109, - 379, - 167, - 280, - 121, - 40, - 278, - 57, - 249, - 200, - 113, - 300, - 138, - 115, - 330, - 57, - 308, - 313, - 221, - 252, - 19, - 6, - 37, - 45, - 380, - 89, - 37, - 310, - 179, - 97, - 262, - 357, - 38, - 38, - 332, - 233, - 374, - 92, - 29, - 194, - 117, - 345, - 317, - 61, - 123, - 17, - 5, - 237, - 244, - 319, - 100, - 310, - 261, - 320, - 239, - 224, - 129, - 365, - 228, - 109, - 168, - 397, - 158, - 361, - 19, - 265, - 228, - 156, - 292, - 76, - 256, - 273, - 52, - 393, - 50, - 50, - 93, - 356, - 93, - 23, - 161, - 46, - 149, - 283, - 68, - 215, - 267, - 24, - 216, - 334, - 65, - 373, - 142, - 212, - 335, - 160, - 337, - 203, - 394, - 362, - 61, - 219, - 20, - 249, - 15, - 386, - 390, - 360, - 391, - 77, - 25, - 170, - 385, - 45, - 280, - 121, - 229, - 73, - 308, - 32, - 260, - 126, - 156, - 288, - 228, - 52, - 184, - 5, - 385, - 105, - 267, - 134, - 111, - 197, - 339, - 111, - 302, - 84, - 16, - 161, - 302, - 191, - 290, - 254, - 153, - 353, - 361, - 101, - 350, - 139, - 130, - 376, - 380, - 396, - 195, - 32, - 143, - 183, - 41, - 16, - 260, - 313, - 386, - 73, - 216, - 151, - 203, - 334, - 168, - 190, - 355, - 305, - 1, - 312, - 322, - 255, - 53, - 317, - 266, - 271, - 137, - 42, - 117, - 15, - 385, - 112, - 400, - 202, - 7, - 313, - 116, - 154, - 108, - 214, - 296, - 377, - 255, - 297, - 342, - 80, - 29, - 17, - 50, - 365, - 233, - 25, - 90, - 253, - 329, - 248, - 59, - 303, - 28, - 374, - 107, - 96, - 243, - 345, - 272, - 254, - 287, - 297, - 200, - 181, - 350, - 329, - 354, - 339, - 78, - 194, - 30, - 373, - 221, - 18, - 34, - 376, - 276, - 129, - 326, - 348, - 193, - 313, - 39, - 66, - 88, - 153, - 43, - 372, - 76, - 246, - 238, - 322, - 201, - 244, - 179, - 385, - 111, - 60, - 367, - 171, - 73, - 159, - 170, - 373, - 85, - 373, - 268, - 42, - 27, - 82, - 192, - 58, - 345, - 43, - 19, - 137, - 346, - 263, - 47, - 105, - 22, - 110, - 168, - 292, - 80, - 285, - 347, - 304, - 199, - 267, - 398, - 129, - 61, - 223, - 311, - 29, - 217, - 115, - 272, - 253, - 101, - 26, - 246, - 330, - 37, - 201, - 142, - 279, - 151, - 237, - 373, - 282, - 140, - 115, - 171, - 236, - 72, - 307, - 310, - 187, - 257, - 22, - 331, - 378, - 83, - 323, - 370, - 93, - 185, - 359, - 199, - 241, - 260, - 220, - 262, - 335, - 101, - 178, - 247, - 387, - 384, - 12, - 74, - 293, - 49, - 250, - 185, - 1, - 193, - 2, - 91, - 70, - 355, - 194, - 266, - 9, - 218, - 167, - 283, - 293, - 269, - 170, - 284, - 30, - 274, - 201, - 47, - 194, - 175, - 358, - 336, - 134, - 371, - 146, - 297, - 50, - 268, - 16, - 50, - 378, - 150, - 195, - 343, - 23, - 379, - 235, - 316, - 8, - 86, - 313, - 106, - 320, - 62, - 292, - 207, - 398, - 140, - 213, - 335, - 393, - 15, - 158, - 222, - 74, - 357, - 345, - 67, - 310, - 63, - 242, - 136, - 202, - 326, - 357, - 247, - 397, - 330, - 352, - 84, - 344, - 105, - 141, - 202, - 163, - 127, - 64, - 21, - 23, - 16, - 260, - 196, - 80, - 172, - 283, - 256, - 276, - 267, - 324, - 374, - 20, - 200, - 162, - 367, - 375, - 50, - 320, - 90, - 340, - 241, - 216, - 378, - 213, - 223, - 172, - 82, - 167, - 191, - 100, - 179, - 322, - 301, - 195, - 243, - 17, - 385, - 132, - 305, - 143, - 85, - 43, - 24, - 239, - 17, - 44, - 252, - 255, - 66, - 310, - 157, - 178, - 170, - 373, - 14, - 142, - 154, - 47, - 358, - 99, - 189, - 77, - 261, - 39, - 14, - 28, - 302, - 132, - 102, - 365, - 378, - 159, - 186, - 292, - 372, - 181, - 284, - 277, - 187, - 268, - 280, - 282, - 307, - 280, - 358, - 125, - 341, - 138, - 299, - 214, - 273, - 43, - 345, - 321, - 248, - 257, - 49, - 222, - 250, - 261, - 29, - 75, - 355, - 238, - 219, - 18, - 265, - 2, - 158, - 290, - 321, - 285, - 141, - 227, - 392, - 93, - 18, - 24, - 134, - 32, - 41, - 345, - 160, - 258, - 182, - 301, - 229, - 54, - 172, - 39, - 29, - 224, - 175, - 318, - 15, - 226, - 385, - 88, - 55, - 329, - 46, - 255, - 335, - 178, - 176, - 116, - 360, - 300, - 321, - 317, - 327, - 278, - 237, - 107, - 326, - 46, - 84, - 283, - 341, - 95, - 320, - 101, - 40, - 129, - 395, - 45, - 371, - 235, - 16, - 46, - 182, - 34, - 256, - 240, - 78, - 37, - 308, - 143, - 195, - 372, - 73, - 129, - 234, - 17, - 314, - 346, - 391, - 184, - 182, - 15, - 216, - 20, - 208, - 1, - 114, - 144, - 168, - 397, - 121, - 344, - 243, - 382, - 141, - 142, - 3, - 28, - 177, - 219, - 267, - 228, - 170, - 206, - 273, - 34, - 176, - 186, - 68, - 283, - 333, - 273, - 298, - 399, - 65, - 358, - 35, - 248, - 364, - 224, - 134, - 154, - 267, - 230, - 383, - 118, - 96, - 82, - 118, - 322, - 348, - 84, - 260, - 18, - 203, - 7, - 27, - 164, - 298, - 123, - 291, - 286, - 323, - 392, - 311, - 25, - 239, - 56, - 330, - 52, - 306, - 185, - 1, - 320, - 41, - 83, - 253, - 251, - 168, - 368, - 352, - 57, - 184, - 280, - 104, - 5, - 343, - 108, - 294, - 341, - 279, - 299, - 10, - 195, - 129, - 102, - 358, - 235, - 56, - 56, - 17, - 348, - 262, - 221, - 321, - 364, - 234, - 221, - 25, - 209, - 203, - 399, - 72, - 114, - 110, - 362, - 390, - 369, - 185, - 31, - 261, - 37, - 345, - 211, - 308, - 310, - 206, - 58, - 30, - 151, - 302, - 355, - 253, - 386, - 16, - 358, - 380, - 205, - 218, - 146, - 123, - 268, - 220, - 182, - 60, - 128, - 62, - 96, - 25, - 94, - 108, - 288, - 295, - 343, - 10, - 134, - 250, - 62, - 125, - 6, - 295, - 257, - 353, - 279, - 204, - 4, - 300, - 121, - 231, - 73, - 226, - 292, - 155, - 290, - 196, - 221, - 202, - 86, - 8, - 384, - 319, - 170, - 363, - 358, - 26, - 23, - 271, - 195, - 6, - 283, - 275, - 240, - 93, - 320, - 1, - 340, - 287, - 140, - 144, - 58, - 184, - 39, - 128, - 258, - 353, - 116, - 149, - 95, - 379, - 85, - 164, - 275, - 238, - 3, - 356, - 23, - 152, - 372, - 77, - 188, - 37, - 81, - 74, - 336, - 77, - 189, - 283, - 254, - 56, - 267, - 81, - 218, - 202, - 332, - 133, - 358, - 237, - 181, - 213, - 335, - 126, - 66, - 313, - 36, - 138, - 207, - 112, - 164, - 146, - 55, - 290, - 297, - 50, - 39, - 228, - 286, - 190, - 238, - 165, - 74, - 301, - 328, - 302, - 96, - 332, - 131, - 151, - 79, - 340, - 112, - 312, - 56, - 87, - 258, - 131, - 138, - 236, - 335, - 313, - 210, - 325, - 343, - 124, - 255, - 193, - 180, - 392, - 348, - 361, - 314, - 240, - 60, - 163, - 114, - 337, - 162, - 316, - 222, - 47, - 117, - 208, - 366, - 98, - 278, - 375, - 260, - 254, - 91, - 395, - 305, - 390, - 50, - 275, - 155, - 190, - 59, - 3, - 287, - 347, - 149, - 292, - 52, - 187, - 157, - 120, - 176, - 135, - 299, - 361, - 193, - 116, - 223, - 344, - 22, - 165, - 337, - 103, - 117, - 341, - 239, - 32, - 137, - 359, - 72, - 89, - 65, - 149, - 160, - 148, - 73, - 280, - 225, - 113, - 387, - 159, - 287, - 95, - 139, - 351, - 325, - 351, - 44, - 50, - 370, - 96, - 377, - 161, - 382, - 323, - 168, - 324, - 309, - 293, - 128, - 263, - 293, - 262, - 266, - 261, - 71, - 385, - 287, - 237, - 190, - 119, - 41, - 184, - 228, - 222, - 258, - 379, - 152, - 272, - 242, - 321, - 22, - 24, - 353, - 133, - 36, - 214, - 9, - 368, - 254, - 249, - 298, - 216, - 320, - 257, - 347, - 136, - 26, - 263, - 79, - 361, - 285, - 280, - 289, - 96, - 125, - 210, - 143, - 248, - 393, - 225, - 324, - 305, - 21, - 378, - 333, - 247, - 297, - 369, - 244, - 373, - 197, - 271, - 164, - 373, - 75, - 195, - 321, - 62, - 63, - 240, - 81, - 172, - 219, - 189, - 47, - 75, - 238, - 258, - 36, - 38, - 24, - 35, - 43, - 52, - 25, - 69, - 111, - 255, - 294, - 396, - 50, - 2, - 203, - 164, - 86, - 164, - 70, - 284, - 24, - 254, - 358, - 36, - 158, - 24, - 72, - 201, - 160, - 182, - 190, - 4, - 171, - 49, - 344, - 260, - 319, - 398, - 332, - 25, - 126, - 296, - 317, - 329, - 271, - 344, - 392, - 386, - 334, - 140, - 45, - 166, - 363, - 234, - 146, - 254, - 113, - 168, - 313, - 383, - 107, - 175, - 138, - 149, - 252, - 121, - 250, - 334, - 291, - 208, - 388, - 111, - 112, - 87, - 39, - 207, - 205, - 173, - 310, - 96, - 252, - 121, - 27, - 360, - 205, - 357, - 337, - 373, - 380, - 177, - 91, - 278, - 189, - 294, - 338, - 324, - 37, - 343, - 354, - 129, - 42, - 374, - 259, - 354, - 135, - 333, - 84, - 228, - 280, - 99, - 244, - 297, - 172, - 263, - 237, - 180, - 240, - 117, - 178, - 22, - 327, - 4, - 109, - 306, - 140, - 182, - 178, - 2, - 4, - 78, - 233, - 325, - 13, - 188, - 231, - 356, - 379, - 377, - 114, - 76, - 82, - 96, - 234, - 365, - 173, - 343, - 101, - 38, - 138, - 175, - 298, - 91, - 150, - 44, - 218, - 239, - 167, - 157, - 81, - 197, - 91, - 63, - 313, - 102, - 151, - 377, - 77, - 138, - 215, - 337, - 257, - 353, - 233, - 388, - 342, - 343, - 10, - 309, - 122, - 40, - 323, - 377, - 352, - 337, - 65, - 173, - 78, - 135, - 364, - 141, - 36, - 191, - 62, - 202, - 53, - 366, - 63, - 326, - 254, - 12, - 55, - 247, - 361, - 190, - 162, - 395, - 19, - 52, - 220, - 6, - 326, - 227, - 8, - 102, - 334, - 358, - 284, - 69, - 216, - 173, - 128, - 58, - 205, - 213, - 84, - 290, - 34, - 379, - 24, - 275, - 222, - 129, - 128, - 384, - 327, - 303, - 138, - 61, - 106, - 124, - 255, - 378, - 194, - 137, - 99, - 357, - 258, - 371, - 131, - 200, - 55, - 71, - 239, - 289, - 343, - 141, - 237, - 112, - 5, - 39, - 32, - 231, - 309, - 37, - 175, - 199, - 45, - 227, - 241, - 332, - 223, - 318, - 310, - 395, - 219, - 275, - 109, - 272, - 187, - 34, - 114, - 311, - 8, - 249, - 55, - 118, - 333, - 53, - 214, - 340, - 133, - 229, - 103, - 154, - 251, - 265, - 153, - 12, - 293, - 108, - 209, - 334, - 277, - 57, - 366, - 36, - 339, - 25, - 135, - 40, - 240, - 271, - 315, - 13, - 390, - 100, - 380, - 26, - 162, - 80, - 88, - 390, - 371, - 339, - 239, - 200, - 115, - 120, - 106, - 59, - 98, - 240, - 15, - 32, - 91, - 108, - 95, - 52, - 275, - 160, - 195, - 98, - 53, - 399, - 59, - 388, - 317, - 337, - 252, - 209, - 68, - 348, - 375, - 18, - 120, - 259, - 248, - 248, - 2, - 35, - 375, - 39, - 23, - 355, - 233, - 31, - 371, - 388, - 319, - 335, - 242, - 374, - 77, - 381, - 251, - 243, - 389, - 262, - 190, - 117, - 324, - 218, - 397, - 263, - 386, - 80, - 360, - 223, - 192, - 177, - 207, - 148, - 75, - 368, - 73, - 395, - 236, - 163, - 230, - 134, - 162, - 262, - 48, - 331, - 162, - 201, - 68, - 209, - 192, - 272, - 331, - 390, - 298, - 227, - 323, - 43, - 297, - 144, - 262, - 64, - 272, - 241, - 137, - 187, - 58, - 336, - 157, - 373, - 66, - 217, - 257, - 336, - 259, - 82, - 77, - 166, - 185, - 385, - 172, - 106, - 309, - 297, - 213, - 377, - 212, - 225, - 239, - 320, - 288, - 316, - 3, - 227, - 154, - 99, - 208, - 210, - 289, - 338, - 226, - 362, - 37, - 250, - 164, - 313, - 315, - 68, - 165, - 386, - 189, - 140, - 103, - 399, - 397, - 229, - 238, - 105, - 100, - 155, - 181, - 310, - 191, - 338, - 314, - 36, - 228, - 293, - 151, - 232, - 170, - 155, - 374, - 272, - 386, - 256, - 331, - 348, - 400, - 165, - 164, - 108, - 320, - 320, - 80, - 131, - 156, - 66, - 83, - 334, - 362, - 327, - 286, - 301, - 300, - 22, - 253, - 108, - 120, - 289, - 118, - 77, - 164, - 124, - 208, - 19, - 45, - 98, - 310, - 338, - 223, - 109, - 398, - 341, - 362, - 25, - 305, - 104, - 181, - 94, - 50, - 353, - 36, - 205, - 96, - 72, - 354, - 281, - 326, - 304, - 395, - 328, - 377, - 188, - 10, - 91, - 185, - 337, - 341, - 392, - 324, - 130, - 193, - 263, - 131, - 258, - 245, - 235, - 14, - 202, - 356, - 155, - 284, - 225, - 372, - 72, - 145, - 290, - 258, - 142, - 233, - 9, - 130, - 245, - 286, - 116, - 132, - 348, - 63, - 335, - 245, - 232, - 38, - 214, - 127, - 246, - 302, - 241, - 176, - 277, - 264, - 22, - 85, - 120, - 172, - 91, - 55, - 52, - 221, - 118, - 355, - 137, - 182, - 209, - 376, - 228, - 47, - 291, - 229, - 384, - 126, - 234, - 267, - 364, - 345, - 250, - 64, - 296, - 35, - 150, - 196, - 381, - 142, - 5, - 122, - 337, - 109, - 183, - 272, - 4, - 191, - 243, - 134, - 36, - 49, - 84, - 377, - 22, - 188, - 89, - 286, - 77, - 160, - 77, - 192, - 331, - 99, - 148, - 34, - 187, - 219, - 339, - 180, - 368, - 110, - 159, - 172, - 125, - 101, - 364, - 156, - 239, - 304, - 349, - 56, - 123, - 225, - 348, - 357, - 47, - 126, - 166, - 165, - 144, - 74, - 51, - 79, - 199, - 45, - 153, - 27, - 225, - 299, - 135, - 387, - 175, - 4, - 347, - 398, - 10, - 358, - 226, - 269, - 307, - 347, - 72, - 196, - 17, - 55, - 96, - 346, - 75, - 196, - 223, - 266, - 299, - 209, - 385, - 146, - 68, - 348, - 395, - 324, - 84, - 256, - 126, - 182, - 75, - 218, - 57, - 217, - 145, - 75, - 283, - 396, - 367, - 290, - 12, - 120, - 261, - 21, - 115, - 39, - 26, - 399, - 62, - 204, - 220, - 300, - 396, - 380, - 129, - 244, - 357, - 362, - 286, - 40, - 29, - 109, - 270, - 86, - 376, - 5, - 24, - 47, - 388, - 123, - 252, - 189, - 137, - 375, - 16, - 148, - 391, - 279, - 396, - 322, - 145, - 123, - 219, - 305, - 272, - 188, - 107, - 376, - 315, - 370, - 251, - 58, - 302, - 17, - 156, - 322, - 376, - 37, - 72, - 43, - 292, - 166, - 398, - 258, - 328, - 261, - 58, - 393, - 43, - 245, - 26, - 130, - 319, - 346, - 35, - 197, - 69, - 131, - 378, - 47, - 231, - 245, - 31, - 188, - 27, - 300, - 20, - 363, - 306, - 225, - 120, - 86, - 219, - 19, - 79, - 105, - 267, - 344, - 284, - 314, - 108, - 202, - 242, - 148, - 46, - 365, - 20, - 226, - 376, - 265, - 148, - 38, - 122, - 267, - 241, - 235, - 398, - 133, - 208, - 238, - 214, - 181, - 124, - 310, - 27, - 156, - 99, - 201, - 16, - 339, - 64, - 134, - 77, - 44, - 157, - 284, - 182, - 29, - 107, - 69, - 161, - 31, - 327, - 82, - 5, - 285, - 377, - 246, - 267, - 244, - 139, - 63, - 238, - 57, - 228, - 200, - 305, - 104, - 389, - 79, - 152, - 201, - 380, - 246, - 383, - 10, - 100, - 304, - 204, - 92, - 104, - 302, - 354, - 33, - 31, - 239, - 273, - 208, - 77, - 366, - 373, - 154, - 123, - 103, - 319, - 71, - 155, - 247, - 106, - 46, - 186, - 78, - 181, - 120, - 280, - 308, - 217, - 288, - 33, - 122, - 241, - 376, - 343, - 190, - 374, - 182, - 154, - 186, - 205, - 192, - 184, - 298, - 115, - 62, - 2, - 324, - 183, - 368, - 198, - 113, - 299, - 67, - 178, - 40, - 131, - 292, - 92, - 368, - 370, - 399, - 200, - 33, - 187, - 245, - 327, - 359, - 17, - 166, - 34, - 340, - 244, - 178, - 240, - 71, - 104, - 74, - 286, - 292, - 384, - 242, - 229, - 166, - 127, - 190, - 184, - 166, - 288, - 252, - 317, - 81, - 32, - 77, - 231, - 204, - 277, - 347, - 345, - 79, - 14, - 261, - 84, - 242, - 111, - 274, - 157, - 315, - 248, - 352, - 66, - 243, - 212, - 83, - 218, - 261, - 126, - 10, - 134, - 135, - 7, - 281, - 166, - 253, - 358, - 108, - 382, - 235, - 271, - 143, - 139, - 286, - 32, - 228, - 387, - 242, - 190, - 177, - 318, - 122, - 354, - 100, - 76, - 160, - 274, - 382, - 114, - 163, - 78, - 55, - 101, - 153, - 130, - 292, - 285, - 291, - 152, - 107, - 11, - 57, - 117, - 173, - 6, - 110, - 182, - 350, - 325, - 195, - 139, - 301, - 210, - 102, - 35, - 195, - 272, - 272, - 393, - 12, - 215, - 97, - 91, - 308, - 162, - 395, - 273, - 244, - 278, - 246, - 327, - 293, - 80, - 265, - 282, - 318, - 268, - 52, - 93, - 294, - 156, - 36, - 184, - 374, - 172, - 291, - 64, - 327, - 208, - 67, - 346, - 228, - 393, - 121, - 387, - 307, - 263, - 392, - 98, - 231, - 294, - 340, - 308, - 270, - 81, - 171, - 160, - 331, - 141, - 204, - 26, - 348, - 33, - 81, - 203, - 24, - 333, - 21, - 351, - 359, - 219, - 203, - 272, - 61, - 321, - 267, - 35, - 225, - 98, - 346, - 253, - 122, - 307, - 20, - 152, - 128, - 121, - 307, - 47, - 74, - 221, - 367, - 339, - 290, - 329, - 313, - 330, - 103, - 369, - 66, - 60, - 169, - 52, - 368, - 90, - 392, - 213, - 45, - 103, - 98, - 125, - 124, - 269, - 74, - 147, - 157, - 78, - 279, - 48, - 396, - 96, - 27, - 384, - 124, - 385, - 132, - 299, - 178, - 98, - 343, - 226, - 277, - 69, - 276, - 208, - 325, - 353, - 369, - 290, - 103, - 301, - 166, - 252, - 202, - 33, - 293, - 195, - 151, - 388, - 345, - 184, - 91, - 8, - 120, - 160, - 23, - 229, - 211, - 169, - 278, - 364, - 78, - 279, - 391, - 351, - 37, - 364, - 249, - 17, - 117, - 55, - 60, - 327, - 178, - 206, - 307, - 70, - 31, - 377, - 400, - 269, - 1, - 274, - 169, - 141, - 174, - 326, - 72, - 257, - 244, - 196, - 78, - 384, - 312, - 229, - 331, - 39, - 85, - 235, - 88, - 165, - 219, - 234, - 31, - 303, - 388, - 364, - 271, - 144, - 376, - 129, - 11, - 199, - 12, - 376, - 178, - 130, - 80, - 53, - 345, - 299, - 15, - 23, - 178, - 189, - 9, - 36, - 288, - 326, - 119, - 20, - 197, - 204, - 329, - 149, - 311, - 143, - 223, - 213, - 242, - 379, - 50, - 55, - 76, - 362, - 308, - 221, - 226, - 27, - 88, - 165, - 315, - 85, - 327, - 168, - 251, - 57, - 3, - 231, - 128, - 392, - 347, - 160, - 386, - 69, - 135, - 377, - 197, - 83, - 339, - 28, - 83, - 117, - 347, - 44, - 234, - 180, - 166, - 69, - 48, - 233, - 252, - 237, - 73, - 58, - 60, - 188, - 98, - 294, - 30, - 39, - 364, - 138, - 160, - 282, - 100, - 167, - 195, - 37, - 76, - 244, - 293, - 290, - 34, - 99, - 315, - 377, - 262, - 173, - 400, - 161, - 5, - 160, - 27, - 337, - 271, - 128, - 2, - 327, - 312, - 163, - 52, - 322, - 329, - 284, - 374, - 99, - 29, - 237, - 124, - 8, - 325, - 293, - 222, - 16, - 242, - 50, - 383, - 94, - 322, - 225, - 155, - 309, - 111, - 169, - 376, - 201, - 94, - 299, - 163, - 167, - 362, - 152, - 194, - 326, - 332, - 305, - 193, - 227, - 120, - 340, - 325, - 294, - 263, - 130, - 262, - 152, - 332, - 25, - 161, - 46, - 337, - 229, - 21, - 170, - 365, - 259, - 23, - 1, - 299, - 374, - 310, - 285, - 243, - 391, - 11, - 129, - 75, - 286, - 140, - 357, - 315, - 390, - 256, - 237, - 245, - 283, - 194, - 338, - 25, - 100, - 188, - 233, - 172, - 158, - 266, - 333, - 77, - 356, - 358, - 241, - 74, - 41, - 46, - 136, - 7, - 283, - 302, - 271, - 23, - 151, - 85, - 209, - 252, - 340, - 166, - 318, - 128, - 75, - 114, - 321, - 69, - 74, - 83, - 62, - 108, - 377, - 86, - 232, - 345, - 225, - 328, - 35, - 268, - 105, - 287, - 181, - 135, - 27, - 48, - 382, - 359, - 144, - 336, - 50, - 3, - 321, - 389, - 313, - 291, - 1, - 363, - 231, - 156, - 185, - 384, - 394, - 245, - 208, - 23, - 385, - 166, - 301, - 165, - 63, - 194, - 83, - 209, - 320, - 229, - 381, - 169, - 182, - 79, - 110, - 20, - 354, - 266, - 26, - 216, - 268, - 303, - 1, - 222, - 135, - 297, - 45, - 313, - 130, - 54, - 242, - 9, - 354, - 370, - 105, - 396, - 205, - 38, - 224, - 131, - 207, - 317, - 225, - 344, - 242, - 241, - 271, - 239, - 42, - 110, - 367, - 257, - 9, - 279, - 107, - 310, - 276, - 322, - 293, - 44, - 99, - 22, - 278, - 137, - 258, - 111, - 221, - 335, - 321, - 153, - 382, - 97, - 58, - 64, - 105, - 170, - 168, - 196, - 136, - 349, - 33, - 57, - 360, - 224, - 133, - 323, - 310, - 292, - 309, - 146, - 35, - 106, - 87, - 202, - 127, - 355, - 156, - 398, - 116, - 281, - 136, - 241, - 231, - 315, - 62, - 301, - 398, - 259, - 247, - 187, - 208, - 15, - 215, - 233, - 124, - 157, - 210, - 279, - 256, - 400, - 102, - 353, - 400, - 392, - 293, - 63, - 131, - 236, - 105, - 307, - 275, - 204, - 169, - 303, - 191, - 397, - 204, - 158, - 341, - 229, - 131, - 244, - 58, - 331, - 368, - 55, - 270, - 162, - 258, - 232, - 237, - 190, - 108, - 105, - 391, - 371, - 304, - 378, - 29, - 201, - 163, - 232, - 317, - 36, - 396, - 318, - 179, - 374, - 286, - 254, - 273, - 251, - 62, - 155, - 41, - 212, - 51, - 380, - 292, - 145, - 331, - 14, - 367, - 306, - 230, - 299, - 157, - 387, - 356, - 181, - 249, - 361, - 376, - 256, - 340, - 111, - 376, - 91, - 76, - 89, - 119, - 67, - 398, - 139, - 378, - 82, - 202, - 91, - 179, - 115, - 215, - 136, - 393, - 245, - 159, - 195, - 400, - 153, - 262, - 187, - 374, - 255, - 98, - 392, - 128, - 266, - 5, - 19, - 121, - 324, - 309, - 274, - 320, - 56, - 398, - 327, - 4, - 330, - 231, - 95, - 96, - 279, - 252, - 297, - 122, - 70, - 18, - 39, - 300, - 61, - 230, - 8, - 293, - 139, - 198, - 282, - 366, - 57, - 241, - 188, - 86, - 276, - 140, - 380, - 119, - 200, - 207, - 153, - 51, - 256, - 322, - 63, - 78, - 158, - 361, - 5, - 264, - 189, - 279, - 162, - 64, - 347, - 383, - 66, - 7, - 110, - 117, - 52, - 74, - 103, - 168, - 181, - 395, - 90, - 317, - 21, - 244, - 78, - 328, - 208, - 195, - 227, - 353, - 340, - 37, - 66, - 118, - 341, - 326, - 148, - 349, - 327, - 28, - 287, - 317, - 178, - 379, - 382, - 186, - 40, - 204, - 344, - 334, - 352, - 383, - 154, - 213, - 108, - 94, - 291, - 313, - 400, - 255, - 173, - 238, - 252, - 31, - 296, - 212, - 267, - 223, - 63, - 138, - 377, - 364, - 178, - 200, - 201, - 215, - 175, - 370, - 90, - 372, - 7, - 77, - 114, - 226, - 368, - 22, - 48, - 228, - 51, - 323, - 103, - 24, - 257, - 164, - 11, - 394, - 99, - 349, - 99, - 20, - 61, - 89, - 47, - 275, - 355, - 69, - 115, - 49, - 274, - 212, - 142, - 41, - 97, - 8, - 281, - 231, - 156, - 260, - 303, - 14, - 200, - 184, - 303, - 146, - 157, - 94, - 193, - 154, - 367, - 360, - 156, - 35, - 182, - 235, - 262, - 295, - 392, - 146, - 115, - 355, - 282, - 131, - 348, - 64, - 361, - 257, - 362, - 287, - 283, - 243, - 330, - 73, - 178, - 357, - 185, - 98, - 318, - 299, - 102, - 268, - 88, - 36, - 227, - 166, - 153, - 317, - 107, - 64, - 3, - 7, - 70, - 175, - 17, - 198, - 158, - 195, - 354, - 261, - 51, - 176, - 296, - 138, - 144, - 288, - 13, - 299, - 325, - 274, - 187, - 33, - 253, - 391, - 349, - 127, - 167, - 124, - 263, - 85, - 49, - 246, - 278, - 361, - 6, - 7, - 286, - 145, - 116, - 126, - 106, - 285, - 103, - 86, - 85, - 30, - 176, - 72, - 253, - 199, - 88, - 216, - 163, - 69, - 217, - 376, - 256, - 82, - 385, - 361, - 116, - 193, - 195, - 394, - 151, - 258, - 182, - 43, - 286, - 109, - 110, - 1, - 176, - 78, - 371, - 219, - 192, - 329, - 50, - 168, - 203, - 214, - 128, - 361, - 250, - 263, - 177, - 337, - 143, - 8, - 178, - 325, - 122, - 204, - 90, - 287, - 398, - 322, - 368, - 176, - 391, - 31, - 358, - 260, - 288, - 30, - 224, - 125, - 362, - 400, - 81, - 74, - 15, - 52, - 209, - 219, - 28, - 182, - 132, - 193, - 183, - 356, - 337, - 315, - 67, - 229, - 102, - 274, - 334, - 391, - 90, - 58, - 162, - 249, - 139, - 109, - 275, - 159, - 246, - 260, - 392, - 138, - 169, - 70, - 83, - 352, - 328, - 110, - 251, - 375, - 153, - 171, - 176, - 393, - 298, - 34, - 89, - 202, - 314, - 246, - 250, - 367, - 10, - 126, - 309, - 42, - 201, - 351, - 41, - 98, - 265, - 6, - 160, - 30, - 112, - 205, - 219, - 356, - 24, - 57, - 224, - 44, - 168, - 143, - 225, - 106, - 192, - 65, - 65, - 8, - 84, - 244, - 394, - 71, - 5, - 307, - 106, - 48, - 66, - 21, - 294, - 235, - 257, - 6, - 203, - 179, - 372, - 161, - 174, - 187, - 359, - 9, - 251, - 318, - 400, - 356, - 301, - 245, - 362, - 305, - 179, - 345, - 134, - 25, - 306, - 361, - 228, - 210, - 239, - 297, - 247, - 203, - 248, - 190, - 138, - 311, - 79, - 232, - 330, - 37, - 157, - 332, - 247, - 151, - 255, - 91, - 1, - 39, - 313, - 369, - 10, - 75, - 292, - 122, - 311, - 311, - 272, - 312, - 212, - 372, - 351, - 80, - 70, - 33, - 9, - 355, - 17, - 290, - 196, - 2, - 181, - 174, - 106, - 3, - 259, - 228, - 247, - 59, - 257, - 154, - 144, - 367, - 78, - 249, - 357, - 246, - 115, - 229, - 241, - 303, - 240, - 197, - 3, - 106, - 363, - 243, - 257, - 79, - 330, - 82, - 148, - 264, - 103, - 205, - 120, - 83, - 207, - 132, - 215, - 293, - 59, - 79, - 88, - 322, - 299, - 390, - 358, - 160, - 360, - 112, - 231, - 18, - 298, - 334, - 223, - 224, - 198, - 244, - 22, - 357, - 114, - 23, - 257, - 387, - 240, - 115, - 351, - 255, - 74, - 104, - 56, - 284, - 105, - 121, - 63, - 127, - 186, - 323, - 233, - 93, - 396, - 45, - 254, - 375, - 188, - 168, - 326, - 221, - 357, - 347, - 289, - 172, - 220, - 361, - 370, - 288, - 149, - 324, - 240, - 325, - 233, - 244, - 129, - 82, - 183, - 108, - 318, - 10, - 84, - 394, - 162, - 194, - 38, - 223, - 204, - 379, - 264, - 354, - 333, - 212, - 126, - 298, - 226, - 191, - 3, - 206, - 32, - 58, - 385, - 278, - 114, - 12, - 271, - 304, - 171, - 59, - 131, - 10, - 267, - 167, - 142, - 1, - 389, - 333, - 344, - 175, - 25, - 295, - 17, - 21, - 110, - 83, - 238, - 319, - 98, - 148, - 288, - 236, - 126, - 87, - 395, - 28, - 200, - 77, - 53, - 138, - 387, - 314, - 4, - 68, - 180, - 23, - 14, - 42, - 303, - 138, - 58, - 325, - 142, - 91, - 186, - 209, - 169, - 162, - 194, - 192, - 239, - 45, - 48, - 6, - 107, - 15, - 109, - 248, - 396, - 114, - 376, - 377, - 399, - 374, - 276, - 56, - 181, - 156, - 320, - 229, - 284, - 59, - 342, - 293, - 117, - 176, - 107, - 264, - 174, - 334, - 197, - 149, - 380, - 216, - 30, - 133, - 166, - 319, - 222, - 328, - 39, - 393, - 144, - 126, - 126, - 217, - 168, - 194, - 226, - 86, - 148, - 12, - 17, - 257, - 108, - 275, - 157, - 273, - 184, - 1, - 276, - 342, - 12, - 110, - 379, - 158, - 73, - 323, - 188, - 114, - 246, - 125, - 41, - 349, - 60, - 40, - 228, - 104, - 88, - 231, - 28, - 280, - 164, - 76, - 196, - 84, - 326, - 149, - 19, - 69, - 142, - 59, - 290, - 385, - 311, - 243, - 324, - 107, - 163, - 63, - 213, - 255, - 191, - 186, - 2, - 300, - 253, - 369, - 254, - 247, - 150, - 50, - 242, - 253, - 77, - 239, - 361, - 92, - 330, - 8, - 374, - 315, - 193, - 15, - 165, - 194, - 111, - 153, - 159, - 207, - 82, - 146, - 21, - 397, - 161, - 150, - 240, - 29, - 77, - 371, - 60, - 27, - 11, - 291, - 261, - 30, - 289, - 369, - 139, - 32, - 158, - 257, - 307, - 293, - 9, - 155, - 228, - 187, - 369, - 393, - 331, - 88, - 160, - 324, - 267, - 31, - 330, - 226, - 387, - 20, - 376, - 394, - 298, - 231, - 138, - 57, - 152, - 253, - 157, - 31, - 287, - 62, - 380, - 79, - 92, - 195, - 367, - 124, - 217, - 8, - 22, - 255, - 202, - 359, - 261, - 138, - 230, - 229, - 156, - 103, - 182, - 235, - 184, - 310, - 330, - 105, - 47, - 141, - 297, - 319, - 283, - 160, - 174, - 342, - 1, - 84, - 229, - 286, - 82, - 40, - 391, - 57, - 216, - 314, - 383, - 344, - 4, - 296, - 353, - 182, - 218, - 354, - 135, - 280, - 378, - 109, - 337, - 10, - 298, - 189, - 209, - 150, - 162, - 388, - 262, - 37, - 239, - 145, - 13, - 137, - 309, - 221, - 201, - 391, - 156, - 17, - 153, - 112, - 273, - 210, - 395, - 136, - 234, - 390, - 173, - 206, - 225, - 132, - 227, - 279, - 330, - 13, - 81, - 262, - 336, - 339, - 365, - 395, - 273, - 293, - 122, - 35, - 208, - 216, - 357, - 143, - 7, - 240, - 151, - 220, - 361, - 64, - 89, - 279, - 180, - 155, - 353, - 178, - 390, - 383, - 39, - 70, - 360, - 34, - 221, - 98, - 99, - 178, - 282, - 257, - 268, - 348, - 61, - 186, - 317, - 189, - 376, - 290, - 140, - 173, - 88, - 83, - 9, - 383, - 321, - 382, - 290, - 392, - 398, - 200, - 248, - 17, - 175, - 67, - 53, - 371, - 62, - 131, - 25, - 330, - 54, - 254, - 157, - 214, - 31, - 76, - 229, - 245, - 114, - 259, - 125, - 353, - 78, - 120, - 336, - 138, - 160, - 212, - 184, - 105, - 146, - 136, - 149, - 40, - 361, - 209, - 204, - 297, - 232, - 142, - 294, - 343, - 180, - 241, - 48, - 80, - 354, - 267, - 78, - 307, - 221, - 4, - 34, - 15, - 100, - 126, - 274, - 319, - 82, - 338, - 237, - 120, - 132, - 232, - 193, - 50, - 338, - 124, - 339, - 129, - 335, - 253, - 146, - 126, - 78, - 163, - 187, - 84, - 205, - 396, - 296, - 279, - 143, - 381, - 285, - 110, - 182, - 135, - 241, - 298, - 157, - 4, - 343, - 161, - 181, - 373, - 226, - 87, - 378, - 26, - 340, - 382, - 22, - 329, - 174, - 83, - 333, - 13, - 228, - 335, - 166, - 298, - 303, - 115, - 274, - 181, - 351, - 378, - 311, - 68, - 152, - 84, - 87, - 266, - 143, - 394, - 12, - 110, - 123, - 242, - 294, - 325, - 90, - 219, - 201, - 93, - 71, - 20, - 181, - 235, - 346, - 385, - 158, - 199, - 91, - 306, - 107, - 318, - 380, - 96, - 346, - 193, - 385, - 365, - 136, - 99, - 283, - 103, - 298, - 170, - 245, - 140, - 145, - 74, - 374, - 381, - 61, - 312, - 251, - 352, - 252, - 299, - 382, - 272, - 280, - 43, - 395, - 26, - 10, - 400, - 50, - 70, - 164, - 220, - 183, - 221, - 374, - 355, - 330, - 169, - 136, - 318, - 23, - 234, - 381, - 184, - 344, - 299, - 289, - 369, - 265, - 263, - 252, - 244, - 398, - 247, - 315, - 168, - 235, - 233, - 141, - 4, - 251, - 201, - 166, - 158, - 16, - 365, - 238, - 52, - 93, - 197, - 88, - 284, - 288, - 116, - 33, - 392, - 164, - 204, - 75, - 343, - 248, - 260, - 258, - 319, - 277, - 166, - 179, - 35, - 287, - 214, - 263, - 48, - 23, - 297, - 273, - 355, - 237, - 127, - 162, - 33, - 142, - 92, - 236, - 144, - 307, - 108, - 72, - 305, - 358, - 79, - 91, - 47, - 54, - 400, - 235, - 193, - 80, - 104, - 235, - 380, - 292, - 120, - 201, - 145, - 209, - 47, - 149, - 193, - 159, - 302, - 181, - 322, - 250, - 205, - 49, - 115, - 149, - 121, - 164, - 316, - 345, - 278, - 338, - 69, - 178, - 66, - 145, - 348, - 395, - 168, - 227, - 233, - 272, - 218, - 122, - 44, - 349, - 257, - 173, - 197, - 109, - 248, - 152, - 345, - 271, - 21, - 334, - 280, - 167, - 130, - 105, - 272, - 115, - 22, - 284, - 274, - 9, - 214, - 272, - 157, - 277, - 82, - 357, - 264, - 100, - 369, - 336, - 260, - 355, - 103, - 158, - 163, - 209, - 61, - 11, - 199, - 188, - 113, - 167, - 378, - 324, - 186, - 361, - 24, - 146, - 172, - 67, - 259, - 288, - 37, - 61, - 253, - 342, - 152, - 8, - 83, - 50, - 391, - 283, - 106, - 196, - 180, - 92, - 187, - 219, - 345, - 369, - 382, - 316, - 89, - 313, - 251, - 318, - 67, - 326, - 321, - 148, - 247, - 31, - 117, - 359, - 388, - 215, - 127, - 318, - 233, - 327, - 265, - 376, - 301, - 8, - 207, - 245, - 23, - 369, - 201, - 8, - 289, - 345, - 259, - 329, - 311, - 241, - 283, - 3, - 361, - 243, - 155, - 110, - 389, - 396, - 349, - 43, - 204, - 64, - 337, - 248, - 201, - 86, - 38, - 304, - 204, - 365, - 233, - 200, - 330, - 198, - 359, - 313, - 147, - 116, - 243, - 7, - 120, - 365, - 66, - 381, - 377, - 222, - 58, - 344, - 385, - 236, - 250, - 183, - 247, - 319, - 164, - 60, - 258, - 39, - 337, - 398, - 78, - 2, - 5, - 341, - 149, - 273, - 194, - 103, - 76, - 161, - 149, - 82, - 279, - 68, - 178, - 268, - 338, - 21, - 228, - 117, - 389, - 48, - 22, - 91, - 300, - 199, - 253, - 358, - 338, - 340, - 74, - 354, - 275, - 262, - 13, - 58, - 52, - 62, - 263, - 224, - 242, - 306, - 87, - 355, - 38, - 44, - 85, - 217, - 135, - 33, - 357, - 29, - 214, - 24, - 312, - 341, - 209, - 303, - 103, - 8, - 112, - 31, - 203, - 311, - 367, - 65, - 118, - 47, - 262, - 59, - 247, - 59, - 18, - 199, - 192, - 80, - 242, - 253, - 359, - 226, - 247, - 25, - 185, - 198, - 337, - 70, - 377, - 366, - 206, - 373, - 357, - 329, - 316, - 290, - 293, - 300, - 67, - 222, - 148, - 76, - 24, - 31, - 41, - 303, - 244, - 210, - 130, - 306, - 368, - 335, - 180, - 303, - 305, - 392, - 68, - 213, - 309, - 148, - 279, - 89, - 255, - 394, - 6, - 162, - 308, - 257, - 290, - 161, - 105, - 362, - 147, - 22, - 351, - 248, - 332, - 173, - 37, - 193, - 11, - 105, - 125, - 70, - 228, - 322, - 74, - 246, - 91, - 315, - 381, - 332, - 374, - 198, - 11, - 222, - 383, - 267, - 143, - 46, - 180, - 183, - 236, - 258, - 16, - 3, - 102, - 4, - 386, - 143, - 113, - 322, - 200, - 61, - 164, - 81, - 18, - 21, - 152, - 252, - 279, - 269, - 82, - 205, - 183, - 91, - 108, - 15, - 61, - 342, - 126, - 181, - 318, - 394, - 16, - 52, - 151, - 91, - 188, - 359, - 126, - 212, - 3, - 14, - 163, - 342, - 67, - 304, - 242, - 97, - 240, - 292, - 228, - 1, - 289, - 328, - 18, - 266, - 29, - 123, - 135, - 79, - 143, - 162, - 210, - 211, - 307, - 199, - 175, - 214, - 214, - 366, - 10, - 378, - 47, - 61, - 148, - 17, - 254, - 389, - 302, - 164, - 185, - 124, - 136, - 379, - 291, - 34, - 130, - 370, - 141, - 171, - 263, - 348, - 381, - 184, - 126, - 338, - 245, - 356, - 14, - 90, - 265, - 150, - 229, - 137, - 38, - 189, - 180, - 67, - 156, - 27, - 30, - 298, - 286, - 1, - 85, - 43, - 155, - 26, - 6, - 61, - 44, - 203, - 352, - 293, - 112, - 224, - 360, - 184, - 276, - 177, - 196, - 166, - 348, - 27, - 397, - 245, - 389, - 66, - 396, - 18, - 214, - 330, - 81, - 3, - 352, - 108, - 323, - 28, - 265, - 37, - 274, - 221, - 355, - 64, - 159, - 270, - 62, - 59, - 187, - 63, - 316, - 39, - 62, - 13, - 151, - 63, - 364, - 380, - 330, - 329, - 22, - 146, - 36, - 141, - 62, - 24, - 294, - 130, - 290, - 254, - 112, - 308, - 155, - 88, - 374, - 328, - 363, - 137, - 274, - 280, - 303, - 154, - 2, - 296, - 29, - 99, - 266, - 138, - 48, - 223, - 89, - 75, - 91, - 229, - 309, - 234, - 13, - 219, - 219, - 7, - 385, - 225, - 273, - 87, - 326, - 317, - 371, - 168, - 294, - 25, - 328, - 345, - 183, - 173, - 291, - 390, - 267, - 383, - 121, - 263, - 58, - 111, - 331, - 331, - 369, - 138, - 109, - 17, - 29, - 192, - 394, - 155, - 353, - 71, - 37, - 251, - 168, - 351, - 385, - 82, - 100, - 196, - 228, - 243, - 189, - 90, - 278, - 327, - 90, - 273, - 56, - 321, - 259, - 377, - 157, - 160, - 7, - 221, - 228, - 72, - 275, - 20, - 358, - 18, - 240, - 335, - 199, - 171, - 372, - 11, - 201, - 277, - 112, - 138, - 55, - 115, - 179, - 192, - 328, - 316, - 128, - 114, - 170, - 387, - 25, - 350, - 319, - 312, - 271, - 181, - 265, - 112, - 322, - 385, - 82, - 139, - 344, - 105, - 100, - 303, - 217, - 161, - 296, - 267, - 374, - 163, - 292, - 227, - 396, - 112, - 104, - 126, - 36, - 67, - 226, - 353, - 220, - 69, - 83, - 294, - 271, - 156, - 148, - 16, - 198, - 181, - 254, - 114, - 277, - 173, - 104, - 228, - 76, - 100, - 195, - 166, - 112, - 331, - 326, - 257, - 400, - 296, - 248, - 126, - 200, - 328, - 328, - 85, - 216, - 81, - 331, - 124, - 87, - 339, - 87, - 381, - 343, - 299, - 396, - 338, - 262, - 144, - 54, - 69, - 299, - 197, - 256, - 388, - 155, - 42, - 283, - 175, - 304, - 273, - 338, - 353, - 44, - 229, - 163, - 354, - 159, - 118, - 368, - 367, - 345, - 59, - 38, - 94, - 103, - 73, - 394, - 155, - 329, - 146, - 43, - 114, - 276, - 45, - 4, - 260, - 313, - 117, - 229, - 71, - 248, - 2, - 384, - 135, - 39, - 321, - 328, - 94, - 385, - 210, - 351, - 128, - 127, - 24, - 46, - 61, - 379, - 30, - 142, - 130, - 147, - 149, - 5, - 275, - 246, - 246, - 93, - 49, - 298, - 200, - 337, - 344, - 320, - 2, - 101, - 260, - 353, - 161, - 205, - 95, - 171, - 397, - 78, - 205, - 216, - 54, - 47, - 278, - 352, - 193, - 295, - 135, - 331, - 116, - 83, - 154, - 265, - 308, - 48, - 363, - 45, - 10, - 3, - 190, - 78, - 267, - 260, - 67, - 247, - 179, - 9, - 231, - 243, - 15, - 36, - 14, - 359, - 320, - 303, - 172, - 266, - 166, - 257, - 130, - 267, - 317, - 119, - 102, - 306, - 114, - 38, - 112, - 192, - 208, - 284, - 107, - 33, - 249, - 238, - 161, - 146, - 341, - 351, - 152, - 60, - 318, - 340, - 240, - 326, - 163, - 198, - 230, - 170, - 331, - 12, - 194, - 122, - 125, - 386, - 398, - 314, - 291, - 337, - 398, - 4, - 25, - 143, - 367, - 208, - 383, - 171, - 375, - 147, - 63, - 292, - 157, - 314, - 303, - 2, - 370, - 117, - 144, - 247, - 35, - 38, - 267, - 7, - 81, - 82, - 338, - 123, - 180, - 207, - 319, - 259, - 129, - 329, - 281, - 384, - 283, - 217, - 223, - 394, - 72, - 215, - 304, - 325, - 383, - 364, - 180, - 3, - 158, - 105, - 181, - 209, - 400, - 344, - 62, - 233, - 155, - 225, - 174, - 282, - 225, - 87, - 168, - 184, - 60, - 104, - 231, - 344, - 77, - 69, - 63, - 106, - 63, - 102, - 255, - 363, - 126, - 134, - 212, - 319, - 336, - 32, - 164, - 96, - 87, - 118, - 196, - 36, - 206, - 333, - 315, - 394, - 201, - 99, - 199, - 126, - 113, - 229, - 155, - 375, - 114, - 16, - 74, - 181, - 347, - 265, - 105, - 54, - 121, - 305, - 297, - 179, - 204, - 373, - 377, - 392, - 242, - 322, - 193, - 228, - 385, - 119, - 79, - 305, - 90, - 243, - 332, - 285, - 7, - 37, - 8, - 30, - 294, - 267, - 112, - 205, - 149, - 165, - 196, - 189, - 78, - 346, - 385, - 136, - 112, - 315, - 375, - 376, - 284, - 213, - 202, - 319, - 18, - 121, - 62, - 140, - 232, - 25, - 385, - 369, - 271, - 345, - 321, - 14, - 352, - 83, - 163, - 43, - 257, - 213, - 8, - 176, - 339, - 91, - 101, - 332, - 334, - 248, - 360, - 49, - 16, - 313, - 352, - 88, - 328, - 180, - 294, - 6, - 51, - 334, - 40, - 290, - 69, - 144, - 316, - 340, - 380, - 13, - 167, - 356, - 317, - 379, - 285, - 321, - 370, - 378, - 97, - 187, - 14, - 340, - 236, - 14, - 157, - 202, - 197, - 126, - 349, - 254, - 392, - 288, - 171, - 46, - 7, - 234, - 222, - 41, - 199, - 153, - 82, - 270, - 317, - 323, - 378, - 320, - 392, - 346, - 299, - 271, - 124, - 201, - 375, - 269, - 52, - 246, - 392, - 34, - 298, - 70, - 272, - 78, - 232, - 86, - 338, - 93, - 127, - 218, - 227, - 113, - 39, - 203, - 66, - 51, - 306, - 89, - 242, - 115, - 133, - 226, - 278, - 266, - 135, - 202, - 127, - 314, - 156, - 32, - 26, - 265, - 222, - 110, - 361, - 275, - 361, - 343, - 63, - 225, - 55, - 76, - 386, - 82, - 112, - 10, - 85, - 174, - 310, - 68, - 201, - 344, - 353, - 94, - 122, - 309, - 392, - 396, - 67, - 112, - 225, - 120, - 374, - 119, - 38, - 40, - 17, - 303, - 201, - 1, - 282, - 328, - 277, - 330, - 393, - 90, - 298, - 199, - 21, - 196, - 363, - 244, - 396, - 36, - 336, - 245, - 313, - 158, - 59, - 376, - 155, - 157, - 28, - 205, - 314, - 192, - 342, - 181, - 325, - 388, - 78, - 399, - 343, - 11, - 52, - 400, - 70, - 47, - 162, - 42, - 15, - 209, - 228, - 330, - 305, - 190, - 285, - 389, - 204, - 221, - 289, - 159, - 377, - 148, - 186, - 87, - 188, - 344, - 116, - 320, - 400, - 223, - 70, - 311, - 20, - 166, - 145, - 189, - 45, - 205, - 122, - 245, - 393, - 340, - 230, - 64, - 279, - 170, - 350, - 154, - 206, - 319, - 370, - 316, - 262, - 326, - 396, - 317, - 329, - 262, - 327, - 282, - 197, - 80, - 299, - 353, - 321, - 124, - 121, - 11, - 245, - 317, - 368, - 189, - 221, - 322, - 382, - 159, - 104, - 135, - 155, - 325, - 241, - 183, - 214, - 85, - 211, - 170, - 168, - 327, - 389, - 94, - 157, - 235, - 385, - 335, - 271, - 236, - 22, - 290, - 220, - 163, - 391, - 224, - 140, - 116, - 268, - 309, - 126, - 89, - 220, - 187, - 252, - 277, - 111, - 263, - 297, - 262, - 92, - 51, - 89, - 228, - 400, - 109, - 156, - 233, - 131, - 115, - 394, - 210, - 161, - 243, - 66, - 150, - 359, - 213, - 368, - 98, - 214, - 335, - 332, - 220, - 26, - 209, - 44, - 280, - 282, - 386, - 24, - 213, - 197, - 352, - 5, - 10, - 42, - 2, - 101, - 36, - 208, - 137, - 247, - 397, - 162, - 344, - 26, - 366, - 25, - 271, - 218, - 188, - 75, - 11, - 24, - 45, - 129, - 384, - 134, - 326, - 23, - 193, - 291, - 15, - 62, - 168, - 364, - 345, - 208, - 291, - 112, - 141, - 202, - 17, - 270, - 154, - 61, - 104, - 19, - 98, - 95, - 202, - 225, - 42, - 244, - 15, - 149, - 171, - 270, - 120, - 341, - 302, - 393, - 275, - 34, - 226, - 152, - 94, - 199, - 392, - 251, - 188, - 340, - 389, - 393, - 216, - 87, - 111, - 359, - 114, - 46, - 165, - 333, - 266, - 358, - 74, - 363, - 134, - 168, - 388, - 145, - 184, - 366, - 376, - 89, - 277, - 259, - 374, - 25, - 346, - 107, - 139, - 42, - 212, - 208, - 129, - 319, - 298, - 275, - 58, - 376, - 93, - 207, - 351, - 268, - 282, - 213, - 125, - 81, - 243, - 238, - 246, - 347, - 188, - 166, - 126, - 110, - 214, - 265, - 234, - 395, - 343, - 119, - 108, - 303, - 4, - 306, - 307, - 196, - 86, - 345, - 112, - 81, - 390, - 297, - 80, - 104, - 212, - 234, - 132, - 316, - 136, - 102, - 83, - 276, - 393, - 29, - 164, - 334, - 386, - 171, - 242, - 246, - 65, - 175, - 333, - 73, - 54, - 173, - 138, - 203, - 260, - 381, - 163, - 196, - 283, - 123, - 169, - 106, - 316, - 156, - 222, - 126, - 115, - 299, - 391, - 251, - 391, - 246, - 330, - 195, - 263, - 238, - 242, - 197, - 62, - 71, - 140, - 312, - 282, - 76, - 105, - 219, - 368, - 240, - 15, - 41, - 53, - 135, - 134, - 207, - 371, - 388, - 82, - 311, - 184, - 147, - 11, - 86, - 293, - 279, - 58, - 258, - 400, - 321, - 330, - 100, - 182, - 28, - 50, - 31, - 166, - 163, - 94, - 172, - 206, - 47, - 191, - 242, - 112, - 313, - 75, - 362, - 187, - 116, - 295, - 332, - 387, - 23, - 183, - 296, - 65, - 228, - 251, - 289, - 161, - 340, - 274, - 214, - 56, - 75, - 36, - 379, - 23, - 211, - 329, - 71, - 80, - 350, - 86, - 107, - 174, - 104, - 367, - 80, - 269, - 273, - 273, - 46, - 331, - 374, - 154, - 135, - 330, - 41, - 82, - 206, - 348, - 118, - 61, - 36, - 315, - 189, - 371, - 218, - 223, - 130, - 1, - 18, - 113, - 73, - 134, - 118, - 17, - 33, - 15, - 266, - 379, - 145, - 185, - 379, - 180, - 75, - 208, - 21, - 327, - 163, - 359, - 193, - 286, - 354, - 205, - 102, - 336, - 394, - 133, - 89, - 178, - 84, - 9, - 151, - 71, - 261, - 283, - 207, - 379, - 99, - 155, - 108, - 374, - 96, - 331, - 363, - 146, - 115, - 246, - 342, - 327, - 176, - 358, - 234, - 104, - 158, - 351, - 350, - 339, - 114, - 88, - 202, - 349, - 217, - 277, - 196, - 16, - 268, - 168, - 202, - 129, - 175, - 22, - 323, - 105, - 143, - 241, - 30, - 215, - 172, - 45, - 22, - 284, - 86, - 20, - 374, - 160, - 244, - 392, - 265, - 319, - 86, - 347, - 188, - 130, - 179, - 136, - 27, - 189, - 288, - 234, - 253, - 19, - 217, - 265, - 127, - 316, - 161, - 37, - 84, - 376, - 382, - 181, - 195, - 85, - 13, - 283, - 111, - 238, - 385, - 291, - 394, - 154, - 80, - 140, - 292, - 132, - 56, - 170, - 209, - 327, - 159, - 216, - 87, - 63, - 123, - 239, - 27, - 184, - 340, - 164, - 177, - 296, - 332, - 340, - 164, - 21, - 87, - 256, - 398, - 143, - 236, - 85, - 359, - 114, - 144, - 356, - 295, - 148, - 43, - 204, - 212, - 48, - 156, - 260, - 287, - 173, - 126, - 147, - 354, - 142, - 274, - 66, - 398, - 150, - 274, - 30, - 342, - 28, - 65, - 177, - 363, - 283, - 268, - 199, - 372, - 272, - 176, - 250, - 46, - 344, - 224, - 292, - 346, - 112, - 73, - 341, - 390, - 344, - 43, - 276, - 17, - 327, - 89, - 39, - 42, - 299, - 202, - 289, - 357, - 288, - 122, - 64, - 6, - 54, - 154, - 235, - 336, - 19, - 311, - 41, - 192, - 303, - 347, - 387, - 201, - 132, - 325, - 273, - 202, - 162, - 214, - 90, - 78, - 118, - 273, - 121, - 225, - 36, - 126, - 370, - 258, - 315, - 288, - 323, - 229, - 52, - 351, - 379, - 128, - 391, - 339, - 138, - 73, - 266, - 393, - 99, - 74, - 378, - 109, - 229, - 293, - 366, - 355, - 219, - 377, - 219, - 246, - 353, - 226, - 241, - 375, - 39, - 229, - 188, - 275, - 240, - 115, - 234, - 352, - 22, - 306, - 302, - 317, - 221, - 224, - 140, - 219, - 155, - 166, - 343, - 313, - 326, - 99, - 168, - 79, - 149, - 57, - 144, - 228, - 28, - 38, - 352, - 112, - 16, - 350, - 66, - 158, - 25, - 292, - 376, - 285, - 163, - 43, - 214, - 395, - 15, - 122, - 365, - 4, - 308, - 16, - 13, - 205, - 256, - 335, - 252, - 301, - 149, - 170, - 206, - 121, - 397, - 387, - 174, - 348, - 72, - 233, - 218, - 254, - 139, - 271, - 101, - 321, - 188, - 366, - 86, - 265, - 182, - 350, - 202, - 393, - 160, - 134, - 312, - 206, - 112, - 28, - 301, - 374, - 312, - 104, - 262, - 100, - 104, - 276, - 199, - 90, - 232, - 124, - 363, - 26, - 269, - 188, - 227, - 344, - 380, - 35, - 67, - 161, - 125, - 386, - 358, - 289, - 276, - 25, - 398, - 105, - 334, - 360, - 273, - 293, - 50, - 350, - 94, - 326, - 23, - 380, - 349, - 123, - 132, - 283, - 121, - 211, - 327, - 186, - 146, - 362, - 307, - 31, - 74, - 338, - 177, - 173, - 132, - 336, - 35, - 273, - 46, - 265, - 110, - 262, - 229, - 197, - 166, - 122, - 13, - 289, - 312, - 229, - 58, - 347, - 2, - 49, - 303, - 195, - 69, - 312, - 223, - 319, - 278, - 151, - 97, - 216, - 197, - 295, - 84, - 204, - 179, - 157, - 380, - 224, - 93, - 58, - 287, - 378, - 56, - 37, - 168, - 370, - 33, - 4, - 362, - 347, - 132, - 351, - 163, - 207, - 109, - 214, - 170, - 327, - 383, - 218, - 64, - 105, - 345, - 212, - 318, - 395, - 384, - 237, - 387, - 83, - 203, - 55, - 163, - 226, - 131, - 203, - 260, - 132, - 214, - 16, - 210, - 239, - 25, - 280, - 295, - 363, - 315, - 326, - 274, - 211, - 272, - 202, - 239, - 63, - 357, - 366, - 181, - 267, - 170, - 378, - 318, - 195, - 178, - 97, - 56, - 354, - 96, - 212, - 376, - 138, - 229, - 261, - 32, - 49, - 256, - 52, - 190, - 227, - 164, - 342, - 228, - 393, - 290, - 24, - 95, - 385, - 281, - 304, - 130, - 235, - 150, - 10, - 297, - 396, - 61, - 235, - 87, - 116, - 189, - 5, - 231, - 45, - 303, - 297, - 347, - 271, - 37, - 195, - 223, - 270, - 309, - 247, - 247, - 203, - 294, - 307, - 238, - 313, - 41, - 323, - 290, - 84, - 391, - 368, - 160, - 236, - 337, - 61, - 85, - 141, - 54, - 48, - 62, - 168, - 245, - 163, - 66, - 323, - 173, - 145, - 184, - 198, - 154, - 347, - 366, - 284, - 257, - 32, - 281, - 344, - 387, - 18, - 196, - 65, - 52, - 233, - 388, - 35, - 68, - 362, - 78, - 275, - 84, - 59, - 172, - 13, - 283, - 218, - 14, - 206, - 203, - 100, - 234, - 376, - 364, - 240, - 82, - 101, - 336, - 1, - 182, - 354, - 385, - 365, - 154, - 390, - 302, - 239, - 46, - 345, - 353, - 107, - 329, - 292, - 145, - 300, - 135, - 320, - 342, - 107, - 349, - 120, - 233, - 55, - 189, - 390, - 201, - 315, - 289, - 310, - 291, - 315, - 196, - 15, - 92, - 326, - 89, - 196, - 286, - 19, - 265, - 370, - 394, - 67, - 138, - 281, - 98, - 201, - 309, - 154, - 37, - 266, - 32, - 345, - 130, - 98, - 250, - 263, - 24, - 315, - 326, - 375, - 362, - 347, - 85, - 50, - 241, - 344, - 67, - 241, - 302, - 162, - 377, - 179, - 80, - 73, - 155, - 75, - 55, - 35, - 273, - 175, - 370, - 234, - 273, - 57, - 91, - 74, - 8, - 44, - 28, - 118, - 356, - 190, - 359, - 243, - 388, - 273, - 381, - 332, - 12, - 106, - 250, - 155, - 70, - 361, - 15, - 124, - 321, - 337, - 44, - 353, - 35, - 247, - 22, - 84, - 301, - 297, - 132, - 225, - 66, - 105, - 348, - 133, - 212, - 152, - 328, - 79, - 49, - 223, - 121, - 74, - 126, - 320, - 67, - 374, - 228, - 173, - 17, - 236, - 12, - 117, - 218, - 192, - 346, - 370, - 138, - 266, - 270, - 391, - 167, - 132, - 233, - 207, - 162, - 65, - 251, - 14, - 173, - 72, - 191, - 165, - 38, - 8, - 204, - 204, - 376, - 203, - 105, - 182, - 336, - 121, - 20, - 69, - 275, - 254, - 40, - 149, - 343, - 197, - 262, - 21, - 259, - 330, - 246, - 383, - 43, - 325, - 46, - 40, - 338, - 262, - 116, - 75, - 266, - 2, - 389, - 90, - 29, - 101, - 244, - 363, - 58, - 3, - 68, - 137, - 195, - 344, - 105, - 113, - 378, - 19, - 107, - 208, - 83, - 250, - 201, - 238, - 283, - 135, - 372, - 74, - 200, - 159, - 216, - 334, - 29, - 108, - 156, - 303, - 300, - 55, - 37, - 366, - 225, - 323, - 181, - 217, - 388, - 143, - 313, - 369, - 81, - 389, - 128, - 139, - 179, - 222, - 110, - 154, - 166, - 5, - 95, - 294, - 339, - 277, - 171, - 320, - 105, - 216, - 374, - 266, - 8, - 78, - 296, - 119, - 367, - 95, - 357, - 180, - 175, - 43, - 7, - 15, - 348, - 26, - 116, - 327, - 321, - 19, - 297, - 62, - 377, - 112, - 175, - 240, - 1, - 178, - 3, - 90, - 149, - 377, - 103, - 296, - 40, - 22, - 43, - 232, - 212, - 343, - 228, - 276, - 68, - 140, - 112, - 314, - 72, - 7, - 274, - 163, - 252, - 153, - 388, - 304, - 218, - 73, - 107, - 246, - 145, - 200, - 211, - 22, - 85, - 197, - 326, - 200, - 373, - 310, - 263, - 86, - 13, - 388, - 309, - 246, - 248, - 305, - 388, - 304, - 165, - 221, - 303, - 397, - 56, - 245, - 246, - 48, - 87, - 266, - 108, - 56, - 144, - 140, - 93, - 245, - 256, - 97, - 226, - 273, - 347, - 165, - 212, - 228, - 207, - 169, - 305, - 371, - 186, - 334, - 396, - 244, - 100, - 352, - 358, - 326, - 339, - 270, - 396, - 301, - 284, - 11, - 177, - 191, - 126, - 68, - 227, - 33, - 366, - 298, - 359, - 193, - 122, - 393, - 122, - 203, - 30, - 303, - 194, - 392, - 151, - 366, - 31, - 293, - 174, - 53, - 26, - 218, - 85, - 136, - 306, - 113, - 10, - 61, - 173, - 48, - 56, - 97, - 70, - 146, - 399, - 283, - 50, - 278, - 366, - 185, - 35, - 323, - 13, - 344, - 144, - 141, - 33, - 279, - 89, - 383, - 267, - 101, - 396, - 337, - 247, - 341, - 224, - 376, - 360, - 9, - 196, - 136, - 104, - 376, - 263, - 383, - 3, - 124, - 314, - 136, - 23, - 46, - 346, - 318, - 338, - 249, - 270, - 205, - 145, - 179, - 232, - 245, - 228, - 230, - 50, - 263, - 119, - 7, - 240, - 2, - 149, - 158, - 120, - 175, - 163, - 63, - 25, - 16, - 263, - 219, - 340, - 339, - 186, - 128, - 29, - 354, - 195, - 387, - 145, - 121, - 184, - 268, - 344, - 9, - 87, - 242, - 355, - 309, - 99, - 220, - 131, - 247, - 82, - 101, - 373, - 220, - 119, - 373, - 332, - 125, - 264, - 247, - 118, - 307, - 305, - 303, - 348, - 275, - 60, - 325, - 154, - 189, - 374, - 374, - 58, - 365, - 353, - 257, - 372, - 315, - 352, - 259, - 312, - 395, - 320, - 181, - 125, - 206, - 195, - 161, - 322, - 389, - 398, - 113, - 77, - 376, - 162, - 8, - 350, - 14, - 298, - 48, - 217, - 217, - 33, - 86, - 224, - 239, - 206, - 35, - 321, - 330, - 287, - 89, - 7, - 134, - 191, - 149, - 274, - 228, - 229, - 108, - 372, - 313, - 237, - 211, - 178, - 101, - 396, - 55, - 86, - 137, - 61, - 118, - 67, - 336, - 327, - 88, - 317, - 32, - 385, - 275, - 164, - 331, - 286, - 49, - 66, - 242, - 20, - 141, - 11, - 313, - 313, - 2, - 324, - 128, - 172, - 282, - 199, - 384, - 313, - 148, - 73, - 200, - 366, - 75, - 260, - 133, - 299, - 269, - 29, - 399, - 355, - 358, - 174, - 102, - 169, - 194, - 343, - 174, - 170, - 171, - 80, - 395, - 329, - 147, - 64, - 328, - 372, - 364, - 228, - 357, - 151, - 85, - 95, - 185, - 345, - 307, - 300, - 312, - 237, - 125, - 132, - 164, - 392, - 70, - 400, - 67, - 126, - 155, - 317, - 57, - 54, - 276, - 146, - 184, - 137, - 107, - 376, - 362, - 6, - 95, - 273, - 327, - 100, - 110, - 352, - 90, - 144, - 288, - 323, - 126, - 200, - 400, - 220, - 59, - 34, - 289, - 354, - 118, - 241, - 148, - 199, - 322, - 40, - 312, - 140, - 77, - 112, - 223, - 140, - 13, - 1, - 185, - 388, - 24, - 131, - 398, - 318, - 280, - 63, - 175, - 47, - 134, - 327, - 206, - 52, - 48, - 64, - 194, - 178, - 377, - 55, - 55, - 107, - 265, - 338, - 263, - 27, - 92, - 373, - 357, - 295, - 207, - 324, - 133, - 119, - 151, - 175, - 2, - 77, - 288, - 151, - 116, - 168, - 371, - 245, - 20, - 142, - 174, - 112, - 203, - 98, - 209, - 73, - 328, - 15, - 33, - 40, - 377, - 124, - 370, - 396, - 25, - 215, - 368, - 135, - 133, - 151, - 282, - 80, - 304, - 280, - 67, - 327, - 177, - 333, - 178, - 151, - 146, - 56, - 76, - 312, - 186, - 212, - 132, - 31, - 296, - 141, - 60, - 75, - 209, - 382, - 49, - 179, - 389, - 106, - 146, - 103, - 158, - 300, - 91, - 239, - 221, - 305, - 164, - 148, - 351, - 270, - 121, - 129, - 383, - 296, - 375, - 49, - 259, - 231, - 272, - 275, - 352, - 222, - 339, - 299, - 54, - 20, - 348, - 80, - 332, - 342, - 227, - 27, - 286, - 243, - 162, - 147, - 164, - 1, - 259, - 222, - 398, - 371, - 322, - 178, - 327, - 33, - 319, - 175, - 272, - 351, - 245, - 247, - 55, - 154, - 325, - 300, - 344, - 8, - 207, - 79, - 138, - 76, - 159, - 115, - 3, - 166, - 336, - 235, - 300, - 344, - 89, - 276, - 110, - 117, - 37, - 52, - 370, - 20, - 345, - 290, - 198, - 158, - 127, - 226, - 355, - 239, - 381, - 158, - 51, - 62, - 152, - 355, - 148, - 97, - 108, - 238, - 107, - 127, - 103, - 332, - 77, - 238, - 258, - 211, - 86, - 374, - 172, - 60, - 339, - 309, - 220, - 63, - 387, - 132, - 222, - 369, - 243, - 388, - 64, - 375, - 264, - 212, - 33, - 121, - 187, - 326, - 35, - 154, - 292, - 303, - 337, - 25, - 18, - 307, - 136, - 197, - 241, - 150, - 181, - 335, - 306, - 208, - 388, - 379, - 75, - 133, - 295, - 343, - 86, - 255, - 193, - 126, - 128, - 200, - 307, - 76, - 79, - 145, - 213, - 249, - 24, - 240, - 384, - 245, - 333, - 72, - 145, - 21, - 306, - 86, - 173, - 172, - 211, - 258, - 226, - 235, - 109, - 286, - 169, - 25, - 331, - 125, - 369, - 176, - 370, - 310, - 235, - 390, - 179, - 136, - 223, - 129, - 155, - 337, - 82, - 292, - 111, - 332, - 252, - 3, - 178, - 201, - 31, - 143, - 154, - 3, - 92, - 263, - 171, - 6, - 151, - 251, - 267, - 29, - 157, - 153, - 29, - 155, - 360, - 338, - 81, - 96, - 166, - 93, - 382, - 7, - 176, - 53, - 43, - 393, - 210, - 87, - 3, - 92, - 384, - 148, - 152, - 181, - 378, - 353, - 202, - 196, - 212, - 235, - 246, - 227, - 236, - 304, - 180, - 201, - 336, - 19, - 17, - 185, - 255, - 99, - 133, - 98, - 227, - 72, - 260, - 260, - 1, - 331, - 219, - 41, - 32, - 344, - 335, - 326, - 98, - 42, - 86, - 90, - 282, - 381, - 88, - 34, - 191, - 96, - 147, - 378, - 354, - 218, - 251, - 384, - 240, - 337, - 120, - 364, - 51, - 95, - 159, - 230, - 373, - 52, - 81, - 249, - 194, - 368, - 374, - 108, - 380, - 57, - 66, - 393, - 222, - 300, - 147, - 158, - 391, - 226, - 64, - 347, - 241, - 134, - 274, - 162, - 293, - 167, - 372, - 176, - 390, - 232, - 354, - 250, - 311, - 191, - 329, - 177, - 208, - 88, - 204, - 342, - 364, - 296, - 222, - 339, - 247, - 144, - 372, - 342, - 233, - 83, - 223, - 210, - 330, - 68, - 282, - 171, - 177, - 203, - 264, - 383, - 308, - 341, - 246, - 352, - 55, - 143, - 193, - 319, - 54, - 311, - 237, - 52, - 9, - 391, - 294, - 96, - 47, - 46, - 132, - 312, - 120, - 231, - 68, - 134, - 61, - 326, - 323, - 314, - 393, - 288, - 322, - 177, - 326, - 322, - 244, - 117, - 322, - 253, - 385, - 258, - 296, - 48, - 189, - 2, - 329, - 351, - 237, - 92, - 69, - 105, - 388, - 37, - 399, - 165, - 300, - 268, - 143, - 322, - 299, - 376, - 221, - 363, - 158, - 156, - 224, - 336, - 126, - 51, - 205, - 107, - 56, - 289, - 395, - 312, - 48, - 310, - 384, - 190, - 173, - 332, - 346, - 227, - 362, - 48, - 270, - 387, - 232, - 303, - 113, - 368, - 295, - 278, - 200, - 20, - 181, - 111, - 16, - 185, - 225, - 282, - 350, - 380, - 156, - 20, - 135, - 302, - 199, - 180, - 194, - 15, - 4, - 341, - 106, - 353, - 294, - 300, - 208, - 161, - 332, - 224, - 387, - 285, - 236, - 262, - 294, - 90, - 50, - 65, - 215, - 111, - 5, - 191, - 138, - 168, - 139, - 369, - 325, - 137, - 273, - 399, - 54, - 314, - 75, - 286, - 349, - 36, - 276, - 306, - 129, - 7, - 165, - 103, - 373, - 227, - 376, - 173, - 326, - 378, - 347, - 63, - 280, - 319, - 46, - 325, - 232, - 170, - 322, - 288, - 364, - 218, - 260, - 86, - 95, - 393, - 190, - 76, - 48, - 378, - 136, - 316, - 223, - 83, - 314, - 42, - 398, - 252, - 384, - 90, - 76, - 310, - 100, - 209, - 301, - 317, - 120, - 324, - 137, - 324, - 35, - 167, - 215, - 235, - 331, - 316, - 310, - 192, - 395, - 180, - 375, - 142, - 105, - 213, - 183, - 82, - 330, - 336, - 130, - 162, - 166, - 124, - 28, - 222, - 332, - 322, - 246, - 31, - 184, - 85, - 111, - 126, - 373, - 393, - 343, - 80, - 50, - 140, - 394, - 9, - 14, - 345, - 10, - 180, - 375, - 313, - 266, - 95, - 287, - 52, - 93, - 239, - 57, - 397, - 175, - 250, - 52, - 64, - 317, - 112, - 330, - 370, - 150, - 224, - 248, - 134, - 143, - 11, - 221, - 203, - 266, - 46, - 297, - 105, - 276, - 255, - 39, - 112, - 9, - 344, - 94, - 61, - 299, - 16, - 190, - 112, - 83, - 208, - 173, - 19, - 258, - 392, - 106, - 208, - 103, - 280, - 137, - 127, - 193, - 335, - 287, - 314, - 390, - 69, - 121, - 162, - 285, - 55, - 364, - 96, - 376, - 314, - 90, - 43, - 214, - 208, - 190, - 125, - 188, - 233, - 297, - 320, - 210, - 217, - 8, - 149, - 70, - 183, - 365, - 90, - 147, - 244, - 5, - 168, - 235, - 60, - 153, - 128, - 214, - 94, - 227, - 159, - 218, - 277, - 134, - 119, - 383, - 113, - 190, - 144, - 77, - 75, - 224, - 272, - 84, - 240, - 98, - 394, - 394, - 40, - 69, - 24, - 27, - 266, - 26, - 22, - 33, - 196, - 210, - 63, - 226, - 31, - 132, - 199, - 28, - 35, - 22, - 79, - 80, - 59, - 365, - 309, - 112, - 133, - 38, - 396, - 159, - 385, - 375, - 8, - 393, - 144, - 55, - 254, - 246, - 359, - 316, - 126, - 362, - 213, - 81, - 357, - 385, - 104, - 97, - 168, - 273, - 234, - 42, - 223, - 18, - 387, - 139, - 50, - 399, - 387, - 227, - 134, - 199, - 204, - 151, - 318, - 217, - 2, - 141, - 167, - 110, - 247, - 380, - 257, - 205, - 119, - 5, - 186, - 236, - 249, - 358, - 65, - 203, - 379, - 372, - 288, - 359, - 342, - 50, - 350, - 244, - 248, - 348, - 294, - 189, - 369, - 188, - 64, - 65, - 24, - 43, - 45, - 215, - 386, - 108, - 1, - 222, - 137, - 239, - 295, - 74, - 183, - 134, - 252, - 376, - 379, - 361, - 394, - 165, - 234, - 285, - 158, - 181, - 201, - 282, - 116, - 260, - 246, - 317, - 27, - 15, - 144, - 119, - 246, - 94, - 272, - 35, - 250, - 291, - 97, - 350, - 37, - 308, - 267, - 166, - 248, - 36, - 242, - 91, - 177, - 111, - 278, - 15, - 353, - 268, - 45, - 189, - 151, - 23, - 322, - 235, - 328, - 240, - 156, - 176, - 57, - 247, - 8, - 81, - 186, - 15, - 254, - 97, - 66, - 253, - 143, - 18, - 345, - 37, - 86, - 255, - 3, - 45, - 373, - 306, - 102, - 379, - 44, - 398, - 365, - 224, - 312, - 14, - 1, - 313, - 268, - 35, - 227, - 47, - 291, - 154, - 208, - 230, - 348, - 394, - 5, - 338, - 318, - 355, - 87, - 181, - 248, - 97, - 321, - 290, - 135, - 352, - 113, - 119, - 390, - 136, - 51, - 119, - 43, - 141, - 38, - 75, - 137, - 14, - 356, - 70, - 100, - 73, - 168, - 44, - 290, - 342, - 113, - 82, - 333, - 187, - 70, - 46, - 125, - 320, - 96, - 228, - 252, - 151, - 343, - 21, - 22, - 196, - 28, - 354, - 331, - 257, - 305, - 289, - 30, - 237, - 156, - 250, - 88, - 184, - 32, - 272, - 171, - 27, - 97, - 265, - 337, - 197, - 67, - 339, - 133, - 16, - 216, - 324, - 388, - 248, - 131, - 357, - 135, - 371, - 392, - 290, - 230, - 90, - 254, - 40, - 359, - 309, - 357, - 336, - 334, - 173, - 155, - 282, - 1, - 263, - 155, - 369, - 332, - 100, - 147, - 383, - 65, - 351, - 209, - 105, - 331, - 100, - 270, - 114, - 108, - 128, - 220, - 375, - 141, - 69, - 19, - 278, - 352, - 365, - 250, - 278, - 234, - 141, - 380, - 43, - 169, - 2, - 256, - 329, - 97, - 368, - 32, - 240, - 374, - 373, - 48, - 268, - 386, - 149, - 7, - 46, - 277, - 127, - 243, - 102, - 294, - 80, - 28, - 71, - 328, - 193, - 87, - 346, - 122, - 276, - 392, - 175, - 227, - 163, - 29, - 91, - 157, - 379, - 114, - 220, - 141, - 29, - 207, - 248, - 130, - 22, - 51, - 383, - 172, - 61, - 25, - 28, - 102, - 103, - 134, - 364, - 74, - 126, - 261, - 288, - 87, - 311, - 274, - 388, - 58, - 400, - 184, - 53, - 123, - 170, - 366, - 175, - 277, - 348, - 243, - 322, - 315, - 35, - 50, - 20, - 388, - 213, - 82, - 34, - 53, - 297, - 369, - 3, - 68, - 152, - 119, - 393, - 57, - 220, - 129, - 97, - 171, - 338, - 282, - 195, - 176, - 257, - 277, - 47, - 237, - 332, - 151, - 383, - 185, - 185, - 106, - 161, - 327, - 45, - 265, - 236, - 170, - 252, - 172, - 64, - 298, - 144, - 262, - 389, - 179, - 308, - 126, - 189, - 128, - 20, - 272, - 129, - 60, - 166, - 217, - 147, - 250, - 248, - 325, - 177, - 84, - 347, - 305, - 363, - 177, - 93, - 29, - 377, - 350, - 284, - 109, - 363, - 178, - 237, - 145, - 115, - 59, - 166, - 168, - 76, - 35, - 25, - 357, - 56, - 157, - 157, - 302, - 222, - 80, - 265, - 392, - 110, - 163, - 300, - 33, - 57, - 88, - 29, - 66, - 106, - 75, - 210, - 331, - 23, - 291, - 377, - 385, - 369, - 327, - 106, - 193, - 36, - 213, - 231, - 195, - 22, - 123, - 308, - 50, - 256, - 372, - 388, - 240, - 399, - 251, - 360, - 41, - 21, - 304, - 298, - 390, - 196, - 105, - 56, - 396, - 102, - 327, - 39, - 91, - 269, - 317, - 127, - 358, - 322, - 301, - 319, - 94, - 268, - 61, - 301, - 259, - 293, - 234, - 311, - 135, - 233, - 143, - 3, - 380, - 179, - 81, - 102, - 314, - 3, - 43, - 62, - 160, - 86, - 39, - 15, - 333, - 288, - 377, - 10, - 253, - 163, - 5, - 273, - 285, - 183, - 116, - 6, - 259, - 374, - 38, - 365, - 345, - 336, - 103, - 51, - 48, - 92, - 146, - 80, - 205, - 185, - 362, - 228, - 257, - 225, - 176, - 49, - 366, - 371, - 308, - 343, - 386, - 9, - 343, - 265, - 284, - 137, - 373, - 372, - 255, - 233, - 154, - 64, - 136, - 48, - 377, - 179, - 153, - 327, - 385, - 349, - 273, - 130, - 261, - 207, - 215, - 311, - 49, - 117, - 78, - 292, - 315, - 70, - 383, - 160, - 21, - 56, - 201, - 328, - 99, - 181, - 68, - 203, - 114, - 180, - 262, - 378, - 397, - 230, - 165, - 355, - 10, - 296, - 109, - 264, - 80, - 202, - 255, - 381, - 55, - 193, - 334, - 397, - 386, - 216, - 356, - 356, - 45, - 9, - 304, - 186, - 334, - 60, - 128, - 317, - 163, - 151, - 234, - 115, - 386, - 77, - 345, - 149, - 240, - 221, - 84, - 143, - 332, - 344, - 204, - 83, - 22, - 304, - 183, - 337, - 311, - 274, - 93, - 276, - 341, - 94, - 174, - 346, - 74, - 90, - 348, - 120, - 291, - 202, - 220, - 3, - 316, - 19, - 212, - 276, - 388, - 228, - 302, - 120, - 150, - 206, - 30, - 130, - 270, - 263, - 358, - 374, - 84, - 208, - 306, - 187, - 258, - 90, - 6, - 355, - 101, - 239, - 80, - 241, - 285, - 368, - 94, - 118, - 380, - 152, - 164, - 400, - 185, - 115, - 270, - 19, - 271, - 298, - 56, - 118, - 253, - 270, - 184, - 372, - 169, - 382, - 327, - 349, - 352, - 177, - 202, - 24, - 129, - 129, - 93, - 42, - 377, - 2, - 249, - 249, - 188, - 82, - 318, - 72, - 349, - 180, - 103, - 308, - 385, - 189, - 370, - 334, - 348, - 161, - 284, - 17, - 166, - 198, - 307, - 323, - 225, - 170, - 219, - 369, - 81, - 247, - 232, - 138, - 57, - 11, - 142, - 236, - 151, - 308, - 14, - 329, - 184, - 170, - 28, - 13, - 49, - 11, - 163, - 10, - 51, - 140, - 96, - 318, - 258, - 149, - 362, - 133, - 39, - 113, - 47, - 100, - 52, - 364, - 34, - 14, - 181, - 354, - 13, - 226, - 258, - 178, - 371, - 321, - 303, - 310, - 131, - 317, - 199, - 52, - 178, - 204, - 8, - 326, - 63, - 53, - 399, - 64, - 5, - 106, - 177, - 258, - 133, - 283, - 346, - 114, - 185, - 313, - 126, - 101, - 342, - 17, - 99, - 321, - 35, - 102, - 395, - 212, - 129, - 147, - 381, - 301, - 206, - 34, - 380, - 127, - 260, - 136, - 258, - 97, - 387, - 150, - 103, - 281, - 302, - 208, - 18, - 198, - 304, - 337, - 311, - 83, - 393, - 112, - 231, - 378, - 392, - 212, - 267, - 32, - 144, - 78, - 193, - 355, - 263, - 84, - 195, - 116, - 143, - 5, - 109, - 199, - 208, - 381, - 53, - 241, - 353, - 90, - 325, - 51, - 186, - 323, - 273, - 208, - 14, - 69, - 88, - 396, - 380, - 353, - 15, - 170, - 333, - 116, - 373, - 262, - 149, - 222, - 312, - 56, - 190, - 247, - 292, - 10, - 53, - 342, - 87, - 65, - 1, - 394, - 43, - 253, - 107, - 112, - 172, - 108, - 164, - 286, - 358, - 259, - 269, - 362, - 217, - 283, - 284, - 200, - 118, - 55, - 201, - 194, - 324, - 374, - 126, - 329, - 177, - 20, - 187, - 53, - 349, - 115, - 189, - 394, - 183, - 55, - 346, - 175, - 1, - 285, - 351, - 309, - 171, - 17, - 268, - 312, - 50, - 45, - 35, - 43, - 70, - 328, - 55, - 200, - 99, - 306, - 147, - 81, - 74, - 247, - 196, - 307, - 91, - 85, - 186, - 398, - 242, - 118, - 244, - 142, - 309, - 32, - 351, - 221, - 176, - 12, - 83, - 102, - 188, - 353, - 127, - 345, - 164, - 169, - 310, - 93, - 240, - 282, - 80, - 204, - 345, - 127, - 59, - 19, - 31, - 225, - 229, - 209, - 154, - 332, - 243, - 186, - 77, - 7, - 207, - 328, - 363, - 81, - 108, - 194, - 388, - 165, - 300, - 184, - 43, - 102, - 392, - 393, - 377, - 267, - 303, - 249, - 178, - 286, - 351, - 297, - 263, - 153, - 347, - 91, - 18, - 341, - 283, - 129, - 124, - 8, - 263, - 204, - 4, - 156, - 177, - 148, - 228, - 207, - 334, - 338, - 382, - 343, - 137, - 116, - 160, - 270, - 223, - 91, - 53, - 349, - 386, - 346, - 126, - 47, - 233, - 320, - 315, - 309, - 363, - 169, - 75, - 368, - 153, - 118, - 101, - 309, - 186, - 89, - 127, - 293, - 31, - 122, - 340, - 125, - 157, - 142, - 88, - 241, - 180, - 225, - 225, - 132, - 236, - 114, - 223, - 129, - 65, - 40, - 397, - 111, - 261, - 314, - 160, - 203, - 346, - 263, - 142, - 398, - 215, - 1, - 120, - 274, - 285, - 341, - 151, - 38, - 119, - 257, - 314, - 332, - 378, - 64, - 206, - 151, - 311, - 283, - 338, - 362, - 19, - 90, - 293, - 21, - 267, - 102, - 181, - 253, - 80, - 251, - 134, - 254, - 276, - 70, - 308, - 228, - 241, - 235, - 68, - 312, - 394, - 276, - 221, - 372, - 31, - 167, - 262, - 358, - 21, - 159, - 70, - 371, - 149, - 132, - 136, - 66, - 171, - 308, - 148, - 301, - 22, - 368, - 50, - 236, - 219, - 159, - 317, - 387, - 357, - 94, - 199, - 263, - 383, - 330, - 112, - 162, - 323, - 263, - 20, - 70, - 96, - 292, - 17, - 309, - 45, - 297, - 355, - 75, - 260, - 232, - 147, - 277, - 368, - 264, - 101, - 23, - 156, - 24, - 318, - 322, - 153, - 256, - 6, - 188, - 176, - 158, - 160, - 200, - 112, - 384, - 52, - 241, - 128, - 56, - 135, - 306, - 239, - 228, - 263, - 152, - 14, - 274, - 273, - 307, - 374, - 76, - 355, - 91, - 326, - 335, - 314, - 400, - 280, - 267, - 44, - 230, - 61, - 385, - 109, - 31, - 6, - 291, - 298, - 65, - 229, - 30, - 188, - 241, - 151, - 59, - 168, - 105, - 308, - 174, - 340, - 393, - 250, - 180, - 327, - 389, - 395, - 314, - 17, - 310, - 197, - 341, - 90, - 128, - 379, - 175, - 7, - 398, - 150, - 261, - 283, - 196, - 168, - 278, - 277, - 120, - 268, - 138, - 340, - 359, - 333, - 100, - 284, - 50, - 11, - 243, - 6, - 149, - 55, - 11, - 104, - 217, - 88, - 254, - 44, - 306, - 48, - 227, - 30, - 205, - 71, - 175, - 241, - 300, - 203, - 73, - 343, - 269, - 20, - 175, - 122, - 70, - 104, - 105, - 66, - 28, - 22, - 196, - 192, - 150, - 328, - 394, - 400, - 9, - 88, - 75, - 361, - 9, - 199, - 228, - 275, - 45, - 399, - 390, - 59, - 144, - 341, - 179, - 11, - 323, - 400, - 392, - 223, - 396, - 304, - 131, - 295, - 136, - 391, - 298, - 390, - 228, - 343, - 390, - 183, - 137, - 129, - 8, - 315, - 27, - 9, - 330, - 9, - 342, - 14, - 86, - 243, - 303, - 133, - 229, - 46, - 144, - 317, - 243, - 219, - 196, - 203, - 244, - 92, - 364, - 85, - 180, - 172, - 346, - 127, - 133, - 224, - 151, - 199, - 243, - 53, - 138, - 165, - 314, - 248, - 248, - 12, - 173, - 273, - 345, - 168, - 70, - 346, - 94, - 364, - 206, - 170, - 244, - 230, - 300, - 387, - 195, - 206, - 185, - 165, - 100, - 133, - 400, - 259, - 373, - 46, - 104, - 352, - 335, - 208, - 297, - 93, - 361, - 119, - 99, - 54, - 63, - 222, - 106, - 91, - 391, - 171, - 268, - 36, - 304, - 284, - 288, - 249, - 233, - 235, - 371, - 226, - 235, - 112, - 42, - 274, - 108, - 101, - 123, - 123, - 167, - 259, - 149, - 133, - 98, - 223, - 78, - 106, - 39, - 220, - 254, - 186, - 12, - 270, - 291, - 273, - 369, - 336, - 44, - 184, - 281, - 30, - 15, - 64, - 231, - 280, - 57, - 110, - 182, - 250, - 326, - 75, - 140, - 110, - 21, - 130, - 278, - 127, - 389, - 60, - 61, - 114, - 259, - 125, - 98, - 327, - 128, - 144, - 317, - 213, - 53, - 231, - 299, - 170, - 312, - 170, - 348, - 72, - 128, - 60, - 173, - 163, - 235, - 149, - 25, - 62, - 385, - 328, - 79, - 155, - 218, - 45, - 171, - 92, - 254, - 42, - 152, - 263, - 22, - 129, - 257, - 253, - 365, - 296, - 388, - 1, - 385, - 366, - 58, - 228, - 172, - 73, - 349, - 207, - 292, - 1, - 208, - 392, - 315, - 18, - 73, - 119, - 326, - 344, - 194, - 90, - 73, - 88, - 26, - 230, - 288, - 342, - 123, - 97, - 286, - 302, - 114, - 88, - 197, - 209, - 360, - 219, - 37, - 143, - 99, - 14, - 27, - 57, - 272, - 26, - 169, - 316, - 209, - 165, - 243, - 377, - 245, - 339, - 100, - 238, - 330, - 110, - 350, - 67, - 213, - 122, - 355, - 55, - 137, - 350, - 172, - 300, - 142, - 214, - 288, - 296, - 154, - 107, - 47, - 226, - 262, - 79, - 305, - 355, - 155, - 137, - 211, - 169, - 91, - 278, - 69, - 314, - 336, - 373, - 383, - 373, - 68, - 166, - 362, - 346, - 6, - 65, - 395, - 94, - 337, - 318, - 87, - 274, - 73, - 389, - 137, - 71, - 369, - 197, - 36, - 19, - 286, - 336, - 98, - 74, - 95, - 205, - 53, - 255, - 256, - 158, - 201, - 54, - 343, - 344, - 30, - 380, - 124, - 344, - 74, - 269, - 346, - 225, - 49, - 172, - 371, - 355, - 103, - 275, - 118, - 365, - 196, - 186, - 180, - 159, - 2, - 110, - 189, - 183, - 362, - 314, - 196, - 304, - 171, - 380, - 63, - 196, - 364, - 118, - 371, - 220, - 163, - 128, - 177, - 326, - 77, - 77, - 296, - 330, - 380, - 304, - 36, - 340, - 314, - 309, - 258, - 238, - 138, - 26, - 15, - 351, - 88, - 84, - 101, - 98, - 224, - 376, - 376, - 243, - 249, - 399, - 221, - 224, - 18, - 177, - 163, - 150, - 378, - 353, - 285, - 45, - 243, - 24, - 344, - 202, - 335, - 248, - 241, - 122, - 371, - 209, - 178, - 232, - 218, - 183, - 72, - 400, - 212, - 379, - 180, - 178, - 284, - 107, - 393, - 151, - 277, - 262, - 162, - 293, - 135, - 357, - 97, - 343, - 9, - 181, - 95, - 347, - 120, - 363, - 88, - 311, - 320, - 64, - 21, - 43, - 354, - 184, - 343, - 387, - 195, - 381, - 262, - 320, - 377, - 188, - 284, - 225, - 316, - 327, - 321, - 368, - 276, - 232, - 119, - 124, - 59, - 284, - 84, - 201, - 289, - 253, - 301, - 233, - 5, - 316, - 300, - 242, - 343, - 30, - 50, - 101, - 51, - 294, - 387, - 292, - 245, - 27, - 210, - 226, - 273, - 232, - 24, - 275, - 122, - 154, - 138, - 221, - 386, - 355, - 44, - 95, - 32, - 136, - 12, - 277, - 260, - 301, - 292, - 172, - 112, - 96, - 217, - 72, - 304, - 89, - 29, - 33, - 35, - 8, - 378, - 94, - 327, - 35, - 279, - 396, - 368, - 251, - 85, - 138, - 357, - 60, - 1, - 209, - 171, - 363, - 324, - 203, - 355, - 98, - 120, - 392, - 285, - 297, - 105, - 134, - 123, - 167, - 134, - 304, - 61, - 257, - 166, - 40, - 214, - 328, - 179, - 330, - 261, - 325, - 78, - 67, - 167, - 395, - 306, - 89, - 305, - 386, - 115, - 4, - 121, - 69, - 41, - 83, - 3, - 10, - 56, - 94, - 338, - 233, - 179, - 378, - 8, - 101, - 216, - 59, - 49, - 95, - 366, - 117, - 355, - 356, - 15, - 287, - 266, - 268, - 189, - 289, - 392, - 204, - 69, - 310, - 264, - 240, - 171, - 277, - 397, - 173, - 397, - 218, - 81, - 124, - 354, - 240, - 166, - 100, - 73, - 274, - 302, - 110, - 268, - 17, - 74, - 62, - 41, - 86, - 106, - 363, - 200, - 67, - 94, - 56, - 161, - 12, - 127, - 184, - 355, - 259, - 95, - 299, - 316, - 247, - 84, - 35, - 33, - 235, - 280, - 376, - 295, - 394, - 179, - 299, - 174, - 325, - 131, - 54, - 295, - 13, - 327, - 231, - 367, - 67, - 353, - 104, - 66, - 381, - 87, - 63, - 45, - 89, - 21, - 263, - 357, - 331, - 183, - 264, - 367, - 250, - 44, - 149, - 94, - 147, - 131, - 327, - 189, - 212, - 172, - 360, - 244, - 206, - 177, - 115, - 79, - 38, - 349, - 152, - 104, - 261, - 265, - 299, - 328, - 242, - 1, - 305, - 216, - 182, - 127, - 332, - 192, - 162, - 225, - 35, - 11, - 390, - 66, - 41, - 266, - 175, - 397, - 156, - 365, - 57, - 363, - 50, - 56, - 301, - 233, - 22, - 136, - 381, - 300, - 4, - 7, - 18, - 359, - 341, - 229, - 29, - 1, - 399, - 146, - 242, - 289, - 230, - 352, - 92, - 105, - 382, - 334, - 233, - 229, - 326, - 50, - 335, - 276, - 196, - 354, - 6, - 104, - 156, - 75, - 301, - 265, - 179, - 383, - 34, - 112, - 29, - 294, - 69, - 249, - 246, - 143, - 191, - 301, - 163, - 309, - 244, - 321, - 78, - 13, - 179, - 236, - 275, - 240, - 283, - 186, - 317, - 105, - 84, - 160, - 308, - 138, - 87, - 37, - 211, - 7, - 85, - 333, - 195, - 265, - 246, - 56, - 16, - 226, - 102, - 171, - 310, - 328, - 63, - 300, - 160, - 136, - 114, - 386, - 247, - 43, - 95, - 217, - 223, - 186, - 130, - 354, - 398, - 132, - 341, - 34, - 249, - 218, - 51, - 197, - 97, - 80, - 25, - 61, - 119, - 28, - 137, - 160, - 222, - 119, - 132, - 44, - 273, - 61, - 110, - 217, - 12, - 32, - 15, - 47, - 260, - 149, - 132, - 92, - 238, - 330, - 116, - 203, - 317, - 306, - 227, - 79, - 193, - 245, - 309, - 54, - 282, - 199, - 108, - 185, - 48, - 73, - 18, - 154, - 379, - 186, - 244, - 209, - 191, - 69, - 187, - 13, - 192, - 45, - 170, - 300, - 23, - 274, - 143, - 128, - 341, - 91, - 65, - 186, - 48, - 154, - 291, - 350, - 301, - 179, - 245, - 33, - 395, - 333, - 155, - 364, - 83, - 79, - 268, - 306, - 252, - 335, - 398, - 90, - 128, - 267, - 146, - 185, - 127, - 300, - 2, - 376, - 345, - 368, - 95, - 287, - 143, - 159, - 216, - 150, - 95, - 272, - 393, - 376, - 355, - 244, - 191, - 270, - 20, - 366, - 235, - 121, - 75, - 40, - 398, - 67, - 354, - 267, - 87, - 336, - 231, - 24, - 111, - 247, - 306, - 400, - 225, - 50, - 329, - 330, - 101, - 97, - 331, - 244, - 323, - 146, - 214, - 63, - 253, - 44, - 6, - 21, - 334, - 60, - 286, - 130, - 11, - 316, - 346, - 232, - 301, - 63, - 24, - 272, - 289, - 60, - 232, - 292, - 333, - 256, - 302, - 305, - 80, - 330, - 13, - 310, - 222, - 358, - 103, - 148, - 277, - 292, - 109, - 90, - 191, - 76, - 277, - 52, - 200, - 184, - 163, - 359, - 323, - 326, - 219, - 295, - 173, - 57, - 351, - 236, - 346, - 254, - 221, - 304, - 91, - 327, - 310, - 345, - 355, - 18, - 19, - 206, - 267, - 356, - 108, - 113, - 173, - 8, - 180, - 374, - 30, - 270, - 249, - 335, - 375, - 350, - 326, - 169, - 343, - 383, - 340, - 54, - 104, - 160, - 6, - 37, - 46, - 36, - 215, - 146, - 324, - 354, - 130, - 156, - 331, - 204, - 235, - 310, - 85, - 102, - 6, - 63, - 98, - 323, - 241, - 191, - 400, - 32, - 399, - 290, - 93, - 70, - 215, - 113, - 349, - 321, - 71, - 60, - 137, - 209, - 135, - 234, - 11, - 94, - 108, - 139, - 66, - 43, - 73, - 280, - 336, - 58, - 329, - 143, - 269, - 39, - 141, - 23, - 133, - 225, - 43, - 323, - 19, - 317, - 342, - 23, - 63, - 177, - 85, - 180, - 153, - 252, - 3, - 186, - 202, - 303, - 338, - 317, - 9, - 50, - 299, - 239, - 263, - 351, - 368, - 256, - 299, - 272, - 326, - 163, - 145, - 346, - 307, - 75, - 390, - 132, - 249, - 139, - 275, - 378, - 226, - 290, - 306, - 141, - 61, - 372, - 205, - 152, - 372, - 225, - 127, - 63, - 307, - 98, - 142, - 131, - 260, - 199, - 97, - 152, - 268, - 21, - 340, - 326, - 238, - 235, - 198, - 45, - 147, - 294, - 2, - 378, - 323, - 337, - 200, - 134, - 391, - 167, - 59, - 129, - 194, - 359, - 276, - 65, - 195, - 245, - 376, - 385, - 277, - 170, - 330, - 12, - 372, - 259, - 374, - 13, - 169, - 27, - 206, - 186, - 85, - 77, - 134, - 343, - 325, - 134, - 385, - 334, - 234, - 329, - 381, - 178, - 211, - 218, - 261, - 245, - 195, - 244, - 389, - 281, - 298, - 132, - 180, - 391, - 237, - 138, - 352, - 99, - 17, - 261, - 368, - 81, - 172, - 143, - 238, - 138, - 88, - 200, - 275, - 168, - 313, - 352, - 26, - 2, - 73, - 348, - 173, - 275, - 327, - 289, - 34, - 90, - 38, - 299, - 212, - 69, - 95, - 186, - 288, - 345, - 138, - 387, - 168, - 32, - 53, - 257, - 181, - 153, - 288, - 24, - 307, - 339, - 165, - 104, - 305, - 279, - 84, - 341, - 259, - 342, - 227, - 359, - 109, - 117, - 28, - 128, - 172, - 228, - 321, - 178, - 161, - 284, - 227, - 241, - 355, - 225, - 154, - 328, - 167, - 184, - 345, - 238, - 156, - 342, - 372, - 378, - 20, - 134, - 192, - 378, - 176, - 277, - 81, - 26, - 120, - 70, - 80, - 192, - 354, - 225, - 8, - 378, - 45, - 342, - 92, - 162, - 113, - 239, - 164, - 125, - 113, - 386, - 69, - 69, - 297, - 170, - 317, - 42, - 162, - 309, - 134, - 301, - 82, - 44, - 153, - 183, - 29, - 350, - 73, - 90, - 53, - 351, - 261, - 69, - 144, - 291, - 199, - 96, - 60, - 230, - 176, - 157, - 180, - 148, - 54, - 131, - 123, - 388, - 64, - 326, - 13, - 263, - 60, - 300, - 68, - 287, - 160, - 41, - 292, - 176, - 291, - 11, - 143, - 334, - 353, - 377, - 283, - 243, - 1, - 247, - 136, - 103, - 124, - 216, - 65, - 349, - 369, - 395, - 310, - 184, - 399, - 85, - 341, - 47, - 361, - 7, - 115, - 88, - 5, - 226, - 102, - 219, - 348, - 259, - 245, - 2, - 351, - 281, - 116, - 380, - 153, - 31, - 187, - 39, - 266, - 107, - 317, - 351, - 27, - 289, - 158, - 275, - 191, - 197, - 326, - 214, - 305, - 275, - 41, - 187, - 266, - 17, - 377, - 338, - 267, - 395, - 2, - 55, - 249, - 374, - 265, - 163, - 339, - 42, - 384, - 185, - 365, - 99, - 156, - 176, - 149, - 291, - 87, - 177, - 40, - 86, - 317, - 24, - 221, - 74, - 25, - 305, - 383, - 285, - 224, - 289, - 72, - 341, - 334, - 36, - 39, - 253, - 20, - 390, - 304, - 194, - 150, - 309, - 29, - 252, - 21, - 101, - 194, - 101, - 358, - 68, - 356, - 1, - 195, - 220, - 63, - 293, - 127, - 205, - 131, - 206, - 69, - 13, - 201, - 373, - 43, - 235, - 387, - 384, - 49, - 356, - 312, - 242, - 68, - 9, - 316, - 85, - 363, - 272, - 216, - 338, - 229, - 283, - 49, - 18, - 69, - 224, - 47, - 127, - 54, - 379, - 15, - 263, - 5, - 75, - 123, - 258, - 218, - 205, - 5, - 202, - 112, - 102, - 268, - 202, - 364, - 104, - 101, - 346, - 357, - 332, - 161, - 354, - 275, - 34, - 237, - 361, - 72, - 137, - 121, - 85, - 74, - 78, - 113, - 397, - 208, - 84, - 10, - 158, - 254, - 172, - 189, - 7, - 69, - 23, - 388, - 283, - 239, - 113, - 185, - 4, - 149, - 313, - 78, - 331, - 193, - 76, - 342, - 326, - 324, - 249, - 249, - 12, - 13, - 192, - 63, - 296, - 230, - 71, - 74, - 391, - 389, - 92, - 247, - 53, - 267, - 311, - 383, - 112, - 33, - 352, - 194, - 379, - 150, - 55, - 344, - 219, - 391, - 232, - 346, - 395, - 322, - 300, - 282, - 317, - 300, - 121, - 370, - 325, - 43, - 22, - 374, - 24, - 121, - 16, - 34, - 234, - 127, - 237, - 369, - 157, - 167, - 277, - 295, - 247, - 382, - 217, - 319, - 227, - 349, - 296, - 369, - 325, - 80, - 72, - 340, - 355, - 88, - 111, - 131, - 128, - 11, - 383, - 167, - 126, - 286, - 303, - 89, - 308, - 83, - 333, - 113, - 312, - 193, - 114, - 15, - 374, - 386, - 269, - 391, - 113, - 43, - 177, - 70, - 142, - 13, - 84, - 204, - 305, - 141, - 167, - 27, - 349, - 333, - 250, - 92, - 193, - 332, - 224, - 328, - 87, - 29, - 73, - 331, - 80, - 194, - 75, - 49, - 312, - 283, - 233, - 152, - 215, - 361, - 170, - 45, - 70, - 92, - 185, - 381, - 120, - 76, - 19, - 79, - 170, - 14, - 48, - 358, - 153, - 354, - 200, - 173, - 250, - 180, - 72, - 202, - 330, - 312, - 37, - 235, - 48, - 17, - 337, - 144, - 301, - 376, - 197, - 179, - 380, - 30, - 61, - 150, - 146, - 170, - 393, - 109, - 374, - 141, - 15, - 77, - 332, - 153, - 400, - 334, - 195, - 87, - 108, - 360, - 321, - 11, - 144, - 17, - 146, - 342, - 301, - 247, - 69, - 239, - 263, - 327, - 1, - 109, - 62, - 82, - 315, - 9, - 192, - 57, - 91, - 98, - 197, - 237, - 398, - 217, - 324, - 76, - 366, - 215, - 111, - 161, - 213, - 228, - 332, - 182, - 278, - 289, - 279, - 138, - 351, - 255, - 356, - 301, - 180, - 378, - 67, - 245, - 204, - 337, - 337, - 397, - 39, - 212, - 387, - 378, - 38, - 213, - 76, - 81, - 33, - 202, - 149, - 68, - 398, - 243, - 375, - 303, - 163, - 150, - 366, - 20, - 156, - 108, - 150, - 41, - 119, - 22, - 67, - 394, - 120, - 90, - 195, - 321, - 361, - 74, - 310, - 372, - 282, - 34, - 394, - 316, - 131, - 143, - 119, - 278, - 86, - 306, - 365, - 238, - 196, - 222, - 330, - 393, - 190, - 35, - 318, - 83, - 67, - 67, - 3, - 43, - 219, - 197, - 264, - 250, - 319, - 131, - 47, - 220, - 255, - 334, - 372, - 358, - 2, - 392, - 32, - 217, - 207, - 271, - 204, - 39, - 338, - 348, - 109, - 246, - 16, - 367, - 198, - 93, - 141, - 248, - 197, - 163, - 264, - 66, - 54, - 293, - 253, - 377, - 233, - 290, - 53, - 351, - 240, - 399, - 74, - 249, - 185, - 137, - 53, - 247, - 334, - 18, - 112, - 162, - 387, - 227, - 7, - 326, - 132, - 22, - 26, - 314, - 359, - 72, - 194, - 148, - 393, - 160, - 49, - 275, - 120, - 346, - 164, - 97, - 317, - 267, - 212, - 297, - 201, - 350, - 332, - 350, - 329, - 223, - 385, - 24, - 167, - 279, - 374, - 128, - 392, - 117, - 41, - 143, - 38, - 312, - 226, - 313, - 78, - 209, - 351, - 320, - 194, - 192, - 333, - 242, - 254, - 340, - 290, - 72, - 359, - 370, - 220, - 241, - 48, - 197, - 31, - 297, - 282, - 375, - 181, - 97, - 70, - 87, - 363, - 63, - 286, - 166, - 114, - 344, - 332, - 31, - 167, - 278, - 75, - 340, - 138, - 83, - 189, - 263, - 221, - 243, - 366, - 190, - 336, - 79, - 235, - 338, - 290, - 128, - 100, - 80, - 347, - 341, - 351, - 160, - 328, - 183, - 351, - 361, - 157, - 91, - 95, - 217, - 365, - 124, - 325, - 293, - 212, - 170, - 376, - 296, - 178, - 140, - 127, - 86, - 200, - 216, - 23, - 239, - 385, - 134, - 316, - 187, - 391, - 71, - 19, - 9, - 286, - 46, - 42, - 172, - 292, - 58, - 67, - 84, - 4, - 159, - 110, - 66, - 213, - 3, - 320, - 40, - 23, - 97, - 86, - 102, - 83, - 119, - 237, - 242, - 171, - 320, - 268, - 377, - 53, - 65, - 133, - 144, - 389, - 275, - 215, - 100, - 134, - 185, - 94, - 213, - 307, - 297, - 250, - 321, - 252, - 106, - 400, - 265, - 266, - 176, - 141, - 14, - 201, - 250, - 295, - 202, - 287, - 301, - 179, - 133, - 68, - 347, - 113, - 181, - 148, - 346, - 356, - 258, - 69, - 130, - 84, - 244, - 85, - 109, - 139, - 268, - 83, - 367, - 129, - 52, - 287, - 217, - 164, - 123, - 202, - 122, - 163, - 79, - 321, - 202, - 302, - 93, - 256, - 29, - 16, - 209, - 348, - 315, - 282, - 391, - 51, - 247, - 184, - 351, - 40, - 96, - 60, - 39, - 278, - 108, - 81, - 389, - 344, - 149, - 176, - 64, - 344, - 165, - 262, - 40, - 75, - 263, - 46, - 392, - 266, - 47, - 8, - 278, - 262, - 192, - 260, - 329, - 332, - 25, - 314, - 15, - 22, - 146, - 101, - 343, - 245, - 238, - 354, - 222, - 69, - 259, - 139, - 352, - 73, - 46, - 223, - 294, - 122, - 292, - 312, - 382, - 338, - 260, - 334, - 165, - 341, - 62, - 108, - 227, - 232, - 208, - 40, - 342, - 281, - 120, - 62, - 185, - 165, - 348, - 114, - 26, - 65, - 146, - 33, - 34, - 340, - 156, - 275, - 68, - 187, - 396, - 205, - 366, - 26, - 298, - 64, - 220, - 73, - 192, - 303, - 57, - 382, - 273, - 313, - 385, - 134, - 261, - 327, - 307, - 325, - 108, - 386, - 251, - 305, - 114, - 392, - 114, - 147, - 72, - 312, - 108, - 264, - 378, - 316, - 398, - 169, - 217, - 39, - 58, - 46, - 12, - 265, - 7, - 187, - 105, - 53, - 133, - 44, - 244, - 115, - 129, - 282, - 22, - 340, - 200, - 121, - 90, - 209, - 97, - 388, - 133, - 345, - 113, - 289, - 298, - 312, - 284, - 72, - 98, - 259, - 201, - 111, - 357, - 337, - 369, - 286, - 346, - 206, - 159, - 20, - 266, - 177, - 386, - 114, - 16, - 334, - 132, - 277, - 214, - 375, - 229, - 29, - 124, - 19, - 95, - 169, - 65, - 318, - 120, - 245, - 31, - 301, - 306, - 197, - 261, - 102, - 290, - 156, - 69, - 330, - 346, - 139, - 159, - 287, - 284, - 126, - 301, - 57, - 274, - 386, - 106, - 147, - 19, - 344, - 11, - 276, - 31, - 252, - 87, - 133, - 73, - 259, - 20, - 85, - 334, - 311, - 352, - 197, - 282, - 348, - 359, - 120, - 18, - 250, - 389, - 233, - 6, - 75, - 395, - 191, - 51, - 156, - 387, - 377, - 155, - 355, - 343, - 49, - 270, - 308, - 95, - 41, - 66, - 380, - 335, - 224, - 162, - 198, - 366, - 44, - 259, - 232, - 170, - 177, - 251, - 256, - 10, - 337, - 175, - 82, - 230, - 54, - 275, - 34, - 113, - 228, - 288, - 151, - 199, - 361, - 244, - 221, - 336, - 336, - 30, - 105, - 228, - 317, - 356, - 227, - 251, - 58, - 6, - 165, - 150, - 400, - 271, - 48, - 343, - 383, - 48, - 144, - 289, - 270, - 147, - 18, - 131, - 302, - 191, - 249, - 143, - 32, - 279, - 245, - 350, - 176, - 154, - 103, - 355, - 359, - 167, - 239, - 121, - 361, - 10, - 217, - 78, - 207, - 391, - 309, - 16, - 65, - 309, - 185, - 299, - 299, - 372, - 86, - 146, - 316, - 207, - 96, - 196, - 97, - 28, - 28, - 128, - 234, - 123, - 108, - 88, - 359, - 124, - 27, - 76, - 377, - 318, - 155, - 251, - 231, - 148, - 352, - 378, - 3, - 93, - 400, - 34, - 235, - 299, - 360, - 118, - 211, - 22, - 282, - 57, - 270, - 295, - 150, - 283, - 204, - 12, - 357, - 231, - 119, - 20, - 173, - 55, - 129, - 61, - 286, - 382, - 303, - 135, - 89, - 249, - 384, - 77, - 379, - 142, - 333, - 178, - 295, - 198, - 293, - 338, - 150, - 10, - 17, - 354, - 177, - 157, - 76, - 38, - 293, - 236, - 205, - 98, - 169, - 265, - 109, - 91, - 172, - 218, - 125, - 298, - 50, - 339, - 115, - 168, - 165, - 26, - 53, - 84, - 236, - 13, - 97, - 400, - 387, - 37, - 243, - 172, - 180, - 285, - 94, - 209, - 125, - 353, - 67, - 257, - 34, - 168, - 360, - 78, - 251, - 320, - 278, - 376, - 317, - 148, - 263, - 32, - 356, - 160, - 208, - 289, - 235, - 249, - 357, - 318, - 55, - 155, - 283, - 134, - 60, - 156, - 21, - 295, - 20, - 65, - 46, - 215, - 321, - 39, - 12, - 346, - 108, - 321, - 270, - 156, - 136, - 334, - 364, - 318, - 168, - 365, - 79, - 90, - 123, - 325, - 330, - 189, - 52, - 123, - 310, - 267, - 231, - 289, - 133, - 293, - 32, - 346, - 288, - 313, - 108, - 398, - 62, - 321, - 25, - 362, - 268, - 313, - 123, - 280, - 353, - 129, - 100, - 170, - 54, - 13, - 348, - 167, - 82, - 167, - 176, - 41, - 235, - 45, - 400, - 216, - 211, - 233, - 297, - 310, - 240, - 193, - 248, - 242, - 375, - 371, - 170, - 342, - 197, - 190, - 367, - 43, - 71, - 249, - 251, - 299, - 317, - 291, - 345, - 69, - 60, - 333, - 21, - 312, - 194, - 6, - 285, - 320, - 201, - 8, - 218, - 286, - 127, - 388, - 183, - 27, - 181, - 263, - 102, - 246, - 134, - 37, - 236, - 262, - 196, - 186, - 157, - 281, - 266, - 263, - 219, - 345, - 120, - 22, - 210, - 246, - 72, - 29, - 121, - 299, - 240, - 167, - 270, - 47, - 229, - 84, - 226, - 26, - 70, - 85, - 197, - 218, - 198, - 278, - 232, - 36, - 1, - 298, - 144, - 130, - 2, - 240, - 86, - 216, - 288, - 135, - 98, - 68, - 41, - 142, - 192, - 301, - 169, - 114, - 261, - 11, - 322, - 148, - 66, - 196, - 358, - 280, - 347, - 15, - 9, - 212, - 383, - 394, - 127, - 194, - 277, - 135, - 231, - 223, - 84, - 284, - 98, - 286, - 367, - 28, - 299, - 74, - 187, - 260, - 273, - 300, - 206, - 23, - 244, - 291, - 364, - 21, - 12, - 52, - 362, - 20, - 353, - 38, - 370, - 188, - 64, - 320, - 226, - 103, - 206, - 25, - 197, - 35, - 348, - 213, - 182, - 364, - 249, - 118, - 352, - 286, - 166, - 101, - 375, - 292, - 258, - 62, - 372, - 102, - 149, - 250, - 223, - 97, - 180, - 129, - 394, - 184, - 132, - 29, - 88, - 104, - 180, - 50, - 97, - 192, - 339, - 166, - 234, - 374, - 219, - 233, - 141, - 337, - 317, - 274, - 44, - 165, - 189, - 112, - 363, - 156, - 291, - 44, - 288, - 142, - 391, - 289, - 17, - 341, - 335, - 6, - 177, - 219, - 285, - 224, - 62, - 20, - 258, - 270, - 91, - 254, - 334, - 124, - 185, - 120, - 8, - 13, - 339, - 306, - 333, - 255, - 41, - 7, - 316, - 236, - 80, - 145, - 247, - 368, - 312, - 124, - 346, - 116, - 1, - 108, - 9, - 126, - 303, - 357, - 5, - 223, - 83, - 172, - 205, - 242, - 77, - 61, - 159, - 121, - 268, - 256, - 331, - 203, - 70, - 217, - 122, - 310, - 142, - 156, - 108, - 379, - 321, - 289, - 379, - 63, - 264, - 372, - 395, - 261, - 190, - 11, - 291, - 148, - 72, - 215, - 259, - 304, - 381, - 38, - 216, - 134, - 62, - 211, - 279, - 213, - 125, - 27, - 254, - 81, - 43, - 150, - 256, - 371, - 295, - 219, - 335, - 230, - 79, - 177, - 159, - 241, - 304, - 63, - 247, - 107, - 143, - 400, - 262, - 369, - 242, - 90, - 82, - 105, - 229, - 162, - 222, - 383, - 363, - 223, - 211, - 114, - 134, - 162, - 245, - 371, - 95, - 329, - 124, - 216, - 201, - 195, - 157, - 85, - 309, - 271, - 384, - 143, - 51, - 366, - 183, - 326, - 170, - 49, - 326, - 351, - 107, - 141, - 334, - 102, - 323, - 286, - 12, - 215, - 4, - 228, - 322, - 255, - 256, - 323, - 69, - 168, - 274, - 148, - 237, - 194, - 331, - 203, - 132, - 151, - 238, - 215, - 46, - 106, - 35, - 225, - 360, - 124, - 386, - 37, - 111, - 331, - 340, - 12, - 181, - 143, - 249, - 348, - 165, - 10, - 282, - 18, - 359, - 346, - 371, - 267, - 355, - 15, - 212, - 68, - 382, - 222, - 110, - 54, - 270, - 53, - 245, - 213, - 152, - 80, - 323, - 6, - 264, - 149, - 360, - 388, - 323, - 284, - 315, - 125, - 119, - 95, - 243, - 218, - 360, - 394, - 383, - 221, - 289, - 113, - 294, - 359, - 140, - 113, - 292, - 48, - 266, - 386, - 30, - 186, - 65, - 384, - 351, - 228, - 31, - 144, - 359, - 352, - 50, - 362, - 362, - 202, - 27, - 294, - 9, - 68, - 164, - 105, - 37, - 137, - 251, - 394, - 20, - 306, - 145, - 176, - 74, - 229, - 235, - 211, - 174, - 14, - 221, - 165, - 116, - 374, - 198, - 136, - 148, - 198, - 271, - 222, - 48, - 143, - 19, - 399, - 386, - 125, - 378, - 40, - 140, - 183, - 78, - 100, - 26, - 66, - 233, - 114, - 122, - 23, - 183, - 115, - 338, - 357, - 255, - 71, - 230, - 65, - 115, - 75, - 86, - 110, - 100, - 90, - 389, - 159, - 318, - 397, - 40, - 70, - 41, - 106, - 55, - 49, - 181, - 344, - 381, - 132, - 26, - 52, - 306, - 172, - 323, - 197, - 116, - 126, - 39, - 154, - 77, - 256, - 48, - 39, - 317, - 384, - 347, - 66, - 178, - 266, - 1, - 110, - 162, - 153, - 2, - 86, - 192, - 145, - 245, - 193, - 396, - 366, - 205, - 369, - 88, - 158, - 160, - 217, - 58, - 287, - 384, - 110, - 345, - 369, - 36, - 366, - 71, - 233, - 246, - 213, - 300, - 68, - 291, - 245, - 208, - 356, - 303, - 212, - 152, - 181, - 292, - 67, - 379, - 354, - 388, - 372, - 30, - 304, - 135, - 123, - 118, - 281, - 380, - 344, - 20, - 53, - 107, - 3, - 216, - 381, - 22, - 363, - 271, - 269, - 196, - 97, - 40, - 399, - 115, - 361, - 219, - 128, - 340, - 15, - 308, - 186, - 8, - 292, - 183, - 63, - 42, - 8, - 273, - 45, - 195, - 108, - 140, - 324, - 230, - 306, - 159, - 324, - 172, - 72, - 109, - 203, - 188, - 329, - 186, - 61, - 174, - 362, - 143, - 10, - 388, - 66, - 211, - 227, - 13, - 239, - 201, - 198, - 96, - 208, - 26, - 345, - 336, - 21, - 145, - 1, - 206, - 393, - 81, - 251, - 303, - 195, - 11, - 68, - 205, - 341, - 144, - 178, - 256, - 348, - 70, - 12, - 6, - 385, - 201, - 108, - 92, - 284, - 140, - 43, - 51, - 106, - 172, - 148, - 195, - 218, - 370, - 73, - 335, - 189, - 138, - 13, - 227, - 227, - 208, - 338, - 137, - 379, - 68, - 308, - 236, - 258, - 293, - 287, - 13, - 129, - 132, - 60, - 174, - 126, - 319, - 185, - 189, - 318, - 232, - 359, - 275, - 364, - 46, - 256, - 179, - 172, - 368, - 45, - 68, - 132, - 201, - 21, - 285, - 99, - 338, - 340, - 140, - 300, - 270, - 208, - 380, - 187, - 188, - 22, - 112, - 304, - 55, - 39, - 198, - 20, - 355, - 257, - 298, - 91, - 235, - 18, - 235, - 58, - 77, - 397, - 232, - 51, - 277, - 284, - 292, - 360, - 369, - 188, - 350, - 158, - 125, - 158, - 49, - 160, - 111, - 64, - 21, - 368, - 390, - 287, - 279, - 104, - 291, - 246, - 294, - 196, - 400, - 161, - 133, - 319, - 310, - 62, - 118, - 205, - 320, - 164, - 44, - 81, - 10, - 270, - 51, - 23, - 265, - 121, - 184, - 389, - 120, - 355, - 221, - 167, - 105, - 289, - 147, - 174, - 133, - 185, - 225, - 228, - 309, - 218, - 320, - 233, - 115, - 126, - 22, - 383, - 356, - 254, - 36, - 19, - 95, - 80, - 327, - 107, - 42, - 327, - 70, - 107, - 45, - 119, - 323, - 83, - 81, - 68, - 261, - 195, - 76, - 45, - 172, - 6, - 154, - 305, - 108, - 263, - 249, - 146, - 120, - 112, - 298, - 207, - 382, - 231, - 371, - 102, - 87, - 155, - 168, - 387, - 309, - 70, - 166, - 95, - 12, - 343, - 302, - 266, - 113, - 41, - 173, - 268, - 350, - 224, - 42, - 70, - 353, - 6, - 319, - 39, - 144, - 223, - 240, - 68, - 11, - 36, - 326, - 364, - 31, - 7, - 329, - 295, - 392, - 147, - 250, - 192, - 24, - 334, - 27, - 272, - 21, - 49, - 398, - 222, - 150, - 255, - 326, - 100, - 149, - 33, - 357, - 143, - 15, - 246, - 30, - 72, - 101, - 398, - 120, - 398, - 87, - 210, - 355, - 354, - 364, - 244, - 360, - 81, - 293, - 140, - 384, - 197, - 371, - 357, - 157, - 139, - 73, - 198, - 151, - 253, - 79, - 155, - 184, - 24, - 99, - 121, - 66, - 330, - 351, - 279, - 280, - 284, - 362, - 384, - 294, - 262, - 80, - 232, - 62, - 15, - 395, - 102, - 287, - 147, - 20, - 380, - 37, - 211, - 292, - 53, - 265, - 159, - 17, - 141, - 22, - 348, - 311, - 224, - 372, - 116, - 138, - 360, - 170, - 210, - 118, - 208, - 367, - 248, - 267, - 194, - 273, - 162, - 124, - 128, - 45, - 30, - 353, - 258, - 204, - 329, - 49, - 101, - 232, - 133, - 95, - 371, - 186, - 128, - 214, - 318, - 233, - 20, - 37, - 253, - 291, - 152, - 223, - 254, - 321, - 277, - 224, - 68, - 346, - 395, - 89, - 23, - 5, - 136, - 52, - 369, - 158, - 2, - 48, - 34, - 102, - 187, - 101, - 117, - 344, - 301, - 294, - 302, - 349, - 272, - 148, - 169, - 82, - 108, - 10, - 302, - 9, - 81, - 124, - 209, - 327, - 371, - 247, - 270, - 26, - 337, - 109, - 128, - 13, - 53, - 148, - 73, - 162, - 390, - 89, - 173, - 86, - 156, - 114, - 394, - 90, - 105, - 61, - 388, - 24, - 318, - 366, - 260, - 34, - 340, - 159, - 293, - 205, - 266, - 87, - 142, - 370, - 355, - 57, - 69, - 369, - 385, - 136, - 379, - 59, - 298, - 141, - 199, - 274, - 137, - 241, - 109, - 253, - 159, - 384, - 180, - 174, - 263, - 302, - 350, - 371, - 273, - 292, - 298, - 184, - 215, - 279, - 60, - 103, - 137, - 50, - 317, - 154, - 380, - 360, - 284, - 68, - 178, - 4, - 125, - 165, - 196, - 36, - 151, - 392, - 99, - 59, - 236, - 197, - 107, - 98, - 207, - 231, - 369, - 240, - 213, - 313, - 36, - 259, - 151, - 189, - 387, - 348, - 392, - 69, - 350, - 214, - 17, - 228, - 29, - 215, - 243, - 216, - 17, - 55, - 113, - 200, - 347, - 217, - 132, - 52, - 57, - 109, - 253, - 288, - 377, - 258, - 281, - 251, - 230, - 298, - 98, - 252, - 347, - 232, - 50, - 157, - 213, - 288, - 381, - 142, - 192, - 142, - 156, - 161, - 24, - 257, - 344, - 160, - 242, - 294, - 214, - 151, - 290, - 274, - 142, - 383, - 219, - 309, - 227, - 110, - 137, - 256, - 127, - 299, - 319, - 34, - 153, - 164, - 168, - 341, - 143, - 200, - 205, - 324, - 225, - 216, - 149, - 237, - 89, - 280, - 244, - 256, - 159, - 394, - 135, - 394, - 99, - 267, - 309, - 159, - 176, - 110, - 393, - 268, - 291, - 55, - 102, - 68, - 85, - 158, - 11, - 224, - 84, - 150, - 272, - 342, - 152, - 7, - 67, - 237, - 202, - 286, - 361, - 179, - 52, - 118, - 182, - 121, - 319, - 92, - 216, - 312, - 163, - 100, - 162, - 53, - 244, - 369, - 307, - 64, - 282, - 354, - 135, - 255, - 5, - 97, - 147, - 384, - 290, - 115, - 83, - 17, - 249, - 308, - 129, - 279, - 199, - 162, - 304, - 392, - 331, - 185, - 305, - 333, - 298, - 243, - 124, - 120, - 231, - 378, - 74, - 311, - 85, - 40, - 43, - 14, - 266, - 169, - 175, - 342, - 133, - 151, - 329, - 186, - 295, - 35, - 324, - 291, - 124, - 187, - 11, - 135, - 195, - 341, - 255, - 281, - 255, - 362, - 329, - 274, - 338, - 182, - 52, - 172, - 219, - 141, - 14, - 64, - 87, - 105, - 132, - 156, - 69, - 106, - 6, - 117, - 249, - 297, - 113, - 123, - 388, - 17, - 164, - 348, - 278, - 93, - 86, - 199, - 385, - 283, - 237, - 80, - 30, - 352, - 51, - 58, - 133, - 127, - 100, - 128, - 234, - 380, - 234, - 42, - 310, - 304, - 32, - 18, - 300, - 215, - 391, - 169, - 107, - 324, - 49, - 157, - 207, - 317, - 282, - 90, - 48, - 145, - 339, - 349, - 120, - 226, - 174, - 64, - 397, - 274, - 295, - 261, - 341, - 157, - 165, - 263, - 186, - 194, - 56, - 128, - 3, - 284, - 57, - 88, - 304, - 151, - 43, - 65, - 86, - 350, - 9, - 203, - 31, - 126, - 249, - 387, - 377, - 298, - 43, - 236, - 310, - 247, - 102, - 143, - 14, - 114, - 262, - 156, - 182, - 108, - 398, - 372, - 100, - 393, - 329, - 359, - 285, - 388, - 59, - 184, - 221, - 303, - 327, - 145, - 124, - 144, - 9, - 107, - 142, - 18, - 56, - 36, - 313, - 329, - 98, - 54, - 367, - 201, - 102, - 325, - 37, - 205, - 123, - 299, - 241, - 84, - 112, - 235, - 46, - 357, - 214, - 361, - 392, - 220, - 171, - 3, - 240, - 388, - 167, - 7, - 293, - 4, - 194, - 269, - 197, - 125, - 78, - 162, - 301, - 222, - 157, - 248, - 74, - 278, - 110, - 156, - 273, - 239, - 161, - 290, - 117, - 27, - 356, - 377, - 328, - 80, - 152, - 302, - 193, - 180, - 256, - 365, - 237, - 194, - 354, - 178, - 199, - 248, - 154, - 336, - 249, - 267, - 315, - 356, - 200, - 379, - 224, - 215, - 104, - 51, - 146, - 28, - 77, - 232, - 346, - 22, - 43, - 16, - 12, - 212, - 120, - 209, - 268, - 213, - 159, - 193, - 260, - 232, - 298, - 153, - 278, - 129, - 109, - 375, - 121, - 151, - 34, - 256, - 7, - 260, - 139, - 255, - 384, - 376, - 130, - 108, - 215, - 103, - 179, - 181, - 24, - 328, - 385, - 213, - 20, - 41, - 74, - 8, - 365, - 195, - 56, - 23, - 310, - 325, - 235, - 307, - 322, - 320, - 218, - 26, - 363, - 220, - 181, - 353, - 369, - 315, - 366, - 78, - 125, - 138, - 177, - 333, - 164, - 54, - 128, - 315, - 1, - 173, - 254, - 259, - 33, - 302, - 219, - 248, - 235, - 72, - 279, - 97, - 389, - 79, - 313, - 198, - 301, - 324, - 338, - 293, - 378, - 124, - 270, - 325, - 170, - 375, - 118, - 224, - 254, - 78, - 117, - 103, - 180, - 303, - 94, - 259, - 54, - 375, - 147, - 399, - 299, - 128, - 122, - 364, - 23, - 330, - 288, - 314, - 71, - 162, - 398, - 96, - 176, - 371, - 30, - 12, - 21, - 130, - 190, - 205, - 52, - 20, - 102, - 262, - 268, - 122, - 23, - 354, - 104, - 221, - 191, - 129, - 33, - 51, - 339, - 198, - 111, - 159, - 395, - 295, - 93, - 272, - 124, - 114, - 254, - 116, - 127, - 272, - 41, - 210, - 384, - 83, - 34, - 393, - 84, - 359, - 137, - 355, - 228, - 316, - 175, - 75, - 280, - 221, - 98, - 43, - 68, - 197, - 194, - 40, - 242, - 50, - 123, - 149, - 206, - 331, - 158, - 224, - 142, - 88, - 201, - 250, - 251, - 186, - 42, - 191, - 317, - 282, - 3, - 250, - 137, - 139, - 305, - 110, - 165, - 269, - 333, - 378, - 360, - 292, - 183, - 370, - 78, - 100, - 344, - 186, - 137, - 120, - 220, - 14, - 302, - 303, - 55, - 381, - 234, - 382, - 93, - 342, - 168, - 213, - 155, - 180, - 201, - 191, - 386, - 296, - 303, - 82, - 131, - 218, - 299, - 360, - 282, - 253, - 49, - 215, - 225, - 67, - 378, - 23, - 109, - 398, - 48, - 15, - 235, - 138, - 373, - 270, - 366, - 7, - 150, - 92, - 372, - 110, - 123, - 57, - 66, - 98, - 210, - 164, - 338, - 341, - 171, - 92, - 277, - 20, - 33, - 280, - 214, - 28, - 363, - 79, - 291, - 256, - 161, - 252, - 322, - 372, - 134, - 203, - 108, - 54, - 127, - 392, - 128, - 180, - 185, - 99, - 7, - 75, - 141, - 188, - 37, - 309, - 1, - 316, - 377, - 345, - 177, - 229, - 133, - 160, - 312, - 294, - 198, - 130, - 363, - 118, - 72, - 52, - 198, - 375, - 52, - 306, - 336, - 300, - 140, - 130, - 395, - 386, - 205, - 263, - 30, - 155, - 301, - 389, - 59, - 47, - 162, - 120, - 360, - 311, - 281, - 102, - 41, - 197, - 46, - 271, - 36, - 179, - 303, - 106, - 316, - 253, - 283, - 292, - 103, - 218, - 199, - 158, - 144, - 54, - 127, - 53, - 293, - 36, - 215, - 168, - 110, - 233, - 192, - 377, - 1, - 170, - 245, - 225, - 363, - 172, - 56, - 110, - 165, - 134, - 139, - 248, - 325, - 84, - 340, - 53, - 78, - 395, - 9, - 288, - 223, - 105, - 165, - 230, - 317, - 189, - 72, - 252, - 296, - 169, - 214, - 75, - 179, - 256, - 60, - 178, - 30, - 138, - 376, - 327, - 98, - 191, - 48, - 14, - 320, - 39, - 172, - 183, - 229, - 291, - 88, - 110, - 400, - 12, - 238, - 159, - 309, - 256, - 170, - 26, - 348, - 191, - 296, - 236, - 275, - 314, - 280, - 126, - 231, - 185, - 263, - 306, - 35, - 35, - 378, - 198, - 162, - 49, - 212, - 224, - 66, - 40, - 47, - 24, - 154, - 226, - 198, - 98, - 193, - 398, - 51, - 130, - 64, - 73, - 378, - 189, - 71, - 158, - 314, - 47, - 209, - 339, - 197, - 372, - 201, - 116, - 33, - 215, - 169, - 211, - 155, - 378, - 11, - 226, - 125, - 188, - 182, - 341, - 102, - 318, - 81, - 359, - 388, - 11, - 174, - 241, - 179, - 367, - 368, - 311, - 232, - 9, - 131, - 174, - 384, - 45, - 355, - 209, - 289, - 372, - 339, - 86, - 40, - 385, - 79, - 15, - 161, - 386, - 386, - 124, - 368, - 305, - 299, - 301, - 384, - 315, - 389, - 378, - 95, - 249, - 394, - 393, - 174, - 291, - 259, - 290, - 268, - 373, - 340, - 39, - 253, - 294, - 254, - 212, - 222, - 164, - 27, - 379, - 39, - 50, - 70, - 153, - 191, - 292, - 21, - 9, - 254, - 100, - 115, - 80, - 117, - 387, - 389, - 236, - 257, - 226, - 292, - 169, - 238, - 92, - 36, - 190, - 73, - 177, - 301, - 24, - 173, - 168, - 242, - 208, - 91, - 366, - 87, - 206, - 247, - 161, - 340, - 105, - 151, - 108, - 26, - 124, - 228, - 268, - 371, - 176, - 360, - 334, - 164, - 190, - 10, - 59, - 63, - 67, - 2, - 135, - 334, - 166, - 266, - 350, - 153, - 142, - 32, - 261, - 107, - 389, - 170, - 1, - 27, - 19, - 331, - 288, - 190, - 311, - 189, - 82, - 34, - 369, - 89, - 127, - 217, - 344, - 248, - 312, - 233, - 215, - 86, - 5, - 203, - 362, - 54, - 278, - 33, - 310, - 342, - 154, - 168, - 376, - 378, - 16, - 140, - 285, - 336, - 237, - 185, - 303, - 222, - 10, - 120, - 341, - 110, - 125, - 16, - 180, - 211, - 362, - 344, - 244, - 199, - 168, - 146, - 114, - 55, - 347, - 242, - 318, - 392, - 298, - 316, - 230, - 109, - 23, - 271, - 289, - 169, - 26, - 96, - 47, - 114, - 159, - 119, - 320, - 367, - 10, - 36, - 171, - 349, - 270, - 384, - 245, - 15, - 393, - 192, - 43, - 356, - 247, - 68, - 320, - 215, - 21, - 366, - 58, - 186, - 335, - 131, - 321, - 7, - 280, - 239, - 224, - 159, - 237, - 271, - 13, - 129, - 231, - 396, - 221, - 359, - 14, - 372, - 253, - 267, - 349, - 375, - 290, - 361, - 243, - 252, - 1, - 261, - 397, - 60, - 375, - 393, - 234, - 105, - 342, - 301, - 380, - 143, - 393, - 282, - 6, - 279, - 321, - 308, - 148, - 143, - 358, - 114, - 192, - 206, - 220, - 382, - 343, - 207, - 186, - 194, - 395, - 144, - 77, - 264, - 19, - 251, - 336, - 60, - 57, - 182, - 363, - 19, - 225, - 226, - 241, - 333, - 260, - 267, - 380, - 375, - 234, - 340, - 27, - 132, - 335, - 379, - 143, - 225, - 50, - 8, - 209, - 306, - 223, - 122, - 127, - 302, - 244, - 194, - 301, - 251, - 393, - 326, - 239, - 50, - 98, - 352, - 100, - 65, - 372, - 365, - 241, - 43, - 336, - 353, - 259, - 144, - 101, - 356, - 209, - 374, - 340, - 336, - 91, - 339, - 370, - 193, - 232, - 254, - 313, - 76, - 198, - 290, - 14, - 378, - 353, - 209, - 233, - 376, - 326, - 391, - 286, - 309, - 10, - 263, - 45, - 83, - 92, - 181, - 239, - 87, - 82, - 171, - 217, - 52, - 127, - 323, - 157, - 270, - 21, - 114, - 172, - 51, - 290, - 276, - 308, - 47, - 296, - 84, - 122, - 365, - 373, - 324, - 104, - 100, - 6, - 382, - 211, - 363, - 210, - 308, - 291, - 128, - 282, - 225, - 218, - 333, - 13, - 377, - 400, - 33, - 348, - 232, - 364, - 276, - 350, - 187, - 47, - 147, - 345, - 198, - 146, - 395, - 294, - 32, - 300, - 322, - 128, - 352, - 334, - 343, - 169, - 355, - 336, - 71, - 15, - 213, - 131, - 25, - 389, - 125, - 107, - 156, - 68, - 111, - 126, - 320, - 276, - 360, - 73, - 92, - 310, - 12, - 346, - 25, - 110, - 396, - 52, - 234, - 348, - 94, - 20, - 250, - 377, - 226, - 10, - 372, - 193, - 108, - 83, - 360, - 322, - 303, - 396, - 94, - 316, - 160, - 102, - 388, - 212, - 357, - 1, - 142, - 63, - 131, - 166, - 221, - 115, - 172, - 375, - 108, - 293, - 210, - 222, - 226, - 137, - 260, - 166, - 260, - 199, - 19, - 344, - 166, - 381, - 304, - 325, - 344, - 343, - 122, - 282, - 16, - 71, - 257, - 306, - 323, - 54, - 366, - 47, - 264, - 262, - 8, - 213, - 64, - 186, - 6, - 222, - 389, - 122, - 178, - 176, - 337, - 380, - 315, - 359, - 169, - 305, - 77, - 30, - 113, - 291, - 341, - 317, - 273, - 47, - 258, - 191, - 159, - 219, - 162, - 73, - 23, - 60, - 344, - 198, - 318, - 138, - 4, - 184, - 16, - 379, - 37, - 306, - 338, - 189, - 193, - 173, - 323, - 164, - 305, - 33, - 157, - 330, - 27, - 16, - 335, - 339, - 352, - 191, - 10, - 36, - 222, - 77, - 307, - 103, - 358, - 196, - 333, - 169, - 386, - 308, - 152, - 34, - 75, - 348, - 219, - 343, - 48, - 11, - 2, - 23, - 367, - 365, - 294, - 275, - 39, - 338, - 154, - 335, - 245, - 313, - 264, - 107, - 223, - 304, - 61, - 306, - 186, - 108, - 147, - 236, - 283, - 147, - 397, - 343, - 111, - 184, - 313, - 264, - 132, - 398, - 49, - 298, - 325, - 370, - 400, - 208, - 146, - 381, - 43, - 153, - 188, - 309, - 212, - 243, - 278, - 184, - 388, - 222, - 46, - 32, - 171, - 230, - 253, - 318, - 128, - 128, - 306, - 298, - 223, - 188, - 277, - 70, - 119, - 232, - 129, - 156, - 167, - 37, - 137, - 356, - 392, - 209, - 324, - 290, - 386, - 319, - 285, - 99, - 339, - 323, - 314, - 301, - 123, - 156, - 311, - 350, - 63, - 246, - 240, - 78, - 110, - 342, - 332, - 374, - 286, - 20, - 253, - 332, - 340, - 37, - 210, - 174, - 324, - 236, - 243, - 395, - 375, - 134, - 288, - 177, - 279, - 33, - 286, - 204, - 134, - 319, - 391, - 181, - 211, - 355, - 32, - 312, - 62, - 69, - 124, - 297, - 38, - 388, - 37, - 350, - 53, - 2, - 129, - 24, - 234, - 372, - 394, - 231, - 168, - 367, - 139, - 345, - 46, - 279, - 180, - 147, - 89, - 364, - 168, - 153, - 94, - 63, - 62, - 127, - 110, - 245, - 229, - 4, - 298, - 352, - 262, - 41, - 269, - 121, - 129, - 40, - 228, - 254, - 114, - 128, - 118, - 73, - 261, - 375, - 65, - 14, - 175, - 128, - 367, - 110, - 50, - 366, - 65, - 59, - 170, - 260, - 58, - 12, - 224, - 246, - 87, - 210, - 12, - 130, - 354, - 123, - 122, - 299, - 143, - 311, - 187, - 298, - 372, - 201, - 159, - 395, - 356, - 15, - 142, - 352, - 212, - 302, - 212, - 213, - 58, - 265, - 209, - 156, - 392, - 261, - 313, - 323, - 293, - 302, - 299, - 171, - 258, - 353, - 382, - 54, - 321, - 78, - 60, - 304, - 146, - 212, - 282, - 237, - 219, - 114, - 2, - 239, - 307, - 247, - 95, - 331, - 247, - 252, - 7, - 289, - 179, - 238, - 328, - 369, - 354, - 130, - 357, - 248, - 292, - 97, - 113, - 297, - 244, - 202, - 21, - 227, - 141, - 78, - 182, - 373, - 191, - 327, - 254, - 61, - 226, - 246, - 1, - 26, - 114, - 335, - 159, - 388, - 273, - 79, - 257, - 361, - 329, - 114, - 368, - 300, - 118, - 329, - 136, - 186, - 281, - 158, - 4, - 132, - 30, - 396, - 361, - 154, - 118, - 151, - 380, - 178, - 238, - 315, - 195, - 179, - 207, - 341, - 231, - 47, - 78, - 37, - 389, - 115, - 329, - 191, - 169, - 217, - 367, - 116, - 61, - 113, - 12, - 21, - 123, - 213, - 128, - 184, - 321, - 260, - 131, - 119, - 34, - 15, - 178, - 58, - 117, - 54, - 35, - 292, - 92, - 271, - 181, - 62, - 168, - 82, - 72, - 310, - 215, - 309, - 334, - 281, - 72, - 351, - 333, - 171, - 207, - 85, - 221, - 232, - 349, - 59, - 258, - 43, - 216, - 54, - 211, - 345, - 131, - 314, - 391, - 39, - 300, - 41, - 35, - 9, - 313, - 269, - 86, - 239, - 189, - 240, - 279, - 331, - 333, - 359, - 128, - 229, - 107, - 87, - 163, - 49, - 151, - 167, - 221, - 327, - 324, - 305, - 281, - 309, - 269, - 141, - 295, - 56, - 66, - 356, - 49, - 289, - 136, - 139, - 117, - 257, - 361, - 297, - 329, - 31, - 142, - 389, - 164, - 32, - 96, - 210, - 149, - 145, - 106, - 51, - 273, - 80, - 211, - 61, - 60, - 106, - 99, - 216, - 309, - 175, - 314, - 370, - 204, - 236, - 148, - 395, - 283, - 55, - 159, - 343, - 292, - 375, - 39, - 237, - 347, - 126, - 192, - 356, - 188, - 357, - 346, - 280, - 308, - 188, - 186, - 159, - 121, - 33, - 52, - 217, - 14, - 191, - 90, - 373, - 5, - 147, - 291, - 332, - 191, - 100, - 27, - 17, - 300, - 63, - 277, - 308, - 235, - 301, - 63, - 208, - 269, - 70, - 134, - 101, - 74, - 393, - 309, - 50, - 69, - 92, - 276, - 89, - 329, - 158, - 346, - 309, - 274, - 274, - 67, - 46, - 45, - 49, - 65, - 254, - 211, - 71, - 206, - 254, - 354, - 301, - 80, - 293, - 229, - 156, - 139, - 155, - 37, - 189, - 159, - 213, - 359, - 284, - 341, - 118, - 307, - 223, - 267, - 345, - 310, - 22, - 136, - 211, - 329, - 209, - 117, - 199, - 164, - 47, - 255, - 281, - 170, - 22, - 313, - 17, - 327, - 304, - 147, - 174, - 229, - 83, - 289, - 92, - 335, - 316, - 143, - 179, - 325, - 121, - 128, - 38, - 61, - 64, - 321, - 69, - 321, - 136, - 101, - 108 - ] -} diff --git a/calyx-py/test/correctness/static/sdn_static.py b/calyx-py/test/correctness/static/sdn_static.py deleted file mode 100644 index c011ef3e4..000000000 --- a/calyx-py/test/correctness/static/sdn_static.py +++ /dev/null @@ -1,9 +0,0 @@ -# Import the sdn module, which is one level up. -import sys -import os - -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import sdn - -if __name__ == "__main__": - sdn.build(static=True).emit() diff --git a/runt.toml b/runt.toml index 8d9d77acb..db540c2ad 100644 --- a/runt.toml +++ b/runt.toml @@ -115,8 +115,8 @@ python3 {} |\ """ [[tests]] -name = "[calyx-py] static correctness" -paths = ["calyx-py/test/correctness/static/*.py"] +name = "[calyx-py] queues correctness" +paths = ["calyx-py/test/correctness/queues/*.py"] cmd = """ name=$(basename {} .py) && dir=$(dirname {}) && @@ -125,7 +125,58 @@ python3 {} |\ --through verilog \ --through dat \ -s verilog.data "$dir/$name.data" \ - -s calyx.flags "-d well-formed" \ + -s jq.expr ".memories" \ + -q +""" + +[[tests]] +name = "[calyx-py] sdn no-promote correctness" +paths = ["calyx-py/test/correctness/queues/sdn.py"] +cmd = """ +name=$(basename {} .py) && +dir=$(dirname {}) && +python3 {} |\ + fud e --from calyx --to jq \ + --through verilog \ + --through dat \ + -s verilog.data "$dir/$name.data" \ + -s calyx.flags ' -d static-promotion' \ + -s jq.expr ".memories" \ + -q +""" + +# A stanza for "non-static with promotion" is unnecessary. +# Such a stanza would have invoked `sdn.py` with no special flags. +# The catch-all queues stanza captures that case. + +[[tests]] +name = "[calyx-py] sdn static no promote correctness" +paths = ["calyx-py/test/correctness/queues/sdn.py"] +cmd = """ +name=$(basename {} .py) && +dir=$(dirname {}) && +python3 {} --static |\ + fud e --from calyx --to jq \ + --through verilog \ + --through dat \ + -s verilog.data "$dir/$name.data" \ + -s calyx.flags ' -d well-formed -d static-promotion' \ + -s jq.expr ".memories" \ + -q +""" + +[[tests]] +name = "[calyx-py] sdn static promote correctness" +paths = ["calyx-py/test/correctness/queues/sdn.py"] +cmd = """ +name=$(basename {} .py) && +dir=$(dirname {}) && +python3 {} --static |\ + fud e --from calyx --to jq \ + --through verilog \ + --through dat \ + -s verilog.data "$dir/$name.data" \ + -s calyx.flags ' -d well-formed' \ -s jq.expr ".memories" \ -q """ From 64079b5527ebaab9d0d7fcc3945f6f7dde4210cf Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 21 Dec 2023 16:51:06 +0530 Subject: [PATCH 118/189] Queues: unified, nicer runner method (#1816) * A little more neatening in SDN * Make stats component optional in runner * Make stats component optional in main * Correctly using the same method for all queues and SDN * Nix the old main method --- calyx-py/calyx/builder.py | 2 +- calyx-py/calyx/queue_call.py | 184 +++++++++++------------- calyx-py/test/correctness/queues/sdn.py | 66 +-------- 3 files changed, 88 insertions(+), 164 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 7a6ce0c0f..e95d18fa8 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -756,7 +756,7 @@ def as_control(obj): "Python sets are not supported in control programs. For a parallel" " composition use `Builder.par` instead." ) - if obj is None: + if obj is None or obj == ast.Empty: return ast.Empty() else: assert False, f"unsupported control type {type(obj)}" diff --git a/calyx-py/calyx/queue_call.py b/calyx-py/calyx/queue_call.py index 708980760..4b2170f7e 100644 --- a/calyx-py/calyx/queue_call.py +++ b/calyx-py/calyx/queue_call.py @@ -1,108 +1,10 @@ # pylint: disable=import-error +from . import py_ast as ast from calyx import queue_util import calyx.builder as cb -def insert_main(prog, queue): - """Inserts the component `main` into the program. - This will be used to `invoke` the component `queue` and feed it a list of commands. - This component will directly interface with external memories and will - finally populate an external memory with the answers. - """ - main: cb.ComponentBuilder = prog.component("main") - - # The user-facing interface of the `main` component is: - # - input 1: a list of commands - # where each command is a 2-bit unsigned integer, with the following format: - # `0`: pop - # `1`: peek - # `2`: push - # - input 2: a list of values to push - # where each value is a 32-bit unsigned integer - # the value at `i` is pushed if the command at `i` is `2`. - # - output: a list of answers, reflecting any pops or peeks from the queue. - # - # The user-facing interface of the `queue` component is assumed to be: - # - input `cmd` - # where each command is a 2-bit unsigned integer, with the following format: - # `0`: pop - # `1`: peek - # `2`: push - # - input `value` - # which is a 32-bit unsigned integer. If `cmd` is `2`, push this value. - # - one ref register, `ans`, into which the result of a pop or peek is written. - # - one ref register, `err`, which is raised if an error occurs. - - commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True) - values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) - - # We'll invoke the queue component, which takes two inputs by reference - # and one input directly. - queue = main.cell("myqueue", queue) - err = main.reg("err", 1) # A flag to indicate an error - ans = main.reg("ans", 32) # A memory to hold the answer of a pop or peek - - # We will set up a while loop that runs over the command list, relaying - # the commands to the `queue` component. - # It will run until the `err` flag is raised by the `queue` component. - - i = main.reg("i", 32) # The index of the command we're currently processing - j = main.reg("j", 32) # The index on the answer-list we'll write to - cmd = main.reg("command", 2) # The command we're currently processing - value = main.reg("value", 32) # The value we're currently processing - - incr_i = main.incr(i) # i++ - incr_j = main.incr(j) # j++ - lower_err = main.reg_store(err, 0, "lower_err") # err := 1 - - cmd_le_1 = main.le_use(cmd.out, 1) # cmd <= 1 - - read_cmd = main.mem_read_seq_d1(commands, i.out, "read_cmd_phase1") - write_cmd_to_reg = main.mem_write_seq_d1_to_reg(commands, cmd, "write_cmd_phase2") - - read_value = main.mem_read_seq_d1(values, i.out, "read_value") - write_value_to_reg = main.mem_write_seq_d1_to_reg( - values, value, "write_value_to_reg" - ) - write_ans = main.mem_store_seq_d1(ans_mem, j.out, ans.out, "write_ans") - - i_lt_max_cmds = main.lt_use(i.out, queue_util.MAX_CMDS) - not_err = main.not_use(err.out) - - main.control += cb.while_with( - i_lt_max_cmds, # Run while i < MAX_CMDS - [ - read_cmd, - write_cmd_to_reg, # `cmd := commands[i]` - read_value, - write_value_to_reg, # `value := values[i]` - cb.invoke( # Invoke the queue. - queue, - in_cmd=cmd.out, - in_value=value.out, - ref_ans=ans, - ref_err=err, - ), - cb.if_with( - not_err, - cb.if_with( - cmd_le_1, # If the command was a pop or peek, - [ - write_ans, # Write the answer to the answer list - incr_j, # And increment the answer index. - ], - ), - ), - lower_err, # Lower the error flag - incr_i, # Increment the command index - ], - ) - - return main - - -def insert_runner(prog, queue, name, stats_component): +def insert_runner(prog, queue, name, stats_component=None): """Inserts the component `name` into the program. This will be used to `invoke` the component `queue` and feed it one command. This component is designed to be invoked by some other component, and does not @@ -116,7 +18,8 @@ def insert_runner(prog, queue, name, stats_component): # We take a stats component by reference, # but all we'll really do with it is pass it to the queue component. - stats = runner.cell("stats_runner", stats_component, is_ref=True) + if stats_component: + stats = runner.cell("stats_runner", stats_component, is_ref=True) # We'll invoke the queue component. queue = runner.cell("myqueue", queue) @@ -195,6 +98,14 @@ def insert_runner(prog, queue, name, stats_component): ref_ans=ans, ref_err=err, ref_stats=stats, + ) + if stats_component + else cb.invoke( # Invoke the queue. + queue, + in_cmd=cmd.out, + in_value=value.out, + ref_ans=ans, + ref_err=err, ), # We're back from the invoke, and it's time for some post-mortem analysis. cb.if_with( @@ -212,3 +123,74 @@ def insert_runner(prog, queue, name, stats_component): ] return runner + + +def insert_main(prog, queue, controller=None, stats_component=None): + """Inserts the component `main` into the program. + It triggers the dataplane and controller components. + """ + + main: cb.ComponentBuilder = prog.component("main") + + stats = main.cell("stats_main", stats_component) if stats_component else None + controller = main.cell("controller", controller) if controller else None + dataplane = insert_runner(prog, queue, "dataplane", stats_component) + dataplane = main.cell("dataplane", dataplane) + + has_ans = main.reg("has_ans", 1) + dataplane_ans = main.reg("dataplane_ans", 32) + dataplane_err = main.reg("dataplane_err", 1) + + commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True) + values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) + ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) + + ans_neq_0 = main.neq_use(dataplane_ans.out, 0) # ans != 0 + + j = main.reg("j", 32) # The index on the answer-list we'll write to + incr_j = main.incr(j) # j++ + write_ans = main.mem_store_seq_d1(ans_mem, j.out, dataplane_ans.out, "write_ans") + # ans_mem[j] = dataplane_ans + lower_has_ans = main.reg_store(has_ans, 0, "lower_has_ans") # has_ans := 0 + + not_err = main.not_use(dataplane_err.out) + + main.control += cb.while_with( + # We will run the dataplane and controller components in sequence, + # in a while loop. The loop will terminate when the dataplane component + # raises `dataplane_err`. + not_err, # While the dataplane component has not errored out. + [ + lower_has_ans, # Lower the has-ans flag. + cb.invoke( # Invoke the dataplane component. + dataplane, + ref_commands=commands, + ref_values=values, + ref_has_ans=has_ans, + ref_component_ans=dataplane_ans, + ref_component_err=dataplane_err, + ref_stats_runner=stats, + ) + if stats_component + else cb.invoke( # Invoke the dataplane component. + dataplane, + ref_commands=commands, + ref_values=values, + ref_has_ans=has_ans, + ref_component_ans=dataplane_ans, + ref_component_err=dataplane_err, + ), + # If the dataplane component has a nonzero answer, + # write it to the answer-list and increment the index `j`. + cb.if_( + has_ans.out, + cb.if_with(ans_neq_0, [write_ans, incr_j]), + ), + cb.invoke( # Invoke the controller component. + controller, + ref_stats_controller=stats, + ) + if controller + else ast.Empty, + ], + ) diff --git a/calyx-py/test/correctness/queues/sdn.py b/calyx-py/test/correctness/queues/sdn.py index 6dd19c5a0..9a55693bb 100644 --- a/calyx-py/test/correctness/queues/sdn.py +++ b/calyx-py/test/correctness/queues/sdn.py @@ -94,71 +94,14 @@ def insert_controller(prog, name, stats_component): return controller -def insert_main(prog, dataplane, controller, stats_component): - """Inserts the component `main` into the program. - It triggers the dataplane and controller components. - """ - - main: cb.ComponentBuilder = prog.component("main") - - stats = main.cell("stats_main", stats_component) - dataplane = main.cell("dataplane", dataplane) - controller = main.cell("controller", controller) - - has_ans = main.reg("has_ans", 1) - dataplane_ans = main.reg("dataplane_ans", 32) - dataplane_err = main.reg("dataplane_err", 1) - - commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True) - values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True) - ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True) - - ans_neq_0 = main.neq_use(dataplane_ans.out, 0) # ans != 0 - - j = main.reg("j", 32) # The index on the answer-list we'll write to - incr_j = main.incr(j) # j++ - write_ans = main.mem_store_seq_d1(ans_mem, j.out, dataplane_ans.out, "write_ans") - # ans_mem[j] = dataplane_ans - lower_has_ans = main.reg_store(has_ans, 0, "lower_has_ans") # has_ans := 0 - - not_err = main.not_use(dataplane_err.out) - - main.control += cb.while_with( - # We will run the dataplane and controller components in parallel, - # in a while loop. The loop will terminate when the dataplane component - # raises `dataplane_err`. - not_err, # While the dataplane component has not errored out. - [ - lower_has_ans, # Lower the has-ans flag. - cb.invoke( # Invoke the dataplane component. - dataplane, - ref_commands=commands, - ref_values=values, - ref_has_ans=has_ans, - ref_component_ans=dataplane_ans, - ref_component_err=dataplane_err, - ref_stats_runner=stats, - ), - # If the dataplane component has a nonzero answer, - # write it to the answer-list and increment the index `j`. - cb.if_( - has_ans.out, - cb.if_with(ans_neq_0, [write_ans, incr_j]), - ), - cb.invoke( # Invoke the controller component. - controller, - ref_stats_controller=stats, - ), - ], - ) - - def build(static=False): """Top-level function to build the program. The `static` flag determines whether the program is static or dynamic. """ prog = cb.Builder() stats_component = insert_stats(prog, "stats", static) + controller = insert_controller(prog, "controller", stats_component) + fifo_purple = fifo.insert_fifo(prog, "fifo_purple") fifo_tangerine = fifo.insert_fifo(prog, "fifo_tangerine") pifo_red = pifo.insert_pifo(prog, "pifo_red", fifo_purple, fifo_tangerine, 100) @@ -167,9 +110,8 @@ def build(static=False): prog, "pifo_root", pifo_red, fifo_blue, 200, stats_component, static ) # The root PIFO will take a stats component by reference. - dataplane = queue_call.insert_runner(prog, pifo_root, "dataplane", stats_component) - controller = insert_controller(prog, "controller", stats_component) - insert_main(prog, dataplane, controller, stats_component) + + queue_call.insert_main(prog, pifo_root, controller, stats_component) return prog.program From f5cd79bef48f309f936240134231aa437c8fce41 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:25:13 -0500 Subject: [PATCH 119/189] [Calyx-FIRRTL backend] Guards and non-primitive Cells (#1817) * Initial commit: added barebones firrtl.rs as a backend option. * Fix formatting errors and try to leverage VerilogBackend * Fix formatting * first pass on inputs and outputs * fix CI formatting issue * more CI formatting fixes * temporary commit before fixing up starter code * Clean up starter firrtl translation code * Fix CI errors * Barebones test containing input/output ports and single assignment * Fix test failure caused by whitespace * clean up unnecessary comments * Port guard support and some refactoring for converting ports to FIRRTL * First steps for recursive guard building + more refactoring * Guard support and tests * Updating firrtl.rs to support guards * Fix formatting issues * additional formatting fix * Added default assignment to 0 for guard failure and fixed expected output * Added default initialization statements for assignments with guards * adding test to make sure that there's only one invalid initialization per unique dest * fixing attributes and "is invalid" initialization * First steps to support non-primitive cells * Fixing hardcoding of main as the top level component * Fix formatting errors * More formatting fixes * Remove unnecessary FIXME * Fix indentation and add comment from PR feedback * Fix small format bug --- calyx-backend/src/firrtl.rs | 168 ++++++++++++++++--- tests/backend/firrtl/and-or-not-guard.expect | 18 ++ tests/backend/firrtl/and-or-not-guard.futil | 9 + tests/backend/firrtl/basic-guard.expect | 16 ++ tests/backend/firrtl/basic-guard.futil | 9 + tests/backend/firrtl/basic-program.expect | 1 + tests/backend/firrtl/comparison-guard.expect | 18 ++ tests/backend/firrtl/comparison-guard.futil | 9 + tests/backend/firrtl/or-guard.expect | 17 ++ tests/backend/firrtl/or-guard.futil | 9 + tests/backend/firrtl/two-or-guards.expect | 21 +++ tests/backend/firrtl/two-or-guards.futil | 10 ++ 12 files changed, 282 insertions(+), 23 deletions(-) create mode 100644 tests/backend/firrtl/and-or-not-guard.expect create mode 100644 tests/backend/firrtl/and-or-not-guard.futil create mode 100644 tests/backend/firrtl/basic-guard.expect create mode 100644 tests/backend/firrtl/basic-guard.futil create mode 100644 tests/backend/firrtl/comparison-guard.expect create mode 100644 tests/backend/firrtl/comparison-guard.futil create mode 100644 tests/backend/firrtl/or-guard.expect create mode 100644 tests/backend/firrtl/or-guard.futil create mode 100644 tests/backend/firrtl/two-or-guards.expect create mode 100644 tests/backend/firrtl/two-or-guards.futil diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs index 06903f198..cce0181a1 100644 --- a/calyx-backend/src/firrtl.rs +++ b/calyx-backend/src/firrtl.rs @@ -4,8 +4,9 @@ //! valid FIRRTL program. use crate::{traits::Backend, VerilogBackend}; -use calyx_ir::{self as ir}; +use calyx_ir::{self as ir, RRC}; use calyx_utils::{CalyxResult, OutputFile}; +use std::collections::HashSet; use std::io; pub(super) const SPACING: &str = " "; @@ -33,6 +34,14 @@ impl Backend for FirrtlBackend { fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { let out = &mut file.get_write(); + let mut top_level_component = String::from("main"); + // Quick pass to check whether there exists a top-level component that we should replace main with. + for comp in ctx.components.iter() { + if comp.attributes.has(ir::BoolAttr::TopLevel) { + top_level_component = comp.name.to_string().clone(); + } + } + writeln!(out, "circuit {}:", top_level_component)?; for comp in ctx.components.iter() { emit_component(comp, out)? } @@ -45,7 +54,6 @@ fn emit_component( comp: &ir::Component, f: &mut F, ) -> io::Result<()> { - writeln!(f, "circuit {}:", comp.name)?; writeln!(f, "{}module {}:", SPACING, comp.name)?; // Inputs and Outputs @@ -84,41 +92,108 @@ fn emit_component( // Add a COMPONENT START: anchor before any code in the component writeln!(f, "{}; COMPONENT START: {}", SPACING.repeat(2), comp.name)?; - // TODO: Cells. NOTE: leaving this one for last + // Cells + for cell in comp.cells.iter() { + let cell_borrowed = cell.as_ref().borrow(); + if cell_borrowed.type_name().is_some() { + match cell_borrowed.prototype { + ir::CellType::Primitive { + name: _, + param_binding: _, + is_comb: _, + latency: _, + } => { + // TODO: use extmodules + writeln!( + f, + "{}; FIXME: attempting to instantiate primitive cell {}", + SPACING.repeat(2), + cell_borrowed.name() + )?; + } + ir::CellType::Component { name } => { + writeln!( + f, + "{}inst {} of {}", + SPACING.repeat(2), + cell_borrowed.name(), + name + )?; + } + ir::CellType::ThisComponent => unreachable!(), + ir::CellType::Constant { val: _, width: _ } => unreachable!(), + } + } + } + let mut dst_set: HashSet = HashSet::new(); + // Emit assignments for asgn in &comp.continuous_assignments { - // TODO: guards match asgn.guard.as_ref() { - ir::Guard::Or(_, _) => todo!(), - ir::Guard::And(_, _) => todo!(), - ir::Guard::Not(_) => todo!(), ir::Guard::True => { // Simple assignment with no guard - let _ = write_assignment(asgn, f); + let _ = write_assignment(asgn, f, 2); + } + _ => { + let dst_canonical = &asgn.dst.as_ref().borrow().canonical(); + let dst_canonical_str = dst_canonical.to_string(); + if !dst_set.contains(&dst_canonical_str) { + // if we don't have a "is invalid" statement yet, then we have to write one. + // an alternative "eager" approach would be to instantiate all possible ports + // (our output ports + all children's input ports) up front. + let _ = write_invalid_initialization(&asgn.dst, f); + dst_set.insert(dst_canonical_str); + } + // need to write out the guard. + let guard_string = get_guard_string(asgn.guard.as_ref()); + writeln!(f, "{}when {}:", SPACING.repeat(2), guard_string)?; + let _ = write_assignment(asgn, f, 3); } - ir::Guard::CompOp(_, _, _) => todo!(), - ir::Guard::Port(_) => {} - ir::Guard::Info(_) => todo!(), } } // Add COMPONENT END: anchor - writeln!(f, "{}; COMPONENT END: {}", SPACING.repeat(2), comp.name)?; + writeln!(f, "{}; COMPONENT END: {}\n", SPACING.repeat(2), comp.name)?; Ok(()) } -// Writes a FIRRTL assignment -fn write_assignment( - asgn: &ir::Assignment, - f: &mut F, -) -> CalyxResult<()> { - let dest_port = asgn.dst.borrow(); - let dest_string = get_port_string(&dest_port, true); - let source_port = asgn.src.borrow(); - let src_string = get_port_string(&source_port, false); - writeln!(f, "{}{} <= {}", SPACING.repeat(2), dest_string, src_string)?; - Ok(()) +// recursive function that writes the FIRRTL representation for a guard. +fn get_guard_string(guard: &ir::Guard) -> String { + match guard { + ir::Guard::Or(l, r) => { + let l_str = get_guard_string(l.as_ref()); + let r_str = get_guard_string(r.as_ref()); + format!("or({}, {})", l_str, r_str) + } + ir::Guard::And(l, r) => { + let l_str = get_guard_string(l.as_ref()); + let r_str = get_guard_string(r.as_ref()); + format!("and({}, {})", l_str, r_str) + } + ir::Guard::Not(g) => { + let g_str = get_guard_string(g); + format!("not({})", g_str) + } + ir::Guard::True => String::from(""), + ir::Guard::CompOp(op, l, r) => { + let l_str = get_port_string(&l.borrow(), false); + let r_str = get_port_string(&r.borrow(), false); + let op_str = match op { + ir::PortComp::Eq => "eq", + ir::PortComp::Neq => "neq", + ir::PortComp::Gt => "gt", + ir::PortComp::Lt => "lt", + ir::PortComp::Geq => "geq", + ir::PortComp::Leq => "leq", + }; + format!("{}({}, {})", op_str, l_str, r_str) + } + ir::Guard::Port(port) => get_port_string(&port.borrow().clone(), false), + ir::Guard::Info(_) => { + panic!("guard should not have info") + } + } } // returns the FIRRTL translation of a port. @@ -147,3 +222,50 @@ fn get_port_string(port: &calyx_ir::Port, is_dst: bool) -> String { } } } + +// variables that get set in assignments should get initialized to avoid the FIRRTL compiler from erroring. +fn write_invalid_initialization( + port: &RRC, + f: &mut F, +) -> CalyxResult<()> { + let default_initialization_str = "; default initialization"; + let dst_string = get_port_string(&port.borrow(), true); + if port.borrow().attributes.has(ir::BoolAttr::Control) { + writeln!( + f, + "{}{} <= UInt(0) {}", + SPACING.repeat(2), + dst_string, + default_initialization_str + )?; + } else { + writeln!( + f, + "{}{} is invalid {}", + SPACING.repeat(2), + dst_string, + default_initialization_str + )?; + } + Ok(()) +} + +// Writes a FIRRTL assignment +fn write_assignment( + asgn: &ir::Assignment, + f: &mut F, + num_indent: usize, +) -> CalyxResult<()> { + let dest_port = asgn.dst.borrow(); + let dest_string = get_port_string(&dest_port, true); + let source_port = asgn.src.borrow(); + let src_string = get_port_string(&source_port, false); + writeln!( + f, + "{}{} <= {}", + SPACING.repeat(num_indent), + dest_string, + src_string + )?; + Ok(()) +} diff --git a/tests/backend/firrtl/and-or-not-guard.expect b/tests/backend/firrtl/and-or-not-guard.expect new file mode 100644 index 000000000..e0dea86d9 --- /dev/null +++ b/tests/backend/firrtl/and-or-not-guard.expect @@ -0,0 +1,18 @@ +circuit main: + module main: + input in: UInt<32> + input cond: UInt<1> + input cond2: UInt<1> + input cond3: UInt<1> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out is invalid ; default initialization + when and(or(not(cond), cond2), cond3): + out <= in + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/and-or-not-guard.futil b/tests/backend/firrtl/and-or-not-guard.futil new file mode 100644 index 000000000..14356fc03 --- /dev/null +++ b/tests/backend/firrtl/and-or-not-guard.futil @@ -0,0 +1,9 @@ +// -b firrtl +component main(in : 32, cond: 1, cond2 : 1, cond3 : 1) -> (out : 32) { + cells {} + wires { + out = (!cond | cond2) & cond3 ? in; + done = 1'd1; + } + control {} +} diff --git a/tests/backend/firrtl/basic-guard.expect b/tests/backend/firrtl/basic-guard.expect new file mode 100644 index 000000000..1545e6ccb --- /dev/null +++ b/tests/backend/firrtl/basic-guard.expect @@ -0,0 +1,16 @@ +circuit main: + module main: + input in: UInt<32> + input cond: UInt<1> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out is invalid ; default initialization + when cond: + out <= in + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/basic-guard.futil b/tests/backend/firrtl/basic-guard.futil new file mode 100644 index 000000000..36fedfdb6 --- /dev/null +++ b/tests/backend/firrtl/basic-guard.futil @@ -0,0 +1,9 @@ +// -b firrtl +component main(in : 32, cond: 1) -> (out : 32) { + cells {} + wires { + out = cond ? in; + done = 1'd1; + } + control {} +} diff --git a/tests/backend/firrtl/basic-program.expect b/tests/backend/firrtl/basic-program.expect index 73af9081f..caabab6c9 100644 --- a/tests/backend/firrtl/basic-program.expect +++ b/tests/backend/firrtl/basic-program.expect @@ -10,3 +10,4 @@ circuit main: done <= UInt(1) out <= in ; COMPONENT END: main + diff --git a/tests/backend/firrtl/comparison-guard.expect b/tests/backend/firrtl/comparison-guard.expect new file mode 100644 index 000000000..ba15ed71c --- /dev/null +++ b/tests/backend/firrtl/comparison-guard.expect @@ -0,0 +1,18 @@ +circuit main: + module main: + input in: UInt<32> + input var: UInt<32> + input var2: UInt<32> + input cond3: UInt<1> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out is invalid ; default initialization + when and(leq(var, var2), cond3): + out <= in + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/comparison-guard.futil b/tests/backend/firrtl/comparison-guard.futil new file mode 100644 index 000000000..0e817516c --- /dev/null +++ b/tests/backend/firrtl/comparison-guard.futil @@ -0,0 +1,9 @@ +// -b firrtl +component main(in : 32, var: 32, var2 : 32, cond3 : 1) -> (out : 32) { + cells {} + wires { + out = (var <= var2) & cond3 ? in; + done = 1'd1; + } + control {} +} diff --git a/tests/backend/firrtl/or-guard.expect b/tests/backend/firrtl/or-guard.expect new file mode 100644 index 000000000..adb0e8311 --- /dev/null +++ b/tests/backend/firrtl/or-guard.expect @@ -0,0 +1,17 @@ +circuit main: + module main: + input in: UInt<32> + input cond: UInt<1> + input cond2: UInt<1> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out is invalid ; default initialization + when or(cond, cond2): + out <= in + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/or-guard.futil b/tests/backend/firrtl/or-guard.futil new file mode 100644 index 000000000..15cc0b126 --- /dev/null +++ b/tests/backend/firrtl/or-guard.futil @@ -0,0 +1,9 @@ +// -b firrtl +component main(in : 32, cond: 1, cond2 : 1) -> (out : 32) { + cells {} + wires { + out = cond | cond2 ? in; + done = 1'd1; + } + control {} +} diff --git a/tests/backend/firrtl/two-or-guards.expect b/tests/backend/firrtl/two-or-guards.expect new file mode 100644 index 000000000..cbd7c2e54 --- /dev/null +++ b/tests/backend/firrtl/two-or-guards.expect @@ -0,0 +1,21 @@ +circuit main: + module main: + input in: UInt<32> + input in2: UInt<32> + input cond: UInt<1> + input cond2: UInt<1> + input cond3: UInt<1> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + done <= UInt(1) + out is invalid ; default initialization + when or(cond, cond2): + out <= in + when or(cond2, cond3): + out <= in2 + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/two-or-guards.futil b/tests/backend/firrtl/two-or-guards.futil new file mode 100644 index 000000000..07c388d77 --- /dev/null +++ b/tests/backend/firrtl/two-or-guards.futil @@ -0,0 +1,10 @@ +// -b firrtl +component main(in : 32, in2 : 32, cond: 1, cond2 : 1, cond3 : 1) -> (out : 32) { + cells {} + wires { + out = cond | cond2 ? in; + out = cond2 | cond3 ? in2; + done = 1'd1; + } + control {} +} From 8ee390a7a1dd630268eceb0820688cbfdbcd0593 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Thu, 21 Dec 2023 11:38:03 -0500 Subject: [PATCH 120/189] Better parsing and help for pass options (#1819) * start working on better option parsing for passes * add stderr to OutputFile * migrate to new parser * fix incorrect name * replace --list-passes with pass-help * remove mentions of --list-passes * print domination information on stderr --- calyx-opt/src/pass_manager.rs | 31 ++- calyx-opt/src/passes/comb_prop.rs | 12 +- calyx-opt/src/passes/component_iniliner.rs | 23 +- calyx-opt/src/passes/infer_share.rs | 37 ++- calyx-opt/src/passes/schedule_compaction.rs | 2 +- .../src/passes/top_down_compile_control.rs | 20 +- .../src/passes/top_down_static_timing/tdst.rs | 16 +- calyx-opt/src/traversal/construct.rs | 254 ++++++++++++++++++ calyx-opt/src/traversal/mod.rs | 4 +- calyx-opt/src/traversal/visitor.rs | 99 +------ calyx-utils/src/out_file.rs | 25 +- interp/src/interpreter/control_interpreter.rs | 4 +- interp/src/main.rs | 2 +- src/cmdline.rs | 26 +- src/main.rs | 21 +- tests/passes/dom-map-static/par-if.expect | 56 ++-- tests/passes/dom-map-static/par-if.futil | 14 +- tests/passes/dom-map-static/repeat.expect | 24 +- tests/passes/dom-map-static/repeat.futil | 14 +- tests/passes/domination-map/blank.expect | 13 +- tests/passes/domination-map/blank.futil | 10 +- .../passes/domination-map/complex-test.expect | 53 ++-- .../passes/domination-map/complex-test.futil | 14 +- tests/passes/domination-map/dyn-repeat.expect | 17 +- tests/passes/domination-map/dyn-repeat.futil | 16 +- .../domination-map/empty-fbranch.expect | 29 +- .../passes/domination-map/empty-fbranch.futil | 10 +- .../passes/domination-map/if-dominated.expect | 23 +- .../passes/domination-map/if-dominated.futil | 12 +- tests/passes/domination-map/nested-seq.expect | 19 +- tests/passes/domination-map/nested-seq.futil | 8 +- .../domination-map/par-if-nested.expect | 41 +-- .../passes/domination-map/par-if-nested.futil | 6 +- tests/passes/domination-map/static-par.expect | 39 +-- tests/passes/domination-map/static-par.futil | 12 +- .../passes/domination-map/while-nested.expect | 31 +-- .../passes/domination-map/while-nested.futil | 10 +- 37 files changed, 655 insertions(+), 392 deletions(-) create mode 100644 calyx-opt/src/traversal/construct.rs diff --git a/calyx-opt/src/pass_manager.rs b/calyx-opt/src/pass_manager.rs index 9f28acc32..ccfa2f2a7 100644 --- a/calyx-opt/src/pass_manager.rs +++ b/calyx-opt/src/pass_manager.rs @@ -48,8 +48,15 @@ impl PassManager { }); self.passes.insert(name.clone(), pass_closure); let mut help = format!("- {}: {}", name, Pass::description()); - for (opt, desc) in Pass::opts() { - write!(&mut help, "\n * {}: {}", opt, desc).unwrap(); + for opt in Pass::opts() { + write!( + &mut help, + "\n * {}: {} (default: {})", + opt.name(), + opt.description(), + opt.default() + ) + .unwrap(); } self.help.insert(name, help); Ok(()) @@ -86,10 +93,24 @@ impl PassManager { Ok(()) } + /// Return the help string for a specific pass. + pub fn specific_help(&self, pass: &str) -> Option { + self.help.get(pass).cloned().or_else(|| { + self.aliases.get(pass).map(|passes| { + let pass_str = passes + .iter() + .map(|p| format!("- {p}")) + .collect::>() + .join("\n"); + format!("`{pass}' is an alias for pass pipeline:\n{}", pass_str) + }) + }) + } + /// Return a string representation to show all available passes and aliases. /// Appropriate for help text. - pub fn show_names(&self) -> String { - let mut ret = String::with_capacity(100); + pub fn complete_help(&self) -> String { + let mut ret = String::with_capacity(1000); // Push all passes. let mut pass_names = self.passes.keys().collect::>(); @@ -145,7 +166,7 @@ impl PassManager { passes.iter().chain(excl_set.iter()).try_for_each(|pass| { if !self.passes.contains_key(pass) { Err(Error::misc(format!( - "Unknown pass: {pass}. Run compiler with --list-passes to view registered passes." + "Unknown pass: {pass}. Run compiler with pass-help subcommand to view registered passes." ))) } else { Ok(()) diff --git a/calyx-opt/src/passes/comb_prop.rs b/calyx-opt/src/passes/comb_prop.rs index e4455abb8..566e2f6d4 100644 --- a/calyx-opt/src/passes/comb_prop.rs +++ b/calyx-opt/src/passes/comb_prop.rs @@ -1,4 +1,6 @@ -use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; +use crate::traversal::{ + Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, +}; use calyx_ir::{self as ir, RRC}; use itertools::Itertools; use std::rc::Rc; @@ -200,7 +202,7 @@ impl ConstructVisitor for CombProp { { let opts = Self::get_opts(ctx); Ok(CombProp { - no_eliminate: opts[0], + no_eliminate: opts[&"no-eliminate"].bool(), }) } @@ -218,10 +220,12 @@ impl Named for CombProp { "propagate unconditional continuous assignments" } - fn opts() -> &'static [(&'static str, &'static str)] { - &[( + fn opts() -> Vec { + vec![PassOpt::new( "no-eliminate", "mark dead assignments with @dead instead of removing them", + ParseVal::Bool(false), + PassOpt::parse_bool, )] } } diff --git a/calyx-opt/src/passes/component_iniliner.rs b/calyx-opt/src/passes/component_iniliner.rs index f7dd93d42..8699513d3 100644 --- a/calyx-opt/src/passes/component_iniliner.rs +++ b/calyx-opt/src/passes/component_iniliner.rs @@ -1,6 +1,7 @@ use crate::analysis; use crate::traversal::{ - Action, ConstructVisitor, Named, Order, VisResult, Visitor, + Action, ConstructVisitor, Named, Order, ParseVal, PassOpt, VisResult, + Visitor, }; use calyx_ir::{self as ir, rewriter, GetAttributes, LibrarySignatures, RRC}; use calyx_utils::Error; @@ -44,13 +45,20 @@ impl Named for ComponentInliner { "inline all component instances marked with @inline attribute" } - fn opts() -> &'static [(&'static str, &'static str)] { - &[ - ( + fn opts() -> Vec { + vec![ + PassOpt::new( "always", "Attempt to inline all components into the main component", + ParseVal::Bool(false), + PassOpt::parse_bool, + ), + PassOpt::new( + "new-fsms", + "Instantiate new FSM for each inlined component", + ParseVal::Bool(false), + PassOpt::parse_bool, ), - ("new-fsms", "Instantiate new FSM for each inlined component"), ] } } @@ -75,7 +83,10 @@ impl ConstructVisitor for ComponentInliner { Self: Sized, { let opts = Self::get_opts(ctx); - Ok(ComponentInliner::new(opts[0], opts[1])) + Ok(ComponentInliner::new( + opts[&"always"].bool(), + opts[&"new-fsms"].bool(), + )) } fn clear_data(&mut self) { diff --git a/calyx-opt/src/passes/infer_share.rs b/calyx-opt/src/passes/infer_share.rs index 93b6e6bea..7a81e4cf2 100644 --- a/calyx-opt/src/passes/infer_share.rs +++ b/calyx-opt/src/passes/infer_share.rs @@ -1,9 +1,10 @@ use crate::analysis::{DominatorMap, ShareSet}; use crate::traversal::{ - Action, ConstructVisitor, Named, Order, VisResult, Visitor, + Action, ConstructVisitor, Named, Order, ParseVal, PassOpt, VisResult, + Visitor, }; use calyx_ir as ir; -use calyx_utils::CalyxResult; +use calyx_utils::{CalyxResult, OutputFile}; /// This pass checks if components are (state) shareable. Here is the process it /// goes through: if a component uses any ref cells, or non-shareable cells then it @@ -11,8 +12,8 @@ use calyx_utils::CalyxResult; /// cell is guaranteed to be dominated by a write to the same cell-- we check this /// by building a domination map. If so, component is state shareable. pub struct InferShare { - print_dmap: bool, - print_static_analysis: bool, + print_dmap: Option, + print_static_analysis: Option, state_shareable: ShareSet, shareable: ShareSet, //name of main (so we can skip it) @@ -28,12 +29,19 @@ impl Named for InferShare { "Infer User Defined Components as Shareable" } - fn opts() -> &'static [(&'static str, &'static str)] { - &[ - ("print-dmap", "Print the domination map"), - ( + fn opts() -> Vec { + vec![ + PassOpt::new( + "print-dmap", + "Print the domination map", + ParseVal::OutStream(OutputFile::Null), + PassOpt::parse_outstream, + ), + PassOpt::new( "print-static-analysis", "Prints the domination analysis for static dmaps", + ParseVal::OutStream(OutputFile::Null), + PassOpt::parse_outstream, ), ] } @@ -50,8 +58,9 @@ impl ConstructVisitor for InferShare { let shareable = ShareSet::from_context::(ctx); Ok(InferShare { - print_dmap: opts[0], - print_static_analysis: opts[1], + print_dmap: opts[&"print-dmap"].not_null_outstream(), + print_static_analysis: opts[&"print-static-analysis"] + .not_null_outstream(), state_shareable, shareable, main: ctx.entrypoint, @@ -104,11 +113,11 @@ impl Visitor for InferShare { DominatorMap::new(&mut comp.control.borrow_mut(), comp.name); // print the domination map if command line argument says so - if self.print_dmap { - println!("{dmap:?}"); + if let Some(s) = &self.print_dmap { + write!(s.get_write(), "{dmap:?}").unwrap(); } - if self.print_static_analysis { - println!("{:?}", dmap.static_par_domination); + if let Some(s) = &self.print_static_analysis { + write!(s.get_write(), "{:?}", dmap.static_par_domination).unwrap(); } for (node, dominators) in dmap.map.iter_mut() { diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index b3b3b93b5..c18bca763 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -20,7 +20,7 @@ impl Named for ScheduleCompaction { } fn description() -> &'static str { - "Aggressively compact schedule for static seqs which were promoted from generic seqs" + "compact execution scheduled for reschedulable static programs" } } diff --git a/calyx-opt/src/passes/top_down_compile_control.rs b/calyx-opt/src/passes/top_down_compile_control.rs index 8a72426cc..44c31cc50 100644 --- a/calyx-opt/src/passes/top_down_compile_control.rs +++ b/calyx-opt/src/passes/top_down_compile_control.rs @@ -1,6 +1,8 @@ use super::math_utilities::get_bit_width_from; use crate::passes; -use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; +use crate::traversal::{ + Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, +}; use calyx_ir::{self as ir, GetAttributes, LibrarySignatures, Printer, RRC}; use calyx_ir::{build_assignments, guard, structure}; use calyx_utils::CalyxResult; @@ -780,8 +782,8 @@ impl ConstructVisitor for TopDownCompileControl { let opts = Self::get_opts(ctx); Ok(TopDownCompileControl { - dump_fsm: opts[0], - early_transitions: opts[1], + dump_fsm: opts[&"dump-fsm"].bool(), + early_transitions: opts[&"early-transitions"].bool(), }) } @@ -799,15 +801,19 @@ impl Named for TopDownCompileControl { "Top-down compilation for removing control constructs" } - fn opts() -> &'static [(&'static str, &'static str)] { - &[ - ( + fn opts() -> Vec { + vec![ + PassOpt::new( "dump-fsm", "Print out the state machine implementing the schedule", + ParseVal::Bool(false), + PassOpt::parse_bool, ), - ( + PassOpt::new( "early-transitions", "Experimental: Enable early transitions for group enables", + ParseVal::Bool(false), + PassOpt::parse_bool, ), ] } diff --git a/calyx-opt/src/passes/top_down_static_timing/tdst.rs b/calyx-opt/src/passes/top_down_static_timing/tdst.rs index c5295771d..fdc183c4a 100644 --- a/calyx-opt/src/passes/top_down_static_timing/tdst.rs +++ b/calyx-opt/src/passes/top_down_static_timing/tdst.rs @@ -2,7 +2,9 @@ use super::compute_states::{END, START}; use crate::analysis::WithStatic; use crate::passes::top_down_static_timing::{ComputeStates, Normalize}; use crate::passes::{self, math_utilities::get_bit_width_from}; -use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; +use crate::traversal::{ + Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, +}; use calyx_ir::{ self as ir, build_assignments, guard, structure, GetAttributes, LibrarySignatures, Printer, RRC, @@ -759,8 +761,8 @@ impl ConstructVisitor for TopDownStaticTiming { let opts = Self::get_opts(ctx); Ok(TopDownStaticTiming { - dump_fsm: opts[0], - force: opts[1], + dump_fsm: opts[&"dump-fsm"].bool(), + force: opts[&"force"].bool(), }) } @@ -778,10 +780,10 @@ impl Named for TopDownStaticTiming { "Top-down latency-sensitive compilation for removing control constructs" } - fn opts() -> &'static [(&'static str, &'static str)] { - &[ - ("dump-fsm", "Print out the state machine implementing the schedule"), - ("force", "Error if the program cannot be fully compiled using static timing") + fn opts() -> Vec { + vec![ + PassOpt::new("dump-fsm", "Print out the state machine implementing the schedule", ParseVal::Bool(false), PassOpt::parse_bool), + PassOpt::new("force", "Error if the program cannot be fully compiled using static timing", ParseVal::Bool(false), PassOpt::parse_bool) ] } } diff --git a/calyx-opt/src/traversal/construct.rs b/calyx-opt/src/traversal/construct.rs new file mode 100644 index 000000000..9f9ff3b76 --- /dev/null +++ b/calyx-opt/src/traversal/construct.rs @@ -0,0 +1,254 @@ +use super::Visitor; +use calyx_ir as ir; +use calyx_utils::{CalyxResult, OutputFile}; +use itertools::Itertools; +use linked_hash_map::LinkedHashMap; + +#[derive(Clone)] +/// The value returned from parsing an option. +pub enum ParseVal { + /// A boolean option. + Bool(bool), + /// A number option. + Num(usize), + /// A list of values. + List(Vec), + /// An output stream (stdout, stderr, file name) + OutStream(OutputFile), +} + +impl ParseVal { + pub fn bool(&self) -> bool { + let ParseVal::Bool(b) = self else { + panic!("Expected bool, got {self}"); + }; + *b + } + + pub fn num(&self) -> usize { + let ParseVal::Num(n) = self else { + panic!("Expected number, got {self}"); + }; + *n + } + + pub fn num_list(&self) -> Vec { + match self { + ParseVal::List(l) => { + l.iter().map(ParseVal::num).collect::>() + } + _ => panic!("Expected list of numbers, got {self}"), + } + } + + /// Returns an output stream if it is not the null stream + pub fn not_null_outstream(&self) -> Option { + match self { + ParseVal::OutStream(o) => { + if matches!(o, OutputFile::Null) { + None + } else { + Some(o.clone()) + } + } + _ => panic!("Expected output stream, got {self}"), + } + } +} +impl std::fmt::Display for ParseVal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParseVal::Bool(b) => write!(f, "{b}"), + ParseVal::Num(n) => write!(f, "{n}"), + ParseVal::List(l) => { + write!(f, "[")?; + for (i, e) in l.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{e}")?; + } + write!(f, "]") + } + ParseVal::OutStream(o) => write!(f, "{}", o.to_string()), + } + } +} + +/// Option that can be passed to a pass. +pub struct PassOpt { + name: &'static str, + description: &'static str, + default: ParseVal, + parse: fn(&str) -> Option, +} + +impl PassOpt { + pub const fn new( + name: &'static str, + description: &'static str, + default: ParseVal, + parse: fn(&str) -> Option, + ) -> Self { + Self { + name, + description, + default, + parse, + } + } + + pub const fn name(&self) -> &'static str { + self.name + } + + pub const fn description(&self) -> &'static str { + self.description + } + + pub const fn default(&self) -> &ParseVal { + &self.default + } + + fn parse(&self, s: &str) -> Option { + (self.parse)(s) + } + + /// Parse of list using parser for the elements. + /// Returns `None` if any of the elements fail to parse. + fn parse_list( + s: &str, + parse: fn(&str) -> Option, + ) -> Option { + let mut res = Vec::new(); + for e in s.split(',') { + res.push(parse(e)?); + } + Some(ParseVal::List(res)) + } + + pub fn parse_bool(s: &str) -> Option { + match s { + "true" => Some(ParseVal::Bool(true)), + "false" => Some(ParseVal::Bool(false)), + _ => None, + } + } + + /// Parse a number from a string. + pub fn parse_num(s: &str) -> Option { + s.parse::().ok().map(ParseVal::Num) + } + + /// Parse a list of numbers from a string. + pub fn parse_num_list(s: &str) -> Option { + Self::parse_list(s, Self::parse_num) + } + + pub fn parse_outstream(s: &str) -> Option { + s.parse::().ok().map(ParseVal::OutStream) + } +} + +/// Trait that describes named things. Calling [`do_pass`](Visitor::do_pass) and [`do_pass_default`](Visitor::do_pass_default). +/// require this to be implemented. +/// +/// This has to be a separate trait from [`Visitor`] because these methods don't recieve `self` which +/// means that it is impossible to create dynamic trait objects. +pub trait Named { + /// The name of a pass. Is used for identifying passes. + fn name() -> &'static str; + /// A short description of the pass. + fn description() -> &'static str; + /// Set of options that can be passed to the pass. + /// The options contains a tuple of the option name and a description. + fn opts() -> Vec { + vec![] + } +} + +/// Trait defining method that can be used to construct a Visitor from an +/// [ir::Context]. +/// This is useful when a pass needs to construct information using the context +/// *before* visiting the components. +/// +/// For passes that don't need to use the context, this trait can be automatically +/// be derived from [Default]. +pub trait ConstructVisitor { + fn get_opts(ctx: &ir::Context) -> LinkedHashMap<&'static str, ParseVal> + where + Self: Named, + { + let opts = Self::opts(); + let n = Self::name(); + let mut values: LinkedHashMap<&'static str, ParseVal> = ctx + .extra_opts + .iter() + .filter_map(|opt| { + // The format is either -x pass:opt or -x pass:opt=val + let mut splits = opt.split(':'); + if let Some(pass) = splits.next() { + if pass == n { + let mut splits = splits.next()?.split('='); + let opt = splits.next()?.to_string(); + let Some(opt) = opts.iter().find(|o| o.name == opt) else { + log::warn!("Ignoring unknown option for pass `{n}`: {opt}"); + return None; + }; + let val = if let Some(v) = splits.next() { + let Some(v) = opt.parse(v) else { + log::warn!( + "Ignoring invalid value for option `{n}:{}`: {v}", + opt.name(), + ); + return None; + }; + v + } else { + ParseVal::Bool(true) + }; + return Some((opt.name(), val)); + } + } + None + }) + .collect(); + + if log::log_enabled!(log::Level::Debug) { + log::debug!( + "Extra options for {}: {}", + Self::name(), + values.iter().map(|(o, v)| format!("{o}->{v}")).join(", ") + ); + } + + // For all options that were not provided with values, fill in the defaults. + for opt in opts { + if !values.contains_key(opt.name()) { + values.insert(opt.name(), opt.default.clone()); + } + } + + values + } + + /// Construct the visitor using information from the Context + fn from(_ctx: &ir::Context) -> CalyxResult + where + Self: Sized; + + /// Clear the data stored in the visitor. Called before traversing the + /// next component by [ir::traversal::Visitor]. + fn clear_data(&mut self); +} + +/// Derive ConstructVisitor when [Default] is provided for a visitor. +impl ConstructVisitor for T { + fn from(_ctx: &ir::Context) -> CalyxResult { + Ok(T::default()) + } + + fn clear_data(&mut self) { + *self = T::default(); + } +} diff --git a/calyx-opt/src/traversal/mod.rs b/calyx-opt/src/traversal/mod.rs index ad95eb992..a7151897f 100644 --- a/calyx-opt/src/traversal/mod.rs +++ b/calyx-opt/src/traversal/mod.rs @@ -1,8 +1,10 @@ //! Helpers for traversing Control programs mod action; +mod construct; mod post_order; mod visitor; pub use action::{Action, VisResult}; +pub use construct::{ConstructVisitor, Named, ParseVal, PassOpt}; pub use post_order::{CompTraversal, Order}; -pub use visitor::{ConstructVisitor, Named, Visitable, Visitor}; +pub use visitor::{Visitable, Visitor}; diff --git a/calyx-opt/src/traversal/visitor.rs b/calyx-opt/src/traversal/visitor.rs index d9a6df383..08a885ef7 100644 --- a/calyx-opt/src/traversal/visitor.rs +++ b/calyx-opt/src/traversal/visitor.rs @@ -2,110 +2,13 @@ //! Program passes implemented as the Visitor are directly invoked on //! [`ir::Context`] to compile every [`ir::Component`] using the pass. use super::action::{Action, VisResult}; -use super::{CompTraversal, Order}; +use super::{CompTraversal, ConstructVisitor, Named, Order}; use calyx_ir::{ self as ir, Component, Context, Control, LibrarySignatures, StaticControl, }; use calyx_utils::CalyxResult; -use itertools::Itertools; -use std::collections::HashSet; use std::rc::Rc; -/// Trait that describes named things. Calling [`do_pass`](Visitor::do_pass) and [`do_pass_default`](Visitor::do_pass_default). -/// require this to be implemented. -/// -/// This has to be a separate trait from [`Visitor`] because these methods don't recieve `self` which -/// means that it is impossible to create dynamic trait objects. -pub trait Named { - /// The name of a pass. Is used for identifying passes. - fn name() -> &'static str; - /// A short description of the pass. - fn description() -> &'static str; - /// Set of options that can be passed to the pass. - /// The options contains a tuple of the option name and a description. - fn opts() -> &'static [(&'static str, &'static str)] { - &[] - } -} - -/// Trait defining method that can be used to construct a Visitor from an -/// [ir::Context]. -/// This is useful when a pass needs to construct information using the context -/// *before* visiting the components. -/// -/// For passes that don't need to use the context, this trait can be automatically -/// be derived from [Default]. -pub trait ConstructVisitor { - fn get_opts(ctx: &ir::Context) -> Vec - where - Self: Named, - { - let opts = Self::opts(); - let n = Self::name(); - let given_opts: HashSet<_> = ctx - .extra_opts - .iter() - .filter_map(|opt| { - let mut splits = opt.split(':'); - if splits.next() == Some(n) { - splits.next() - } else { - None - } - }) - .collect(); - - let values = opts - .iter() - .map(|(o, _)| given_opts.contains(o)) - .collect_vec(); - - if let Some(unknown) = given_opts - .iter() - .find(|&&o| !opts.iter().any(|(opts, _)| opts == &o)) - { - log::warn!( - "Ignoring unknown option for pass `{}`: {}", - Self::name(), - unknown - ); - } - - if log::log_enabled!(log::Level::Debug) { - log::debug!( - "Extra options for {}: {}", - Self::name(), - opts.iter() - .zip(values.iter()) - .map(|((o, _), v)| format!("{o}->{v}")) - .join(", ") - ); - } - - values - } - - /// Construct the visitor using information from the Context - fn from(_ctx: &ir::Context) -> CalyxResult - where - Self: Sized; - - /// Clear the data stored in the visitor. Called before traversing the - /// next component by [ir::traversal::Visitor]. - fn clear_data(&mut self); -} - -/// Derive ConstructVisitor when [Default] is provided for a visitor. -impl ConstructVisitor for T { - fn from(_ctx: &ir::Context) -> CalyxResult { - Ok(T::default()) - } - - fn clear_data(&mut self) { - *self = T::default(); - } -} - /// The visiting interface for a [`ir::Control`](crate::Control) program. /// Contains two kinds of functions: /// 1. start_: Called when visiting top-down. diff --git a/calyx-utils/src/out_file.rs b/calyx-utils/src/out_file.rs index 4e5c61e0f..9191576d5 100644 --- a/calyx-utils/src/out_file.rs +++ b/calyx-utils/src/out_file.rs @@ -4,19 +4,25 @@ use std::{ str::FromStr, }; -/// Possible choices for output streams. -/// Used by the `-o` option to the compiler. -#[derive(Default, Debug)] +/// Possible choices for output streams. Used by the `-o` option to the compiler. +/// * "-" and "" are treated as stdout. +/// * "" is treated as stderr. +/// * "" is treated as a null output stream. +/// * All other strings are treated as file paths. +#[derive(Debug, Clone)] pub enum OutputFile { - #[default] + Null, Stdout, + Stderr, File(PathBuf), } impl OutputFile { pub fn as_path_string(&self) -> String { match self { + OutputFile::Null => "".to_string(), OutputFile::Stdout => "".to_string(), + OutputFile::Stderr => "".to_string(), OutputFile::File(path) => path.to_string_lossy().to_string(), } } @@ -26,7 +32,9 @@ impl FromStr for OutputFile { type Err = String; fn from_str(s: &str) -> std::result::Result { match s { - "-" => Ok(OutputFile::Stdout), + "-" | "" => Ok(OutputFile::Stdout), + "" => Ok(OutputFile::Stderr), + "" => Ok(OutputFile::Null), _ => Ok(OutputFile::File(PathBuf::from(s))), } } @@ -36,6 +44,8 @@ impl ToString for OutputFile { fn to_string(&self) -> String { match self { OutputFile::Stdout => "-".to_string(), + OutputFile::Stderr => "".to_string(), + OutputFile::Null => "".to_string(), OutputFile::File(p) => p.to_str().unwrap().to_string(), } } @@ -45,16 +55,19 @@ impl OutputFile { pub fn isatty(&self) -> bool { match self { OutputFile::Stdout => atty::is(atty::Stream::Stdout), - OutputFile::File(_) => false, + OutputFile::Stderr => atty::is(atty::Stream::Stderr), + OutputFile::Null | OutputFile::File(_) => false, } } pub fn get_write(&self) -> Box { match self { OutputFile::Stdout => Box::new(BufWriter::new(std::io::stdout())), + OutputFile::Stderr => Box::new(BufWriter::new(std::io::stderr())), OutputFile::File(path) => { Box::new(BufWriter::new(std::fs::File::create(path).unwrap())) } + OutputFile::Null => Box::new(io::sink()), } } } diff --git a/interp/src/interpreter/control_interpreter.rs b/interp/src/interpreter/control_interpreter.rs index 75d75b792..c63d66189 100644 --- a/interp/src/interpreter/control_interpreter.rs +++ b/interp/src/interpreter/control_interpreter.rs @@ -835,7 +835,7 @@ impl WhileInterpreter { .copy_span() .into_option() .map(|x| x.show()) - .unwrap_or_else(|| "".to_string()); + .unwrap_or_default(); warn!(logger,"While loop has violated its bounds. The annotation suggests that the body should execute {target} times, but it exited after {current} iterations. \n {line}"); } } @@ -853,7 +853,7 @@ impl WhileInterpreter { .copy_span() .into_option() .map(|x| x.show()) - .unwrap_or_else(|| "".to_string()); + .unwrap_or_default(); warn!(logger,"While loop has violated its bounds. The annotation suggests that the body should execute {target} times, but it has entered its {current} iteration. \n {line}"); } } diff --git a/interp/src/main.rs b/interp/src/main.rs index 29e1af9b7..883907acb 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -30,7 +30,7 @@ pub struct Opts { option, short = 'o', long = "output", - default = "OutputFile::default()" + default = "OutputFile::Stdout" )] pub output: OutputFile, diff --git a/src/cmdline.rs b/src/cmdline.rs index c65fdde41..61cb1fb4f 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -13,15 +13,35 @@ use std::path::Path; use std::path::PathBuf; use std::str::FromStr; +/// help information about passes +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "pass-help")] +pub struct Help { + /// alias or pass name to get help for + #[argh(positional)] + pub name: Option, +} + +/// supported subcommands +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +pub enum Subcommand { + /// Help mode + Help(Help), +} + #[derive(FromArgs)] /// Options passed to the Calyx compiler. pub struct Opts { + #[argh(subcommand)] + pub sub: Option, + /// input calyx program #[argh(positional, from_str_fn(read_path))] pub file: Option, /// output file - #[argh(option, short = 'o', default = "OutputFile::default()")] + #[argh(option, short = 'o', default = "OutputFile::Stdout")] pub output: OutputFile, /// path to the primitives library @@ -64,10 +84,6 @@ pub struct Opts { #[argh(option, short = 'x', long = "extra-opt")] pub extra_opts: Vec, - /// list all avaliable pass options - #[argh(switch, long = "list-passes")] - pub list_passes: bool, - /// enable verbose printing #[argh(option, long = "log", default = "log::LevelFilter::Warn")] pub log_level: log::LevelFilter, diff --git a/src/main.rs b/src/main.rs index 0919959f1..399bc9909 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,10 +37,23 @@ fn main() -> CalyxResult<()> { let pm = PassManager::default_passes()?; - // list all the avaliable pass options when flag --list-passes is enabled - if opts.list_passes { - println!("{}", pm.show_names()); - return Ok(()); + // list all the avaliable pass options when pass-help subcommand is used + if let Some(sub) = opts.sub { + match sub { + cmdline::Subcommand::Help(cmdline::Help { name }) => { + match name { + Some(n) => { + if let Some(help) = pm.specific_help(&n) { + println!("{}", help); + } else { + println!("Unknown pass or alias: {}", n); + } + } + None => println!("{}", pm.complete_help()), + } + return Ok(()); + } + } } // Construct the namespace. diff --git a/tests/passes/dom-map-static/par-if.expect b/tests/passes/dom-map-static/par-if.expect index cd813e339..3a2320013 100644 --- a/tests/passes/dom-map-static/par-if.expect +++ b/tests/passes/dom-map-static/par-if.expect @@ -1,31 +1,3 @@ -This maps ids of par blocks to "node timing maps", which map node ids to the first interval (i,j) that the node (i.e., enable/invoke/if conditional) is active for, - relative to the start of the given par block -============ Map for Component "example" ============ -========Par Node ID: 0======== -====MUST EXECUTE==== -2 -- (0, 4) -3 -- (4, 5) -4 -- (5, 6) -14 -- (12, 15) -16 -- (0, 3) -17 -- (3, 5) -18 -- (5, 8) -19 -- (8, 10) -====MAY EXECUTE==== -7 -- (5, 9) -8 -- (9, 12) -10 -- (5, 6) -11 -- (6, 8) -12 -- (5, 10) -========Par Node ID: 5======== -====MUST EXECUTE==== -7 -- (0, 4) -8 -- (4, 7) -10 -- (0, 1) -11 -- (1, 3) -====MAY EXECUTE==== - - import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -100,3 +72,31 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +This maps ids of par blocks to "node timing maps", which map node ids to the first interval (i,j) that the node (i.e., enable/invoke/if conditional) is active for, + relative to the start of the given par block +============ Map for Component "example" ============ +========Par Node ID: 0======== +====MUST EXECUTE==== +2 -- (0, 4) +3 -- (4, 5) +4 -- (5, 6) +14 -- (12, 15) +16 -- (0, 3) +17 -- (3, 5) +18 -- (5, 8) +19 -- (8, 10) +====MAY EXECUTE==== +7 -- (5, 9) +8 -- (9, 12) +10 -- (5, 6) +11 -- (6, 8) +12 -- (5, 10) +========Par Node ID: 5======== +====MUST EXECUTE==== +7 -- (0, 4) +8 -- (4, 7) +10 -- (0, 1) +11 -- (1, 3) +====MAY EXECUTE==== + diff --git a/tests/passes/dom-map-static/par-if.futil b/tests/passes/dom-map-static/par-if.futil index 59a42c3fe..be64d1fa9 100644 --- a/tests/passes/dom-map-static/par-if.futil +++ b/tests/passes/dom-map-static/par-if.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-static-analysis +// -p infer-share -x infer-share:print-static-analysis= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { static<4> group A { @@ -37,8 +37,8 @@ component example() -> () { control { static par { static seq { - A; - B; + A; + B; static if lt.out { static par { static seq { G; H; } @@ -46,9 +46,9 @@ component example() -> () { } } else { - Z; + Z; } - J; + J; } static seq {C; D; E; F;} } @@ -65,6 +65,6 @@ component main() -> () { } control { - invoke e()(); + invoke e()(); } } \ No newline at end of file diff --git a/tests/passes/dom-map-static/repeat.expect b/tests/passes/dom-map-static/repeat.expect index 2f6275453..43f194af5 100644 --- a/tests/passes/dom-map-static/repeat.expect +++ b/tests/passes/dom-map-static/repeat.expect @@ -1,15 +1,3 @@ -This maps ids of par blocks to "node timing maps", which map node ids to the first interval (i,j) that the node (i.e., enable/invoke/if conditional) is active for, - relative to the start of the given par block -============ Map for Component "example" ============ -========Par Node ID: 0======== -====MUST EXECUTE==== -2 -- (0, 4) -4 -- (4, 5) -5 -- (14, 17) -7 -- (0, 5) -====MAY EXECUTE==== - - import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -49,3 +37,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +This maps ids of par blocks to "node timing maps", which map node ids to the first interval (i,j) that the node (i.e., enable/invoke/if conditional) is active for, + relative to the start of the given par block +============ Map for Component "example" ============ +========Par Node ID: 0======== +====MUST EXECUTE==== +2 -- (0, 4) +4 -- (4, 5) +5 -- (14, 17) +7 -- (0, 5) +====MAY EXECUTE==== + diff --git a/tests/passes/dom-map-static/repeat.futil b/tests/passes/dom-map-static/repeat.futil index 8cee4211e..0abe05068 100644 --- a/tests/passes/dom-map-static/repeat.futil +++ b/tests/passes/dom-map-static/repeat.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-static-analysis +// -p infer-share -x infer-share:print-static-analysis= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { static<4> group A { @@ -17,14 +17,14 @@ component example() -> () { control { static par { static seq { - A; + A; static repeat 10 { - B; + B; } - C; + C; } static repeat 3 { - D; + D; } } } @@ -40,6 +40,6 @@ component main() -> () { } control { - invoke e()(); + invoke e()(); } } \ No newline at end of file diff --git a/tests/passes/domination-map/blank.expect b/tests/passes/domination-map/blank.expect index cd4b8acc5..a39721f4a 100644 --- a/tests/passes/domination-map/blank.expect +++ b/tests/passes/domination-map/blank.expect @@ -1,9 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells {} @@ -19,3 +13,10 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +} \ No newline at end of file diff --git a/tests/passes/domination-map/blank.futil b/tests/passes/domination-map/blank.futil index 348b3b3a0..7a2afca20 100644 --- a/tests/passes/domination-map/blank.futil +++ b/tests/passes/domination-map/blank.futil @@ -1,13 +1,13 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { } wires { - + } control { - + } } @@ -21,7 +21,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/complex-test.expect b/tests/passes/domination-map/complex-test.expect index 118c7a7bd..09dd24db2 100644 --- a/tests/passes/domination-map/complex-test.expect +++ b/tests/passes/domination-map/complex-test.expect @@ -1,29 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 1 -- Dominators: [1] -Node: 2 -- Dominators: [1, 2] -Node: 3 -- Dominators: [1, 2, 3] -Node: 4 -- Dominators: [1, 2, 3, 4] -Node: 5 -- Dominators: [1, 2, 3, 4, 5] -Node: 8 -- Dominators: [1, 2, 3, 4, 5, 8] -Node: 9 -- Dominators: [1, 2, 3, 4, 5, 9] -Node: 10 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10] -Node: 12 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12] -Node: 14 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12, 14] -Node: 15 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12, 15] -Node: 17 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 17] -Node: 18 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 18] -Node: 19 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 19] -Node: 20 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 20] -Node: 22 -- Dominators: [1, 2, 3, 4, 22] -Node: 23 -- Dominators: [1, 2, 3, 4, 23] -Node: 24 -- Dominators: [1, 2, 3, 4, 24] -Node: 25 -- Dominators: [1, 2, 3, 4, 25] -Node: 26 -- Dominators: [1, 2, 3, 4, 25, 26] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -114,3 +88,30 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 1 -- Dominators: [1] +Node: 2 -- Dominators: [1, 2] +Node: 3 -- Dominators: [1, 2, 3] +Node: 4 -- Dominators: [1, 2, 3, 4] +Node: 5 -- Dominators: [1, 2, 3, 4, 5] +Node: 8 -- Dominators: [1, 2, 3, 4, 5, 8] +Node: 9 -- Dominators: [1, 2, 3, 4, 5, 9] +Node: 10 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10] +Node: 12 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12] +Node: 14 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12, 14] +Node: 15 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 12, 15] +Node: 17 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 17] +Node: 18 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 18] +Node: 19 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 19] +Node: 20 -- Dominators: [1, 2, 3, 4, 5, 8, 9, 10, 20] +Node: 22 -- Dominators: [1, 2, 3, 4, 22] +Node: 23 -- Dominators: [1, 2, 3, 4, 23] +Node: 24 -- Dominators: [1, 2, 3, 4, 24] +Node: 25 -- Dominators: [1, 2, 3, 4, 25] +Node: 26 -- Dominators: [1, 2, 3, 4, 25, 26] +} \ No newline at end of file diff --git a/tests/passes/domination-map/complex-test.futil b/tests/passes/domination-map/complex-test.futil index 5d26d2ef1..9baf56c15 100644 --- a/tests/passes/domination-map/complex-test.futil +++ b/tests/passes/domination-map/complex-test.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group P0{ @@ -63,9 +63,9 @@ component example() -> () { par {X;Y;Z;} } Z; - } + } } - + } @@ -78,9 +78,9 @@ component main() -> () { } control { - par { - invoke e() (); + par { + invoke e() (); } } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/dyn-repeat.expect b/tests/passes/domination-map/dyn-repeat.expect index 2d270292d..b8b0311ab 100644 --- a/tests/passes/domination-map/dyn-repeat.expect +++ b/tests/passes/domination-map/dyn-repeat.expect @@ -1,11 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 4 -- Dominators: [4] -Node: 5 -- Dominators: [4, 5] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -40,3 +32,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 4 -- Dominators: [4] +Node: 5 -- Dominators: [4, 5] +} \ No newline at end of file diff --git a/tests/passes/domination-map/dyn-repeat.futil b/tests/passes/domination-map/dyn-repeat.futil index b6d07fb3b..e7a23ead2 100644 --- a/tests/passes/domination-map/dyn-repeat.futil +++ b/tests/passes/domination-map/dyn-repeat.futil @@ -1,9 +1,9 @@ -// -p infer-share -x infer-share:print-dmap -// should ignore `repeat 0` stmts in domination map +// -p infer-share -x infer-share:print-dmap= +// should ignore `repeat 0` stmts in domination map import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group A{ @@ -15,12 +15,12 @@ component example() -> () { } control { repeat 0 { - A; + A; } repeat 2 { - B; + B; } - C; + C; } } @@ -34,7 +34,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/empty-fbranch.expect b/tests/passes/domination-map/empty-fbranch.expect index 58b14f19f..96ff3d24b 100644 --- a/tests/passes/domination-map/empty-fbranch.expect +++ b/tests/passes/domination-map/empty-fbranch.expect @@ -1,17 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 1 -- Dominators: [1] -Node: 2 -- Dominators: [1, 2] -Node: 3 -- Dominators: [1, 2, 3] -Node: 5 -- Dominators: [1, 2, 3, 5] -Node: 6 -- Dominators: [1, 2, 3, 6] -Node: 7 -- Dominators: [1, 2, 3, 7] -Node: 8 -- Dominators: [1, 2, 8] -Node: 9 -- Dominators: [1, 2, 8, 9] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -55,3 +41,18 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 1 -- Dominators: [1] +Node: 2 -- Dominators: [1, 2] +Node: 3 -- Dominators: [1, 2, 3] +Node: 5 -- Dominators: [1, 2, 3, 5] +Node: 6 -- Dominators: [1, 2, 3, 6] +Node: 7 -- Dominators: [1, 2, 3, 7] +Node: 8 -- Dominators: [1, 2, 8] +Node: 9 -- Dominators: [1, 2, 8, 9] +} \ No newline at end of file diff --git a/tests/passes/domination-map/empty-fbranch.futil b/tests/passes/domination-map/empty-fbranch.futil index fb02d1f23..def20b08d 100644 --- a/tests/passes/domination-map/empty-fbranch.futil +++ b/tests/passes/domination-map/empty-fbranch.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group A0{ @@ -27,7 +27,7 @@ component example() -> () { } } Z; - } + } } } @@ -41,7 +41,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/if-dominated.expect b/tests/passes/domination-map/if-dominated.expect index c5a75092b..4a595b512 100644 --- a/tests/passes/domination-map/if-dominated.expect +++ b/tests/passes/domination-map/if-dominated.expect @@ -1,14 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 2 -- Dominators: [2] -Node: 3 -- Dominators: [2, 3, 6] -Node: 4 -- Dominators: [2, 3, 4, 6] -Node: 5 -- Dominators: [2, 3, 5] -Node: 6 -- Dominators: [6] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -43,3 +32,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 2 -- Dominators: [2] +Node: 3 -- Dominators: [2, 3, 6] +Node: 4 -- Dominators: [2, 3, 4, 6] +Node: 5 -- Dominators: [2, 3, 5] +Node: 6 -- Dominators: [6] +} \ No newline at end of file diff --git a/tests/passes/domination-map/if-dominated.futil b/tests/passes/domination-map/if-dominated.futil index 4f2258649..6bc279281 100644 --- a/tests/passes/domination-map/if-dominated.futil +++ b/tests/passes/domination-map/if-dominated.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { static<4> group A{ @@ -15,10 +15,10 @@ component example() -> () { control { static par { static seq { - A; + A; static if lt.out {B;} } - C; + C; } } } @@ -33,7 +33,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/nested-seq.expect b/tests/passes/domination-map/nested-seq.expect index 4b7df4b29..8631bb043 100644 --- a/tests/passes/domination-map/nested-seq.expect +++ b/tests/passes/domination-map/nested-seq.expect @@ -1,12 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 2 -- Dominators: [2] -Node: 3 -- Dominators: [2, 3] -Node: 4 -- Dominators: [2, 3, 4] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -41,3 +32,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 2 -- Dominators: [2] +Node: 3 -- Dominators: [2, 3] +Node: 4 -- Dominators: [2, 3, 4] +} \ No newline at end of file diff --git a/tests/passes/domination-map/nested-seq.futil b/tests/passes/domination-map/nested-seq.futil index 87eeca980..fb44dbfcc 100644 --- a/tests/passes/domination-map/nested-seq.futil +++ b/tests/passes/domination-map/nested-seq.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group A{ @@ -33,7 +33,7 @@ component main() -> () { wires { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/par-if-nested.expect b/tests/passes/domination-map/par-if-nested.expect index 0396ad205..77203957d 100644 --- a/tests/passes/domination-map/par-if-nested.expect +++ b/tests/passes/domination-map/par-if-nested.expect @@ -1,23 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 1 -- Dominators: [1] -Node: 2 -- Dominators: [1, 2] -Node: 3 -- Dominators: [1, 2, 3] -Node: 5 -- Dominators: [1, 2, 3, 5] -Node: 7 -- Dominators: [1, 2, 3, 5, 7] -Node: 9 -- Dominators: [1, 2, 3, 5, 9] -Node: 10 -- Dominators: [1, 2, 3, 5, 9, 10] -Node: 11 -- Dominators: [1, 2, 3, 5, 9, 10, 11] -Node: 13 -- Dominators: [1, 2, 3, 5, 13] -Node: 14 -- Dominators: [1, 2, 3, 5, 14] -Node: 15 -- Dominators: [1, 2, 3, 5, 15] -Node: 16 -- Dominators: [1, 2, 3, 16] -Node: 17 -- Dominators: [1, 2, 3, 17] -Node: 18 -- Dominators: [1, 2, 3, 5, 15, 16, 17, 18] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -90,3 +70,24 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 1 -- Dominators: [1] +Node: 2 -- Dominators: [1, 2] +Node: 3 -- Dominators: [1, 2, 3] +Node: 5 -- Dominators: [1, 2, 3, 5] +Node: 7 -- Dominators: [1, 2, 3, 5, 7] +Node: 9 -- Dominators: [1, 2, 3, 5, 9] +Node: 10 -- Dominators: [1, 2, 3, 5, 9, 10] +Node: 11 -- Dominators: [1, 2, 3, 5, 9, 10, 11] +Node: 13 -- Dominators: [1, 2, 3, 5, 13] +Node: 14 -- Dominators: [1, 2, 3, 5, 14] +Node: 15 -- Dominators: [1, 2, 3, 5, 15] +Node: 16 -- Dominators: [1, 2, 3, 16] +Node: 17 -- Dominators: [1, 2, 3, 17] +Node: 18 -- Dominators: [1, 2, 3, 5, 15, 16, 17, 18] +} \ No newline at end of file diff --git a/tests/passes/domination-map/par-if-nested.futil b/tests/passes/domination-map/par-if-nested.futil index 3ffd6369c..2c93a3b4b 100644 --- a/tests/passes/domination-map/par-if-nested.futil +++ b/tests/passes/domination-map/par-if-nested.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group P0{ @@ -70,6 +70,6 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } } \ No newline at end of file diff --git a/tests/passes/domination-map/static-par.expect b/tests/passes/domination-map/static-par.expect index 8557fe03d..f8f526239 100644 --- a/tests/passes/domination-map/static-par.expect +++ b/tests/passes/domination-map/static-par.expect @@ -1,22 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 1 -- Dominators: [1] -Node: 4 -- Dominators: [1, 4] -Node: 5 -- Dominators: [1, 4, 5, 8, 11] -Node: 6 -- Dominators: [1, 4, 5, 6, 8, 9, 10, 11] -Node: 8 -- Dominators: [1, 8] -Node: 9 -- Dominators: [1, 8, 9, 11] -Node: 10 -- Dominators: [1, 4, 8, 9, 10, 11] -Node: 11 -- Dominators: [1, 11] -Node: 14 -- Dominators: [1, 11, 14] -Node: 15 -- Dominators: [1, 4, 8, 11, 14, 15, 16] -Node: 16 -- Dominators: [1, 11, 16] -Node: 17 -- Dominators: [1, 11, 17] -Node: 18 -- Dominators: [1, 4, 5, 6, 8, 9, 10, 11, 17, 18] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -83,3 +64,23 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 1 -- Dominators: [1] +Node: 4 -- Dominators: [1, 4] +Node: 5 -- Dominators: [1, 4, 5, 8, 11] +Node: 6 -- Dominators: [1, 4, 5, 6, 8, 9, 10, 11] +Node: 8 -- Dominators: [1, 8] +Node: 9 -- Dominators: [1, 8, 9, 11] +Node: 10 -- Dominators: [1, 4, 8, 9, 10, 11] +Node: 11 -- Dominators: [1, 11] +Node: 14 -- Dominators: [1, 11, 14] +Node: 15 -- Dominators: [1, 4, 8, 11, 14, 15, 16] +Node: 16 -- Dominators: [1, 11, 16] +Node: 17 -- Dominators: [1, 11, 17] +Node: 18 -- Dominators: [1, 4, 5, 6, 8, 9, 10, 11, 17, 18] +} \ No newline at end of file diff --git a/tests/passes/domination-map/static-par.futil b/tests/passes/domination-map/static-par.futil index a87abfa22..12f1ba48b 100644 --- a/tests/passes/domination-map/static-par.futil +++ b/tests/passes/domination-map/static-par.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group A{ @@ -30,14 +30,14 @@ component example() -> () { } control { seq { - A; + A; static par { static seq {B; C; D;} static seq {E; F; G;} static if lt.out { static par { static seq {X; Y;} - Z; + Z; } } } @@ -56,7 +56,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file diff --git a/tests/passes/domination-map/while-nested.expect b/tests/passes/domination-map/while-nested.expect index e28d9e3e2..ae1d1e8fa 100644 --- a/tests/passes/domination-map/while-nested.expect +++ b/tests/passes/domination-map/while-nested.expect @@ -1,18 +1,3 @@ -The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes -that are attached to each non-empty control statement when the domination map is built. -To see which ID's refer to which control statement, look at the Calyx Program, which should -be printed along with the map when it is printed. -Domination Map for component "example" { -Node: 0 -- Dominators: [0] -Node: 1 -- Dominators: [0, 1] -Node: 2 -- Dominators: [0, 1, 2] -Node: 4 -- Dominators: [0, 1, 2, 4] -Node: 5 -- Dominators: [0, 1, 2, 4, 5] -Node: 7 -- Dominators: [0, 1, 2, 4, 5, 7] -Node: 8 -- Dominators: [0, 1, 2, 4, 5, 7, 8] -Node: 9 -- Dominators: [0, 1, 2, 4, 5, 9] -Node: 10 -- Dominators: [0, 1, 2, 4, 5, 9, 10] -} import "primitives/core.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -63,3 +48,19 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { invoke e()(); } } +---STDERR--- +The numbers in the domination map refer to the BEGIN_ID, END_ID, and NODE_ID attributes +that are attached to each non-empty control statement when the domination map is built. +To see which ID's refer to which control statement, look at the Calyx Program, which should +be printed along with the map when it is printed. +Domination Map for component "example" { +Node: 0 -- Dominators: [0] +Node: 1 -- Dominators: [0, 1] +Node: 2 -- Dominators: [0, 1, 2] +Node: 4 -- Dominators: [0, 1, 2, 4] +Node: 5 -- Dominators: [0, 1, 2, 4, 5] +Node: 7 -- Dominators: [0, 1, 2, 4, 5, 7] +Node: 8 -- Dominators: [0, 1, 2, 4, 5, 7, 8] +Node: 9 -- Dominators: [0, 1, 2, 4, 5, 9] +Node: 10 -- Dominators: [0, 1, 2, 4, 5, 9, 10] +} \ No newline at end of file diff --git a/tests/passes/domination-map/while-nested.futil b/tests/passes/domination-map/while-nested.futil index 787ab79eb..d3fd05223 100644 --- a/tests/passes/domination-map/while-nested.futil +++ b/tests/passes/domination-map/while-nested.futil @@ -1,8 +1,8 @@ -// -p infer-share -x infer-share:print-dmap +// -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; component example() -> () { cells { - lt = std_lt(4); + lt = std_lt(4); } wires { group A{ @@ -25,7 +25,7 @@ component example() -> () { while lt.out with less_than{ while lt.out with less_than{ seq{ - A; + A; while lt.out with less_than{ seq{ B1; @@ -51,7 +51,7 @@ component main() -> () { } control { - invoke e() (); + invoke e() (); } - + } \ No newline at end of file From 0667a0a47ea96e1f6898191046513e9147a7428c Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Fri, 22 Dec 2023 12:58:35 -0500 Subject: [PATCH 121/189] Add that in guards ports can be literals to docs (#1821) * Add that ports can be literals in guards to docs * Update docs/lang/ref.md Co-authored-by: Adrian Sampson --------- Co-authored-by: Adrian Sampson --- docs/lang/ref.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/lang/ref.md b/docs/lang/ref.md index 109a6f52a..a0de7729a 100644 --- a/docs/lang/ref.md +++ b/docs/lang/ref.md @@ -227,6 +227,8 @@ Guards can use the following constructs: - `guard || guard`: Disjunction between two guards - `guard && guard`: Conjunction of two guards +In the context of guards, a port can also be a literal (i.e., `counter.out == 3'd2` is a valid guard). + > **Well-formedness**: For each input port on the LHS, only one guard should be active in any given cycle during the execution of a Calyx program. ### Continuous Assignments From 10e5db3fca3e5d2d73d81eac2bc318048c5456a7 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Fri, 22 Dec 2023 19:57:03 -0500 Subject: [PATCH 122/189] Add Ayaka to list of contributors (#1822) --- docs/contributors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributors.md b/docs/contributors.md index c0db387eb..d12a5d87a 100644 --- a/docs/contributors.md +++ b/docs/contributors.md @@ -14,6 +14,7 @@ Here is a list of all the people who have worked on Calyx: - Caleb Kim - Andrew Butt - [Anshuman Mohan](https://www.cs.cornell.edu/~amohan/) +- [Ayaka Yorihiro](https://ayakayorihiro.github.io/) **Previous Contributors** From 248f1a2b746696da7f743f05c0db04f099762f4a Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 24 Dec 2023 13:18:03 -0500 Subject: [PATCH 123/189] rename cucapra/calyx to calyxir/calyx (#1823) --- Cargo.toml | 2 +- Dockerfile | 2 +- calyx-backend/src/xilinx/xml.rs | 2 +- calyx-opt/src/passes/dump_ports.rs | 2 +- calyx-opt/src/passes/static_inliner.rs | 2 +- calyx-opt/src/passes/wrap_main.rs | 2 +- calyx-py/pyproject.toml | 4 +- docs/builder/calyx-py.md | 4 +- docs/compiler-as-library.md | 2 +- docs/contributors.md | 2 +- docs/debug/debug.md | 6 +-- docs/frontends/ntt.md | 2 +- docs/frontends/systolic-array.md | 2 +- docs/frontends/tvm-relay.md | 10 ++--- docs/fud/axi-gen.md | 6 +-- docs/fud/circt.md | 2 +- docs/fud/index.md | 2 +- docs/fud/xilinx.md | 6 +-- docs/intro.md | 8 ++-- docs/lang/attributes.md | 2 +- docs/lang/memories-by-reference.md | 2 +- docs/lang/sync.md | 22 +++++------ docs/lang/undefined.md | 16 ++++---- docs/tools/data-gen.md | 24 ++++++------ docs/tutorial/frontend-tut.md | 26 ++++++------- docs/tutorial/language-tut.md | 10 ++--- frontends/relay/dahlia_impl.py | 12 +++--- runt.toml | 39 ++++++++----------- .../static-control/seq-component-chain.futil | 2 +- web/js/index.js | 28 ++++++------- 30 files changed, 122 insertions(+), 129 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 70dedd238..ca029447d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ exclude = ["site"] authors = ["The Calyx Team"] license-file = "LICENSE" keywords = ["ir", "compiler"] -repository = "https://github.com/cucapra/calyx" +repository = "https://github.com/calyxir/calyx" readme = "README.md" description = "Compiler Infrastructure for Hardware Accelerator Generation" categories = ["compilers"] diff --git a/Dockerfile b/Dockerfile index 0358b6dc2..d17eb728b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM rust:1.70 # Connect to the Calux repository. -LABEL org.opencontainers.image.source https://github.com/cucapra/calyx +LABEL org.opencontainers.image.source https://github.com/calyxir/calyx # Install apt dependencies RUN echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | tee /etc/apt/sources.list.d/sbt.list && \ diff --git a/calyx-backend/src/xilinx/xml.rs b/calyx-backend/src/xilinx/xml.rs index 2c0759382..6301836d3 100644 --- a/calyx-backend/src/xilinx/xml.rs +++ b/calyx-backend/src/xilinx/xml.rs @@ -179,7 +179,7 @@ impl Backend for XilinxXmlBackend { range: "0xFFFFFFFFFFFFFFFF", // Width should match the bus data width of memory modules // described in hardware, for example see - // https://github.com/cucapra/calyx/blob/c2b12a0fe6b1ee3aaaae0c66e7c4619ee6c82614/src/backend/xilinx/toplevel.rs#L58 + // https://github.com/calyxir/calyx/blob/c2b12a0fe6b1ee3aaaae0c66e7c4619ee6c82614/src/backend/xilinx/toplevel.rs#L58 data_width: 512, port_type: "addressable", base: "0x0", diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index afe6a5b98..ce3eeb340 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -43,7 +43,7 @@ where // If we do not eliminate the @clk and @reset ports, we may // get signals conflicting the original @clk and @reset signals of - // the component, see https://github.com/cucapra/calyx/issues/1034 + // the component, see https://github.com/calyxir/calyx/issues/1034 let ports_inline = cell .ports .iter() diff --git a/calyx-opt/src/passes/static_inliner.rs b/calyx-opt/src/passes/static_inliner.rs index 3fe598da6..d5faa0397 100644 --- a/calyx-opt/src/passes/static_inliner.rs +++ b/calyx-opt/src/passes/static_inliner.rs @@ -75,7 +75,7 @@ impl StaticInliner { // this means that all of the tru branch assigns can get the cond_wire ? in front of them, // and all false branch assigns can get !cond_wire ? in front of them // makes the following assignments: - // read more here: https://github.com/cucapra/calyx/issues/1344 (specifically + // read more here: https://github.com/calyxir/calyx/issues/1344 (specifically // the section "Conditionl") fn make_cond_assigns( cond: ir::RRC, diff --git a/calyx-opt/src/passes/wrap_main.rs b/calyx-opt/src/passes/wrap_main.rs index b3c27810f..73b486260 100644 --- a/calyx-opt/src/passes/wrap_main.rs +++ b/calyx-opt/src/passes/wrap_main.rs @@ -9,7 +9,7 @@ use ir::build_assignments; /// and makes it the top-level component. /// This is useful because a lot of our tools rely on the name `main` being the design under test (DUT). /// -/// For more information, see https://github.com/cucapra/calyx/issues/1376 +/// For more information, see https://github.com/calyxir/calyx/issues/1376 pub struct WrapMain; impl Named for WrapMain { diff --git a/calyx-py/pyproject.toml b/calyx-py/pyproject.toml index 1f5b27b32..2edf91ccf 100644 --- a/calyx-py/pyproject.toml +++ b/calyx-py/pyproject.toml @@ -4,12 +4,12 @@ build-backend = "flit_core.buildapi" [project] name = "calyx-ast" -authors = [{name = "The Calyx Authors"}] +authors = [{ name = "The Calyx Authors" }] classifiers = ["License :: OSI Approved :: MIT License"] dynamic = ["version", "description"] readme = "README.md" requires-python = ">=3.4" -urls.Source = "https://github.com/cucapra/calyx" +urls.Source = "https://github.com/calyxir/calyx" [tool.flit.module] name = "calyx" diff --git a/docs/builder/calyx-py.md b/docs/builder/calyx-py.md index c7923a09a..cb2dd1a19 100644 --- a/docs/builder/calyx-py.md +++ b/docs/builder/calyx-py.md @@ -117,9 +117,9 @@ python calyx-py/test/builder_example.py Other examples using the builder can also be found in the `calyx-py` [test directory][test]. All of our frontends were also written using this library, in case you'd like even more examples! [cont]: ../lang/ref.md#continuous-assignments -[example]: https://github.com/cucapra/calyx/blob/master/calyx-py/test/builder_example.py +[example]: https://github.com/calyxir/calyx/blob/master/calyx-py/test/builder_example.py [flit]: https://flit.readthedocs.io/en/latest/ [godone]: ..lang/ref.md#the-go-done-interface [guarded]: ../lang/ref.md#guarded-assignments [ref]: ref.md -[test]: https://github.com/cucapra/calyx/tree/master/calyx-py/test/ +[test]: https://github.com/calyxir/calyx/tree/master/calyx-py/test/ diff --git a/docs/compiler-as-library.md b/docs/compiler-as-library.md index 473c0ba47..8dad214c7 100644 --- a/docs/compiler-as-library.md +++ b/docs/compiler-as-library.md @@ -9,7 +9,7 @@ You'll also need `calyx-frontend` and `calyx-utils` if you're parsing frontend c ## Building the `calyx` Binary -The [`calyx` binary][calyx-crate] is published using Rust's crates.io repository. It provides the [compiler interface](./compiler.md) which can be used without requiring the user to build the compiler from source. The `calyx` binary also ships all its [primitives library][prims-lib] which is done through a somewhat complex bootstrapping process (see [#1678](https://github.com/cucapra/calyx/pull/1678)) +The [`calyx` binary][calyx-crate] is published using Rust's crates.io repository. It provides the [compiler interface](./compiler.md) which can be used without requiring the user to build the compiler from source. The `calyx` binary also ships all its [primitives library][prims-lib] which is done through a somewhat complex bootstrapping process (see [#1678](https://github.com/calyxir/calyx/pull/1678)) 1. The [`calyx-stdlib`][calyx-stdlib] package pulls in the sources of all the primitives using the Rust `include_str!` macro. 2. The `calyx` binary defines a build script that depends on `calyx-stdlib` as a build dependency. diff --git a/docs/contributors.md b/docs/contributors.md index d12a5d87a..285c9de03 100644 --- a/docs/contributors.md +++ b/docs/contributors.md @@ -32,4 +32,4 @@ Here is a list of all the people who have worked on Calyx: - Jiaxuan (Crystal) Hu - [Priya Srikumar](https://priyasrikumar.com/) -If you're missing from this list, please [add yourself](https://github.com/cucapra/calyx/edit/master/docs/contributors.md)! +If you're missing from this list, please [add yourself](https://github.com/calyxir/calyx/edit/master/docs/contributors.md)! diff --git a/docs/debug/debug.md b/docs/debug/debug.md index 4523c0402..4eb625d68 100644 --- a/docs/debug/debug.md +++ b/docs/debug/debug.md @@ -14,7 +14,7 @@ To disable the passes, add the flag `-p no-opt` to compiler invocation: If the output is still incorrect then one of the core compilation passes is incorrect. Our best bet at this point is to reduce the test file such that the output from the interpreter and the Calyx compiler still disagree and [report the -bug](https://github.com/cucapra/calyx/issues/new). We can use the [waveform +bug](https://github.com/calyxir/calyx/issues/new). We can use the [waveform debugging](#waveform-debugging) to figure out which part of the compilation pipeline generates the incorrect result. @@ -115,7 +115,7 @@ In this debugging strategy, we'll do the following: 3. Open the waveform viewer and find clock cycles where the FSM takes the corresponding values and identify other signals that we care about. -Consider the control section from [examples/futil/dot-product.futil](https://github.com/cucapra/calyx/blob/master/examples/futil/dot-product.futil): +Consider the control section from [examples/futil/dot-product.futil](https://github.com/calyxir/calyx/blob/master/examples/futil/dot-product.futil): ``` {{#include ../../examples/futil/dot-product.futil:control}} ``` @@ -170,5 +170,5 @@ the `fsm` register has the value 1 and check to see if the assignments in [gtkwave]: http://gtkwave.sourceforge.net/ [wavetrace]: https://marketplace.visualstudio.com/items?itemName=wavetrace.wavetrace -[flag-cmp]: https://github.com/cucapra/calyx/blob/master/tools/flag-compare.sh +[flag-cmp]: https://github.com/calyxir/calyx/blob/master/tools/flag-compare.sh [dgr]: https://docs.rs/calyx-opt/latest/calyx_opt/passes/struct.DeadGroupRemoval.html diff --git a/docs/frontends/ntt.md b/docs/frontends/ntt.md index 1d96799c1..f0f1f3881 100644 --- a/docs/frontends/ntt.md +++ b/docs/frontends/ntt.md @@ -63,4 +63,4 @@ pipeline. - `--parallel_reduction`: Decreases fan-out by reducing the number of groups executed in parallel by this factor. [longa-etal-ntt]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/05/RLWE-1.pdf -[ntt]: https://github.com/cucapra/calyx/tree/master/frontends/ntt-pipeline +[ntt]: https://github.com/calyxir/calyx/tree/master/frontends/ntt-pipeline diff --git a/docs/frontends/systolic-array.md b/docs/frontends/systolic-array.md index 2429405ba..f46f152ff 100644 --- a/docs/frontends/systolic-array.md +++ b/docs/frontends/systolic-array.md @@ -29,4 +29,4 @@ can be configured. - `--top-depth`, `--left-depth`: The length of the input streams from top and left sides of the array. [kung-systolic]: http://www.eecs.harvard.edu/~htk/publication/1982-kung-why-systolic-architecture.pdf -[systolic-lang]: https://github.com/cucapra/calyx/tree/master/frontends/systolic-lang +[systolic-lang]: https://github.com/calyxir/calyx/tree/master/frontends/systolic-lang diff --git a/docs/frontends/tvm-relay.md b/docs/frontends/tvm-relay.md index 04a41f4f1..38f0ab8a2 100644 --- a/docs/frontends/tvm-relay.md +++ b/docs/frontends/tvm-relay.md @@ -33,8 +33,8 @@ intermediate representation. cd ../python && python3 setup.py bdist_wheel pip3 install --user dist/tvm-*.whl - > If you get an error with `shutil`, try deleting the `python/` directory, restoring it, and rerunning the above command: `cd .. && rm -rf python && git checkout -- python` - > If you are on MacOS - Big Sur and are getting an error similar to "(wheel).whl is not a supported wheel on this platform", try changing part of the wheel's filename from 11_0 to 10_9. See this github [issue](https://github.com/apple/tensorflow_macos/issues/46) for more information. + > If you get an error with `shutil`, try deleting the `python/` directory, restoring it, and rerunning the above command: `cd .. && rm -rf python && git checkout -- python` + > If you are on MacOS - Big Sur and are getting an error similar to "(wheel).whl is not a supported wheel on this platform", try changing part of the wheel's filename from 11_0 to 10_9. See this github [issue](https://github.com/apple/tensorflow_macos/issues/46) for more information. 6. Install ANTLR v4.7.2 (required for the Relay text format parser): @@ -89,12 +89,12 @@ determine what preprocessing should be done on the image. e.g. `"mnist"` or `"im 2. `relay`: Output a file with the corresponding Relay program. `.relay` 3. `calyx`: Output a `.data` file and Calyx program for simulation. `.futil`, `.data` 4. `all`: All the above. -- `-s`: This is an optional boolean argument that signifies `save_mem`, and is set to true by default. If this flag is set to true, then it will produce a Calyx -design that requires less internal memory usage compared to the design that is produced when this flag is false. +- `-s`: This is an optional boolean argument that signifies `save_mem`, and is set to true by default. If this flag is set to true, then it will produce a Calyx +design that requires less internal memory usage compared to the design that is produced when this flag is false. [lenet]: https://github.com/ekut-es/pico-cnn/blob/master/data/lenet/lenet.onnx -[relay-lang]: https://github.com/cucapra/calyx/tree/master/frontends/relay +[relay-lang]: https://github.com/calyxir/calyx/tree/master/frontends/relay [roesch-etal]: https://arxiv.org/abs/1904.08368 [vgg net]: https://github.com/apache/incubator-tvm/blob/main/python/tvm/relay/testing/vgg.py [mlp net]: https://github.com/apache/incubator-tvm/blob/main/python/tvm/relay/testing/mlp.py diff --git a/docs/fud/axi-gen.md b/docs/fud/axi-gen.md index c6500bd1a..e96995343 100644 --- a/docs/fud/axi-gen.md +++ b/docs/fud/axi-gen.md @@ -30,7 +30,7 @@ Our [toplevel][toplevel] is generated through files in `src/backend/xilinx/`. ### AXI memory controller Here, the [toplevel][toplevel] component of a Calyx program is queried and memories marked [`@external`][external] are turned into AXI buses. -To note, separate AXI interfaces are created for each memory +To note, separate AXI interfaces are created for each memory (meaning, there is no shared bus between memories). Each memory has its own (single port) BRAM which writes data taken from an `mi_axi_RDATA` wire where `i` is the index of the memory. Eventually the BRAMs are read and fed into the @@ -74,10 +74,10 @@ allow this. [pynq]: https://github.com/Xilinx/PYNQ [xclbin]: https://xilinx.github.io/XRT/2021.2/html/formats.html#xclbin -[xilinx_tools]: https://github.com/cucapra/calyx/blob/master/docs/fud/xilinx.md +[xilinx_tools]: https://github.com/calyxir/calyx/blob/master/docs/fud/xilinx.md [kernel_xml]: https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/RTL-Kernel-XML-File [external]: https://docs.calyxir.org/lang/attributes.html?highlight=external#external -[issues]: https://github.com/cucapra/calyx/issues +[issues]: https://github.com/calyxir/calyx/issues [signals]: https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification/Signal-Descriptions?lang=en [bursting]: https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification/Single-Interface-Requirements/Transaction-structure/Address-structure?lang=en [access_protection]: https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI3-and-AXI4-Protocol-Specification/Transaction-Attributes/Access-permissions?lang=en diff --git a/docs/fud/circt.md b/docs/fud/circt.md index 38a49ea6f..c7fdf8049 100644 --- a/docs/fud/circt.md +++ b/docs/fud/circt.md @@ -78,7 +78,7 @@ If you desperately need this, please [open an issue][issue], and we'll try to pr [synth]: ../fud/xilinx.html#synthesis-only [axi-gen]: ../fud/axi-gen.html [`@external`]: ../lang/attributes.html#external -[issue]:https://github.com/cucapra/calyx/issues/new +[issue]:https://github.com/calyxir/calyx/issues/new [circt]: https://circt.llvm.org/ [circt-setup]: https://github.com/llvm/circt#setting-this-up diff --git a/docs/fud/index.md b/docs/fud/index.md index df61a21bf..cf1dad4eb 100644 --- a/docs/fud/index.md +++ b/docs/fud/index.md @@ -9,7 +9,7 @@ incomplete yet daunting list of CLI tools used by Calyx is: - Waveform viewers to see the results of simulation `fud` aims to provide a simple interface for using these toolchains and executing them in a pipeline. -The source for fud is [here](https://github.com/cucapra/calyx/tree/master/fud). +The source for fud is [here](https://github.com/calyxir/calyx/tree/master/fud). ## Installation diff --git a/docs/fud/xilinx.md b/docs/fud/xilinx.md index e0b811543..0b89e7bb5 100644 --- a/docs/fud/xilinx.md +++ b/docs/fud/xilinx.md @@ -46,13 +46,13 @@ The following commands enable remote usage of `vivado` and `vivado-hls` by defau The server must have `vivado` and `vivado_hls` available on the remote machine's path. (If you need the executable names to be something else, please file an issue.) -To tell if this has been set up correctly, run `ssh @` and ensure that you are not prompted for a password. The `ssh-copy-id` command will let you setup your server to authenticate without a password. Note that after you SSH into the server, the Vivado command should work without needing to run any source command. +To tell if this has been set up correctly, run `ssh @` and ensure that you are not prompted for a password. The `ssh-copy-id` command will let you setup your server to authenticate without a password. Note that after you SSH into the server, the Vivado command should work without needing to run any source command. Here's how you would ssh into Havarti: ssh user@havarti.cs.cornell.edu user@havarti:~$ vivado - + ****** Vivado v2020.2 (64-bit) @@ -253,7 +253,7 @@ It sets up the necessary input files and constructs a command line that looks mu [axi]: https://en.wikipedia.org/wiki/Advanced_eXtensible_Interface [xrt]: https://xilinx.github.io/XRT/ [xclbin]: https://xilinx.github.io/XRT/2021.2/html/formats.html#xclbin -[gen_xo]: https://github.com/cucapra/calyx/blob/master/fud/bitstream/gen_xo.tcl +[gen_xo]: https://github.com/calyxir/calyx/blob/master/fud/bitstream/gen_xo.tcl [u50]: https://www.xilinx.com/products/boards-and-kits/alveo/u50.html [wdb]: https://support.xilinx.com/s/article/64000?language=en_US [vitis_tutorial]: https://github.com/Xilinx/Vitis-Tutorials/blob/2021.2/Getting_Started/Vitis/Part2.md diff --git a/docs/intro.md b/docs/intro.md index 7b3355289..872f9dad8 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -34,7 +34,7 @@ If you want just to play with the compiler, install the [`calyx` crate][calyx-cr ``` cargo install calyx ``` -This will install the `calyx` binary which can optimize and compile Calyx programs. You will still need the [`primitives/core.futil`][core-lib] and [its accompanying Verilog file](https://github.com/cucapra/calyx/blob/master/primitives/core.sv) library to compile most programs. +This will install the `calyx` binary which can optimize and compile Calyx programs. You will still need the [`primitives/core.futil`][core-lib] and [its accompanying Verilog file](https://github.com/calyxir/calyx/blob/master/primitives/core.sv) library to compile most programs. ### Installing from Source (to use and extend Calyx) @@ -43,7 +43,7 @@ This should automatically install `cargo`. Clone the repository: ``` -git clone https://github.com/cucapra/calyx.git +git clone https://github.com/calyxir/calyx.git ``` Then build the compiler: ``` @@ -172,6 +172,6 @@ Congratulations! You've simulated your first hardware design with Calyx. [fud-verilator]: ./fud/index.md#verilator [icarus-install-source]: https://iverilog.fandom.com/wiki/Installation_Guide#Installation_From_Source [calyx-crate]: https://crates.io/crates/calyx -[core-lib]: https://github.com/cucapra/calyx/blob/master/primitives/core.futil -[calyx-docker]: https://github.com/cucapra/calyx/pkgs/container/calyx +[core-lib]: https://github.com/calyxir/calyx/blob/master/primitives/core.futil +[calyx-docker]: https://github.com/calyxir/calyx/pkgs/container/calyx [hw-design]: ./intro.md#running-a-hardware-design diff --git a/docs/lang/attributes.md b/docs/lang/attributes.md index ce1c1f063..80e6ca671 100644 --- a/docs/lang/attributes.md +++ b/docs/lang/attributes.md @@ -200,6 +200,6 @@ in = out; Since the value `'x` can be replaced with anything. -[datapath-components]: https://github.com/cucapra/calyx/issues/1169 +[datapath-components]: https://github.com/calyxir/calyx/issues/1169 [builder]: https://docs.rs/calyx-ir/latest/calyx_ir/struct.Builder.html [externalize]: https://docs.rs/calyx-opt/latest/calyx_opt/passes/struct.Externalize.html \ No newline at end of file diff --git a/docs/lang/memories-by-reference.md b/docs/lang/memories-by-reference.md index 74ca26269..aea5329e9 100644 --- a/docs/lang/memories-by-reference.md +++ b/docs/lang/memories-by-reference.md @@ -226,4 +226,4 @@ Here is an example of a memory copy (referred to as `mem_cpy` in the C language) {{#include ../../tests/correctness/invoke-memory.futil}} ``` -[arbiter_6.futil]: https://github.com/cucapra/calyx/blob/master/calyx-py/test/arbiter_6.futil \ No newline at end of file +[arbiter_6.futil]: https://github.com/calyxir/calyx/blob/master/calyx-py/test/arbiter_6.futil \ No newline at end of file diff --git a/docs/lang/sync.md b/docs/lang/sync.md index 861e96c30..51794d833 100644 --- a/docs/lang/sync.md +++ b/docs/lang/sync.md @@ -14,11 +14,11 @@ Consider the following control program in calyx: {{#include ../../examples/sync/unsync-example/unsync-doc-example.futil:control}} ``` -where groups `add_r_to_accm` and `incr_r` reads value and increments value in register `r`, respectively, as indicated by their names. +where groups `add_r_to_accm` and `incr_r` reads value and increments value in register `r`, respectively, as indicated by their names. Because calyx does not make any guarantee of the order of execution for threads running in parallel, it is impossible for us to determine which thread will access r first for each iteration. -Nondeterminism when running parallel threads is beneficial on the compiler's end, as it will give the compiler more freedom for optimization. However, we sometimes do want to give parallel threads a measure of ordering while still taking advantage of the performance boost of parallelism. The `@sync` attribute allows us to do that. +Nondeterminism when running parallel threads is beneficial on the compiler's end, as it will give the compiler more freedom for optimization. However, we sometimes do want to give parallel threads a measure of ordering while still taking advantage of the performance boost of parallelism. The `@sync` attribute allows us to do that. ## Using the `@sync` attribute @@ -32,7 +32,7 @@ Now we want to modify the program above so that in every iteration, thread A alw First and foremost, always remember to import "primitives/sync.futil" when using the @sync attribute. The `@sync` syntax can only be marked with empty statements. `@sync` means that the thread -marked with a certain value, now called barrier index, for this attribute, must stop and wait for all other threads marked with the same barrier index to arrive, at which point they can proceed. +marked with a certain value, now called barrier index, for this attribute, must stop and wait for all other threads marked with the same barrier index to arrive, at which point they can proceed. In the modified program above, we see that `incr_idx` and `incr_r` must both finish in order for either thread to go forth. Because `add_r_to_accm` is executed after `incr_idx` in thread A, we know that in each iteration, `incr_r` will always increment `r` before `add_r_to_accm` reads it. We've also inserted another barrier at the end of the while loops for each thread, which essentially means `add_r_to_accm` has to finish before either thread enters the next iteration. @@ -41,26 +41,26 @@ We can also have "barriers" in `if` branches: ``` {{#include ../../examples/sync/sync-if.futil:control}} ``` -In this control program, both branches of thread 1 have statements marked with `@sync(1)`, +In this control program, both branches of thread 1 have statements marked with `@sync(1)`, which syncs it up with thread 2. Be really really careful when using the `@sync` attribute in conditional branches! -If the other thread sharing one "barrier" with your thread is blocked unconditionally, +If the other thread sharing one "barrier" with your thread is blocked unconditionally, then you would probably want to have the same `@sync` value in both branches; since -having the same `@sync` value in only one branch would likely lead to a "deadlock" -situation: if thread A is running in the unlocked branch while the thread B +having the same `@sync` value in only one branch would likely lead to a "deadlock" +situation: if thread A is running in the unlocked branch while the thread B has a "barrier" that is expecting two threads, thread B may never proceed because thread A never arrives at the "barrier". ## More Complex Example -If you want to see a more complex design using `@sync`, see -[sync-dot-product](https://github.com/cucapra/calyx/blob/master/tests/correctness/sync/sync-dot-product.futil) +If you want to see a more complex design using `@sync`, see +[sync-dot-product](https://github.com/calyxir/calyx/blob/master/tests/correctness/sync/sync-dot-product.futil) ## Limitations -Currently we only support two threads sharing the same "barrier", i.e., only two threads can have control with the `@sync` attribute marked with the same value. +Currently we only support two threads sharing the same "barrier", i.e., only two threads can have control with the `@sync` attribute marked with the same value. [par-undef]: ./undefined.md#semantics-of-par [m-struct]: http://composition.al/blog/2013/09/22/some-example-mvar-ivar-and-lvar-programs-in-haskell/ - [ex]: https://github.com/cucapra/calyx/blob/master/examples/sync/sync.futil \ No newline at end of file + [ex]: https://github.com/calyxir/calyx/blob/master/examples/sync/sync.futil \ No newline at end of file diff --git a/docs/lang/undefined.md b/docs/lang/undefined.md index 65931e1ee..0fe978965 100644 --- a/docs/lang/undefined.md +++ b/docs/lang/undefined.md @@ -6,27 +6,27 @@ Undefined behavior in Calyx is either intentional or unintentional. This page tr The `go` and `done` signals form the two core interface signals in Calyx. Their semantics are baked into the compiler and pervasively used to define the meaning of programs. -- [Isolation and stateful "doneness" (#651)](https://github.com/cucapra/calyx/discussions/651) -- [Well-formedness of `done` signals (#788)](https://github.com/cucapra/calyx/discussions/788) +- [Isolation and stateful "doneness" (#651)](https://github.com/calyxir/calyx/discussions/651) +- [Well-formedness of `done` signals (#788)](https://github.com/calyxir/calyx/discussions/788) ## Undriven Ports Calyx's continuous assignments do not make any static guarantees about which ports need to be driven when. Current efforts attempt to codify *when* reading from an undriven port is incorrect. -- [Port validity as a first class concept (#588)](https://github.com/cucapra/calyx/discussions/588) -- [A few notes on undefinedness (#922)](https://github.com/cucapra/calyx/discussions/922) +- [Port validity as a first class concept (#588)](https://github.com/calyxir/calyx/discussions/588) +- [A few notes on undefinedness (#922)](https://github.com/calyxir/calyx/discussions/922) ## Semantics of `par` `par` blocks in Calyx represent parallel execution of groups. Currently, there is no clear semantics for interactions between groups executing in parallel. The interpreter implements a form of lockstep semantics that disallows certain forms of concurrent reads and writes while the code generated by the compiler allows for arbitrary communication. -- [On the semantics of `par` (#921)](https://github.com/cucapra/calyx/discussions/921) -- [Formalizing the semantics of `par` (#932)](https://github.com/cucapra/calyx/discussions/932) +- [On the semantics of `par` (#921)](https://github.com/calyxir/calyx/discussions/921) +- [Formalizing the semantics of `par` (#932)](https://github.com/calyxir/calyx/discussions/932) ## Isolation Guarantees Calyx groups have a strong isolation guarantee---they must execute for at least one cycle and guarantee that signals inside are not visible after they are done executing. However, the isolation guarantees for combinational groups, continuous assignments, and `with` blocks is not clear. -- [Isolation guarantees of combinational groups](https://github.com/cucapra/calyx/discussions/927) -- [The `with` operator](https://github.com/cucapra/calyx/discussions/934) +- [Isolation guarantees of combinational groups](https://github.com/calyxir/calyx/discussions/927) +- [The `with` operator](https://github.com/calyxir/calyx/discussions/934) diff --git a/docs/tools/data-gen.md b/docs/tools/data-gen.md index bcf605cc3..9b0d531ba 100644 --- a/docs/tools/data-gen.md +++ b/docs/tools/data-gen.md @@ -1,17 +1,17 @@ -# Data Gen +# Data Gen -Data Gen is a tool that can generate a memory json from a Calyx file. It reads -the Calyx file and generates an entry in the json for each cell marked with the -`@external` attribute. Currently, there are two types of number representation formats that can be generated as the data for the memory json: 1) unsigned 32 bit bitnums all equal to 0 and 2) signed, 32 bit fixed point numbers with `frac_width` = 16, and the data is randomly generated. +Data Gen is a tool that can generate a memory json from a Calyx file. It reads +the Calyx file and generates an entry in the json for each cell marked with the +`@external` attribute. Currently, there are two types of number representation formats that can be generated as the data for the memory json: 1) unsigned 32 bit bitnums all equal to 0 and 2) signed, 32 bit fixed point numbers with `frac_width` = 16, and the data is randomly generated. -## How to Run -The following command can be run to generate unsigned, 32-bit zeroes: -`cargo run -p data_gen -- ` +## How to Run +The following command can be run to generate unsigned, 32-bit zeroes: +`cargo run -p data_gen -- ` -To generate random fixed point numbers, run: -`cargo run -p data_gen -- -f true` +To generate random fixed point numbers, run: +`cargo run -p data_gen -- -f true` -It will print the json in the command line +It will print the json in the command line -## Current Limitations -As you can see, the tool is right now pretty limited, because it only supports 2 different representations of numbers. What if you want to generate random, 8 bit, unsigned ints in your memory? Data Gen currently wouldn't support that. Ideally, we would want each Calyx memory cell to have its own attribute(s) which can hold information about what type of number representation format the memory wants. This [github issue](https://github.com/cucapra/calyx/issues/1163) goes into more detail about future improvements for the tool. \ No newline at end of file +## Current Limitations +As you can see, the tool is right now pretty limited, because it only supports 2 different representations of numbers. What if you want to generate random, 8 bit, unsigned ints in your memory? Data Gen currently wouldn't support that. Ideally, we would want each Calyx memory cell to have its own attribute(s) which can hold information about what type of number representation format the memory wants. This [github issue](https://github.com/calyxir/calyx/issues/1163) goes into more detail about future improvements for the tool. \ No newline at end of file diff --git a/docs/tutorial/frontend-tut.md b/docs/tutorial/frontend-tut.md index 3d46bf0bb..fdfbad215 100644 --- a/docs/tutorial/frontend-tut.md +++ b/docs/tutorial/frontend-tut.md @@ -445,13 +445,13 @@ mrxl frontends/mrxl/test/squares.mrxl --data frontends/mrxl/test/squares.mrxl.da This transformation is achieved using a [`fud`][fud] pass that converts MrXL-native data files into Calyx-native data files. -[astcode]: https://github.com/cucapra/calyx/blob/mrxl/mrxl/mrxl/ast.py +[astcode]: https://github.com/calyxir/calyx/blob/mrxl/mrxl/mrxl/ast.py [mrxldocs-install]: https://docs.calyxir.org/frontends/mrxl.html#install [fud]: ../fud/index.md [fud-data]: ../lang/data-format.md [json]: https://www.json.org/json-en.html [calyx-tut]: ./language-tut.md -[mrxl-ast]: https://github.com/cucapra/calyx/blob/master/frontends/mrxl/mrxl/ast.py +[mrxl-ast]: https://github.com/calyxir/calyx/blob/master/frontends/mrxl/mrxl/ast.py [lf-cells]: ../lang/ref.md#cells [lf-wires]: ../lang/ref.md#the-wires-section [lf-groups]: ../lang/ref.md#group-definitions @@ -459,22 +459,22 @@ This transformation is achieved using a [`fud`][fud] pass that converts MrXL-nat [lf-while]: ../lang/ref.md#while [lf-comb-group]: ../lang/ref.md#comb-group-definitions [lf-par]: ../lang/ref.md#par -[impl]: https://github.com/cucapra/calyx/blob/master/frontends/mrxl/mrxl/gen_calyx.py +[impl]: https://github.com/calyxir/calyx/blob/master/frontends/mrxl/mrxl/gen_calyx.py [reduc-trees]: http://www.cs.ucr.edu/~nael/217-f15/lectures/217-lec10.pdf -[builder-arb]: https://github.com/cucapra/calyx/blob/master/calyx-py/test/arbiter_6.py -[builder-red-tree]: https://github.com/cucapra/calyx/blob/master/calyx-py/test/reduction_tree.py +[builder-arb]: https://github.com/calyxir/calyx/blob/master/calyx-py/test/arbiter_6.py +[builder-red-tree]: https://github.com/calyxir/calyx/blob/master/calyx-py/test/reduction_tree.py [flit]: https://flit.readthedocs.io/en/latest/index.html [calyx-py-lib]: ../calyx-py.md [python dataclasses]: https://docs.python.org/3/library/dataclasses.html -[reg-calyx]: https://github.com/cucapra/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/primitives/compile.futil#L22 -[reg-verilog]: https://github.com/cucapra/calyx/blob/master/primitives/compile.futil#L31 -[mem-calyx]: https://github.com/cucapra/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/primitives/compile.futil#L22 -[mem-verilog]: https://github.com/cucapra/calyx/blob/master/primitives/core.sv#L220 -[compute-par]: https://github.com/cucapra/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/frontends/mrxl/mrxl/gen_calyx.py#L312 +[reg-calyx]: https://github.com/calyxir/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/primitives/compile.futil#L22 +[reg-verilog]: https://github.com/calyxir/calyx/blob/master/primitives/compile.futil#L31 +[mem-calyx]: https://github.com/calyxir/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/primitives/compile.futil#L22 +[mem-verilog]: https://github.com/calyxir/calyx/blob/master/primitives/core.sv#L220 +[compute-par]: https://github.com/calyxir/calyx/blob/45075345ae2858b23a599d65d94b0ed7bf949a61/frontends/mrxl/mrxl/gen_calyx.py#L312 [par-undef]: ../lang/ref.md#par -[binary-mult]: https://github.com/cucapra/calyx/blob/master/primitives/binary_operators.sv#L27-L45 +[binary-mult]: https://github.com/calyxir/calyx/blob/master/primitives/binary_operators.sv#L27-L45 [verilator]: https://www.veripool.org/wiki/verilator -[docker]: https://github.com/cucapra/calyx/pkgs/container/calyx +[docker]: https://github.com/calyxir/calyx/pkgs/container/calyx [running-mrxl-example]: #running-mrxl -[mymap-stub]: https://github.com/cucapra/calyx/blob/master/frontends/mrxl/mrxl/gen_calyx.py#L171-L191 +[mymap-stub]: https://github.com/calyxir/calyx/blob/master/frontends/mrxl/mrxl/gen_calyx.py#L171-L191 [banking-need]: #memory-banking diff --git a/docs/tutorial/language-tut.md b/docs/tutorial/language-tut.md index 433fd845b..20bf4a660 100644 --- a/docs/tutorial/language-tut.md +++ b/docs/tutorial/language-tut.md @@ -76,7 +76,7 @@ Assignments at the top level in the `wires` section, like these, are "continuous They always happen, without any need for `control` statements to orchestrate them. We'll see later how to organize assignments into groups. -> The complete program for this section is available under [examples/tutorial/language-tutorial-mem.futil](https://github.com/cucapra/calyx/blob/master/examples/tutorial/language-tutorial-mem.futil). +> The complete program for this section is available under [examples/tutorial/language-tutorial-mem.futil](https://github.com/calyxir/calyx/blob/master/examples/tutorial/language-tutorial-mem.futil). ## Compile & Run @@ -146,7 +146,7 @@ If you're curious to see how the Calyx compiler lowers this program to a Verilog Notably, you'll see `control {}` in the output, meaning that the compiler has eliminated all the control statements and replaced them with continuous assignments in `wires`. -> The complete program for this section is available under [examples/tutorial/language-tutorial-control.futil](https://github.com/cucapra/calyx/blob/master/examples/tutorial/language-tutorial-control.futil). +> The complete program for this section is available under [examples/tutorial/language-tutorial-control.futil](https://github.com/calyxir/calyx/blob/master/examples/tutorial/language-tutorial-control.futil). ## Add an Adder @@ -197,7 +197,7 @@ We will need a `seq` statement to say we want to the three steps sequentially: Try running this program again. The memory's initial value was 10, and its final value after execution should be 14. -> The complete program for this section is available under [examples/tutorial/language-tutorial-compute.futil](https://github.com/cucapra/calyx/blob/master/examples/tutorial/language-tutorial-compute.futil). +> The complete program for this section is available under [examples/tutorial/language-tutorial-compute.futil](https://github.com/calyxir/calyx/blob/master/examples/tutorial/language-tutorial-compute.futil). ## Iterate @@ -258,14 +258,14 @@ By comparing with 8, we should now be running our loop body 8 times. Try running this program again. The output should be the result of adding 4 to the initial value 8 times, so 10 + 8 × 4. -> The complete program for this section is available under [examples/tutorial/language-tutorial-iterate.futil](https://github.com/cucapra/calyx/blob/master/examples/tutorial/language-tutorial-iterate.futil). +> The complete program for this section is available under [examples/tutorial/language-tutorial-iterate.futil](https://github.com/calyxir/calyx/blob/master/examples/tutorial/language-tutorial-iterate.futil). Take a look at the [full language reference][lang-ref] for details on the complete language. [ext-attr]: ../lang/attributes.html#external [json]: https://www.json.org/ [verilator]: https://www.veripool.org/wiki/verilator -[tutorial]: https://github.com/cucapra/calyx/tree/master/examples/tutorial +[tutorial]: https://github.com/calyxir/calyx/tree/master/examples/tutorial [icarus verilog]: http://iverilog.icarus.com [fud]: ../fud/index.md [data-format]: ../lang/data-format.md diff --git a/frontends/relay/dahlia_impl.py b/frontends/relay/dahlia_impl.py index 8365410ae..9ce512dfb 100644 --- a/frontends/relay/dahlia_impl.py +++ b/frontends/relay/dahlia_impl.py @@ -118,7 +118,7 @@ def dropout(fd: DahliaFuncDef) -> str: return emit_dahlia_definition(fd, emit_dahlia_loop(res, loop_body)) -# https://github.com/cucapra/calyx/issues/401 +# https://github.com/calyxir/calyx/issues/401 # Please read the issue above before trying # to lower this using `relay.fromtext`. def expand_dims(fd: DahliaFuncDef) -> str: @@ -344,9 +344,9 @@ def dense(fd: DahliaFuncDef, save_mem=True) -> str: """ tvm.apache.org/docs/api/python/relay/nn.html#tvm.relay.nn.dense If save_mem=True, instead of actually building the transpose of the weight matrix, - we just access W[j][i] everytime we would have accessed W^T[i][j]. It seems - to be a better way (in terms of resource usage) to calculate dense, which - is why it has been save_mem is the default setting. + we just access W[j][i] everytime we would have accessed W^T[i][j]. It seems + to be a better way (in terms of resource usage) to calculate dense, which + is why it has been save_mem is the default setting. """ a, b, res = fd.args[0], fd.args[1], fd.dest type = fd.data_type @@ -495,7 +495,7 @@ def reshape(fd: DahliaFuncDef) -> str: E.g. let %x: Tensor[(1, 2, 2, 2), float32] = ...; let %x1: Tensor[(1, 8), float32] = reshape(%x, newshape[-1, 8]); - + Or supports reshape when the first dimension of the new size is 1 Or supports reshape when all you are going from a 4d to 2d array, but the @@ -781,7 +781,7 @@ def lrn(fd: DahliaFuncDef) -> str: }} }} let __divisor: {data_type} = fp_pow_full((({bias} as {data_type}) + (({alpha} as {data_type}) * __sum)), ({beta} as {data_type})); - {res.id.name}[__n][__c][__h][__w] := {data.id.name}[__n][__c][__h][__w] / __divisor; + {res.id.name}[__n][__c][__h][__w] := {data.id.name}[__n][__c][__h][__w] / __divisor; }} }} }} diff --git a/runt.toml b/runt.toml index db540c2ad..2d971a2f4 100644 --- a/runt.toml +++ b/runt.toml @@ -207,8 +207,11 @@ timeout = 120 [[tests]] name = "correctness static timing" -paths = ["tests/correctness/*.futil", "tests/correctness/ref-cells/*.futil", -"tests/correctness/static-interface/*.futil" ] +paths = [ + "tests/correctness/*.futil", + "tests/correctness/ref-cells/*.futil", + "tests/correctness/static-interface/*.futil", +] cmd = """ fud exec --from calyx --to jq \ --through verilog \ @@ -239,7 +242,7 @@ fud exec --from calyx --to jq \ timeout = 120 # Tests to ensure that static compilation maintains its guarantees -# See: https://github.com/cucapra/calyx/discussions/1331 +# See: https://github.com/calyxir/calyx/discussions/1331 [[tests]] name = "correctness static scheduling" paths = ["tests/correctness/static/*.futil"] @@ -256,7 +259,7 @@ fud exec --from calyx --to jq \ timeout = 120 # Tests to ensure that static compilation maintains its guarantees -# See: https://github.com/cucapra/calyx/discussions/1331 & https://github.com/cucapra/calyx/issues/1344 +# See: https://github.com/calyxir/calyx/discussions/1331 & https://github.com/calyxir/calyx/issues/1344 [[tests]] name = "correctness static control" paths = [ @@ -332,9 +335,7 @@ fud e --from systolic --to jq \ [[tests]] name = "[frontend] systolic array mmult static correctness" -paths = [ - "tests/correctness/systolic/mmult-inputs/*.data" -] +paths = ["tests/correctness/systolic/mmult-inputs/*.data"] cmd = """ fud e --from systolic --to jq \ --through verilog \ @@ -345,13 +346,11 @@ fud e --from systolic --to jq \ -s jq.expr ".memories" \ {}_static.systolic -q """ -expect_dir="tests/correctness/systolic/mmult-expect" +expect_dir = "tests/correctness/systolic/mmult-expect" [[tests]] name = "[frontend] systolic array mmult dynamic correctness" -paths = [ - "tests/correctness/systolic/mmult-inputs/*.data" -] +paths = ["tests/correctness/systolic/mmult-inputs/*.data"] cmd = """ fud e --from systolic --to jq \ --through verilog \ @@ -362,13 +361,11 @@ fud e --from systolic --to jq \ -s jq.expr ".memories" \ {}_dynamic.systolic -q """ -expect_dir="tests/correctness/systolic/mmult-expect" +expect_dir = "tests/correctness/systolic/mmult-expect" [[tests]] name = "[frontend] systolic array relu static correctness" -paths = [ - "tests/correctness/systolic/relu-inputs/*.data" -] +paths = ["tests/correctness/systolic/relu-inputs/*.data"] cmd = """ fud e --from systolic --to jq \ --through verilog \ @@ -379,13 +376,11 @@ fud e --from systolic --to jq \ -s jq.expr ".memories" \ {}_static.systolic -q """ -expect_dir="tests/correctness/systolic/relu-expect" +expect_dir = "tests/correctness/systolic/relu-expect" [[tests]] name = "[frontend] systolic array relu dynamic correctness" -paths = [ - "tests/correctness/systolic/relu-inputs/*.data" -] +paths = ["tests/correctness/systolic/relu-inputs/*.data"] cmd = """ fud e --from systolic --to jq \ --through verilog \ @@ -396,13 +391,11 @@ fud e --from systolic --to jq \ -s jq.expr ".memories" \ {}_dynamic.systolic -q """ -expect_dir="tests/correctness/systolic/relu-expect" +expect_dir = "tests/correctness/systolic/relu-expect" [[tests]] name = "[frontend] systolic array leaky relu correctness" -paths = [ - "tests/correctness/systolic/leaky-relu/*.systolic", -] +paths = ["tests/correctness/systolic/leaky-relu/*.systolic"] cmd = """ fud e --from systolic --to dat \ --through verilog \ diff --git a/tests/correctness/static-control/seq-component-chain.futil b/tests/correctness/static-control/seq-component-chain.futil index 287116951..f5c64d2d2 100644 --- a/tests/correctness/static-control/seq-component-chain.futil +++ b/tests/correctness/static-control/seq-component-chain.futil @@ -5,7 +5,7 @@ import "primitives/pipelined.futil"; /** * Checks to see if the FSM generated for seq activates a component for * exactly the right amount of time. -* Regression: https://github.com/cucapra/calyx/pull/446 +* Regression: https://github.com/calyxir/calyx/pull/446 */ component main() -> () { diff --git a/web/js/index.js b/web/js/index.js index 39da4b006..f6ecb03b6 100644 --- a/web/js/index.js +++ b/web/js/index.js @@ -31,7 +31,7 @@ function createToggle(pass) { button.classList.add("toggle"); button.classList.add("off"); button.innerHTML = pass.title; - button.onclick = function() { + button.onclick = function () { buttonSet(pass, !pass.active); compile(); }; @@ -60,7 +60,7 @@ function selectPasses(item) { } } -document.getElementById("compile").onclick = function() { +document.getElementById("compile").onclick = function () { compile(); }; @@ -109,7 +109,7 @@ async function getLibrary(library, root) { } async function fetchLibs(names, root) { - let proms = names.map(async function(lib) { + let proms = names.map(async function (lib) { let code = await getLibrary(lib, root); return { name: lib, code: code }; }); @@ -117,7 +117,7 @@ async function fetchLibs(names, root) { } const input = document.getElementById("input"); -input.oninput = function() { +input.oninput = function () { CURRENT_CODE.code = input.innerText; }; @@ -126,10 +126,10 @@ input.oninput = function() { // Add examples for the selector const examples_select = document.getElementById("examples-select"); for (let item of config.examples) { - let option = document.createElement('option'); - option.text = item.name; - option.value = JSON.stringify(item); - examples_select.add(option); + let option = document.createElement('option'); + option.text = item.name; + option.value = JSON.stringify(item); + examples_select.add(option); } // Load example from the github repository @@ -148,7 +148,7 @@ async function getExample(name, root) { } // Define onchange method for example selector. -examples_select.onchange = function() { +examples_select.onchange = function () { const input = document.getElementById("input"); const output = document.getElementById("output"); input.innerHTML = "loading..."; @@ -157,10 +157,10 @@ examples_select.onchange = function() { getExample(value.file, value.root) .then(t => CURRENT_CODE = t) .then(() => { - input.innerHTML = CURRENT_CODE.code; - const editor = document.getElementById("diffEditor"); - const srcDiv = editor.querySelector("#input"); - Prism.highlightElement(srcDiv); + input.innerHTML = CURRENT_CODE.code; + const editor = document.getElementById("diffEditor"); + const srcDiv = editor.querySelector("#input"); + Prism.highlightElement(srcDiv); }) .then(() => selectPasses(value)); }; @@ -173,7 +173,7 @@ examples_select.onchange() const ver_div = document.getElementById("calyx-version"); const git_link = document.createElement('a'); git_link.appendChild(document.createTextNode(calyx_info.version.slice(0, 8))); -git_link.href = "https://github.com/cucapra/calyx/tree/" + calyx_info.version; +git_link.href = "https://github.com/calyxir/calyx/tree/" + calyx_info.version; ver_div.appendChild(document.createTextNode("Built with Calyx version ")); ver_div.appendChild(git_link); From 039a9f7dac00345a8a3779e53d28e28d01d2e55b Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 24 Dec 2023 15:31:51 -0500 Subject: [PATCH 124/189] Build docker image if dockerfile changes (#1824) * build docker image if dockerfile changes * change ref * needs * add tag * allow read packages * here goes nothing * if * init * init and remote * try different remote * force --- .github/workflows/depot.yml | 2 +- .github/workflows/rust.yml | 86 ++++++++++++++++++++++++++++++++++--- docs/intro.md | 2 +- web/data/config.json | 2 +- 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/.github/workflows/depot.yml b/.github/workflows/depot.yml index ac6af6480..e64d22cde 100644 --- a/.github/workflows/depot.yml +++ b/.github/workflows/depot.yml @@ -25,7 +25,7 @@ jobs: id: meta uses: docker/metadata-action@v4 with: - images: ghcr.io/cucapra/calyx + images: ghcr.io/calyxir/calyx tags: | type=semver,pattern={{version}} type=raw,value=latest,enable={{is_default_branch}} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6b0bba593..9fc332f41 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -9,10 +9,70 @@ concurrency: cancel-in-progress: true jobs: + # Get the hash of the Dockerfile + hash: + name: Get Docker Hash + runs-on: ubuntu-latest + outputs: + hash: ${{ steps.hash.outputs.hash }} + exists: ${{ steps.exists.outputs.exists }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + repository: calyxir/calyx + ref: ${{ github.sha }} + fetch-depth: 0 + - name: Get hash + id: hash + run: git log -s -n 1 --pretty=format:"%H" -- Dockerfile | echo "hash=$(cat)" >> "$GITHUB_OUTPUT" + - name: Check if image exists + id: exists + run: (docker buildx imagetools inspect ghcr.io/calyxir/calyx:${{ steps.hash.outputs.hash }} &> /dev/null && echo "exists=true" || echo "exists=false") >> "$GITHUB_OUTPUT" + + # Build a docker image for this commit if needed + docker: + name: Build and push docker image + needs: hash + if: ${{ needs.hash.outputs.exists == 'false' }} + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + packages: write + steps: + - name: Login to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ghcr.io/calyxir/calyx + tags: | + type=raw,value=${{ needs.hash.outputs.hash }},enable=true + type=raw,value=latest,enable={{is_default_branch}} + flavor: latest=false + - uses: depot/setup-action@v1 + - uses: depot/build-push-action@v1 + with: + project: zmf9xmg5nl + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + interpreter: name: Test Interpreter + needs: [docker, hash] + if: always() && !failure() && !cancelled() runs-on: ubuntu-latest - container: ghcr.io/cucapra/calyx:0.3.0 + permissions: + packages: read + container: ghcr.io/calyxir/calyx:${{ needs.hash.outputs.hash }} steps: - name: Copy fud configuration run: | @@ -28,8 +88,10 @@ jobs: - name: Checkout commit that triggered run working-directory: /home/calyx run: | + git init + git remote add origin https://github.com/calyxir/calyx.git git fetch --all - git checkout $GITHUB_SHA + git checkout -f $GITHUB_SHA - name: Build uses: actions-rs/cargo@v1 @@ -61,8 +123,12 @@ jobs: compiler: name: Test Compiler + needs: [docker, hash] + if: always() && !failure() && !cancelled() runs-on: ubuntu-latest - container: ghcr.io/cucapra/calyx:0.3.0 + permissions: + packages: read + container: ghcr.io/calyxir/calyx:${{ needs.hash.outputs.hash }} steps: - name: Copy fud configuration run: | @@ -78,8 +144,10 @@ jobs: - name: Checkout commit that triggered run working-directory: /home/calyx run: | + git init + git remote add origin https://github.com/calyxir/calyx.git git fetch --all - git checkout $GITHUB_SHA + git checkout -f $GITHUB_SHA - name: Install calyx-py & MrXL working-directory: /home/calyx @@ -119,8 +187,12 @@ jobs: evaluation: name: Polybench Integration + needs: [docker, hash] + if: always() && !failure() && !cancelled() runs-on: ubuntu-latest - container: ghcr.io/cucapra/calyx:0.3.0 + permissions: + packages: read + container: ghcr.io/calyxir/calyx:${{ needs.hash.outputs.hash }} steps: - name: Copy and clean up fud configuration run: | @@ -136,8 +208,10 @@ jobs: - name: Checkout commit that triggered run working-directory: /home/calyx run: | + git init + git remote add origin https://github.com/calyxir/calyx.git git fetch --all - git checkout $GITHUB_SHA + git checkout -f $GITHUB_SHA - name: Build uses: actions-rs/cargo@v1 diff --git a/docs/intro.md b/docs/intro.md index 872f9dad8..2cf7b61a2 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -18,7 +18,7 @@ The easiest way is to use the [Calyx Docker image][calyx-docker] that provides a The following commands will fetch the Docker image and start a container with an interactive shell: ```sh -docker run -it --rm ghcr.io/cucapra/calyx:latest +docker run -it --rm ghcr.io/calyxir/calyx:latest ``` The `--rm` flag will remove the container after you exit the shell. If you want to keep the container around, remove the flag. diff --git a/web/data/config.json b/web/data/config.json index f0b81ce22..fd32665c5 100644 --- a/web/data/config.json +++ b/web/data/config.json @@ -1,5 +1,5 @@ { - "url_prefix": "https://raw.githubusercontent.com/cucapra/calyx/", + "url_prefix": "https://raw.githubusercontent.com/calyxir/calyx/", "examples": [ { "name": "Sequence", From cdf192cc891029db33f12774315ab04a494a8210 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 26 Dec 2023 16:07:59 -0500 Subject: [PATCH 125/189] Register options for `cell-share` (#1826) * register opts for cell-share * New opts interface for `static-promotion` (#1827) * New opts interface for `static-promotion` * update tests --- calyx-opt/src/passes/cell_share.rs | 185 +++++------------- calyx-opt/src/passes/static_promotion.rs | 93 +++------ calyx-opt/src/traversal/construct.rs | 34 +++- tests/passes/cell-share/bounded.expect | 3 +- tests/passes/cell-share/bounded.futil | 52 ++--- tests/passes/cell-share/calyx_2020.expect | 3 +- tests/passes/cell-share/calyx_2020.futil | 52 ++--- tests/passes/cell-share/static-par.futil | 42 ++-- tests/passes/par-timing-map/nested-par.expect | 54 ++--- tests/passes/par-timing-map/nested-par.futil | 54 ++--- .../passes/par-timing-map/nested-while.expect | 34 ++-- .../passes/par-timing-map/nested-while.futil | 32 +-- tests/passes/par-timing-map/simple.expect | 47 +++-- tests/passes/par-timing-map/simple.futil | 58 +++--- 14 files changed, 324 insertions(+), 419 deletions(-) diff --git a/calyx-opt/src/passes/cell_share.rs b/calyx-opt/src/passes/cell_share.rs index def1c69b1..9ec5f5c5a 100644 --- a/calyx-opt/src/passes/cell_share.rs +++ b/calyx-opt/src/passes/cell_share.rs @@ -1,14 +1,15 @@ use crate::analysis::{ GraphColoring, LiveRangeAnalysis, ReadWriteSet, ShareSet, StaticParTiming, }; -use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; +use crate::traversal::{ + Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, +}; use calyx_ir::rewriter; use calyx_ir::{self as ir}; -use calyx_utils::CalyxResult; +use calyx_utils::{CalyxResult, OutputFile}; use itertools::Itertools; use serde_json::{json, Value}; use std::collections::{HashMap, HashSet}; -use std::fs; // function to turn cell types to string when we are building the json for // share_freqs @@ -94,25 +95,27 @@ pub struct CellShare { /// Cell active in continuous assignments, or ref cells (we want to ignore both) cont_ref_cells: HashSet, - /// The number of times a given class of cell can be shared. bounds should be - /// length 3 to hold the 3 classes: comb cells, registers, and everything else - bounds: Vec>, + /// Maps cell types to the corresponding pdf. Each pdf is a hashmap which maps + /// the number of times a given cell name reused (i.e., shared) to the + /// number of cells that have been shared that many times times. + share_freqs: HashMap>>, /// maps the ids of groups to a set of tuples (i,j), the clock cycles (relative /// to the start of the par) that group is live par_timing_map: StaticParTiming, - print_par_timing: bool, + // ========= Pass Options ============ + /// The number of times a given class of cell can be shared. bounds should be + /// length 3 to hold the 3 classes: comb cells, registers, and everything else + bounds: [Option; 3], + /// executes cell share pass using Calyx 2020 benchmarks: no component /// sharing, and only sharing registers and combinational components calyx_2020: bool, - /// Maps cell types to the corresponding pdf. Each pdf is a hashmap which maps - /// the number of times a given cell name reused (i.e., shared) to the - /// number of cells that have been shared that many times times. - share_freqs: HashMap>>, /// whether or not to print the share_freqs - print_share_freqs: Option, + print_share_freqs: Option, + print_par_timing: Option, } impl Named for CellShare { @@ -122,14 +125,42 @@ impl Named for CellShare { fn description() -> &'static str { "use the fewest possible cells" } + + fn opts() -> Vec { + vec![ + PassOpt::new( + "print-share-freqs", + "print sharing frequencies", + ParseVal::OutStream(OutputFile::Null), + PassOpt::parse_outstream + ), + PassOpt::new( + "bounds", + "maximum amount of sharing for combinational components, registers, and other components. Negative valye means no bound", + ParseVal::List(vec![]), + PassOpt::parse_num_list + ), + PassOpt::new( + "print-par-timing", + "print timing information for `par` blocks", + ParseVal::OutStream(OutputFile::Null), + PassOpt::parse_outstream + ), + PassOpt::new( + "calyx-2020", + "share using the Calyx 2020 settings: no component sharing, only share registers/combinational components", + ParseVal::Bool(false), + PassOpt::parse_bool + ) + ] + } } impl ConstructVisitor for CellShare { fn from(ctx: &ir::Context) -> CalyxResult { let state_shareable = ShareSet::from_context::(ctx); let shareable = ShareSet::from_context::(ctx); - let (print_share_freqs, bounds, print_par_timing, calyx_2020) = - Self::parse_args(ctx); + let opts = Self::get_opts(ctx); Ok(CellShare { live: LiveRangeAnalysis::default(), @@ -137,12 +168,12 @@ impl ConstructVisitor for CellShare { cont_ref_cells: HashSet::new(), state_shareable, shareable, - bounds, par_timing_map: StaticParTiming::default(), - print_par_timing, - calyx_2020, share_freqs: HashMap::new(), - print_share_freqs, + calyx_2020: opts["calyx-2020"].bool(), + bounds: opts["bounds"].num_list_exact::<3>(), + print_par_timing: opts["print-par-timing"].not_null_outstream(), + print_share_freqs: opts["print-share-freqs"].not_null_outstream(), }) } @@ -185,8 +216,8 @@ impl CellShare { comp.name, &self.live, ); - if self.print_par_timing { - println!("{:?}", self.par_timing_map); + if let Some(stream) = &self.print_par_timing { + write!(stream.get_write(), "{:?}", self.par_timing_map).unwrap(); } } @@ -202,110 +233,6 @@ impl CellShare { } } - // given a ctx, gets the - // 1) file to write the sharing frequencies. for example, if "-x cell-share:print-share-freqs=a.json", - // we would return Some(a.json). - // 2) gets the bounds. For example, if "-x cell-share:bounds=2,3,4" is passed - // we would return [Some(2),Some(3),Some(4)]. - // 3) whether to print the par timing map. For exampe, if "-x cell-share:print_par_timing" - ///4) whether to run sharing with Calyx 2020 settings: no component sharing, - /// only share registers/combinational components (e.g., "-x cell-share:calyx_2020") - /// 5) whether to share across static par threads (e.g., "-x cell-share:share_static_par") - // is passed, then we would return true. - fn parse_args( - ctx: &ir::Context, - ) -> (Option, Vec>, bool, bool) - where - Self: Named, - { - let n = Self::name(); - - // getting the given opts for -x cell-share:__ - let given_opts: HashSet<_> = ctx - .extra_opts - .iter() - .filter_map(|opt| { - let mut splits = opt.split(':'); - if splits.next() == Some(n) { - splits.next() - } else { - None - } - }) - .collect(); - - // searching for "-x cell-share:bounds=x,y,z" and getting back "x,y,z" - let bounds_arg = given_opts.iter().find_map(|arg| { - let split: Vec<&str> = arg.split('=').collect(); - if let Some(str) = split.first() { - if str == &"bounds" && split.len() == 2 { - return Some(split[1]); - } - } - None - }); - - let (mut print_par_timing, mut calyx_2020) = (false, false); - // these we know what the exact flags will be so we don't have to pars,e - // just check if they're there - given_opts.iter().for_each(|arg| { - if *arg == "print_par_timing" { - print_par_timing = true - } else if *arg == "calyx_2020" { - calyx_2020 = true - } - }); - - // searching for "-x cell-share:print-share-freqs=file_name" and getting Some(file_name) back - let print_pdf_arg = given_opts.iter().find_map(|arg| { - let split: Vec<&str> = arg.split('=').collect(); - if let Some(str) = split.first() { - if str == &"print-share-freqs" && split.len() == 2 { - return Some(split[1].to_string()); - } - } - None - }); - - let mut bounds = Vec::new(); - let mut set_default = false; - - // if bounds_arg = "x,y,z", set bounds to [Some(x),Some(y),Some(z)] - // a -1 argument means no bound since that means we always want to share - if let Some(s) = bounds_arg { - bounds = s - .split(',') - .map(|s| { - let val = s.parse::().unwrap_or(-2); - if val == -1 { - None - } else { - Some(val) - } - }) - .collect(); - } else { - set_default = true; - } - - if bounds.len() != 3 || bounds.contains(&Some(-2)) { - set_default = true; - } - - if set_default { - // could possibly put vec![x,y,z] where x,y, and z are deliberately - // chosen numbers here instead - ( - print_pdf_arg, - vec![None, None, None], - print_par_timing, - calyx_2020, - ) - } else { - (print_pdf_arg, bounds, print_par_timing, calyx_2020) - } - } - // prints the json if self.print_share_freqs is not None fn print_share_json(&self) { if let Some(file) = &self.print_share_freqs { @@ -325,15 +252,7 @@ impl CellShare { }) .collect(); let json_share_freqs: Value = json!(printable_share_freqs); - if file == "stdout" { - println!("{json_share_freqs}"); - } else if file == "stderr" { - eprintln!("{json_share_freqs}"); - std::process::exit(1); - } else { - fs::write(file, format!("{}", json_share_freqs)) - .expect("unable to write file"); - } + write!(file.get_write(), "{}", json_share_freqs).unwrap() } } } diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index e5c3210d0..2d3182cea 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -1,12 +1,13 @@ use crate::analysis::{GraphAnalysis, ReadWriteSet}; use crate::traversal::{ - Action, ConstructVisitor, Named, Order, VisResult, Visitor, + Action, ConstructVisitor, Named, Order, ParseVal, PassOpt, VisResult, + Visitor, }; use calyx_ir::{self as ir, LibrarySignatures, RRC}; use calyx_utils::{CalyxResult, Error}; use ir::GetAttributes; use itertools::Itertools; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; @@ -177,13 +178,13 @@ impl ConstructVisitor for StaticPromotion { } latency_data.insert(prim.name, GoDone::new(go_ports)); } - let (threshold, cycle_limit) = Self::get_threshold(ctx); + let opts = Self::get_opts(ctx); Ok(StaticPromotion { latency_data, static_group_name: HashMap::new(), static_component_latencies: HashMap::new(), - threshold, - cycle_limit, + threshold: opts["threshold"].pos_num().unwrap(), + cycle_limit: opts["cycle-limit"].pos_num(), }) } @@ -199,71 +200,28 @@ impl Named for StaticPromotion { } fn description() -> &'static str { - "promote groups and controls whose latency can be inferred to static groups and controls" + "promote dynamic control programs to static when possible" } -} - -impl StaticPromotion { - // Looks through ctx to get the given command line threshold. - // Default threshold = 1 - fn get_threshold(ctx: &ir::Context) -> (u64, Option) - where - Self: Named, - { - let n = Self::name(); - - // getting the given opts for -x cell-share:__ - let given_opts: HashSet<_> = ctx - .extra_opts - .iter() - .filter_map(|opt| { - let mut splits = opt.split(':'); - if splits.next() == Some(n) { - splits.next() - } else { - None - } - }) - .collect(); - // searching for "-x static-promotion:cycle-limit=200" and getting back "200" - let cycle_limit_str: Option<&str> = given_opts.iter().find_map(|arg| { - let split: Vec<&str> = arg.split('=').collect(); - if let Some(str) = split.first() { - if str == &"cycle-limit" { - return Some(split[1]); - } - } - None - }); - - // Default to None. There may be a more idiomatic way to do this. - let cycle_limit = match cycle_limit_str.unwrap_or("None").parse::() - { - Ok(n) => Some(n), - Err(_) => None, - }; - - // searching for "-x static-promotion:threshold=1" and getting back "1" - let threshold: Option<&str> = given_opts.iter().find_map(|arg| { - let split: Vec<&str> = arg.split('=').collect(); - if let Some(str) = split.first() { - if str == &"threshold" { - return Some(split[1]); - } - } - None - }); - - // Need to convert string argument into int argument - // Always default to threshold=1 - // Default cycle limit = 2^25 = 33554432 - ( - threshold.unwrap_or("1").parse::().unwrap_or(1), - cycle_limit, - ) + fn opts() -> Vec { + vec![ + PassOpt::new( + "threshold", + "minimum number of groups needed to promote a dynamic control program to static", + ParseVal::Num(1), + PassOpt::parse_num, + ), + PassOpt::new( + "cycle-limit", + "maximum number of cycles to promote a dynamic control program to static", + ParseVal::Num(33554432), + PassOpt::parse_num, + ) + ] } +} +impl StaticPromotion { /// Return true if the edge (`src`, `dst`) meet one these criteria, and false otherwise: /// - `src` is an "out" port of a constant, and `dst` is a "go" port /// - `src` is a "done" port, and `dst` is a "go" port @@ -496,7 +454,8 @@ impl StaticPromotion { /// Will raise an error if neither of these is true. fn get_inferred_latency(c: &ir::Control) -> u64 { let ir::Control::Static(sc) = c else { - let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) else { + let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) + else { unreachable!("Called get_latency on control that is neither static nor promotable") }; return latency; diff --git a/calyx-opt/src/traversal/construct.rs b/calyx-opt/src/traversal/construct.rs index 9f9ff3b76..e9b64b590 100644 --- a/calyx-opt/src/traversal/construct.rs +++ b/calyx-opt/src/traversal/construct.rs @@ -3,6 +3,7 @@ use calyx_ir as ir; use calyx_utils::{CalyxResult, OutputFile}; use itertools::Itertools; use linked_hash_map::LinkedHashMap; +use std::iter; #[derive(Clone)] /// The value returned from parsing an option. @@ -10,7 +11,7 @@ pub enum ParseVal { /// A boolean option. Bool(bool), /// A number option. - Num(usize), + Num(i64), /// A list of values. List(Vec), /// An output stream (stdout, stderr, file name) @@ -25,14 +26,23 @@ impl ParseVal { *b } - pub fn num(&self) -> usize { + pub fn num(&self) -> i64 { let ParseVal::Num(n) = self else { panic!("Expected number, got {self}"); }; *n } - pub fn num_list(&self) -> Vec { + pub fn pos_num(&self) -> Option { + let n = self.num(); + if n < 0 { + None + } else { + Some(n as u64) + } + } + + pub fn num_list(&self) -> Vec { match self { ParseVal::List(l) => { l.iter().map(ParseVal::num).collect::>() @@ -41,6 +51,22 @@ impl ParseVal { } } + /// Parse a list that should have exactly N elements. If elements are missing, then add None + /// to the end of the list. + pub fn num_list_exact(&self) -> [Option; N] { + let list = self.num_list(); + let len = list.len(); + if len > N { + panic!("Expected list of {N} numbers, got {len}"); + } + list.into_iter() + .map(Some) + .chain(iter::repeat(None).take(N - len)) + .collect::>() + .try_into() + .unwrap() + } + /// Returns an output stream if it is not the null stream pub fn not_null_outstream(&self) -> Option { match self { @@ -137,7 +163,7 @@ impl PassOpt { /// Parse a number from a string. pub fn parse_num(s: &str) -> Option { - s.parse::().ok().map(ParseVal::Num) + s.parse::().ok().map(ParseVal::Num) } /// Parse a list of numbers from a string. diff --git a/tests/passes/cell-share/bounded.expect b/tests/passes/cell-share/bounded.expect index ccb0b742a..ebb847794 100644 --- a/tests/passes/cell-share/bounded.expect +++ b/tests/passes/cell-share/bounded.expect @@ -1,4 +1,3 @@ -{"main":{"std_add_WIDTH_32":{"2":3},"std_mult_pipe_WIDTH_32":{"6":1},"std_reg_WIDTH_32":{"2":1,"4":1}}} import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @@ -107,3 +106,5 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +{"main":{"std_add_WIDTH_32":{"2":3},"std_mult_pipe_WIDTH_32":{"6":1},"std_reg_WIDTH_32":{"2":1,"4":1}}} \ No newline at end of file diff --git a/tests/passes/cell-share/bounded.futil b/tests/passes/cell-share/bounded.futil index b5ca66e16..a66b62b6b 100644 --- a/tests/passes/cell-share/bounded.futil +++ b/tests/passes/cell-share/bounded.futil @@ -1,5 +1,5 @@ -// -p cell-share -x cell-share:bounds=2,4,-1 -x cell-share:print-share-freqs=stdout -p dead-cell-removal -p remove-ids -// share adders twice, registers 3 times, and mults 4 times +// -p cell-share -x cell-share:bounds=2,4,-1 -x cell-share:print-share-freqs= -p dead-cell-removal -p remove-ids +// share adders twice, registers 3 times, and mults 4 times import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { @@ -67,40 +67,40 @@ component main() -> () { let5[done] = f.done; } group m0{ - mult0.go = 1'd1; - mult0.left = 32'd1; - mult0.right = 32'd2; - m0[done] = mult0.done; + mult0.go = 1'd1; + mult0.left = 32'd1; + mult0.right = 32'd2; + m0[done] = mult0.done; } group m1{ - mult1.go = 1'd1; - mult1.left = 32'd1; - mult1.right = 32'd2; - m1[done] = mult1.done; + mult1.go = 1'd1; + mult1.left = 32'd1; + mult1.right = 32'd2; + m1[done] = mult1.done; } group m2{ - mult2.go = 1'd1; - mult2.left = 32'd1; - mult2.right = 32'd2; - m2[done] = mult2.done; + mult2.go = 1'd1; + mult2.left = 32'd1; + mult2.right = 32'd2; + m2[done] = mult2.done; } group m3{ - mult3.go = 1'd1; - mult3.left = 32'd1; - mult3.right = 32'd2; - m3[done] = mult3.done; + mult3.go = 1'd1; + mult3.left = 32'd1; + mult3.right = 32'd2; + m3[done] = mult3.done; } group m4{ - mult4.go = 1'd1; - mult4.left = 32'd1; - mult4.right = 32'd2; - m4[done] = mult4.done; + mult4.go = 1'd1; + mult4.left = 32'd1; + mult4.right = 32'd2; + m4[done] = mult4.done; } group m5{ - mult5.go = 1'd1; - mult5.left = 32'd1; - mult5.right = 32'd2; - m5[done] = mult5.done; + mult5.go = 1'd1; + mult5.left = 32'd1; + mult5.right = 32'd2; + m5[done] = mult5.done; } } control { diff --git a/tests/passes/cell-share/calyx_2020.expect b/tests/passes/cell-share/calyx_2020.expect index cfcabc0f6..aedb4dd14 100644 --- a/tests/passes/cell-share/calyx_2020.expect +++ b/tests/passes/cell-share/calyx_2020.expect @@ -1,4 +1,3 @@ -{"main":{"std_add_WIDTH_32":{"6":1},"std_mult_pipe_WIDTH_32":{"1":6},"std_reg_WIDTH_32":{"6":1}}} import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @@ -109,3 +108,5 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +{"main":{"std_add_WIDTH_32":{"6":1},"std_mult_pipe_WIDTH_32":{"1":6},"std_reg_WIDTH_32":{"6":1}}} \ No newline at end of file diff --git a/tests/passes/cell-share/calyx_2020.futil b/tests/passes/cell-share/calyx_2020.futil index 93047034c..83f2d9c43 100644 --- a/tests/passes/cell-share/calyx_2020.futil +++ b/tests/passes/cell-share/calyx_2020.futil @@ -1,5 +1,5 @@ -// -p cell-share -x cell-share:calyx_2020 -x cell-share:print-share-freqs=stdout -p dead-cell-removal -p remove-ids -// share adders twice, registers 3 times, and mults 4 times +// -p cell-share -x cell-share:calyx-2020 -x cell-share:print-share-freqs= -p dead-cell-removal -p remove-ids +// share adders twice, registers 3 times, and mults 4 times import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { @@ -67,40 +67,40 @@ component main() -> () { let5[done] = f.done; } group m0{ - mult0.go = 1'd1; - mult0.left = 32'd1; - mult0.right = 32'd2; - m0[done] = mult0.done; + mult0.go = 1'd1; + mult0.left = 32'd1; + mult0.right = 32'd2; + m0[done] = mult0.done; } group m1{ - mult1.go = 1'd1; - mult1.left = 32'd1; - mult1.right = 32'd2; - m1[done] = mult1.done; + mult1.go = 1'd1; + mult1.left = 32'd1; + mult1.right = 32'd2; + m1[done] = mult1.done; } group m2{ - mult2.go = 1'd1; - mult2.left = 32'd1; - mult2.right = 32'd2; - m2[done] = mult2.done; + mult2.go = 1'd1; + mult2.left = 32'd1; + mult2.right = 32'd2; + m2[done] = mult2.done; } group m3{ - mult3.go = 1'd1; - mult3.left = 32'd1; - mult3.right = 32'd2; - m3[done] = mult3.done; + mult3.go = 1'd1; + mult3.left = 32'd1; + mult3.right = 32'd2; + m3[done] = mult3.done; } group m4{ - mult4.go = 1'd1; - mult4.left = 32'd1; - mult4.right = 32'd2; - m4[done] = mult4.done; + mult4.go = 1'd1; + mult4.left = 32'd1; + mult4.right = 32'd2; + m4[done] = mult4.done; } group m5{ - mult5.go = 1'd1; - mult5.left = 32'd1; - mult5.right = 32'd2; - m5[done] = mult5.done; + mult5.go = 1'd1; + mult5.left = 32'd1; + mult5.right = 32'd2; + m5[done] = mult5.done; } } control { diff --git a/tests/passes/cell-share/static-par.futil b/tests/passes/cell-share/static-par.futil index 8dc5917f1..aa38fdf43 100644 --- a/tests/passes/cell-share/static-par.futil +++ b/tests/passes/cell-share/static-par.futil @@ -1,4 +1,4 @@ -// -p cell-share -x cell-share:share_static_par -p remove-ids +// -p cell-share -p remove-ids import "primitives/core.futil"; component main() -> () { cells { @@ -6,63 +6,63 @@ component main() -> () { a = std_reg(32); b = std_reg(32); c = std_reg(16); - d = std_reg(16); + d = std_reg(16); x = std_reg(4); sl = std_slice(16, 4); } wires { static<1> group wr_a { - a.write_en = 1'd1; - a.in = 32'd2; + a.write_en = 1'd1; + a.in = 32'd2; } static<1> group wr_b { - b.write_en = 1'd1; - b.in = 32'd2; + b.write_en = 1'd1; + b.in = 32'd2; } static<1> group wr_x { - x.write_en = 1'd1; - x.in = 4'd2; + x.write_en = 1'd1; + x.in = 4'd2; } static<1> group wr_c { - c.write_en = 1'd1; - c.in = 16'd4; + c.write_en = 1'd1; + c.in = 16'd4; } static<1> group wr_d { d.write_en = 1'd1; - d.in = 16'd4; + d.in = 16'd4; } static<1> group read_c { - sl.in = c.out; - x.write_en = 1'd1; - x.in = sl.out; + sl.in = c.out; + x.write_en = 1'd1; + x.in = sl.out; } } control { seq{ - // a and b should be shared, never will be live at same time + // a and b should be shared, never will be live at same time static par { static if lt.out{ wr_a; } else{ - wr_b; + wr_b; } static seq { - wr_x; + wr_x; wr_b; } } - // c and d shouldn't shared + // c and d shouldn't shared static par{ static seq{ - wr_c; + wr_c; wr_x; read_c; } static seq{ - wr_x; + wr_x; wr_d; - wr_x; + wr_x; } } } diff --git a/tests/passes/par-timing-map/nested-par.expect b/tests/passes/par-timing-map/nested-par.expect index 7eed3ac6f..9f3ca69d9 100644 --- a/tests/passes/par-timing-map/nested-par.expect +++ b/tests/passes/par-timing-map/nested-par.expect @@ -1,30 +1,3 @@ -This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, - relative to the start of the given par block -============ Map for Component "main" ============ -========Par Node ID: 0 ======== -====Child/Thread ID: 1 ==== -Id { id: "b" } -- [(4, 8)] -Id { id: "a" } -- [(0, 4)] -Id { id: "c" } -- [(8, 12)] -====Child/Thread ID: 5 ==== -Id { id: "e" } -- [(1, 5)] -Id { id: "d" } -- [(0, 1), (9, 10)] -Id { id: "f" } -- [(5, 9)] -Id { id: "h" } -- [(3, 5)] -Id { id: "g" } -- [(1, 3)] -====Child/Thread ID: 15 ==== -Id { id: "j" } -- [(1, 2), (3, 4), (5, 6), (7, 8)] -Id { id: "i" } -- [(0, 1), (2, 3), (4, 5), (6, 7)] - -========Par Node ID: 7 ======== -====Child/Thread ID: 8 ==== -Id { id: "e" } -- [(0, 4)] -Id { id: "f" } -- [(4, 8)] -====Child/Thread ID: 11 ==== -Id { id: "h" } -- [(2, 4)] -Id { id: "g" } -- [(0, 2)] - - import "primitives/core.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -112,3 +85,30 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, + relative to the start of the given par block +============ Map for Component "main" ============ +========Par Node ID: 0 ======== +====Child/Thread ID: 1 ==== +Id { id: "b" } -- [(4, 8)] +Id { id: "a" } -- [(0, 4)] +Id { id: "c" } -- [(8, 12)] +====Child/Thread ID: 5 ==== +Id { id: "e" } -- [(1, 5)] +Id { id: "d" } -- [(0, 1), (9, 10)] +Id { id: "f" } -- [(5, 9)] +Id { id: "h" } -- [(3, 5)] +Id { id: "g" } -- [(1, 3)] +====Child/Thread ID: 15 ==== +Id { id: "j" } -- [(1, 2), (3, 4), (5, 6), (7, 8)] +Id { id: "i" } -- [(0, 1), (2, 3), (4, 5), (6, 7)] + +========Par Node ID: 7 ======== +====Child/Thread ID: 8 ==== +Id { id: "e" } -- [(0, 4)] +Id { id: "f" } -- [(4, 8)] +====Child/Thread ID: 11 ==== +Id { id: "h" } -- [(2, 4)] +Id { id: "g" } -- [(0, 2)] + diff --git a/tests/passes/par-timing-map/nested-par.futil b/tests/passes/par-timing-map/nested-par.futil index a35860a86..1cc81fa62 100644 --- a/tests/passes/par-timing-map/nested-par.futil +++ b/tests/passes/par-timing-map/nested-par.futil @@ -1,4 +1,4 @@ -// -p cell-share -x cell-share:print_par_timing +// -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -16,55 +16,55 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<4> group A { - a.write_en = 1'd1; - a.in = 32'd2; + a.write_en = 1'd1; + a.in = 32'd2; } static<4> group B { - b.write_en = 1'd1; - b.in = 32'd2; + b.write_en = 1'd1; + b.in = 32'd2; } static<4> group C { - c.write_en = 1'd1; - c.in = 32'd2; + c.write_en = 1'd1; + c.in = 32'd2; } static<1> group D { - d.write_en = 1'd1; - d.in = 32'd2; + d.write_en = 1'd1; + d.in = 32'd2; } static<4> group E { - e.write_en = 1'd1; - e.in = 32'd2; + e.write_en = 1'd1; + e.in = 32'd2; } static<4> group F { - f.write_en = 1'd1; - f.in = 32'd2; + f.write_en = 1'd1; + f.in = 32'd2; } static<2> group G { - g.write_en = 1'd1; - g.in = 32'd2; + g.write_en = 1'd1; + g.in = 32'd2; } static<2> group H { - h.write_en = 1'd1; - h.in = 32'd2; + h.write_en = 1'd1; + h.in = 32'd2; } static<1> group I { - i.write_en = 1'd1; - i.in = 32'd2; + i.write_en = 1'd1; + i.in = 32'd2; } static<1> group J { - j.write_en = 1'd1; - j.in = 32'd2; + j.write_en = 1'd1; + j.in = 32'd2; } } control { static par { static seq { A; B; C;} - static seq { - D; - static par{ - static seq { E; F;} - static seq { G; H;} - } + static seq { + D; + static par{ + static seq { E; F;} + static seq { G; H;} + } D; } static repeat 4 {static seq{ I; J;}} diff --git a/tests/passes/par-timing-map/nested-while.expect b/tests/passes/par-timing-map/nested-while.expect index ab5bffa21..532e7a034 100644 --- a/tests/passes/par-timing-map/nested-while.expect +++ b/tests/passes/par-timing-map/nested-while.expect @@ -1,20 +1,3 @@ -This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, - relative to the start of the given par block -============ Map for Component "main" ============ -========Par Node ID: 1 ======== -====Child/Thread ID: 2 ==== -Id { id: "b" } -- [(0, 3), (11, 14), (22, 25), (37, 40), (48, 51), (59, 62)] -Id { id: "a" } -- [(0, 3), (11, 14), (22, 25), (37, 40), (48, 51), (59, 62)] -Id { id: "d" } -- [(33, 37), (70, 74)] -Id { id: "c" } -- [(3, 7), (7, 11), (14, 18), (18, 22), (25, 29), (29, 33), (40, 44), (44, 48), (51, 55), (55, 59), (62, 66), (66, 70)] - -========Par Node ID: 6 ======== -====Child/Thread ID: 7 ==== -Id { id: "a" } -- [(0, 3)] -====Child/Thread ID: 8 ==== -Id { id: "b" } -- [(0, 3)] - - import "primitives/core.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -85,3 +68,20 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, + relative to the start of the given par block +============ Map for Component "main" ============ +========Par Node ID: 1 ======== +====Child/Thread ID: 2 ==== +Id { id: "b" } -- [(0, 3), (11, 14), (22, 25), (37, 40), (48, 51), (59, 62)] +Id { id: "a" } -- [(0, 3), (11, 14), (22, 25), (37, 40), (48, 51), (59, 62)] +Id { id: "d" } -- [(33, 37), (70, 74)] +Id { id: "c" } -- [(3, 7), (7, 11), (14, 18), (18, 22), (25, 29), (29, 33), (40, 44), (44, 48), (51, 55), (55, 59), (62, 66), (66, 70)] + +========Par Node ID: 6 ======== +====Child/Thread ID: 7 ==== +Id { id: "a" } -- [(0, 3)] +====Child/Thread ID: 8 ==== +Id { id: "b" } -- [(0, 3)] + diff --git a/tests/passes/par-timing-map/nested-while.futil b/tests/passes/par-timing-map/nested-while.futil index 700470b2f..b2fd1b0e9 100644 --- a/tests/passes/par-timing-map/nested-while.futil +++ b/tests/passes/par-timing-map/nested-while.futil @@ -1,4 +1,4 @@ -// -p cell-share -x cell-share:print_par_timing +// -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -13,32 +13,32 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<3> group A { - a.write_en = 1'd1; - a.in = 32'd2; + a.write_en = 1'd1; + a.in = 32'd2; } static<3> group B { - b.write_en = 1'd1; - b.in = 32'd2; + b.write_en = 1'd1; + b.in = 32'd2; } static<4> group C { - c.write_en = 1'd1; - c.in = 32'd2; + c.write_en = 1'd1; + c.in = 32'd2; } static<4> group D { - d.write_en = 1'd1; - d.in = 32'd2; + d.write_en = 1'd1; + d.in = 32'd2; } static<4> group E { - e.write_en = 1'd1; - e.in = 32'd2; + e.write_en = 1'd1; + e.in = 32'd2; } static<4> group F { - f.write_en = 1'd1; - f.in = 32'd2; + f.write_en = 1'd1; + f.in = 32'd2; } static<4> group G { - g.write_en = 1'd1; - g.in = 32'd2; + g.write_en = 1'd1; + g.in = 32'd2; } } @@ -62,7 +62,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } static seq { - E; + E; F; G; } diff --git a/tests/passes/par-timing-map/simple.expect b/tests/passes/par-timing-map/simple.expect index 235246eb8..9e82b2ae6 100644 --- a/tests/passes/par-timing-map/simple.expect +++ b/tests/passes/par-timing-map/simple.expect @@ -1,27 +1,3 @@ -This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, - relative to the start of the given par block -============ Map for Component "comp" ============ -========Par Node ID: 6 ======== -====Child/Thread ID: 7 ==== -Id { id: "e" } -- [(2, 3)] -Id { id: "d" } -- [(0, 2)] -====Child/Thread ID: 10 ==== -Id { id: "f" } -- [(0, 1)] -Id { id: "g" } -- [(1, 3)] - - -This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, - relative to the start of the given par block -============ Map for Component "main" ============ -========Par Node ID: 0 ======== -====Child/Thread ID: 1 ==== -Id { id: "b" } -- [(0, 3)] -Id { id: "a" } -- [(0, 2)] -Id { id: "c" } -- [(3, 6)] -====Child/Thread ID: 7 ==== -Id { id: "d" } -- [(0, 4)] - - import "primitives/core.futil"; component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -130,3 +106,26 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } +---STDERR--- +This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, + relative to the start of the given par block +============ Map for Component "comp" ============ +========Par Node ID: 6 ======== +====Child/Thread ID: 7 ==== +Id { id: "e" } -- [(2, 3)] +Id { id: "d" } -- [(0, 2)] +====Child/Thread ID: 10 ==== +Id { id: "f" } -- [(0, 1)] +Id { id: "g" } -- [(1, 3)] + +This maps ids of par blocks to " cell timing maps ", which map cells to intervals (i,j), that signify the clock cycles the group is active for, + relative to the start of the given par block +============ Map for Component "main" ============ +========Par Node ID: 0 ======== +====Child/Thread ID: 1 ==== +Id { id: "b" } -- [(0, 3)] +Id { id: "a" } -- [(0, 2)] +Id { id: "c" } -- [(3, 6)] +====Child/Thread ID: 7 ==== +Id { id: "d" } -- [(0, 4)] + diff --git a/tests/passes/par-timing-map/simple.futil b/tests/passes/par-timing-map/simple.futil index 78771228f..5399026bc 100644 --- a/tests/passes/par-timing-map/simple.futil +++ b/tests/passes/par-timing-map/simple.futil @@ -1,4 +1,4 @@ -// -p cell-share -x cell-share:print_par_timing +// -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -13,35 +13,35 @@ component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { group A{ - a.write_en = 1'd1; - a.in = 32'd2; + a.write_en = 1'd1; + a.in = 32'd2; A[done] = a.done; } group B{ - b.write_en = 1'd1; - b.in = 32'd2; + b.write_en = 1'd1; + b.in = 32'd2; B[done] = b.done; } group C{ - c.write_en = 1'd1; - c.in = 32'd2; - C[done] = c.done; + c.write_en = 1'd1; + c.in = 32'd2; + C[done] = c.done; } static<2> group D { - d.write_en = 1'd1; - d.in = 32'd2; + d.write_en = 1'd1; + d.in = 32'd2; } static<1> group E { - e.write_en = 1'd1; - e.in = 32'd2; + e.write_en = 1'd1; + e.in = 32'd2; } static<1> group F { - f.write_en = 1'd1; - f.in = 32'd2; + f.write_en = 1'd1; + f.in = 32'd2; } static<2> group G { - g.write_en = 1'd1; - g.in = 32'd2; + g.write_en = 1'd1; + g.in = 32'd2; } } @@ -51,11 +51,11 @@ component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } else{ seq{ - C; + C; static par { static seq { D; E; } static seq { F; G; } - } + } } } } @@ -71,20 +71,20 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<2> group A { - a.write_en = 1'd1; - a.in = 32'd2; + a.write_en = 1'd1; + a.in = 32'd2; } static<3> group B { - b.write_en = 1'd1; - b.in = 32'd2; + b.write_en = 1'd1; + b.in = 32'd2; } static<3> group C { - c.write_en = 1'd1; - c.in = 32'd2; + c.write_en = 1'd1; + c.in = 32'd2; } static<4> group D { - d.write_en = 1'd1; - d.in = 32'd2; + d.write_en = 1'd1; + d.in = 32'd2; } } control { @@ -94,11 +94,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { A; } else{ - B; + B; } - C; + C; } - D; + D; } } } \ No newline at end of file From d86a5bd5c1d7ff38851e69e8092fa4d70d2da8a5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 26 Dec 2023 18:03:37 -0500 Subject: [PATCH 126/189] Update SA docs and command-line opts (#1829) --- docs/frontends/systolic-array.md | 2 ++ .../systolic-lang/systolic_arg_parser.py | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/frontends/systolic-array.md b/docs/frontends/systolic-array.md index f46f152ff..607d513ae 100644 --- a/docs/frontends/systolic-array.md +++ b/docs/frontends/systolic-array.md @@ -27,6 +27,8 @@ can be configured. - `--top-length`, `--left-length`: The length of top and left sides of the systolic array. - `--top-depth`, `--left-depth`: The length of the input streams from top and left sides of the array. +- `--post-op`: Specify the post operation to be performed on the result of the matrix-multiply. +- `--fixed-dim`: Generate systolic array that only processes matrices with the given sizes. The default strategy supports matrices with any contraction dimension. [kung-systolic]: http://www.eecs.harvard.edu/~htk/publication/1982-kung-why-systolic-architecture.pdf [systolic-lang]: https://github.com/calyxir/calyx/tree/master/frontends/systolic-lang diff --git a/frontends/systolic-lang/systolic_arg_parser.py b/frontends/systolic-lang/systolic_arg_parser.py index 0e30d601c..325472d5d 100644 --- a/frontends/systolic-lang/systolic_arg_parser.py +++ b/frontends/systolic-lang/systolic_arg_parser.py @@ -20,14 +20,30 @@ def parse_arguments(self): """ # Arg parsing - parser = argparse.ArgumentParser(description="Process some integers.") + parser = argparse.ArgumentParser( + description="Generate an output-stationary systolic array in Calyx." + ) parser.add_argument("file", nargs="?", type=str) parser.add_argument("-tl", "--top-length", type=int) parser.add_argument("-td", "--top-depth", type=int) parser.add_argument("-ll", "--left-length", type=int) parser.add_argument("-ld", "--left-depth", type=int) - parser.add_argument("-p", "--post-op", type=str, default=None) - parser.add_argument("-s", "--static", action="store_true") + parser.add_argument( + "-p", + "--post-op", + help="post operation to be performed on the matrix-multiply result", + type=str, + default=None, + ) + parser.add_argument( + "--fixed-dim", + help=( + "systolic array that only processes fixed dimension matrices." + " By default, generated array can process matrices " + " with any contraction dimension" + ), + action="store_true", + ) args = parser.parse_args() @@ -38,7 +54,7 @@ def parse_arguments(self): self.left_length = args.left_length self.left_depth = args.left_depth self.post_op = args.post_op - self.static = args.static + self.static = args.fixed_dim elif args.file is not None: with open(args.file, "r") as f: spec = json.load(f) From d5ba289809f94cccac212645c65dc5ca008d7dbc Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 26 Dec 2023 19:07:51 -0500 Subject: [PATCH 127/189] make stability check a warning (#1830) --- .github/workflows/rust.yml | 3 +++ calyx-ir/src/control.rs | 3 +-- calyx-opt/src/passes/compile_static.rs | 2 +- calyx-opt/src/passes/well_formed.rs | 8 +++---- runt.toml | 2 +- tests/errors/comb-port-in-condition.expect | 7 ++++-- tests/errors/while-unstable.expect | 24 +++++++++++++++++++ .../while-unstable.futil | 0 .../passes/well-formed/while-unstable.expect | 4 ---- 9 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 tests/errors/while-unstable.expect rename tests/{passes/well-formed => errors}/while-unstable.futil (100%) delete mode 100644 tests/passes/well-formed/while-unstable.expect diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9fc332f41..33c04ab62 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -92,6 +92,7 @@ jobs: git remote add origin https://github.com/calyxir/calyx.git git fetch --all git checkout -f $GITHUB_SHA + git clean -fd - name: Build uses: actions-rs/cargo@v1 @@ -148,6 +149,7 @@ jobs: git remote add origin https://github.com/calyxir/calyx.git git fetch --all git checkout -f $GITHUB_SHA + git clean -fd - name: Install calyx-py & MrXL working-directory: /home/calyx @@ -212,6 +214,7 @@ jobs: git remote add origin https://github.com/calyxir/calyx.git git fetch --all git checkout -f $GITHUB_SHA + git clean -fd - name: Build uses: actions-rs/cargo@v1 diff --git a/calyx-ir/src/control.rs b/calyx-ir/src/control.rs index 7f4dc719e..10dac5ea7 100644 --- a/calyx-ir/src/control.rs +++ b/calyx-ir/src/control.rs @@ -350,7 +350,6 @@ pub enum Control { #[derive(Debug)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub enum StaticControl { - /// Essentially a Static While Loop Repeat(StaticRepeat), Enable(StaticEnable), Par(StaticPar), @@ -597,7 +596,7 @@ impl Control { pub fn take_static_control(&mut self) -> StaticControl { let empty = Control::empty(); let control = std::mem::replace(self, empty); - let Control::Static(static_control) = control else { + let Control::Static(static_control) = control else { unreachable!("Called take_static_control on non-static control") }; static_control diff --git a/calyx-opt/src/passes/compile_static.rs b/calyx-opt/src/passes/compile_static.rs index ba2a86c64..3f91527e3 100644 --- a/calyx-opt/src/passes/compile_static.rs +++ b/calyx-opt/src/passes/compile_static.rs @@ -31,7 +31,7 @@ impl Named for CompileStatic { } fn description() -> &'static str { - "Compiles Static Islands" + "compiles static sub-programs into a dynamic group" } } diff --git a/calyx-opt/src/passes/well_formed.rs b/calyx-opt/src/passes/well_formed.rs index afd5b5fc1..3f918e662 100644 --- a/calyx-opt/src/passes/well_formed.rs +++ b/calyx-opt/src/passes/well_formed.rs @@ -607,7 +607,7 @@ impl Visitor for WellFormed { "If statement has no comb group and its condition port {} is unstable", s.port.borrow().canonical() )); - return Err(calyx_utils::Error::malformed_control(msg)); + log::warn!("{msg}"); } Ok(Action::Continue) } @@ -621,10 +621,10 @@ impl Visitor for WellFormed { ) -> VisResult { if !s.port.borrow().has_attribute(ir::BoolAttr::Stable) { let msg = s.attributes.copy_span().format(format!( - "Static If statement's condition port {} is unstable", + "static if statement's condition port {} is unstable", s.port.borrow().canonical() )); - Err(calyx_utils::Error::malformed_control(msg))? + log::warn!("{msg}"); } Ok(Action::Continue) } @@ -674,7 +674,7 @@ impl Visitor for WellFormed { "While loop has no comb group and its condition port {} is unstable", s.port.borrow().canonical() )); - return Err(calyx_utils::Error::malformed_control(msg)); + log::warn!("{msg}"); } Ok(Action::Continue) } diff --git a/runt.toml b/runt.toml index 2d971a2f4..103013c96 100644 --- a/runt.toml +++ b/runt.toml @@ -39,7 +39,7 @@ paths = [ "tests/errors/parser/*.futil", ] cmd = """ -./target/debug/calyx {} -p well-formed -p papercut -p synthesis-papercut -l . +./target/debug/calyx {} -p well-formed -p papercut -p synthesis-papercut -l . -m file """ [[tests]] diff --git a/tests/errors/comb-port-in-condition.expect b/tests/errors/comb-port-in-condition.expect index ad4634a98..d5d636cce 100644 --- a/tests/errors/comb-port-in-condition.expect +++ b/tests/errors/comb-port-in-condition.expect @@ -1,6 +1,9 @@ ---CODE--- 1 ---STDERR--- -Error: Malformed Control: tests/errors/comb-port-in-condition.futil +[WARN calyx_opt::passes::well_formed] tests/errors/comb-port-in-condition.futil + 8 | if le.out { seq {} } + | ^^^^^^^^^^^^^^^^^^^^ If statement has no comb group and its condition port le.out is unstable +Error: tests/errors/comb-port-in-condition.futil 8 | if le.out { seq {} } - | ^^^^^^^^^^^^^^^^^^^^ If statement has no comb group and its condition port le.out is unstable + | ^^^^^^^^^^^^^^^^^^^^ [Papercut] Port `le.out` is an output port on combinational primitive `std_le` and will always output 0. Add a `with` statement to the `if` statement to ensure it has a valid value during execution. diff --git a/tests/errors/while-unstable.expect b/tests/errors/while-unstable.expect new file mode 100644 index 000000000..a13735806 --- /dev/null +++ b/tests/errors/while-unstable.expect @@ -0,0 +1,24 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r1 = std_reg(32); + lt = std_lt(32); + } + wires { + static<2> group A { + r1.write_en = 1'd1; + r1.in = 32'd2; + } + lt.left = r1.out; + lt.right = 32'd4; + } + control { + while lt.out { + A; + } + } +} +---STDERR--- +[WARN calyx_opt::passes::well_formed] tests/errors/while-unstable.futil + 19 | while lt.out { + | ^^^^^^^^^^^^^^ While loop has no comb group and its condition port lt.out is unstable diff --git a/tests/passes/well-formed/while-unstable.futil b/tests/errors/while-unstable.futil similarity index 100% rename from tests/passes/well-formed/while-unstable.futil rename to tests/errors/while-unstable.futil diff --git a/tests/passes/well-formed/while-unstable.expect b/tests/passes/well-formed/while-unstable.expect deleted file mode 100644 index b687a1a3d..000000000 --- a/tests/passes/well-formed/while-unstable.expect +++ /dev/null @@ -1,4 +0,0 @@ ----STDERR--- -Error: Malformed Control: tests/passes/well-formed/while-unstable.futil -19 | while lt.out { - | ^^^^^^^^^^^^^^ While loop has no comb group and its condition port lt.out is unstable From b84823f7cd217e92058c96e634b3a335f11af297 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 26 Dec 2023 19:23:16 -0500 Subject: [PATCH 128/189] Remove `tdst` (#1831) --- calyx-opt/src/default_passes.rs | 6 +- calyx-opt/src/passes/mod.rs | 2 - .../top_down_static_timing/compute_states.rs | 199 ---- .../src/passes/top_down_static_timing/mod.rs | 7 - .../top_down_static_timing/normalize.rs | 117 --- .../src/passes/top_down_static_timing/tdst.rs | 927 ------------------ runt.toml | 25 +- .../static-timing/compile-if-static.expect | 11 - .../static-timing/compile-if-static.futil | 45 - .../static-timing/compile-par-static.expect | 11 - .../static-timing/compile-par-static.futil | 33 - .../static-timing/compile-seq-mixed.futil | 48 - .../static-timing/compile-seq-mixed.skip | 6 - .../static-timing/compile-seq-static.expect | 9 - .../static-timing/compile-seq-static.futil | 39 - .../static-timing/compile-while-static.expect | 17 - .../static-timing/compile-while-static.futil | 43 - tests/passes/tdcc/seq-with-same-done.futil | 2 +- tests/passes/tdcc/while-if.futil | 2 +- tests/passes/tdcc/while.futil | 2 +- tools/flag-compare.sh | 2 +- 21 files changed, 8 insertions(+), 1545 deletions(-) delete mode 100644 calyx-opt/src/passes/top_down_static_timing/compute_states.rs delete mode 100644 calyx-opt/src/passes/top_down_static_timing/mod.rs delete mode 100644 calyx-opt/src/passes/top_down_static_timing/normalize.rs delete mode 100644 calyx-opt/src/passes/top_down_static_timing/tdst.rs delete mode 100644 tests/passes/static-timing/compile-if-static.expect delete mode 100644 tests/passes/static-timing/compile-if-static.futil delete mode 100644 tests/passes/static-timing/compile-par-static.expect delete mode 100644 tests/passes/static-timing/compile-par-static.futil delete mode 100644 tests/passes/static-timing/compile-seq-mixed.futil delete mode 100644 tests/passes/static-timing/compile-seq-mixed.skip delete mode 100644 tests/passes/static-timing/compile-seq-static.expect delete mode 100644 tests/passes/static-timing/compile-seq-static.futil delete mode 100644 tests/passes/static-timing/compile-while-static.expect delete mode 100644 tests/passes/static-timing/compile-while-static.futil diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index f082493b3..2528692c3 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -9,8 +9,8 @@ use crate::passes::{ InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, RegisterUnsharing, RemoveIds, ResetInsertion, ScheduleCompaction, SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticPromotion, - SynthesisPapercut, TopDownCompileControl, TopDownStaticTiming, - UnrollBounded, WellFormed, WireInliner, WrapMain, + SynthesisPapercut, TopDownCompileControl, UnrollBounded, WellFormed, + WireInliner, WrapMain, }; use crate::traversal::Named; use crate::{pass_manager::PassManager, register_alias}; @@ -49,7 +49,6 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -116,7 +115,6 @@ impl PassManager { CompileStaticInterface, DeadGroupRemoval, CompileStatic, - TopDownStaticTiming, TopDownCompileControl ] ); diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index 414870fdf..cba2e17ea 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -41,7 +41,6 @@ mod discover_external; mod simplify_with_control; mod synthesis_papercut; mod top_down_compile_control; -mod top_down_static_timing; mod unroll_bound; mod well_formed; mod wire_inliner; @@ -88,7 +87,6 @@ pub use add_guard::AddGuard; pub use compile_static_interface::CompileStaticInterface; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; -pub use top_down_static_timing::TopDownStaticTiming; pub use unroll_bound::UnrollBounded; pub use well_formed::WellFormed; pub use wire_inliner::WireInliner; diff --git a/calyx-opt/src/passes/top_down_static_timing/compute_states.rs b/calyx-opt/src/passes/top_down_static_timing/compute_states.rs deleted file mode 100644 index f6d309fe1..000000000 --- a/calyx-opt/src/passes/top_down_static_timing/compute_states.rs +++ /dev/null @@ -1,199 +0,0 @@ -use crate::passes::math_utilities::get_bit_width_from; -use calyx_ir::{self as ir, guard, structure, RRC}; -use ir::Nothing; -use std::rc::Rc; - -/// Name of the attributes added by this pass. -pub const ID: ir::Attribute = ir::Attribute::Internal(ir::InternalAttr::ST_ID); -pub const LOOP: ir::Attribute = ir::Attribute::Internal(ir::InternalAttr::LOOP); -pub const START: ir::Attribute = - ir::Attribute::Internal(ir::InternalAttr::START); -pub const END: ir::Attribute = ir::Attribute::Internal(ir::InternalAttr::END); - -/// Computes the states associated with control nodes in a static program. -/// Each enable statement gets a number corresponding to the FSM state when it -/// can be scheduled. -/// -/// While loops instantiate an indexor is used by -/// [crate::passes::TopDownStaticTiming] to implement the compilation logic. We -/// allocate these in this pass so that [ComputeStates] can correctly compute the -/// exit edges for a given control program. -pub struct ComputeStates { - /// Current state - cur_st: u64, - /// Mapping for loop indices - indices: Vec>, -} -impl Default for ComputeStates { - fn default() -> Self { - Self { - /// 0 is a special start state allocated to the start of the - /// program so we start with the state 1. - cur_st: 1, - indices: vec![], - } - } -} - -impl ComputeStates { - /// Compute the states associated with the control program. - pub fn new(con: &mut ir::Control, builder: &mut ir::Builder) -> Self { - let mut cs = Self::default(); - cs.recur(con, builder); - cs - } - - fn recur(&mut self, con: &mut ir::Control, builder: &mut ir::Builder) { - match con { - ir::Control::Enable(en) => { - debug_assert!(en.attributes.get(ID).is_none()); - en.attributes.insert(ID, self.cur_st); - let time = en.attributes.get(ir::NumAttr::Static).unwrap(); - self.cur_st += time; - } - ir::Control::Static(_) => { - panic!("Static behavior on tdst TBD") - } - ir::Control::Seq(seq) => { - for stmt in &mut seq.stmts { - self.recur(stmt, builder); - } - } - ir::Control::If(ir::If { - tbranch, fbranch, .. - }) => { - self.recur(tbranch, builder); - self.recur(fbranch, builder); - } - ir::Control::While(wh) => self.compute_while(wh, builder), - ir::Control::Par(par) => { - par.attributes.insert(ID, self.cur_st); - // All statements should only contain enables and get the same - // start state as the `par` block. - for stmt in &mut par.stmts { - if let ir::Control::Enable(en) = stmt { - en.attributes.insert(ID, self.cur_st); - } else { - unreachable!("Par should only contain enables") - } - } - let time = par.attributes.get(ir::NumAttr::Static).unwrap(); - self.cur_st += time; - } - ir::Control::Invoke(_) => unreachable!( - "Invoke statements should have been compiled away." - ), - ir::Control::Repeat(_) => { - unreachable!("Repeats should've been compiled away.") - } - ir::Control::Empty(_) => { - unreachable!("Empty blocks should have been compiled away") - } - } - } - - fn compute_while(&mut self, wh: &mut ir::While, builder: &mut ir::Builder) { - // Compute START, END, and LOOP index attributes - wh.attributes.insert(START, self.cur_st); - let body_time = wh.attributes.get(ir::NumAttr::Static).unwrap(); - // Instantiate the indexing variable for this while loop - let size = get_bit_width_from(body_time + 1); - structure!(builder; - let idx = prim std_reg(size); - ); - self.indices.push(idx); - let idx_pos = self.indices.len() - 1; - // Add attribute to track the loop counter - wh.attributes.insert(LOOP, idx_pos as u64); - self.recur(&mut wh.body, builder); - // Mark the end state of the body - wh.attributes.insert(END, self.cur_st); - } - - /// Computes the outgoing edges from the control programs. - /// **Requires**: `con` is a sub-program of the control program used to - /// construct this [States] instance. - pub fn control_exits( - &self, - con: &ir::Control, - builder: &mut ir::Builder, - exits: &mut Vec<(u64, ir::Guard)>, - ) { - match con { - ir::Control::Enable(en) => { - let st = en.attributes.get(ID).unwrap() - + en.attributes.get(ir::NumAttr::Static).unwrap() - - 1; - exits.push((st, ir::Guard::True)); - } - ir::Control::Static(_) => { - panic!("Static behavior on tdst TBD") - } - ir::Control::Par(par) => { - let st = par.attributes.get(ID).unwrap() - + par.attributes.get(ir::NumAttr::Static).unwrap() - - 1; - exits.push((st, ir::Guard::True)) - } - ir::Control::Seq(s) => { - if let Some(stmt) = s.stmts.last() { - self.control_exits(stmt, builder, exits); - } - } - ir::Control::If(if_) => { - let ir::If { - tbranch, fbranch, .. - } = if_; - self.control_exits(tbranch, builder, exits); - self.control_exits(fbranch, builder, exits); - } - ir::Control::While(wh) => { - let ir::While { body, .. } = wh; - // Compute the exit conditions for the loop body - let mut loop_exits = Vec::new(); - self.control_exits(body, builder, &mut loop_exits); - - // Guard the exit edges for the body with the loop exit condition - let (idx, bound) = self.loop_bounds(wh, builder); - let guard = guard!(idx["out"] == bound["out"]); - exits.extend( - loop_exits - .into_iter() - .map(|(st, g)| (st, g & guard.clone())), - ); - } - ir::Control::Invoke(_) => { - unreachable!("Invoke should have been compiled away") - } - ir::Control::Repeat(_) => { - unreachable!("Repeat should have been compiled away") - } - ir::Control::Empty(_) => { - unreachable!("Empty block in control_exits") - } - } - } - - /// Generate the guard condition for exiting the given loop. - /// **Requires**: The loop is a sub-program of the control program used to - /// generate this [States] instance. - pub fn loop_bounds( - &self, - wh: &ir::While, - builder: &mut ir::Builder, - ) -> (RRC, RRC) { - let max_count = wh.attributes.get(ir::NumAttr::Static).unwrap(); - let size = get_bit_width_from(max_count + 1); - structure!(builder; - let max = constant(max_count, size); - ); - let idx_pos = wh.attributes.get(LOOP).unwrap() as usize; - let idx = Rc::clone(&self.indices[idx_pos]); - (idx, max) - } - - /// Return iterator over all defined loop indexing cells - pub fn indices(self) -> impl Iterator> { - self.indices.into_iter() - } -} diff --git a/calyx-opt/src/passes/top_down_static_timing/mod.rs b/calyx-opt/src/passes/top_down_static_timing/mod.rs deleted file mode 100644 index 7de6073d5..000000000 --- a/calyx-opt/src/passes/top_down_static_timing/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod compute_states; -mod normalize; -mod tdst; - -pub(super) use compute_states::ComputeStates; -pub(super) use normalize::Normalize; -pub use tdst::TopDownStaticTiming; diff --git a/calyx-opt/src/passes/top_down_static_timing/normalize.rs b/calyx-opt/src/passes/top_down_static_timing/normalize.rs deleted file mode 100644 index 255743344..000000000 --- a/calyx-opt/src/passes/top_down_static_timing/normalize.rs +++ /dev/null @@ -1,117 +0,0 @@ -use calyx_ir::{self as ir, GetAttributes}; -use std::{cmp, iter}; - -/// Implements normalization for static `if` and `while`. -/// - `if`: Ensure both the branches take the same number of cycles. -/// - `while`: Directly nested bounded loops are de-nested. -pub struct Normalize { - /// Enable for the group used to balance `if` branches. - balance: ir::Enable, -} - -impl Normalize { - /// Apply the `if` and `while` normalization to a static control program. - /// **Requires**: The control program has a static attribute. - pub fn apply(con: &mut ir::Control, builder: &mut ir::Builder) { - debug_assert!( - con.get_attribute(ir::NumAttr::Static).is_some(), - "Attempting to normalize non-static program" - ); - let balance = builder.add_group("balance"); - balance - .borrow_mut() - .attributes - .insert(ir::NumAttr::Static, 1); - let mut balance = ir::Enable { - group: balance, - attributes: ir::Attributes::default(), - }; - balance.attributes.insert(ir::NumAttr::Static, 1); - let norm = Normalize { balance }; - norm.recur(con); - } - - fn recur(&self, con: &mut ir::Control) { - match con { - ir::Control::Par(ir::Par { stmts, .. }) - | ir::Control::Seq(ir::Seq { stmts, .. }) => { - stmts.iter_mut().for_each(|c| self.recur(c)) - } - ir::Control::If(ir::If { - tbranch, fbranch, .. - }) => { - self.recur(tbranch); - self.recur(fbranch); - let ttime = tbranch.get_attribute(ir::NumAttr::Static).unwrap(); - let ftime = fbranch.get_attribute(ir::NumAttr::Static).unwrap(); - let max_time = cmp::max(ttime, ftime); - self.extend_control(tbranch, max_time, &self.balance); - self.extend_control(fbranch, max_time, &self.balance); - } - ir::Control::While(wh) => { - Self::denest_loop(wh); - self.recur(&mut wh.body); - } - ir::Control::Invoke(_) - | ir::Control::Enable(_) - | ir::Control::Static(_) - | ir::Control::Repeat(_) - | ir::Control::Empty(_) => {} - } - } - - /// Take a control program and extend it to ensure that its execution time is at least `time`. - /// **Requires**: The control program must have a `static` attribute. - fn extend_control( - &self, - con: &mut Box, - time: u64, - balance: &ir::Enable, - ) { - let cur_time = con.get_attribute(ir::NumAttr::Static).unwrap(); - - if cur_time < time { - let bal = ir::Control::Enable(ir::Cloner::enable(balance)); - let inner = *std::mem::replace(con, Box::new(ir::Control::empty())); - let extra = (0..time - cur_time).map(|_| ir::Cloner::control(&bal)); - let mut seq = if matches!(&inner, ir::Control::Empty(_)) { - ir::Control::seq(extra.collect()) - } else { - ir::Control::seq(iter::once(inner).chain(extra).collect()) - }; - seq.get_mut_attributes().insert(ir::NumAttr::Static, time); - *con = Box::new(seq); - } - } - - /// Transform nested bounded loops into a singly nested loop: - /// ``` - /// @bound(m) while r0.out { - /// @bound(n) while r1.out { - /// @bound(l) while r2.out { body } - /// } - /// } - /// ``` - /// Into: - /// ``` - /// @bound(m*n*l) while r0.out { body } - /// ``` - /// - /// Note that after this transformation, it is no longer correct to lower - /// the loop using TDCC since we've ignored the loop entry conditions. - fn denest_loop(wh: &mut ir::While) { - let mut body = - std::mem::replace(&mut wh.body, Box::new(ir::Control::empty())); - let mut bound = wh.attributes.get(ir::NumAttr::Bound).unwrap(); - let mut body_time = body.get_attribute(ir::NumAttr::Static).unwrap(); - - while let ir::Control::While(inner) = *body { - bound *= inner.attributes.get(ir::NumAttr::Bound).unwrap(); - body = inner.body; - body_time = body.get_attribute(ir::NumAttr::Static).unwrap(); - } - wh.body = body; - wh.attributes.insert(ir::NumAttr::Bound, bound); - wh.attributes.insert(ir::NumAttr::Static, body_time * bound); - } -} diff --git a/calyx-opt/src/passes/top_down_static_timing/tdst.rs b/calyx-opt/src/passes/top_down_static_timing/tdst.rs deleted file mode 100644 index fdc183c4a..000000000 --- a/calyx-opt/src/passes/top_down_static_timing/tdst.rs +++ /dev/null @@ -1,927 +0,0 @@ -use super::compute_states::{END, START}; -use crate::analysis::WithStatic; -use crate::passes::top_down_static_timing::{ComputeStates, Normalize}; -use crate::passes::{self, math_utilities::get_bit_width_from}; -use crate::traversal::{ - Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, -}; -use calyx_ir::{ - self as ir, build_assignments, guard, structure, GetAttributes, - LibrarySignatures, Printer, RRC, -}; -use calyx_utils::{CalyxResult, Error}; -use ir::Nothing; -use itertools::Itertools; -use std::collections::{HashMap, HashSet}; -use std::io::Write; -use std::iter; -use std::ops::Not; -use std::rc::Rc; - -use super::compute_states::ID; - -/// A range of FSM states. -type Range = (u64, u64); - -type Conditional = (u64, u64, ir::Guard); - -/// A schedule keeps track of two things: -/// 1. `enables`: Specifies which groups are active during a range of -/// FSM states. -/// 2. `transitions`: Transitions for the FSM registers. A static FSM normally -/// transitions from `state` to `state + 1`. However, special transitions -/// are needed for loops, conditionals, and reseting the FSM. -struct Schedule<'b, 'a: 'b> { - /// Enable assignments in a particular range - enables: HashMap>>, - /// Transition from one state to another when a guard is true - transitions: HashSet, - // Builder for the associated component - builder: &'b mut ir::Builder<'a>, - states: ComputeStates, -} - -impl<'b, 'a: 'b> Schedule<'b, 'a> { - fn new(builder: &'b mut ir::Builder<'a>, states: ComputeStates) -> Self { - Self { - enables: HashMap::default(), - transitions: HashSet::new(), - builder, - states, - } - } -} - -impl Schedule<'_, '_> { - fn last(&self) -> u64 { - debug_assert!(!self.transitions.is_empty()); - self.transitions.iter().max_by_key(|(_, e, _)| e).unwrap().1 - } - - /// Add a new transition between the range [start, end). - fn add_transition( - &mut self, - start: u64, - end: u64, - guard: ir::Guard, - ) { - debug_assert!( - !(start == end && guard.is_true()), - "Unconditional transition to the same state {start}" - ); - self.transitions.insert((start, end, guard)); - } - - // Add enables that are active in the range [start, end). - // Automatically ignores any enable statements that refer to the balance group. - fn add_enables( - &mut self, - start: u64, - end: u64, - assigns: impl IntoIterator>, - ) { - debug_assert!( - start != end, - "Attempting to enable groups in empty range [{start}, {start})" - ); - self.enables - .entry((start, end)) - .or_default() - .extend(assigns); - } - - fn add_transitions( - &mut self, - transitions: impl Iterator, - ) { - transitions.for_each(|(s, e, g)| self.add_transition(s, e, g)); - } - - fn display(&self, name: String) { - let out = &mut std::io::stdout(); - writeln!(out, "======== {name} =========").unwrap(); - let (uncond, cond) = - Self::calculate_runs(self.transitions.iter().cloned()); - - self.enables - .iter() - .sorted_by(|(k1, _), (k2, _)| k1.cmp(k2)) - .for_each(|((start, end), assigns)| { - if *end == start + 1 { - println!("{}:", start); - } else { - println!("[{}, {}):", start, end); - } - assigns.iter().for_each(|assign| { - print!(" "); - Printer::write_assignment(assign, 0, out) - .expect("Printing failed!"); - println!(); - }); - if assigns.is_empty() { - println!(" "); - } - }); - if !cond.is_empty() { - println!("transitions:"); - cond.iter() - .sorted_by(|(k1, k2, g1), (k3, k4, g2)| { - k1.cmp(k3).then_with(|| k2.cmp(k4)).then_with(|| g1.cmp(g2)) - }) - .for_each(|(i, f, g)| { - println!(" ({}, {}): {}", i, f, Printer::guard_str(g)); - }); - } - - // Unconditional +1 transitions - if !uncond.is_empty() { - let uncond_trans = uncond - .into_iter() - .map(|(s, e)| format!("({}, {})", s, e)) - .join(", "); - println!("Unconditional runs:\n {}", uncond_trans); - } - } - - /// Returns "runs" of FSM states where transitions happen unconditionally - fn calculate_runs(transitions: I) -> (Vec, Vec) - where - I: Iterator, - { - // XXX(rachit): This only works for "true" guards and fails to compress if there is any - // other guard. For example, if there is a sequence under a conditional branch, this will - // fail to compress that sequence. - let (unconditional, conditional): (Vec<_>, Vec<_>) = transitions - .partition(|(s, e, guard)| *e == s + 1 && guard.is_true()); - - let mut unconditional = - unconditional.into_iter().map(|(s, _, _)| s).sorted(); - - let mut ranges: Vec = Vec::new(); - if let Some(mut cur_s) = unconditional.next() { - let mut start_s = cur_s; - - // Extract the next state - for nxt_s in unconditional { - if nxt_s != cur_s + 1 { - ranges.push((start_s, cur_s + 1)); - start_s = nxt_s; - } - cur_s = nxt_s - } - ranges.push((start_s, cur_s + 1)); - } - - (ranges, conditional) - } - - fn range_guard( - builder: &mut ir::Builder, - s: u64, - e: u64, - fsm_size: u64, - fsm: &RRC, - ) -> ir::Guard { - structure!(builder; - let lb = constant(s, fsm_size); - let ub = constant(e, fsm_size); - ); - if s == 0 { - guard!(fsm["out"] < ub["out"]) - } else if e == s + 1 { - guard!(fsm["out"] == lb["out"]) - } else if e == 1 << fsm_size { - guard!(fsm["out"] >= lb["out"]) - } else { - guard!((fsm["out"] >= lb["out"]) & (fsm["out"] < ub["out"])) - } - } - - /// Construct hardware to implement the given schedule. - /// - /// Requires the outgoing edges from the control program and the final state of the FSM. - /// All the hardware is instantiated using the builder associated with this schedule. - fn realize_schedule( - self, - mut out_edges: Vec, - dump_fsm: bool, - ) -> RRC { - let last = self.last(); - - let group = self.builder.add_group("tdst"); - if dump_fsm { - self.display(format!( - "{}:{}", - self.builder.component.name, - group.borrow().name() - )); - } - let builder = self.builder; - let (unconditional, conditional) = - Self::calculate_runs(self.transitions.into_iter()); - let fsm_size = get_bit_width_from(last) + 1; - - structure!(builder; - let st_fsm = prim std_reg(fsm_size); - let signal_on = constant(1, 1); - let first_state = constant(0, fsm_size); - ); - - // Enable assignments. - group.borrow_mut().assignments.extend( - self.enables - .into_iter() - .sorted_by(|(k1, _), (k2, _)| k1.cmp(k2)) - .flat_map(|((lb, ub), mut assigns)| { - let state_guard = - Self::range_guard(builder, lb, ub, fsm_size, &st_fsm); - assigns.iter_mut().for_each(|assign| { - assign.guard.update(|g| g.and(state_guard.clone())) - }); - assigns - }), - ); - - // Conditional Transition assignments. - group.borrow_mut().assignments.extend( - conditional - .into_iter() - .sorted_by_key(|(start, _, _)| *start) - .flat_map(|(start, end, guard)| { - structure!(builder; - let start_const = constant(start, fsm_size); - let end_const = constant(end, fsm_size); - ); - - let transition_guard = guard!((st_fsm["out"] == start_const["out"]) & guard); - - let assigns = build_assignments!(builder; - st_fsm["in"] = transition_guard ? end_const["out"]; - st_fsm["write_en"] = transition_guard ? signal_on["out"]; - ); - drop(end_const); - assigns - }), - ); - // Unconditional Transitions - if !unconditional.is_empty() { - let uncond_guard: ir::Guard = unconditional - .into_iter() - .fold(ir::Guard::True.not(), |g, (s, e)| { - let range = - Self::range_guard(builder, s, e, fsm_size, &st_fsm); - g.or(range) - }); - structure!(builder; - let fsm_incr = prim std_add(fsm_size); - let one = constant(1, fsm_size); - ); - let uncond_incr = build_assignments!(builder; - fsm_incr["left"] = ? st_fsm["out"]; - fsm_incr["right"] = ? one["out"]; - st_fsm["in"] = uncond_guard ? fsm_incr["out"]; - st_fsm["write_en"] = uncond_guard ? signal_on["out"]; - ); - group.borrow_mut().assignments.extend(uncond_incr); - } - - // Done condition for group. - let (st, g) = out_edges.pop().expect("No outgoing edges"); - let c = builder.add_constant(st, fsm_size); - let mut done_guard = guard!((st_fsm["out"] == c["out"]) & g); - for (st, g) in out_edges { - let stc = builder.add_constant(st, fsm_size); - let st_guard = guard!((st_fsm["out"] == stc["out"]) & g); - done_guard |= st_guard; - } - let done_assign = build_assignments!(builder; - group["done"] = done_guard ? signal_on["out"]; - ); - group.borrow_mut().assignments.extend(done_assign); - - // Cleanup: Add a transition from last state to the first state. - let reset_fsm = build_assignments!(builder; - st_fsm["in"] = done_guard ? first_state["out"]; - st_fsm["write_en"] = done_guard ? signal_on["out"]; - ); - // Reset all loop indices to 0 - let reset_indices = self - .states - .indices() - .flat_map(|c: RRC| { - let size = c.borrow().get_parameter("WIDTH").unwrap(); - let zero = builder.add_constant(0, size); - let assigns = build_assignments!(builder; - c["in"] = done_guard ? zero["out"]; - c["write_en"] = done_guard ? signal_on["out"]; - ); - drop(zero); - assigns - }) - .collect_vec(); - builder - .component - .continuous_assignments - .extend(reset_fsm.into_iter().chain(reset_indices)); - - group - } -} - -/// Represents an edge from a predeccesor to the current control node. -/// The `u64` represents the FSM state of the predeccesor and the guard needs -/// to be true for the predeccesor to transition to the current state. -type PredEdge = (u64, ir::Guard); - -impl Schedule<'_, '_> { - fn calculate_states( - &mut self, - con: &mut ir::Control, - // Predecessors - preds: Vec, - ) -> CalyxResult> { - debug_assert!(!preds.is_empty(), "Predecessors should not be empty."); - - match con { - ir::Control::Enable(e) => { - self.enable_calculate_states(e, preds) - } - ir::Control::Seq(s) => { - self.seq_calculate_states(s, preds) - } - ir::Control::If(i) => { - self.if_calculate_states(i, preds) - } - ir::Control::While(w) => { - self.while_calculate_states(w, preds) - } - ir::Control::Par(par) => { - self.par_calculate_states(par, preds) - } - ir::Control::Static(_) => { - unimplemented!( - "TDST doesn't support `static` statements (Eventually we want to rewrite static compilation as to render TDST obselete)" - ) - } - ir::Control::Invoke(_) => unreachable!( - "`invoke` statements should have been compiled away. Run `{}` before this pass.", - passes::CompileInvoke::name()), - ir::Control::Repeat(_) => unreachable!( - "`repeat` statements should have been compiled away. Run `{}` before this pass.", - passes::CompileRepeat::name()), - ir::Control::Empty(_) => unreachable!( - "`empty` statements should have been compiled away. Run `{}` before this pass.", - passes::CompileEmpty::name()), - } - } - - /// Generate transitions from all predecessors to the enable and keep it - /// active for its specified static time. - /// The start state of the enable is computed by taking the max of all - /// predecessors states. - fn enable_calculate_states( - &mut self, - con: &ir::Enable, - preds: Vec, - ) -> CalyxResult> { - let time_option = con.attributes.get(ir::NumAttr::Static); - let Some(time) = time_option else { - return Err(Error::pass_assumption( - TopDownStaticTiming::name(), - "enable is missing @static annotation. This happens when the enclosing control program has a @static annotation but the enable is missing one.".to_string(), - ).with_pos(&con.attributes)); - }; - - let cur_st = con.attributes.get(ID).unwrap(); - - // Enable the group during the transition. Note that this is similar to - // what tdcc does the early transitions flag. However, unlike tdcc, we - // know that transitions do not use groups' done signals. - preds.clone().into_iter().for_each(|(st, g)| { - let group = &con.group; - structure!(self.builder; - let signal_on = constant(1, 1); - ); - let assigns = build_assignments!(self.builder; - group["go"] = g ? signal_on["out"]; - ); - // We only enable this in the state when the transition starts - self.add_enables(st, st + 1, assigns); - }); - - // Transition from all predecessors to the start state - self.add_transitions(preds.into_iter().map(|(st, g)| (st, cur_st, g))); - - // Activate the group during the latency. Subtract one because the group - // is also active during the transition when not in the start state. - let last_st = cur_st + time - 1; - // Add additional transitions if the group's latency is not 1 - if time != 1 { - let group = &con.group; - structure!(self.builder; - let signal_on = constant(1, 1); - ); - let assigns = build_assignments!(self.builder; - group["go"] = ? signal_on["out"]; - ); - self.add_enables(cur_st, last_st, assigns); - - // Add any necessary internal transitions. In the case time is 1 and there - // is a single transition, it is taken care of by the parent. - self.add_transitions( - (cur_st..last_st).map(|s| (s, s + 1, ir::Guard::True)), - ); - } - - Ok(vec![(last_st, ir::Guard::True)]) - } - - fn seq_calculate_states( - &mut self, - con: &mut ir::Seq, - preds: Vec, - ) -> CalyxResult> { - let mut cur_preds = preds; - for stmt in &mut con.stmts { - cur_preds = self.calculate_states(stmt, cur_preds)?; - } - - Ok(cur_preds) - } - - /// Requires that all the threads are group enables. - /// Compilation simply compiles each enable with the current predecessors as - /// they must all start executing at the same time. - /// - /// They will all add transitions to their end time, possibly duplicating - /// transition edges but the group with the longest latency will add all the - /// needed transitions for last state. - fn par_calculate_states( - &mut self, - con: &mut ir::Par, - preds: Vec, - ) -> CalyxResult> { - for stmt in &mut con.stmts { - if let ir::Control::Enable(en) = stmt { - self.enable_calculate_states(en, preds.clone())?; - } else { - unreachable!("Par should only contain enables") - } - } - Ok(vec![( - con.attributes.get(ID).unwrap() - + con.attributes.get(ir::NumAttr::Static).unwrap() - - 1, - ir::Guard::True, - )]) - } - - /// Compute the states needed for the `if` by allocating a path for the true - /// branch and another one for the false branch and ensuring it takes the same - /// amount of time regardless. - /// - /// For example: - /// ``` - /// - /// if lt.out { - /// @static(3) tru; - /// } else { - /// @static(5) fal; - /// } - /// - /// ``` - /// - /// We need to ensure that the previous group has finished performing its - /// computation before transitions to either the true or false branch. - /// - /// TODO: Add documentation - /// - /// Where `PREV` and `EXIT` represent the predecessor and exit states of the - /// `if` construct. - fn if_calculate_states( - &mut self, - con: &mut ir::If, - preds: Vec, - ) -> CalyxResult> { - let ir::If { - port, - cond, - tbranch, - fbranch, - .. - } = con; - if cond.is_some() { - return Err(Error::pass_assumption( - TopDownStaticTiming::name(), - format!( - "if-with construct should have been compiled away. Run `{}` before this pass.", - passes::SimplifyWithControl::name())) - .with_pos(&con.attributes)); - } - - let port_guard: ir::Guard = Rc::clone(port).into(); - let mut tpreds = self.calculate_states( - tbranch, - preds - .iter() - .map(|(st, g)| (*st, g.clone() & port_guard.clone())) - .collect(), - )?; - - // Compute the false branch transitions by starting from the end of the true branch states - let fpreds = self.calculate_states( - fbranch, - preds - .into_iter() - .map(|(st, g)| (st, g & !port_guard.clone())) - .collect(), - )?; - - tpreds.extend(fpreds); - - Ok(tpreds) - } - - /// Define a group that increments a counter every cycle - fn incr_group(&mut self, idx: &RRC) -> RRC { - let group = self - .builder - .add_group(format!("incr_{}", idx.borrow().name())); - let size = idx.borrow().get_parameter("WIDTH").unwrap(); - structure!(self.builder; - let st_incr = prim std_add(size); - let one = constant(1, size); - let on = constant(1, 1); - ); - let incr_assigns = build_assignments!(self.builder; - st_incr["left"] = ? idx["out"]; - st_incr["right"] = ? one["out"]; - idx["in"] = ? st_incr["out"]; - idx["write_en"] = ? on["out"]; - group["done"] = ? idx["done"]; - ); - group.borrow_mut().assignments.extend(incr_assigns); - group - } - - /// Define a group that resets a counter to 0 - fn reset_group(&mut self, idx: &RRC) -> RRC { - let group = self - .builder - .add_group(format!("reset_{}", idx.borrow().name())); - let size = idx.borrow().get_parameter("WIDTH").unwrap(); - structure!(self.builder; - let zero = constant(0, size); - let on = constant(1, 1); - ); - let assigns = build_assignments!(self.builder; - idx["in"] = ? zero["out"]; - idx["write_en"] = ? on["out"]; - group["done"] = ? idx["done"]; - ); - group.borrow_mut().assignments.extend(assigns); - group - } - - /// Compute the transitions for a bounded while loop. - /// Iterations are guaranteed to execute the cycle right after the body - /// finishes executing. - /// - /// Instantiates a counter that increments every cycle while the `while` loop is active and exits the - /// loop body when the counter reaches `body*bound`. - /// - /// For example: - /// ``` - /// @bound(10) while lt.out { - /// @static(1) one; - /// @static(2) two; - /// } - /// ``` - /// - /// Generates the following transitions: - /// ``` - /// [0, 1): - /// one[go] = 1 - /// idx = idx < 10 : idx + 1 : 0 - /// [1, 3): two[go] = 1 - /// - /// cond transitions: - /// (PREV) -> 0: idx < 10 - /// 2 -> 0: idx < 10 - /// 2 -> (EXIT): idx == 10 - /// ``` - fn while_calculate_states( - &mut self, - wh: &mut ir::While, - preds: Vec, - ) -> CalyxResult> { - if wh.cond.is_some() { - return Err(Error::pass_assumption( - TopDownStaticTiming::name(), - format!( - "while-with construct should have been compiled away. Run `{}` before this pass.", - passes::SimplifyWithControl::name()) - ).with_pos(&wh.attributes)); - } - - // Construct the index and incrementing logic. - let bound = wh.attributes.get(ir::NumAttr::Bound).unwrap(); - // Loop bound should not be less than 1. - if bound < 1 { - return Err(Error::malformed_structure( - "Loop bound is less than 1", - ) - .with_pos(&wh.attributes)); - } - - let (idx, total) = self.states.loop_bounds(wh, self.builder); - structure!(self.builder; - let on = constant(1, 1); - ); - // Add back edges - let enter_guard = guard!(idx["out"] < total["out"]); - let mut exits = vec![]; - self.states - .control_exits(&wh.body, self.builder, &mut exits); - let back_edges = exits - .clone() - .into_iter() - .map(|(st, g)| (st, g & enter_guard.clone())); - - // Compute the body transitions. - let body_preds = self.calculate_states( - &mut wh.body, - preds.clone().into_iter().chain(back_edges).collect_vec(), - )?; - - // Index incrementing logic - let incr_group = self.incr_group(&idx); - let incr_activate = self.builder.build_assignment( - incr_group.borrow().get("go"), - on.borrow().get("out"), - enter_guard, - ); - // Even though the assignments are active during [cur_state, body_nxt), we expect only `bound*body` number of - // states will actually be traversed internally. - let cur_state = wh.attributes.get(START).unwrap(); - let body_nxt = wh.attributes.get(END).unwrap(); - self.add_enables( - cur_state, - body_nxt, - iter::once(incr_activate.clone()), - ); - // Activate increment assignments while transitioning into the loop - for (st, guard) in preds { - let mut assign = incr_activate.clone(); - *assign.guard &= guard.clone(); - self.add_enables(st, st + 1, iter::once(assign)); - } - - // Reset the index when exiting the loop - let exit = guard!(idx["out"] == total["out"]); - let reset_group = self.reset_group(&idx); - let reset_activate = self.builder.build_assignment( - reset_group.borrow().get("go"), - on.borrow().get("out"), - exit.clone(), - ); - for (st, _) in exits { - // Ensure that reset assignments are active when exiting the loop. - self.add_enables(st, st + 1, iter::once(reset_activate.clone())); - } - - let exits = body_preds - .into_iter() - .map(|(st, g)| (st, g & exit.clone())) - .collect_vec(); - - Ok(exits) - } -} - -impl Schedule<'_, '_> { - fn compile( - con: &mut ir::Control, - builder: &mut ir::Builder, - dump_fsm: bool, - ) -> CalyxResult> { - debug_assert!( - con.get_attribute(ir::NumAttr::Static).is_some(), - "Attempted to compile non-static program" - ); - // Normalize the program - Normalize::apply(con, builder); - // Compute the states associated with the program - let states = ComputeStates::new(con, builder); - // Generate a schedule for this program - let mut schedule = Schedule::new(builder, states); - let out_edges = - schedule.calculate_states(con, vec![(0, ir::Guard::True)])?; - Ok(schedule.realize_schedule(out_edges, dump_fsm)) - } -} - -/// **Core Lowering Pass**: Generates latency-sensitive FSMs when control sub-programs have `@static`. -/// Must be invoked for programs that need to use cycle-level reasoning. Expects that combinational -/// groups and invoke statements have been compiled away. -/// -/// Compilation proceeds in the following high-level steps: -/// 1. *Normalization*: Ensures all `if` branches are balanced, i.e. take the same number of cycles, -/// and directly nested, bounded while loops are de-nested. -/// 2. *State computation*: Assigns states to enables based on their timing. -/// 3. *FSM Generation*: Generates FSM for each static control program and replaces the sub-program -/// with an enable for the group implementing the schedule. -/// -/// The pass provides strong guarantees on cycle-level execution of groups unlike [passes::TopDownCompileControl]. -/// - `seq { a; b; c }`: `b` starts execution exactly in the `a` is done. -/// - `if port { t } else { f }`: Either branch will start executing as soon as the `if` program starts executing. -/// - `@bound(n) while port { b }`: Each iteration starts execution exactly when the previous iteration is done. -/// - `par { a; b }`: `a` and `b` start executing in the same cycle. -/// -/// ## Compilation -/// Like [passes::TopDownCompileControl], this pass first walks over the control -/// program and compiles all `@static par` control programs by allocating each -/// thread in the `par` with a separate FSM. -/// -/// After this first traversal, the pass walks over the control program again -/// and compiles each sub-program is marked as `@static`. -/// [Schedule] encapsulates the compilation logic for each supported compilation operator. -pub struct TopDownStaticTiming { - /// Print out the FSM representation to STDOUT. - dump_fsm: bool, - /// Make sure that the program is fully compiled by this pass - force: bool, -} - -impl ConstructVisitor for TopDownStaticTiming { - fn from(ctx: &ir::Context) -> CalyxResult - where - Self: Sized + Named, - { - let opts = Self::get_opts(ctx); - - Ok(TopDownStaticTiming { - dump_fsm: opts[&"dump-fsm"].bool(), - force: opts[&"force"].bool(), - }) - } - - fn clear_data(&mut self) { - /* All data can be transferred between components */ - } -} - -impl Named for TopDownStaticTiming { - fn name() -> &'static str { - "tdst" - } - - fn description() -> &'static str { - "Top-down latency-sensitive compilation for removing control constructs" - } - - fn opts() -> Vec { - vec![ - PassOpt::new("dump-fsm", "Print out the state machine implementing the schedule", ParseVal::Bool(false), PassOpt::parse_bool), - PassOpt::new("force", "Error if the program cannot be fully compiled using static timing", ParseVal::Bool(false), PassOpt::parse_bool) - ] - } -} - -impl TopDownStaticTiming { - fn compile_sub_programs( - con: &mut ir::Control, - builder: &mut ir::Builder, - dump_fsm: bool, - ) -> CalyxResult<()> { - // Do not attempt to compile Enable and Empty statement - if matches!(con, ir::Control::Enable(_) | ir::Control::Empty(_)) { - return Ok(()); - } - if let Some(time) = con.get_attribute(ir::NumAttr::Static) { - let group = Schedule::compile(con, builder, dump_fsm)?; - let mut en = ir::Control::enable(group); - en.get_mut_attributes().insert(ir::NumAttr::Static, time); - *con = en; - } else { - match con { - ir::Control::Seq(ir::Seq { stmts, .. }) - | ir::Control::Par(ir::Par { stmts, .. }) => { - for stmt in stmts.iter_mut() { - Self::compile_sub_programs(stmt, builder, dump_fsm)?; - } - } - ir::Control::If(ir::If { - tbranch, fbranch, .. - }) => { - Self::compile_sub_programs(tbranch, builder, dump_fsm)?; - Self::compile_sub_programs(fbranch, builder, dump_fsm)?; - } - ir::Control::While(ir::While { body, .. }) => { - Self::compile_sub_programs(body, builder, dump_fsm)?; - } - ir::Control::Enable(_) - | ir::Control::Invoke(_) - | ir::Control::Static(_) - | ir::Control::Repeat(_) - | ir::Control::Empty(_) => {} - } - } - Ok(()) - } -} - -impl Visitor for TopDownStaticTiming { - fn precondition(ctx: &ir::Context) -> Option { - let comp = ctx.entrypoint(); - let has_subcomponents = - comp.cells.iter().any(|c| c.borrow().is_component()); - if has_subcomponents { - Some("Subcomponents with static timing not supported".to_string()) - } else if !comp.control.borrow().has_attribute(ir::NumAttr::Static) { - Some( - "Mixed static-dynamic control programs are not supported" - .to_string(), - ) - } else { - None - } - } - - fn start( - &mut self, - comp: &mut ir::Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let mut con = comp.control.borrow_mut(); - - // Dont compile empty or single-enable control programs - if matches!(&*con, ir::Control::Enable(_) | ir::Control::Empty(_)) { - return Ok(Action::Stop); - } - - if !con.has_attribute(ir::NumAttr::Static) { - unreachable!("Entire program must be static"); - } - - // Propagate all static information through the control program. - con.update_static(&HashMap::new()); - Ok(Action::Continue) - } - fn finish_par( - &mut self, - con: &mut ir::Par, - comp: &mut ir::Component, - sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - if !con.attributes.has(ir::NumAttr::Static) { - return Ok(Action::Continue); - } - let mut builder = ir::Builder::new(comp, sigs); - // Ensure that all threads in the `par` block are group enables - for stmt in &mut con.stmts { - match stmt { - ir::Control::Enable(_) => {} - con => { - let time = con.get_attribute(ir::NumAttr::Static).unwrap(); - let group = - Schedule::compile(con, &mut builder, self.dump_fsm)?; - let mut en = ir::Control::enable(group); - en.get_mut_attributes().insert(ir::NumAttr::Static, time); - *con = en; - } - } - } - Ok(Action::Continue) - } - - fn finish( - &mut self, - comp: &mut ir::Component, - sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - // Take ownership of the control program - let mut con = comp.control.replace(ir::Control::empty()); - - // Compile all sub-programs - let mut builder = ir::Builder::new(comp, sigs); - Self::compile_sub_programs(&mut con, &mut builder, self.dump_fsm)?; - - // Add the control program back. - comp.control = ir::rrc(con); - - // If the force flag is set, make sure that we only have one group remaining - if self.force - && !matches!(&*comp.control.borrow(), ir::Control::Enable(_)) - { - return Err(Error::pass_assumption( - Self::name(), - "`force` flag was set but the final control program is not an enable" - )); - } - Ok(Action::Continue) - } -} diff --git a/runt.toml b/runt.toml index 103013c96..3d2fbc566 100644 --- a/runt.toml +++ b/runt.toml @@ -46,7 +46,7 @@ cmd = """ name = "[core] futil examples" paths = ["examples/futil/*.futil"] cmd = """ -./target/debug/calyx {} -m file -d tdst -l . +./target/debug/calyx {} -m file -l . """ ##### Backend Tests ##### @@ -198,7 +198,6 @@ fud exec --from calyx --to jq \ --through dat \ -s verilog.data {}.data \ -s calyx.exec './target/debug/calyx' \ - -s calyx.flags ' -d tdst' \ -s verilog.cycle_limit 500 \ -s jq.expr ".memories" \ {} -q @@ -241,23 +240,6 @@ fud exec --from calyx --to jq \ """ timeout = 120 -# Tests to ensure that static compilation maintains its guarantees -# See: https://github.com/calyxir/calyx/discussions/1331 -[[tests]] -name = "correctness static scheduling" -paths = ["tests/correctness/static/*.futil"] -cmd = """ -fud exec --from calyx --to jq \ - --through verilog \ - --through dat \ - -s calyx.exec './target/debug/calyx' \ - -s calyx.flags ' -x tdst:force -p all -d group2invoke' \ - -s verilog.cycle_limit 500 \ - -s verilog.data {}.data \ - {} -q -""" -timeout = 120 - # Tests to ensure that static compilation maintains its guarantees # See: https://github.com/calyxir/calyx/discussions/1331 & https://github.com/calyxir/calyx/issues/1344 [[tests]] @@ -271,7 +253,7 @@ fud exec --from calyx --to jq \ --through verilog \ --through dat \ -s calyx.exec './target/debug/calyx' \ - -s calyx.flags '-p all -d tdst -d group2invoke' \ + -s calyx.flags '-p all -d group2invoke' \ -s verilog.cycle_limit 500 \ -s verilog.data {}.data \ {} -q @@ -464,7 +446,6 @@ name = "[examples] language tutorial" paths = ["examples/tutorial/*.futil"] cmd = """ fud e {} -s verilog.cycle_limit 500 \ - -s calyx.flags ' -d tdst' \ --through verilog \ -s verilog.data examples/tutorial/data.json \ --from calyx --to dat -q @@ -475,7 +456,6 @@ name = "[examples] sync primitives" paths = ["examples/sync/*.futil"] cmd = """ fud e {} -s verilog.cycle_limit 500 \ - -s calyx.flags ' -d tdst' \ --through verilog \ -s verilog.data {}.data \ --from calyx --to dat -q @@ -486,7 +466,6 @@ name = "[examples] memory by reference tutorial" paths = ["examples/futil/memory-by-reference/*.futil"] cmd = """ fud e {} -s verilog.cycle_limit 500 \ - -s calyx.flags ' -d tdst' \ --through verilog \ -s verilog.data {}.data \ --from calyx --to dat -q diff --git a/tests/passes/static-timing/compile-if-static.expect b/tests/passes/static-timing/compile-if-static.expect deleted file mode 100644 index 05d449dcb..000000000 --- a/tests/passes/static-timing/compile-if-static.expect +++ /dev/null @@ -1,11 +0,0 @@ -======== main:tdst ========= -0: - cond0[go] = 1'd1; -1: - true[go] = comb_reg.out ? 1'd1; - false[go] = !comb_reg.out ? 1'd1; -transitions: - (1, 2): comb_reg.out - (1, 3): !comb_reg.out -Unconditional runs: - (0, 1) diff --git a/tests/passes/static-timing/compile-if-static.futil b/tests/passes/static-timing/compile-if-static.futil deleted file mode 100644 index 8d452ad70..000000000 --- a/tests/passes/static-timing/compile-if-static.futil +++ /dev/null @@ -1,45 +0,0 @@ -// -x tdst:dump-fsm -p tdst -b none - -import "primitives/core.futil"; - -component main() -> () { - cells { - t = std_reg(1); - f = std_reg(1); - comb_reg = std_reg(1); - lt = std_lt(1); - } - - wires { - group true<"static"=1> { - t.in = 1'b1; - t.write_en = 1'b1; - true[done] = t.done; - } - - group false<"static"=1> { - f.in = 1'b1; - f.write_en = 1'b1; - false[done] = f.done; - } - - group cond0<"static"=1> { - lt.left = 1'd1; - lt.right = 1'd0; - comb_reg.in = lt.out; - comb_reg.write_en = 1'd1; - cond0[done] = comb_reg.done ? 1'd1; - } - } - - control { - @static(3) seq { - @static cond0; - @static(2) if comb_reg.out { - @static true; - } else { - @static false; - } - } - } -} diff --git a/tests/passes/static-timing/compile-par-static.expect b/tests/passes/static-timing/compile-par-static.expect deleted file mode 100644 index 7bbe67419..000000000 --- a/tests/passes/static-timing/compile-par-static.expect +++ /dev/null @@ -1,11 +0,0 @@ -======== main:tdst ========= -0: - C[go] = 1'd1; - A[go] = 1'd1; - B[go] = 1'd1; -1: - B[go] = 1'd1; -[1, 3): - C[go] = 1'd1; -Unconditional runs: - (0, 3) diff --git a/tests/passes/static-timing/compile-par-static.futil b/tests/passes/static-timing/compile-par-static.futil deleted file mode 100644 index 004ae463c..000000000 --- a/tests/passes/static-timing/compile-par-static.futil +++ /dev/null @@ -1,33 +0,0 @@ -// -p well-formed -x tdst:dump-fsm -p tdst -b none - -import "primitives/core.futil"; - -component main() -> () { - cells { - a = std_reg(1); - b = std_reg(1); - c = std_reg(1); - } - - wires { - group A<"static"=1> { - A[done] = a.out; - } - - group B<"static"=2> { - B[done] = b.out; - } - - group C<"static"=3> { - C[done] = c.out; - } - } - - control { - @static(3) par { - C; - A; - B; - } - } -} diff --git a/tests/passes/static-timing/compile-seq-mixed.futil b/tests/passes/static-timing/compile-seq-mixed.futil deleted file mode 100644 index 18c2ace18..000000000 --- a/tests/passes/static-timing/compile-seq-mixed.futil +++ /dev/null @@ -1,48 +0,0 @@ -// -x tdst:dump-fsm -p tdst -b none - -import "primitives/core.futil"; - -component main() -> () { - cells { - r0 = std_reg(32); - r1 = std_reg(32); - r2 = std_reg(32); - r3 = std_reg(32); - } - - wires { - group incr_r0<"static"=1> { - r0.write_en = 1'd1; - r0.in = 32'd10; - incr_r0[done] = r0.done; - } - group incr_r1<"static"=1> { - r1.write_en = 1'd1; - r1.in = 32'd10; - incr_r1[done] = r1.done; - } - group incr_r2 { - r2.write_en = 1'd1; - r2.in = 32'd10; - incr_r2[done] = r2.done ? 1'd1; - } - group incr_r3 { - r3.write_en = 1'd1; - r3.in = 32'd10; - incr_r3[done] = r2.done ? 1'd1; - } - } - - control { - seq { - @static(2) seq { - @static incr_r0; - @static incr_r1; - } - seq { - incr_r2; - incr_r3; - } - } - } -} diff --git a/tests/passes/static-timing/compile-seq-mixed.skip b/tests/passes/static-timing/compile-seq-mixed.skip deleted file mode 100644 index 6bab42532..000000000 --- a/tests/passes/static-timing/compile-seq-mixed.skip +++ /dev/null @@ -1,6 +0,0 @@ -0: - incr_r0[go] = 1'd1; -1: - incr_r1[go] = 1'd1; -Unconditional runs: - (0, 2) diff --git a/tests/passes/static-timing/compile-seq-static.expect b/tests/passes/static-timing/compile-seq-static.expect deleted file mode 100644 index 0c5c85844..000000000 --- a/tests/passes/static-timing/compile-seq-static.expect +++ /dev/null @@ -1,9 +0,0 @@ -======== main:tdst ========= -0: - A[go] = 1'd1; -1: - B[go] = 1'd1; -2: - C[go] = 1'd1; -Unconditional runs: - (0, 3) diff --git a/tests/passes/static-timing/compile-seq-static.futil b/tests/passes/static-timing/compile-seq-static.futil deleted file mode 100644 index 1c61acb09..000000000 --- a/tests/passes/static-timing/compile-seq-static.futil +++ /dev/null @@ -1,39 +0,0 @@ -// -x tdst:dump-fsm -p tdst -b none - -import "primitives/core.futil"; - -component main() -> () { - cells { - a = std_reg(2); - b = std_reg(2); - c = std_reg(2); - } - - wires { - group A<"static"=1> { - a.in = 2'd0; - a.write_en = 1'b1; - A[done] = a.done; - } - - group B<"static"=1> { - b.in = 2'd1; - b.write_en = 1'b1; - B[done] = b.done; - } - - group C<"static"=1> { - c.in = 2'd2; - c.write_en = 1'b1; - C[done] = c.done; - } - } - - control { - @static(3) seq { - @static A; - @static B; - @static C; - } - } -} diff --git a/tests/passes/static-timing/compile-while-static.expect b/tests/passes/static-timing/compile-while-static.expect deleted file mode 100644 index d13b2f8b5..000000000 --- a/tests/passes/static-timing/compile-while-static.expect +++ /dev/null @@ -1,17 +0,0 @@ -======== main:tdst ========= -0: - cond0[go] = 1'd1; -1: - do_add[go] = 1'd1; - incr_idx[go] = idx.out < 3'd4 ? 1'd1; -2: - cond0[go] = 1'd1; -[2, 4): - incr_idx[go] = idx.out < 3'd4 ? 1'd1; -3: - do_add[go] = idx.out < 3'd4 ? 1'd1; - reset_idx[go] = idx.out == 3'd4 ? 1'd1; -transitions: - (3, 2): idx.out < 3'd4 -Unconditional runs: - (0, 3) diff --git a/tests/passes/static-timing/compile-while-static.futil b/tests/passes/static-timing/compile-while-static.futil deleted file mode 100644 index 17dd2ee23..000000000 --- a/tests/passes/static-timing/compile-while-static.futil +++ /dev/null @@ -1,43 +0,0 @@ -// -x tdst:dump-fsm -p tdst -b none - -import "primitives/core.futil"; - -component main() -> () { - cells { - add = std_add(32); - add_r = std_reg(32); // to make body not combinational - comb_reg = std_reg(1); - - lt = std_lt(32); - } - - wires { - group do_add<"static"=1> { - add.right = 32'd4; - add.left = 32'd4; - add_r.in = add.out; - add_r.write_en = 1'b1; - do_add[done] = add_r.done; - } - - group cond0<"static"=1> { - lt.right = 32'd5; - lt.left = 32'd1; - comb_reg.in = lt.out; - comb_reg.write_en = 1'd1; - cond0[done] = comb_reg.done ? 1'd1; - } - } - - control { - @static(5) seq { - @static cond0; - @bound(2) @static(4) while comb_reg.out { - @static(2) seq { - @static do_add; - @static cond0; - } - } - } - } -} diff --git a/tests/passes/tdcc/seq-with-same-done.futil b/tests/passes/tdcc/seq-with-same-done.futil index da3703c47..d5b14e3e1 100644 --- a/tests/passes/tdcc/seq-with-same-done.futil +++ b/tests/passes/tdcc/seq-with-same-done.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d tdst -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { diff --git a/tests/passes/tdcc/while-if.futil b/tests/passes/tdcc/while-if.futil index 216408af2..19864ccad 100644 --- a/tests/passes/tdcc/while-if.futil +++ b/tests/passes/tdcc/while-if.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d tdst -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/while.futil b/tests/passes/tdcc/while.futil index 821a5f0ce..1b9266d7f 100644 --- a/tests/passes/tdcc/while.futil +++ b/tests/passes/tdcc/while.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d tdst -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; diff --git a/tools/flag-compare.sh b/tools/flag-compare.sh index 403d61830..b909be250 100755 --- a/tools/flag-compare.sh +++ b/tools/flag-compare.sh @@ -6,7 +6,7 @@ set -uf -o pipefail flag1=' -p dead-group-removal -p all' -flag2=' -p dead-group-removal -p all -d tdst' +flag2=' -p dead-group-removal -p all' file="$1" data="$2" out_stage=${3:-dat} From 8d7bda8f8803560d1c514210d119024e969eedfc Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:36:27 -0500 Subject: [PATCH 129/189] Promote if branches that don't have else stmts (#1792) * fix * add empty test * rewrite tests * set default limit --- calyx-opt/src/passes/static_promotion.rs | 32 ++++++++++++++++++- tests/correctness/exp/degree-4-signed.expect | 2 +- tests/correctness/exp/degree-8-signed.expect | 2 +- tests/correctness/exp/neg-base.expect | 2 +- .../static-control/static-island.expect | 2 +- tests/passes/static-promotion/if-diff.expect | 29 +++++++++++++++++ tests/passes/static-promotion/if-diff.futil | 24 ++++++++++++++ .../passes/static-promotion/if-no-else.expect | 18 +++++++++++ .../passes/static-promotion/if-no-else.futil | 24 ++++++++++++++ 9 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 tests/passes/static-promotion/if-diff.expect create mode 100644 tests/passes/static-promotion/if-diff.futil create mode 100644 tests/passes/static-promotion/if-no-else.expect create mode 100644 tests/passes/static-promotion/if-no-else.futil diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 2d3182cea..750b5e9ad 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -143,6 +143,8 @@ pub struct StaticPromotion { static_component_latencies: HashMap, /// Threshold for promotion threshold: u64, + /// Threshold for difference in latency for if statements + if_diff_limit: Option, /// Whether we should stop promoting when we see a loop. cycle_limit: Option, } @@ -184,6 +186,7 @@ impl ConstructVisitor for StaticPromotion { static_group_name: HashMap::new(), static_component_latencies: HashMap::new(), threshold: opts["threshold"].pos_num().unwrap(), + if_diff_limit: opts["if-diff-limit"].pos_num(), cycle_limit: opts["cycle-limit"].pos_num(), }) } @@ -216,6 +219,12 @@ impl Named for StaticPromotion { "maximum number of cycles to promote a dynamic control program to static", ParseVal::Num(33554432), PassOpt::parse_num, + ), + PassOpt::new( + "if-diff-limit", + "the maximum difference between if branches that we tolerate for promotion", + ParseVal::Num(1), + PassOpt::parse_num, ) ] } @@ -480,6 +489,13 @@ impl StaticPromotion { latency < self.cycle_limit.unwrap() } + fn within_if_diff_limit(&self, diff: u64) -> bool { + if self.if_diff_limit.is_none() { + return true; + } + diff <= self.if_diff_limit.unwrap() + } + /// If we've already constructed the static group then use the already existing /// group. Otherwise construct `static group` and then return that. fn construct_static_group( @@ -869,6 +885,17 @@ impl Visitor for StaticPromotion { Ok(Action::Continue) } + fn empty( + &mut self, + s: &mut ir::Empty, + _comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + s.attributes.insert(ir::NumAttr::PromoteStatic, 0); + Ok(Action::Continue) + } + fn enable( &mut self, s: &mut ir::Enable, @@ -1049,7 +1076,7 @@ impl Visitor for StaticPromotion { ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); if Self::can_be_promoted(&s.tbranch) - && Self::can_be_promoted(&s.fbranch) + && (Self::can_be_promoted(&s.fbranch)) { // Both branches can be promoted let approx_size_if = Self::approx_size(&s.tbranch) @@ -1059,8 +1086,11 @@ impl Visitor for StaticPromotion { Self::get_inferred_latency(&s.tbranch), Self::get_inferred_latency(&s.fbranch), ); + let branch_diff = Self::get_inferred_latency(&s.tbranch) + .abs_diff(Self::get_inferred_latency(&s.fbranch)); if approx_size_if > self.threshold && self.within_cycle_limit(latency) + && self.within_if_diff_limit(branch_diff) { // Meets size threshold so promote to static let static_tbranch = diff --git a/tests/correctness/exp/degree-4-signed.expect b/tests/correctness/exp/degree-4-signed.expect index 6e5849619..b09674cdc 100644 --- a/tests/correctness/exp/degree-4-signed.expect +++ b/tests/correctness/exp/degree-4-signed.expect @@ -1,5 +1,5 @@ { - "cycles": 53, + "cycles": 56, "memories": { "ret": [ "2.7182769775390625" diff --git a/tests/correctness/exp/degree-8-signed.expect b/tests/correctness/exp/degree-8-signed.expect index 1c94cc1ff..5caebdbb6 100644 --- a/tests/correctness/exp/degree-8-signed.expect +++ b/tests/correctness/exp/degree-8-signed.expect @@ -1,5 +1,5 @@ { - "cycles": 136, + "cycles": 134, "memories": { "ret": [ "0.0001068115234375" diff --git a/tests/correctness/exp/neg-base.expect b/tests/correctness/exp/neg-base.expect index 2ff0c5df1..1a659a4e2 100644 --- a/tests/correctness/exp/neg-base.expect +++ b/tests/correctness/exp/neg-base.expect @@ -1,5 +1,5 @@ { - "cycles": 223, + "cycles": 221, "memories": { "b": [ "-2.600006103515625" diff --git a/tests/correctness/static-control/static-island.expect b/tests/correctness/static-control/static-island.expect index ab1a3839b..da12f2886 100644 --- a/tests/correctness/static-control/static-island.expect +++ b/tests/correctness/static-control/static-island.expect @@ -1,5 +1,5 @@ { - "cycles": 21, + "cycles": 18, "memories": { "m": [ 80 diff --git a/tests/passes/static-promotion/if-diff.expect b/tests/passes/static-promotion/if-diff.expect new file mode 100644 index 000000000..c87729aa2 --- /dev/null +++ b/tests/passes/static-promotion/if-diff.expect @@ -0,0 +1,29 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + cond = std_reg(1); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + } + control { + @promote_static(5) if cond.out { + @compactable static<5> seq { + A0; + A0; + A0; + A0; + A0; + } + } + } +} diff --git a/tests/passes/static-promotion/if-diff.futil b/tests/passes/static-promotion/if-diff.futil new file mode 100644 index 000000000..c90174948 --- /dev/null +++ b/tests/passes/static-promotion/if-diff.futil @@ -0,0 +1,24 @@ +// -p well-formed -p static-promotion -x static-promotion:if-diff-limit=3 + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + cond = std_reg(1); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + } + + control { + if cond.out { + seq {A; A; A; A; A;} + } + } +} diff --git a/tests/passes/static-promotion/if-no-else.expect b/tests/passes/static-promotion/if-no-else.expect new file mode 100644 index 000000000..7513abda0 --- /dev/null +++ b/tests/passes/static-promotion/if-no-else.expect @@ -0,0 +1,18 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + cond = std_reg(1); + } + wires { + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + } + control { + static<1> if cond.out { + A0; + } + } +} diff --git a/tests/passes/static-promotion/if-no-else.futil b/tests/passes/static-promotion/if-no-else.futil new file mode 100644 index 000000000..96250f8ea --- /dev/null +++ b/tests/passes/static-promotion/if-no-else.futil @@ -0,0 +1,24 @@ +// -p well-formed -p static-promotion -p dead-group-removal + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + cond = std_reg(1); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + } + + control { + if cond.out { + A; + } + } +} From 2434c6af3fd0fc1650cbed370992ec63abe9f9d3 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:43:12 -0500 Subject: [PATCH 130/189] [Calyx-FIRRTL backend] Primitive Cells (#1835) * Initial commit: added barebones firrtl.rs as a backend option. * Fix formatting errors and try to leverage VerilogBackend * Fix formatting * first pass on inputs and outputs * fix CI formatting issue * more CI formatting fixes * temporary commit before fixing up starter code * Clean up starter firrtl translation code * Fix CI errors * Barebones test containing input/output ports and single assignment * Fix test failure caused by whitespace * clean up unnecessary comments * Port guard support and some refactoring for converting ports to FIRRTL * First steps for recursive guard building + more refactoring * Guard support and tests * Updating firrtl.rs to support guards * Fix formatting issues * additional formatting fix * Added default assignment to 0 for guard failure and fixed expected output * Added default initialization statements for assignments with guards * adding test to make sure that there's only one invalid initialization per unique dest * fixing attributes and "is invalid" initialization * First steps to support non-primitive cells * Fixing hardcoding of main as the top level component * Fix formatting errors * More formatting fixes * Remove unnecessary FIXME * Create extmodule name from primitive information. Need to extract into a function * extracted function to get a FIRRTL module name given internal primitive data * emit extmodule declarations * Fix formatting errors * Add test for instantiating cells and creating extmodules for primitive cells * merged main and made changes based on PR comments * Fix typo * add another simple test * Fixes from PR comments --- calyx-backend/src/firrtl.rs | 122 ++++++++++++-------- tests/backend/firrtl/basic-cell.expect | 41 +++++++ tests/backend/firrtl/basic-cell.futil | 26 +++++ tests/backend/firrtl/primitive-cells.expect | 48 ++++++++ tests/backend/firrtl/primitive-cells.futil | 30 +++++ 5 files changed, 222 insertions(+), 45 deletions(-) create mode 100644 tests/backend/firrtl/basic-cell.expect create mode 100644 tests/backend/firrtl/basic-cell.futil create mode 100644 tests/backend/firrtl/primitive-cells.expect create mode 100644 tests/backend/firrtl/primitive-cells.futil diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs index cce0181a1..c9e0b6d44 100644 --- a/calyx-backend/src/firrtl.rs +++ b/calyx-backend/src/firrtl.rs @@ -4,8 +4,8 @@ //! valid FIRRTL program. use crate::{traits::Backend, VerilogBackend}; -use calyx_ir::{self as ir, RRC}; -use calyx_utils::{CalyxResult, OutputFile}; +use calyx_ir::{self as ir, Binding, RRC}; +use calyx_utils::{CalyxResult, Id, OutputFile}; use std::collections::HashSet; use std::io; @@ -34,14 +34,31 @@ impl Backend for FirrtlBackend { fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { let out = &mut file.get_write(); - let mut top_level_component = String::from("main"); - // Quick pass to check whether there exists a top-level component that we should replace main with. - for comp in ctx.components.iter() { - if comp.attributes.has(ir::BoolAttr::TopLevel) { - top_level_component = comp.name.to_string().clone(); + writeln!(out, "circuit {}:", ctx.entrypoint)?; + // Pass to output any necessary extmodule statements (for primitive calls) + let mut extmodule_set: HashSet = HashSet::new(); + for comp in &ctx.components { + for cell in comp.cells.iter() { + let cell_borrowed = cell.as_ref().borrow(); + if let ir::CellType::Primitive { + name, + param_binding, + .. + } = &cell_borrowed.prototype + { + let curr_module_name = + get_primitive_module_name(name, param_binding); + if extmodule_set.insert(curr_module_name.clone()) { + emit_primitive_extmodule( + &curr_module_name, + name, + param_binding, + out, + )?; + } + }; } } - writeln!(out, "circuit {}:", top_level_component)?; for comp in ctx.components.iter() { emit_component(comp, out)? } @@ -96,37 +113,27 @@ fn emit_component( for cell in comp.cells.iter() { let cell_borrowed = cell.as_ref().borrow(); if cell_borrowed.type_name().is_some() { - match cell_borrowed.prototype { + let module_name = match &cell_borrowed.prototype { ir::CellType::Primitive { - name: _, - param_binding: _, + name, + param_binding, is_comb: _, latency: _, - } => { - // TODO: use extmodules - writeln!( - f, - "{}; FIXME: attempting to instantiate primitive cell {}", - SPACING.repeat(2), - cell_borrowed.name() - )?; - } - ir::CellType::Component { name } => { - writeln!( - f, - "{}inst {} of {}", - SPACING.repeat(2), - cell_borrowed.name(), - name - )?; - } - ir::CellType::ThisComponent => unreachable!(), - ir::CellType::Constant { val: _, width: _ } => unreachable!(), - } + } => get_primitive_module_name(name, param_binding), + ir::CellType::Component { name } => name.to_string(), + _ => unreachable!(), + }; + writeln!( + f, + "{}inst {} of {}", + SPACING.repeat(2), + cell_borrowed.name(), + module_name + )?; } } - let mut dst_set: HashSet = HashSet::new(); + let mut dst_set: HashSet = HashSet::new(); // Emit assignments for asgn in &comp.continuous_assignments { match asgn.guard.as_ref() { @@ -135,19 +142,18 @@ fn emit_component( let _ = write_assignment(asgn, f, 2); } _ => { - let dst_canonical = &asgn.dst.as_ref().borrow().canonical(); - let dst_canonical_str = dst_canonical.to_string(); - if !dst_set.contains(&dst_canonical_str) { + let dst_canonical = asgn.dst.as_ref().borrow().canonical(); + if !dst_set.contains(&dst_canonical) { // if we don't have a "is invalid" statement yet, then we have to write one. // an alternative "eager" approach would be to instantiate all possible ports // (our output ports + all children's input ports) up front. - let _ = write_invalid_initialization(&asgn.dst, f); - dst_set.insert(dst_canonical_str); + write_invalid_initialization(&asgn.dst, f)?; + dst_set.insert(dst_canonical); } // need to write out the guard. let guard_string = get_guard_string(asgn.guard.as_ref()); writeln!(f, "{}when {}:", SPACING.repeat(2), guard_string)?; - let _ = write_assignment(asgn, f, 3); + write_assignment(asgn, f, 3)?; } } } @@ -158,6 +164,33 @@ fn emit_component( Ok(()) } +// creates a FIRRTL module name given the internal information of a primitive. +fn get_primitive_module_name(name: &Id, param_binding: &Binding) -> String { + let mut primitive_string = name.to_string(); + for (_, size) in param_binding.as_ref().iter() { + primitive_string.push('_'); + primitive_string.push_str(&size.to_string()); + } + primitive_string +} + +fn emit_primitive_extmodule( + curr_module_name: &String, + name: &Id, + param_binding: &Binding, + f: &mut F, +) -> io::Result<()> { + writeln!(f, "{}extmodule {}:", SPACING, curr_module_name)?; + writeln!(f, "{}defname = {}", SPACING.repeat(2), name)?; + for (id, size) in param_binding.as_ref().iter() { + writeln!(f, "{}parameter {} = {}", SPACING.repeat(2), id, size)?; + } + writeln!(f)?; + Ok(()) +} + +// fn create_primitive_extmodule() {} + // recursive function that writes the FIRRTL representation for a guard. fn get_guard_string(guard: &ir::Guard) -> String { match guard { @@ -189,7 +222,7 @@ fn get_guard_string(guard: &ir::Guard) -> String { }; format!("{}({}, {})", op_str, l_str, r_str) } - ir::Guard::Port(port) => get_port_string(&port.borrow().clone(), false), + ir::Guard::Port(port) => get_port_string(&port.borrow(), false), ir::Guard::Info(_) => { panic!("guard should not have info") } @@ -227,7 +260,7 @@ fn get_port_string(port: &calyx_ir::Port, is_dst: bool) -> String { fn write_invalid_initialization( port: &RRC, f: &mut F, -) -> CalyxResult<()> { +) -> io::Result<()> { let default_initialization_str = "; default initialization"; let dst_string = get_port_string(&port.borrow(), true); if port.borrow().attributes.has(ir::BoolAttr::Control) { @@ -237,7 +270,7 @@ fn write_invalid_initialization( SPACING.repeat(2), dst_string, default_initialization_str - )?; + ) } else { writeln!( f, @@ -245,9 +278,8 @@ fn write_invalid_initialization( SPACING.repeat(2), dst_string, default_initialization_str - )?; + ) } - Ok(()) } // Writes a FIRRTL assignment @@ -255,7 +287,7 @@ fn write_assignment( asgn: &ir::Assignment, f: &mut F, num_indent: usize, -) -> CalyxResult<()> { +) -> io::Result<()> { let dest_port = asgn.dst.borrow(); let dest_string = get_port_string(&dest_port, true); let source_port = asgn.src.borrow(); diff --git a/tests/backend/firrtl/basic-cell.expect b/tests/backend/firrtl/basic-cell.expect new file mode 100644 index 000000000..2fb32a31e --- /dev/null +++ b/tests/backend/firrtl/basic-cell.expect @@ -0,0 +1,41 @@ +circuit main: + extmodule std_wire_1: + defname = std_wire + parameter WIDTH = 1 + + module identity: + input in: UInt<32> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: identity + done <= UInt(1) + out <= in + ; COMPONENT END: identity + + module main: + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + inst id of identity + inst invoke0_go of std_wire_1 + inst invoke0_done of std_wire_1 + done is invalid ; default initialization + when invoke0_done.out: + done <= UInt(1) + id.clk <= clk + id.go is invalid ; default initialization + when invoke0_go.out: + id.go <= UInt(1) + id.reset <= reset + id.in is invalid ; default initialization + when invoke0_go.out: + id.in <= UInt(5) + invoke0_go.in <= go + invoke0_done.in <= id.done + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/basic-cell.futil b/tests/backend/firrtl/basic-cell.futil new file mode 100644 index 000000000..1359c6772 --- /dev/null +++ b/tests/backend/firrtl/basic-cell.futil @@ -0,0 +1,26 @@ +// -b firrtl +import "primitives/core.futil"; +component identity(in : 32) -> (out : 32) { + cells {} + wires { + out = in; + done = 1'd1; + } + control {} +} + +component main() -> () { + cells { + id = identity(); + } + wires { + group run_id { + id.in = 32'd5; + id.go = 1'd1; + run_id[done] = id.done; + } + } + control { + seq { run_id; } + } +} diff --git a/tests/backend/firrtl/primitive-cells.expect b/tests/backend/firrtl/primitive-cells.expect new file mode 100644 index 000000000..00b06e5f9 --- /dev/null +++ b/tests/backend/firrtl/primitive-cells.expect @@ -0,0 +1,48 @@ +circuit main: + extmodule std_add_32: + defname = std_add + parameter WIDTH = 32 + + extmodule std_wire_1: + defname = std_wire + parameter WIDTH = 1 + + module plus_one: + input in: UInt<32> + output out: UInt<32> + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: plus_one + inst add of std_add_32 + done <= UInt(1) + out <= add.out + add.left <= UInt(1) + add.right <= in + ; COMPONENT END: plus_one + + module main: + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + ; COMPONENT START: main + inst po of plus_one + inst invoke0_go of std_wire_1 + inst invoke0_done of std_wire_1 + done is invalid ; default initialization + when invoke0_done.out: + done <= UInt(1) + invoke0_go.in <= go + invoke0_done.in <= po.done + po.clk <= clk + po.go is invalid ; default initialization + when invoke0_go.out: + po.go <= UInt(1) + po.reset <= reset + po.in is invalid ; default initialization + when invoke0_go.out: + po.in <= UInt(5) + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/primitive-cells.futil b/tests/backend/firrtl/primitive-cells.futil new file mode 100644 index 000000000..8bf993496 --- /dev/null +++ b/tests/backend/firrtl/primitive-cells.futil @@ -0,0 +1,30 @@ +// -b firrtl +import "primitives/core.futil"; +component plus_one(in : 32) -> (out : 32) { + cells { + add = std_add(32); + } + wires { + add.left = 32'd1; + add.right = in; + out = add.out; + done = 1'd1; + } + control {} +} + +component main() -> () { + cells { + po = plus_one(); + } + wires { + group run_po { + po.in = 32'd5; + po.go = 1'd1; + run_po[done] = po.done; + } + } + control { + seq { run_po; } + } +} From 02ebf993c1fa22a60f2823bff338b8d4a6a06a35 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:41:30 -0500 Subject: [PATCH 131/189] [Calyx-FIRRTL] Primitive cell bug fix (#1838) * First commit of what I believe is the fix for primitive extmodule port bug. Need to fix the code clone * fix code clone * Update tests. Need to manually test whether this will compile in FIRRTL * Fix formatting error * recover panic message for an inout port * Fixes from review comments --- calyx-backend/src/firrtl.rs | 80 ++++++++++++++------- tests/backend/firrtl/basic-cell.expect | 2 + tests/backend/firrtl/primitive-cells.expect | 5 ++ 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs index c9e0b6d44..ec9c06649 100644 --- a/calyx-backend/src/firrtl.rs +++ b/calyx-backend/src/firrtl.rs @@ -6,6 +6,7 @@ use crate::{traits::Backend, VerilogBackend}; use calyx_ir::{self as ir, Binding, RRC}; use calyx_utils::{CalyxResult, Id, OutputFile}; +use ir::Port; use std::collections::HashSet; use std::io; @@ -50,6 +51,7 @@ impl Backend for FirrtlBackend { get_primitive_module_name(name, param_binding); if extmodule_set.insert(curr_module_name.clone()) { emit_primitive_extmodule( + cell.borrow().ports(), &curr_module_name, name, param_binding, @@ -77,33 +79,7 @@ fn emit_component( let sig = comp.signature.borrow(); for (_idx, port_ref) in sig.ports.iter().enumerate() { let port = port_ref.borrow(); - let direction_string = - // NOTE: The signature port definitions are reversed inside the component. - match port.direction { - ir::Direction::Input => {"output"} - ir::Direction::Output => {"input"} - ir::Direction::Inout => { - panic!("Unexpected Inout port on Component: {}", port.name) - } - }; - if port.has_attribute(ir::BoolAttr::Clk) { - writeln!( - f, - "{}{} {}: Clock", - SPACING.repeat(2), - direction_string, - port.name - )?; - } else { - writeln!( - f, - "{}{} {}: UInt<{}>", - SPACING.repeat(2), - direction_string, - port.name, - port.width - )?; - } + emit_port(port, true, f)?; } // Add a COMPONENT START: anchor before any code in the component @@ -175,12 +151,17 @@ fn get_primitive_module_name(name: &Id, param_binding: &Binding) -> String { } fn emit_primitive_extmodule( + ports: &[RRC], curr_module_name: &String, name: &Id, param_binding: &Binding, f: &mut F, ) -> io::Result<()> { writeln!(f, "{}extmodule {}:", SPACING, curr_module_name)?; + for port in ports { + let port_borrowed = port.borrow(); + emit_port(port_borrowed, false, f)?; + } writeln!(f, "{}defname = {}", SPACING.repeat(2), name)?; for (id, size) in param_binding.as_ref().iter() { writeln!(f, "{}parameter {} = {}", SPACING.repeat(2), id, size)?; @@ -189,6 +170,51 @@ fn emit_primitive_extmodule( Ok(()) } +fn emit_port( + port: std::cell::Ref<'_, Port>, + reverse_direction: bool, + f: &mut F, +) -> Result<(), io::Error> { + let direction_string = match port.direction { + calyx_frontend::Direction::Input => { + if reverse_direction { + "output" + } else { + "input" + } + } + calyx_frontend::Direction::Output => { + if reverse_direction { + "input" + } else { + "output" + } + } + calyx_frontend::Direction::Inout => { + panic!("Unexpected Inout port on Component: {}", port.name) + } + }; + if port.has_attribute(ir::BoolAttr::Clk) { + writeln!( + f, + "{}{} {}: Clock", + SPACING.repeat(2), + direction_string, + port.name + )?; + } else { + writeln!( + f, + "{}{} {}: UInt<{}>", + SPACING.repeat(2), + direction_string, + port.name, + port.width + )?; + }; + Ok(()) +} + // fn create_primitive_extmodule() {} // recursive function that writes the FIRRTL representation for a guard. diff --git a/tests/backend/firrtl/basic-cell.expect b/tests/backend/firrtl/basic-cell.expect index 2fb32a31e..4ed144029 100644 --- a/tests/backend/firrtl/basic-cell.expect +++ b/tests/backend/firrtl/basic-cell.expect @@ -1,5 +1,7 @@ circuit main: extmodule std_wire_1: + input in: UInt<1> + output out: UInt<1> defname = std_wire parameter WIDTH = 1 diff --git a/tests/backend/firrtl/primitive-cells.expect b/tests/backend/firrtl/primitive-cells.expect index 00b06e5f9..0a9437a5d 100644 --- a/tests/backend/firrtl/primitive-cells.expect +++ b/tests/backend/firrtl/primitive-cells.expect @@ -1,9 +1,14 @@ circuit main: extmodule std_add_32: + input left: UInt<32> + input right: UInt<32> + output out: UInt<32> defname = std_add parameter WIDTH = 32 extmodule std_wire_1: + input in: UInt<1> + output out: UInt<1> defname = std_wire parameter WIDTH = 1 From 97a05a5d2be6a1e2f2e368f6f5505ca397ee6e87 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Sat, 6 Jan 2024 10:45:20 -0500 Subject: [PATCH 132/189] Working Calyx Implementation of AXI Read channels (#1820) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calyx * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * remove a guard in favor of 1'b1 to simplify reading of source code --------- Co-authored-by: Rachit Nigam --- .gitignore | 3 + yxi/axi-calyx/axi-reads-calyx.futil | 374 +++++++++++++++++++++++++ yxi/axi-calyx/cocotb/Makefile | 23 ++ yxi/axi-calyx/cocotb/axi-read-tests.py | 188 +++++++++++++ 4 files changed, 588 insertions(+) create mode 100644 yxi/axi-calyx/axi-reads-calyx.futil create mode 100644 yxi/axi-calyx/cocotb/Makefile create mode 100644 yxi/axi-calyx/cocotb/axi-read-tests.py diff --git a/.gitignore b/.gitignore index 8a97d3c2f..ccf0b37de 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,10 @@ __pycache__ !.vscode/launch.json !.vscode/tasks.json +# cocotb artifacts tests/xilinx/cocotb/**/hdl +sim_build/ +results.xml !cider-dap/calyxDebug/package.json diff --git a/yxi/axi-calyx/axi-reads-calyx.futil b/yxi/axi-calyx/axi-reads-calyx.futil new file mode 100644 index 000000000..7b5760e72 --- /dev/null +++ b/yxi/axi-calyx/axi-reads-calyx.futil @@ -0,0 +1,374 @@ +// ### +// This file contains the components needed to perform read transacitons via AXI. +// Current goal is to create a cocotb testbench that tests correctness of this. +// See https://github.com/cucapra/calyx/issues/1733 for more information. +// +// This wrapper assumes it is part of a dot product computation with vectors of +// length 16 +// It assumes a bus data width of 32 +// This is largely a work in progress and as of Nov 20 2023 is not intended to +// actually be used for anything +// ### + +import "primitives/core.futil"; +import "primitives/compile.futil"; +import "primitives/math.futil"; +import "primitives/memories.futil"; + + +//this goes m->s unlike read channel +component m_arread_channel( + ARESET: 1, + ARREADY: 1 +) -> ( + ARVALID: 1, + // This needs to be 64, see link below `m_axi` section. + ARADDR: 64, + // 2^ARSIZE is bytes used in transfer. For memory-mapped AXI (which is what we + // are doing I believe), should match width of data bus (to shell?, so 32 wide? This + // is 3'b010) + // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements + // for restrictions + ARSIZE: 3, + // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. + ARLEN : 8, + // 00 for fixed, 01 for incrementing, 2 for wrap, + // needs to be incr for RTL kernels (can't use wrapped of fixed + ARBURST : 2, + // required by spec. We hardwire this to priviliged access, non secure, data access. + ARPROT : 3) { + cells{ + is_arvalid = std_reg(1); + + // gets set high with ARVALID and remains high + arvalid_was_high = std_reg(1); + // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` + // but for now will live here. + ref base_addr = std_reg(64); + + // number of trasfers in a transaction. This is sent to subordinate + txn_len = std_reg(8); + + // number of txns we want to occur before entire m_arread_channel is done + // this is internal to the channel (unlike txn_len) + txn_n = std_const(32,1); + txn_count = std_reg(32); + perform_reads = std_neq(32); + txn_adder = std_add(32); + + //"block_transfer" register. need to put into a reg to avoid combinational loops + bt_reg = std_reg(1); + + + } + + wires{ + + ARVALID = is_arvalid.out; + + group deassert_val { + is_arvalid.in = 1'b0; + is_arvalid.write_en = 1'b1; + deassert_val[done] = is_arvalid.done; + } + + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + // this asserts valid and defines all inputs correctly + // because valid should not be deasserted until handshake occurs + // this all needs to be one group + // this contains blocking logic previously in its own group + group do_ar_transfer { + //assert ARVALID + is_arvalid.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + + // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high + // but for now we will be explicit and reduce this in generation maybe. Not sure + // it even matters. + // This makes ARVALID go low after a single cycle. Without it it stays high for 2. + is_arvalid.in = is_arvalid.out & ARREADY & arvalid_was_high.out ? 1'b0; + is_arvalid.write_en = 1'b1; + + + arvalid_was_high.in = 1'b1; + arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + + + // drive output signals for transfer + ARADDR = base_addr.out; + // see link above, needs to match data width to host. + // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. + ARSIZE = 3'b010; + // For now this can be taken from .yxi, as size of mem, because we are assuming + // data_bus width that matches size of memory cells + // If we want to use bigger mems need to be able to update base addr + ARLEN = txn_len.out; + ARBURST = 2'b01; //incr + // privileged, non-secure, instruction access + ARPROT = 3'b110; + + + //done when one cycle after handshake (handshake happens for a single cycle) + bt_reg.in = ARREADY & is_arvalid.out ? 1'b1; + bt_reg.in = !(ARREADY & is_arvalid.out) ? 1'b0; + bt_reg.write_en = 1'b1; + do_ar_transfer[done] = bt_reg.out; + } + + + //txn bookkeeping. + //We are done performing reads when txn_count == txn_n + group txn_count_init { + txn_count.in = 32'b0; + txn_count.write_en = 1'b1; + txn_count_init[done] = txn_count.done; + + } + + group txn_len_init { + //TODO(nathanielnrn): 15 is good for word wide data bus. We'd + //expect 16 transfers. Number of transfers that occur is ARLEN + 1 + txn_len.in = 8'd15; + txn_len.write_en = 1'b1; + txn_len_init[done] = txn_len.done; + } + + group txn_incr { + txn_adder.left = txn_count.out; + txn_adder.right = 32'b1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'b1; + txn_incr[done] = txn_count.done; + + } + + comb group check_reads_done { + perform_reads.left = txn_count.out; + perform_reads.right = txn_n.out; + } + } + + control{ + //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? + seq{ + txn_count_init; + txn_len_init; + while perform_reads.out with check_reads_done{ + seq{ + reset_bt; + do_ar_transfer; + deassert_val; + txn_incr; + } + } + } + } +} + + + + +component m_read_channel( + ARESET : 1, + RVALID : 1, + RLAST : 1, + RDATA : 32, + RRESP : 2, // Note: This is generated in subordinate! had this backwards in earlier version +) -> ( + // NOTE: In general, according to ZipCPU we want xREADY signals to be registered + // because (IIRC) it helps avoid combinational loops between READY and VALID. + RREADY : 1, +) { + cells { + // 16 is due to dot-product vector length assumption + // For this manual implementation we are just writing into this data based + // on the data we read from cocotb + ref data_received = seq_mem_d1(32, 16, 64); + is_rdy = std_reg(1); + ref curr_addr = std_reg(64); + + // registered because RLAST is high with last transfer, not after + // before this was registered we were terminating immediately with + // last transfer and not servicing it + n_RLAST = std_reg(1); + + // TODO: get this width from yxi + read_data_reg = std_reg(32); + + //address of seq_d1_mem we are writing to + curr_addr_adder = std_add(64); + + // block_transfer reg to avoid combinational loops + bt_reg = std_reg(1); + + } + wires{ + + RREADY = is_rdy.out; + data_received.read_en = 1'b0; + + group init_n_RLAST { + n_RLAST.in = 1'b1; + n_RLAST.write_en = 1'b1; + init_n_RLAST[done] = n_RLAST.done; + } + + // Used to block any servicing until handshake occurs. + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + // NOTE: xVALID signals must be high until xREADY is high as well, so this works + // because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip + // and group will be done by bt_reg.out + group block_transfer { + // set RREADY high + // TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). + // Could we simplify this we just making things ready when we are in + // block_transfer && RVALID? + + //NOTE: is_rdy.in = 1'b1; does not work, it leaves RREADY high for 2 cycles + // this both asserts and deasserts one cycle later + // TODO(nathanielnrn): Spec recommends defaulting xREADY high as it + // can get rid of extra cycle. Maybe doing so here would be useful? + // as opposed to waiting for RVALID + is_rdy.in = !(RVALID & is_rdy.out) ? 1'b1; + is_rdy.in = RVALID & is_rdy.out ? 1'b0; + is_rdy.write_en = 1'b1; + + + //store the data we want to write + read_data_reg.in = RDATA; + read_data_reg.write_en = is_rdy.out; + + //update n_RLAST reg + n_RLAST.in = RLAST ? 1'b0; + n_RLAST.in = !RLAST ? 1'b1; + n_RLAST.write_en = 1'b1; + + + // we are done after handshake + bt_reg.in = is_rdy.out & RVALID ? 1'b1; + bt_reg.in = !(is_rdy.out & RVALID) ? 1'b0; + bt_reg.write_en = 1'b1; + block_transfer[done] = bt_reg.out; + } + + group receive_r_transfer{ + // keep RREADY low; + is_rdy.in = 1'b0; + is_rdy.write_en = 1'b1; + + //write the data we received during transfer to seq_d1_mem + data_received.addr0 = curr_addr.out; + data_received.write_en = 1'b1; + data_received.write_data = read_data_reg.out; + receive_r_transfer[done] = data_received.write_done; + + } + + group incr_curr_addr{ + curr_addr_adder.left = 64'd1 ; + curr_addr_adder.right = curr_addr.out; + curr_addr.in = curr_addr_adder.out; + curr_addr.write_en = 1'b1; + incr_curr_addr[done] = curr_addr.done; + } + } + control{ + init_n_RLAST; + while n_RLAST.out{ + seq{ + reset_bt; + block_transfer; + receive_r_transfer; + incr_curr_addr; + } + } + } +} + +//TODO(nathanielnrn): this is axi_wrapper, prefer to use @toplevel attribute but its not working +// See individual channel components for explanations of signals +component main( + m_ARESET : 1, + m_ARREADY : 1, + + m_RVALID : 1, + m_RLAST : 1, + m_RDATA : 32, + m_RRESP : 2, + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m_RID : 1, +) -> ( + m_ARVALID : 1, + m_ARADDR: 64, + m_ARSIZE: 3, + m_ARLEN : 8, + m_ARBURST : 2, + + m_RREADY : 1, + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m_ARID : 1 +) { + cells{ + vec1_data = seq_mem_d1(32,16,64); + output_data = seq_mem_d1(32,1,0); + + curr_addr = std_reg(64); + base_addr = std_reg(64); + + read_channel = m_read_channel(); + arread_channel = m_arread_channel(); + + } + + wires{ + + m_ARID = 1'b0; + + group set_curr_to_base_addr{ + curr_addr.in = base_addr.out; + curr_addr.write_en = 1'b1; + set_curr_to_base_addr[done] = curr_addr.done; + } + } + control{ + seq{ + invoke arread_channel[base_addr = base_addr] + ( + ARESET = m_ARESET, + ARREADY = m_ARREADY + ) + ( + ARVALID = m_ARVALID, + ARADDR = m_ARADDR, + ARSIZE = m_ARSIZE, + ARLEN = m_ARLEN, + ARBURST = m_ARBURST + ); + + set_curr_to_base_addr; + + invoke read_channel[data_received = vec1_data, curr_addr = curr_addr] + ( + ARESET = m_ARESET, + RVALID = m_RVALID, + RLAST = m_RLAST, + RDATA = m_RDATA, + RRESP = m_RRESP + ) + ( + RREADY = m_RREADY + ); + } + } + + +} diff --git a/yxi/axi-calyx/cocotb/Makefile b/yxi/axi-calyx/cocotb/Makefile new file mode 100644 index 000000000..3ae9a87d4 --- /dev/null +++ b/yxi/axi-calyx/cocotb/Makefile @@ -0,0 +1,23 @@ +# Makefile + +# defaults +SIM ?= icarus +TOPLEVEL_LANG ?= verilog + + +#Needed to extract desired test from runt invocation + +VERILOG_SOURCES += $(PWD)/../outputs/axi-reads.v + +#Defines build directory, if left to default only a single computation is run +SIM_BUILD=sim_build/axi-reads + +# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file +TOPLEVEL = main + +# MODULE is the basename of the Python test file +MODULE = axi-read-tests + + +# include cocotb's make rules to take care of the simulator setup +include $(shell cocotb-config --makefiles)/Makefile.sim diff --git a/yxi/axi-calyx/cocotb/axi-read-tests.py b/yxi/axi-calyx/cocotb/axi-read-tests.py new file mode 100644 index 000000000..1c54e4fde --- /dev/null +++ b/yxi/axi-calyx/cocotb/axi-read-tests.py @@ -0,0 +1,188 @@ +import cocotb +from cocotb.clock import Clock +from cocotbext.axi import AxiReadBus, AxiRamRead +from cocotb.triggers import Timer, ClockCycles +import mmap +import struct +from typing import Union, Literal, List + +# TODO(nathanielnrn): If optional signals like WSTRB are not recognized, +# install cocotb-bus directly from github, as 0.2.1 has a bug + + +# Reads 16 elements from mmap of 16*4 bytes. Writes these elements to 16 cells in calyx defined seq_d1 mem. +@cocotb.test() +async def read_channels_happy_path(main): + happy_data_vec = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384, + 32768, + ] + await read_axi_test_helper(main, happy_data_vec, happy_data_vec) + + +# Adding extra data to backing mmap does not ruin reading of 16 elements and writing them correctly. +@cocotb.test() +async def read_channels_extra_mmap_data(main): + large_data_vec = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384, + 32768, + 2**32 - 1, + ] + await read_axi_test_helper(main, large_data_vec, large_data_vec[0:16]) + + +# Using a small mmap will have the AXI read loop back around +# NOTE: From what I can tell, this is not part of AXI spec, but rather behavior of cocotb AXI. +# Still think it is useful to test for to see if anything breaks with this +@cocotb.test() +async def read_channels_small_mmap_data(main): + small_data_vec = [1, 2, 4, 8, 2**32 - 1] + expected_data_vec = [ + 1, + 2, + 4, + 8, + 2**32 - 1, + 1, + 2, + 4, + 8, + 2**32 - 1, + 1, + 2, + 4, + 8, + 2**32 - 1, + 1, + ] + await read_axi_test_helper(main, small_data_vec, expected_data_vec) + + +async def read_axi_test_helper( + module, data_vec: List[int], expected: List[int], mmap_size: int = None +): + """Create an mmap with data of `data_vec` and use this to initialize + a cocotb-axi-ram (read only) with this data. Assert that the data that + our AXI program reads has been written to the memory inside our Calyx program + correctly and matches `expected.` + + mmap_size is in bytes. + + """ + cocotb.start_soon(Clock(module.clk, 2, units="ns").start()) + + # Assert reset for 5 cycles (reuqired for Calyx interfacing) + module.reset.value = 1 + await ClockCycles(module.clk, 5) # wait a bit + module.reset.value = 0 + + # Start the execution + module.go.value = 1 + + if mmap_size is None: + # 4 bytes per integer + mmap_size = len(data_vec) * 4 + # anonymous mmep for now to back axiram + memmap = mmap.mmap(-1, mmap_size) + axi_ram_read = AxiRamRead( + # NOTE: prefix should not contain the final "_" + AxiReadBus.from_prefix(module, "m"), + module.clk, + module.reset, + # size in bytes + size=mmap_size, + mem=memmap, + ) + + data_vec_bytes = int_to_bytes(data_vec) + memmap.seek(0) + memmap.write(data_vec_bytes) + memmap.seek(0) + + await Timer(20, "ns") + # axi_ram_read.hexdump(0x0000, mmap_size, prefix="RAM") + + await Timer(500, "ns") + assert ( + cocotb_mem_to_ints(module.vec1_data) == expected + ), f"main.vec1_data: {cocotb_mem_to_ints(module.vec1_data)} does not contain the data in expected: {expected}." + + +# TODO(nathanielnrn): Decide between these and xilinx cocotb tests, refactor out +# after determining which is better + + +# Returns 4-byte representation of an integer +# Does not yet support unsigned, can be changed by changing to `i` as opposed to `I`. +# Not supported cause haven't yet thought about how AXI is affected +def int_to_bytes( + integers, byteorder: Union[Literal["little"], Literal["big"]] = "little" +): + frmt = get_format(byteorder, integers) + return struct.pack(frmt, *integers) + + +# returns iterable of ints or a single int depending on size of bytes argument +def bytes_to_int(bytes, byteorder="little"): + assert len(bytes) % 4 == 0, "bytes length not divisble by 4." + frmt = get_format(byteorder, bytes) + ints = struct.unpack(frmt, bytes) + if len(ints) == 1: + return ints[0] + return ints + + +# Returns format used by Struct, assuming we are interested in integers (so 4 bytes) +def get_format(byteorder: Union[Literal["little"], Literal["big"]], input_list): + frmt = "" + if byteorder == "little": + frmt += "<" + elif byteorder == "big": + frmt += ">" + else: + raise ValueError("byteorder must be 'little' or 'big'.") + + if type(input_list) is bytes: + assert len(input_list) % 4 == 0, "input_list length not divisble by 4." + frmt += f"{len(input_list)//4}" + elif type(input_list[0]) is int: + frmt += f"{len(input_list)}" + + frmt += "I" + return frmt + + +# Takes in top level cocotb memory structure and returns integers of bytes contained in it. +def cocotb_mem_to_ints(memory) -> List[int]: + integers = list(map(lambda e: e.integer, memory.mem.value)) + # Cocotb mem.value seems to store integers in reverse order? So memory cell 0 is + # at index -1 and memory cell n-1 is at index 0 + return integers[::-1] From 1d9dd52eb81b5f4c8bba16dad0599b38d6ade871 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:28:51 -0500 Subject: [PATCH 133/189] [Calyx-Firrtl] Fix undefined values bug by initializing to zero (#1841) * Initializing to zero resolves the optimization issue we were seeing with language-tutorial-compute * update tests to have zero initialization --- calyx-backend/src/firrtl.rs | 3 ++- tests/backend/firrtl/and-or-not-guard.expect | 1 + tests/backend/firrtl/basic-cell.expect | 3 +++ tests/backend/firrtl/basic-guard.expect | 1 + tests/backend/firrtl/comparison-guard.expect | 1 + tests/backend/firrtl/or-guard.expect | 1 + tests/backend/firrtl/primitive-cells.expect | 3 +++ tests/backend/firrtl/two-or-guards.expect | 1 + 8 files changed, 13 insertions(+), 1 deletion(-) diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs index ec9c06649..cc03abec2 100644 --- a/calyx-backend/src/firrtl.rs +++ b/calyx-backend/src/firrtl.rs @@ -304,7 +304,8 @@ fn write_invalid_initialization( SPACING.repeat(2), dst_string, default_initialization_str - ) + )?; + writeln!(f, "{}{} <= UInt(0)", SPACING.repeat(2), dst_string) } } diff --git a/tests/backend/firrtl/and-or-not-guard.expect b/tests/backend/firrtl/and-or-not-guard.expect index e0dea86d9..e5cfd4b30 100644 --- a/tests/backend/firrtl/and-or-not-guard.expect +++ b/tests/backend/firrtl/and-or-not-guard.expect @@ -12,6 +12,7 @@ circuit main: ; COMPONENT START: main done <= UInt(1) out is invalid ; default initialization + out <= UInt(0) when and(or(not(cond), cond2), cond3): out <= in ; COMPONENT END: main diff --git a/tests/backend/firrtl/basic-cell.expect b/tests/backend/firrtl/basic-cell.expect index 4ed144029..7245170f0 100644 --- a/tests/backend/firrtl/basic-cell.expect +++ b/tests/backend/firrtl/basic-cell.expect @@ -27,14 +27,17 @@ circuit main: inst invoke0_go of std_wire_1 inst invoke0_done of std_wire_1 done is invalid ; default initialization + done <= UInt(0) when invoke0_done.out: done <= UInt(1) id.clk <= clk id.go is invalid ; default initialization + id.go <= UInt(0) when invoke0_go.out: id.go <= UInt(1) id.reset <= reset id.in is invalid ; default initialization + id.in <= UInt(0) when invoke0_go.out: id.in <= UInt(5) invoke0_go.in <= go diff --git a/tests/backend/firrtl/basic-guard.expect b/tests/backend/firrtl/basic-guard.expect index 1545e6ccb..c58d6e8d7 100644 --- a/tests/backend/firrtl/basic-guard.expect +++ b/tests/backend/firrtl/basic-guard.expect @@ -10,6 +10,7 @@ circuit main: ; COMPONENT START: main done <= UInt(1) out is invalid ; default initialization + out <= UInt(0) when cond: out <= in ; COMPONENT END: main diff --git a/tests/backend/firrtl/comparison-guard.expect b/tests/backend/firrtl/comparison-guard.expect index ba15ed71c..7bfdf4ba7 100644 --- a/tests/backend/firrtl/comparison-guard.expect +++ b/tests/backend/firrtl/comparison-guard.expect @@ -12,6 +12,7 @@ circuit main: ; COMPONENT START: main done <= UInt(1) out is invalid ; default initialization + out <= UInt(0) when and(leq(var, var2), cond3): out <= in ; COMPONENT END: main diff --git a/tests/backend/firrtl/or-guard.expect b/tests/backend/firrtl/or-guard.expect index adb0e8311..80fd80b9a 100644 --- a/tests/backend/firrtl/or-guard.expect +++ b/tests/backend/firrtl/or-guard.expect @@ -11,6 +11,7 @@ circuit main: ; COMPONENT START: main done <= UInt(1) out is invalid ; default initialization + out <= UInt(0) when or(cond, cond2): out <= in ; COMPONENT END: main diff --git a/tests/backend/firrtl/primitive-cells.expect b/tests/backend/firrtl/primitive-cells.expect index 0a9437a5d..c92396340 100644 --- a/tests/backend/firrtl/primitive-cells.expect +++ b/tests/backend/firrtl/primitive-cells.expect @@ -37,16 +37,19 @@ circuit main: inst invoke0_go of std_wire_1 inst invoke0_done of std_wire_1 done is invalid ; default initialization + done <= UInt(0) when invoke0_done.out: done <= UInt(1) invoke0_go.in <= go invoke0_done.in <= po.done po.clk <= clk po.go is invalid ; default initialization + po.go <= UInt(0) when invoke0_go.out: po.go <= UInt(1) po.reset <= reset po.in is invalid ; default initialization + po.in <= UInt(0) when invoke0_go.out: po.in <= UInt(5) ; COMPONENT END: main diff --git a/tests/backend/firrtl/two-or-guards.expect b/tests/backend/firrtl/two-or-guards.expect index cbd7c2e54..897ce97b5 100644 --- a/tests/backend/firrtl/two-or-guards.expect +++ b/tests/backend/firrtl/two-or-guards.expect @@ -13,6 +13,7 @@ circuit main: ; COMPONENT START: main done <= UInt(1) out is invalid ; default initialization + out <= UInt(0) when or(cond, cond2): out <= in when or(cond2, cond3): From 96bf129e55a82439af792ba3418399a156dbf851 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Thu, 11 Jan 2024 21:19:40 -0500 Subject: [PATCH 134/189] Promote AXI-Read implementation to a complete AXI wrapper (#1842) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * add python file that enables waveform (vcd/fst) generation * formatting --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-combined-calyx.futil | 1244 ++++++++++++++++++++ yxi/axi-calyx/axi-reads-calyx.futil | 3 +- yxi/axi-calyx/axi-writes-calyx.futil | 521 ++++++++ yxi/axi-calyx/cocotb/Makefile | 6 +- yxi/axi-calyx/cocotb/axi-combined-tests.py | 230 ++++ yxi/axi-calyx/cocotb/axi-write-tests.py | 171 +++ yxi/axi-calyx/cocotb/sim.sh | 8 + yxi/axi-calyx/vcdump.py | 40 + 8 files changed, 2218 insertions(+), 5 deletions(-) create mode 100644 yxi/axi-calyx/axi-combined-calyx.futil create mode 100644 yxi/axi-calyx/axi-writes-calyx.futil create mode 100644 yxi/axi-calyx/cocotb/axi-combined-tests.py create mode 100644 yxi/axi-calyx/cocotb/axi-write-tests.py create mode 100644 yxi/axi-calyx/cocotb/sim.sh create mode 100755 yxi/axi-calyx/vcdump.py diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil new file mode 100644 index 000000000..78ef049b4 --- /dev/null +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -0,0 +1,1244 @@ +// ### +// This program wraps an element wise vector addition component +// With components that implement an AXI interface. +// As of Jan 2024 this works correctly with cocotb-axi extension + +// This wrapper assumes vectors of length 8. It uses two input (A0, B0) memories +// and one output memory (Sum0). +// It assumes a bus data width of 32. + +// This hardcoded work will be used to guide generation work of AXI moving forward. +// it is somewhat messy and is hopefully destined to be removed from the repo eventually. +// ### + +import "primitives/core.futil"; +import "primitives/compile.futil"; +import "primitives/math.futil"; +import "primitives/memories.futil"; + + +// ############################# +// #########Reads Start######### +// ############################# + + +//this goes m->s unlike read channel +component m_arread_channel( + ARESET: 1, + ARREADY: 1 +) -> ( + ARVALID: 1, + // This needs to be 64, see link below `m_axi` section. + ARADDR: 64, + // 2^ARSIZE is bytes used in transfer. For memory-mapped AXI (which is what we + // are doing I believe), should match width of data bus (to shell?, so 32 wide? This + // is 3'b010) + // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements + // for restrictions + ARSIZE: 3, + // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. + ARLEN : 8, + // 00 for fixed, 01 for incrementing, 2 for wrap, + // needs to be incr for RTL kernels (can't use wrapped or fixed) + ARBURST : 2, + // required by spec. We hardwire this to priviliged access, non secure, data access. + ARPROT : 3) { + cells{ + is_arvalid = std_reg(1); + + // gets set high with ARVALID and remains high + arvalid_was_high = std_reg(1); + // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` + // but for now will live here. + ref base_addr = std_reg(64); + + // number of trasfers in a transaction. This is sent to subordinate + txn_len = std_reg(8); + + // number of txns we want to occur before entire m_arread_channel is done + // this is internal to the channel (unlike txn_len) + txn_n = std_const(32,1); + txn_count = std_reg(32); + perform_reads = std_neq(32); + txn_adder = std_add(32); + + //"block_transfer" register. need to put into a reg to avoid combinational loops + bt_reg = std_reg(1); + + + } + + wires{ + + ARVALID = is_arvalid.out; + + group deassert_val { + is_arvalid.in = 1'b0; + is_arvalid.write_en = 1'b1; + deassert_val[done] = is_arvalid.done; + } + + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + group reset_was_high { + arvalid_was_high.in = 1'b0; + arvalid_was_high.write_en = 1'b1; + reset_was_high[done] = arvalid_was_high.done; + } + + // this asserts valid and defines all inputs correctly + // because valid should not be deasserted until handshake occurs + // this all needs to be one group + // this contains blocking logic previously in its own group + group do_ar_transfer { + //assert ARVALID + + is_arvalid.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + + // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high + // but for now we will be explicit and reduce this in generation maybe. Not sure + // it even matters. + + // This makes ARVALID go low after a single cycle. + // Without it it stays high for 2 cycles + // See issue #1828: https://github.com/calyxir/calyx/issues/1828 + is_arvalid.in = is_arvalid.out & ARREADY & arvalid_was_high.out ? 1'b0; + is_arvalid.write_en = 1'b1; + + arvalid_was_high.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + + + // drive output signals for transfer + ARADDR = base_addr.out; + // see link above, needs to match data width to host. + // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. + ARSIZE = 3'b010; + // For now this can be taken from .yxi, as size of mem, because we are assuming + // data_bus width that matches size of memory cells + // If we want to use bigger mems need to be able to update base addr + ARLEN = txn_len.out; + ARBURST = 2'b01; //incr + // privileged, non-secure, instruction access + ARPROT = 3'b110; + + + //done when one cycle after handshake (handshake happens for a single cycle) + bt_reg.in = ARREADY & is_arvalid.out ? 1'b1; + bt_reg.in = !(ARREADY & is_arvalid.out) ? 1'b0; + bt_reg.write_en = 1'b1; + do_ar_transfer[done] = bt_reg.out; + } + + + //txn bookkeeping. + //We are done performing reads when txn_count == txn_n + group txn_count_init { + txn_count.in = 32'b0; + txn_count.write_en = 1'b1; + txn_count_init[done] = txn_count.done; + + } + + group txn_len_init { + // TODO(nathanielnrn):Parametrize this. + // 7 is good for word wide data bus and 8 element vec_add We'd + // expect 8 transfers. Number of transfers that occur is ARLEN + 1 + txn_len.in = 8'd7; + txn_len.write_en = 1'b1; + txn_len_init[done] = txn_len.done; + } + + group txn_incr { + txn_adder.left = txn_count.out; + txn_adder.right = 32'b1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'b1; + txn_incr[done] = txn_count.done; + + } + + //txn_count == txn_n + comb group check_reads_done { + perform_reads.left = txn_count.out; + perform_reads.right = txn_n.out; + } + } + + control{ + //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? + seq{ + txn_count_init; + txn_len_init; + while perform_reads.out with check_reads_done{ + seq{ + par { + reset_bt; + reset_was_high; + } + do_ar_transfer; + deassert_val; + txn_incr; + } + } + } + } +} + + + + +component m_read_channel( + ARESET : 1, + RVALID : 1, + RLAST : 1, + RDATA : 32, + RRESP : 2, // Note: This is generated in subordinate! had this backwards in earlier version +) -> ( + // NOTE: In general, according to ZipCPU we want xREADY signals to be registered + // because (IIRC) it helps avoid combinational loops between READY and VALID. + RREADY : 1, +) { + cells { + // 16 is due to dot-product vector length assumption + // For this manual implementation we are just writing into this data based + // on the data we read from cocotb + ref data_received = seq_mem_d1(32, 8, 64); + is_rdy = std_reg(1); + ref curr_addr = std_reg(64); + + // registered because RLAST is high with last transfer, not after + // before this was registered we were terminating immediately with + // last transfer and not servicing it + n_RLAST = std_reg(1); + + // TODO: get this width from yxi + read_data_reg = std_reg(32); + + //address of seq_d1_mem we are writing to + curr_addr_adder = std_add(64); + + // block_transfer reg to avoid combinational loops + bt_reg = std_reg(1); + + } + wires{ + + RREADY = is_rdy.out; + data_received.read_en = 1'b0; + + group init_n_RLAST { + n_RLAST.in = 1'b1; + n_RLAST.write_en = 1'b1; + init_n_RLAST[done] = n_RLAST.done; + } + + // Used to block any servicing until handshake occurs. + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + // NOTE: xVALID signals must be high until xREADY is high as well, so this works + // because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip + // and group will be done by bt_reg.out + group block_transfer { + // set RREADY high + // TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). + // Could we simplify this we just making things ready when we are in + // block_transfer && RVALID? + + //NOTE: is_rdy.in = 1'b1; does not work, it leaves RREADY high for 2 cycles + // this both asserts and deasserts one cycle later + // See issue #1828: https://github.com/calyxir/calyx/issues/1828 + + // TODO(nathanielnrn): Spec recommends defaulting xREADY high as it + // can get rid of extra cycle. Maybe doing so here would be useful? + // as opposed to waiting for RVALID + is_rdy.in = !(RVALID & is_rdy.out) ? 1'b1; + is_rdy.in = RVALID & is_rdy.out ? 1'b0; + is_rdy.write_en = 1'b1; + + + //store the data we want to write + read_data_reg.in = RDATA; + read_data_reg.write_en = is_rdy.out; + + //update n_RLAST reg + n_RLAST.in = RLAST ? 1'b0; + n_RLAST.in = !RLAST ? 1'b1; + n_RLAST.write_en = 1'b1; + + + // we are done after handshake + bt_reg.in = is_rdy.out & RVALID ? 1'b1; + bt_reg.in = !(is_rdy.out & RVALID) ? 1'b0; + bt_reg.write_en = 1'b1; + block_transfer[done] = bt_reg.out; + } + + group receive_r_transfer{ + // keep RREADY low; + is_rdy.in = 1'b0; + is_rdy.write_en = 1'b1; + + //write the data we received during transfer to seq_d1_mem + data_received.addr0 = curr_addr.out; + data_received.write_en = 1'b1; + data_received.write_data = read_data_reg.out; + receive_r_transfer[done] = data_received.write_done; + + } + + group incr_curr_addr{ + curr_addr_adder.left = 64'd1 ; + curr_addr_adder.right = curr_addr.out; + curr_addr.in = curr_addr_adder.out; + curr_addr.write_en = 1'b1; + incr_curr_addr[done] = curr_addr.done; + } + } + control{ + init_n_RLAST; + while n_RLAST.out{ + seq{ + reset_bt; + block_transfer; + receive_r_transfer; + incr_curr_addr; + } + } + } +} + + +// ############################# +// ##########Reads End########## +// ############################# + +// ################################################################################## + +// ############################# +// ########Vec Add Start######## +// ############################# + + + +component vec_add() -> () { + cells { + //Modified to 64 width address because XRT expects 64 bit memory addresses + ref A0 = seq_mem_d1(32,8,64); + A_read0_0 = std_reg(32); + ref B0 = seq_mem_d1(32,8,64); + B_read0_0 = std_reg(32); + ref Sum0 = seq_mem_d1(32,8,64); + add0 = std_add(32); + add1 = std_add(64); + const0 = std_const(64,0); + const1 = std_const(64,7); + const2 = std_const(64,1); + i0 = std_reg(64); + le0 = std_le(64); + } + wires { + comb group cond0 { + le0.left = i0.out; + le0.right = const1.out; + } + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + //modified upd0 and upd1 to use seq_mem correctly + group upd0<"static"=2> { + A_read0_0.write_en = A0.read_done; + A0.addr0 = i0.out; + A0.read_en = 1'b1; + A_read0_0.in = 1'd1 ? A0.read_data; + upd0[done] = A_read0_0.done ? 1'd1; + } + //see comment for upd0 + group upd1<"static"=2> { + B_read0_0.write_en = B0.read_done; + B0.addr0 = i0.out; + B0.read_en = 1'b1; + B_read0_0.in = 1'd1 ? B0.read_data; + upd1[done] = B_read0_0.done ? 1'd1; + } + group upd2<"static"=1> { + Sum0.addr0 = i0.out; + Sum0.write_en = 1'd1; + add0.left = A_read0_0.out; + add0.right = B_read0_0.out; + Sum0.write_data = 1'd1 ? add0.out; + upd2[done] = Sum0.write_done ? 1'd1; + } + group upd3<"static"=1> { + i0.write_en = 1'd1; + add1.left = i0.out; + add1.right = const2.out; + i0.in = 1'd1 ? add1.out; + upd3[done] = i0.done ? 1'd1; + } + } + control { + seq { + let0; + while le0.out with cond0 { + seq { + par { + upd0; + upd1; + } + upd2; + upd3; + } + } + } + } +} + + +// ############################# +// #########Vec Add End######### +// ############################# + + +// ################################################################################## + +// ############################## +// #########Writes Start######### +// ############################## + + + +//this goes m->s +component m_awwrite_channel( + ARESET: 1, + AWREADY: 1 +) -> ( + AWVALID: 1, + // This needs to be 64, see link below `m_axi` section. + AWADDR: 64, + // 2^AWSIZE is bytes used in transfer. For memory-mapped AXI (which is what we + // are doing I believe), should match width of data bus (to shell?, so 32 wide? This + // is 3'b010) + // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements + // for restrictions + AWSIZE: 3, + // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. + AWLEN : 8, + // 00 for fixed, 01 for incrementing, 2 for wrap, + // needs to be incr for RTL kernels (can't use wrapped or fixed) + AWBURST : 2, + // required according to spec. We hardcode this + AWPROT : 3) { + cells{ + is_awvalid = std_reg(1); + + // gets set high with AWVALID and remains high + awvalid_was_high = std_reg(1); + // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` + // but for now will live here. + ref base_addr = std_reg(64); + + //we write to this here and read from it in m_write_channel + ref max_trnsfrs = std_reg(8); + + // number of transfers in a transaction. This is sent to subordinate + txn_len = std_reg(8); + + // number of txns we want to occur before entire m_awwrite_channel is done + // this is internal to the channel (unlike txn_len) + txn_n = std_const(32,1); + txn_count = std_reg(32); + perform_write_txns = std_neq(32); + txn_adder = std_add(32); + + //"block_transfer" register. need to put into a reg to avoid combinational loops + bt_reg = std_reg(1); + + + } + + wires{ + + AWVALID = is_awvalid.out; + + group deassert_val { + is_awvalid.in = 1'b0; + is_awvalid.write_en = 1'b1; + deassert_val[done] = is_awvalid.done; + } + + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + + group reset_was_high { + awvalid_was_high.in = 1'b0; + awvalid_was_high.write_en = 1'b1; + reset_was_high[done] = awvalid_was_high.done; + } + + // this asserts valid and defines all inputs correctly + // because valid should not be deasserted until handshake occurs + // this all needs to be one group + // this contains blocking logic previously in its own group + group do_aw_transfer { + //assert AWVALID + is_awvalid.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + + // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high + // but for now we will be explicit and reduce this in generation maybe. Not sure + // it even matters. + // This makes AWVALID go low after a single cycle. Without it it stays high for 2. + is_awvalid.in = is_awvalid.out & AWREADY & awvalid_was_high.out ? 1'b0; + is_awvalid.write_en = 1'b1; + + awvalid_was_high.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + awvalid_was_high.write_en = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + + + // drive output signals for transfer + AWADDR = base_addr.out; + // see link above, needs to match data width to host. + // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. + AWSIZE = 3'b010; + // For now this can be taken from .yxi, as size of mem, because we are assuming + // data_bus width that matches size of memory cells + // If we want to use bigger mems need to be able to update base addr + AWLEN = txn_len.out; + AWBURST = 2'b01; //incr + // 3'b110 is [privileged access] [Non-secure access] [Data access]] + AWPROT = 3'b110; + + + // TODO(nathanielnrn): This is used to tell write_channel how many transfers to do + // we eventually want this to correspond to AWLEN + // (need a case statement or mux or something) + // for now hardcoding to 15 for 16 transfers + max_trnsfrs.in = 8'd7; + max_trnsfrs.write_en = 1'b1; + + //done when one cycle after handshake (handshake happens for a single cycle) + bt_reg.in = AWREADY & is_awvalid.out ? 1'b1; + bt_reg.in = !(AWREADY & is_awvalid.out) ? 1'b0; + bt_reg.write_en = 1'b1; + do_aw_transfer[done] = bt_reg.out; + } + + + //txn bookkeeping. + //We are done performing reads when txn_count == txn_n + group txn_count_init { + txn_count.in = 32'b0; + txn_count.write_en = 1'b1; + txn_count_init[done] = txn_count.done; + + } + + group txn_len_init { + //TODO(nathanielnrn): 15 is good for word wide data bus. We'd + //expect 16 transfers. Number of transfers that occur is AWLEN + 1 + txn_len.in = 8'd7; + txn_len.write_en = 1'b1; + txn_len_init[done] = txn_len.done; + } + + group txn_incr { + txn_adder.left = txn_count.out; + txn_adder.right = 32'b1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'b1; + txn_incr[done] = txn_count.done; + + } + + comb group check_writes_done { + perform_write_txns.left = txn_count.out; + perform_write_txns.right = txn_n.out; + } + } + + control{ + //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? + seq{ + txn_count_init; + txn_len_init; + while perform_write_txns.out with check_writes_done{ + seq{ + par { + reset_bt; + reset_was_high; + } + do_aw_transfer; + deassert_val; + txn_incr; + } + } + } + } +} + + +component m_write_channel( + ARESET : 1, + WREADY : 1, +) -> ( + WVALID : 1, + WLAST : 1, + WDATA : 32, +) { + cells { + // 16 is due to dot-product vector length assumption + // For this manual implementation we are just writing into this data based + // on the data we read from cocotb + ref internal_mem = seq_mem_d1(32, 8, 64); + wvalid = std_reg(1); + wvalid_was_high = std_reg(1); + // used internally to access our seq_mem_d1 + ref curr_addr = std_reg(64); + + //this increments + curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count + //this is number of transfer we want to do + ref max_trnsfrs = std_reg(8); + + // registered because wlast is high with last transfer, not after + // before this was registered we were terminating immediately with + // last transfer and not servicing it. This is for while loop in control group + n_finished_last_trnsfr = std_reg(1); + + //used for address of seq_d1_mem we are reading from + curr_addr_adder = std_add(64); + curr_trnsfr_count_adder = std_add(8); + + + // block_transfer reg to avoid combinational loops + bt_reg = std_reg(1); + + + + curr_addr_slice = std_slice(64,32); + + } + wires{ + + WVALID = wvalid.out; + + group reset_curr_addr{ + curr_addr.in = 64'b0; + curr_addr.write_en = 1'b1; + reset_curr_addr[done] = curr_addr.done; + } + + group init_n_finished_last_trnsfr { + n_finished_last_trnsfr.in = 1'b1; + n_finished_last_trnsfr.write_en = 1'b1; + init_n_finished_last_trnsfr[done] = n_finished_last_trnsfr.done; + } + + //Used to block any servicing until handshake occurs. + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + //NOTE: xVALID signals must be high until xREADY is high as well, so this works + //because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip + //and group will be done by bt_reg.out + group do_write_transfer { + //set RREADY high + //TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). + //Could we simplify this we just making things ready when we are in + //block_transfer && RVALID? + + //NOTE: wvalid.in = 1'b1; does not work, it leaves RREADY high for 2 cycles + // this both asserts and deasserts one cycle later + wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; + // TODO(nathanielnrn): Can prob get rid of wvalid_was_high + wvalid.in = wvalid.out & WREADY & wvalid_was_high.out ? 1'b0; + wvalid.write_en = 1'b1; + + //set to 1 after valid has been high even once + wvalid_was_high.in = 1'b1; + wvalid_was_high.write_en = !(wvalid.out & WREADY) & !wvalid_was_high.out ? 1'b1; + + + // set data output based on curr_addr register + internal_mem.addr0 = curr_addr.out; + internal_mem.read_en = 1'b1; + WDATA = internal_mem.read_data; + + //set wlast + WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; + WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; + + //set high only when WLAST is high and a handshake occurs. + n_finished_last_trnsfr.in = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b0; + n_finished_last_trnsfr.write_en = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b1; + + + + // we are done after handshake + bt_reg.in = wvalid.out & WREADY ? 1'b1; + bt_reg.in = !(wvalid.out & WREADY) ? 1'b0; + bt_reg.write_en = 1'b1; + do_write_transfer[done] = bt_reg.out; + } + + group incr_curr_addr{ + curr_addr_adder.left = 64'd1 ; + curr_addr_adder.right = curr_addr.out; + curr_addr.in = curr_addr_adder.out; + curr_addr.write_en = 1'b1; + incr_curr_addr[done] = curr_addr.done; + } + + group incr_curr_trnsfr_count { + curr_trnsfr_count_adder.left = 8'd1; + curr_trnsfr_count_adder.right = curr_trnsfr_count.out; + curr_trnsfr_count.in = curr_trnsfr_count_adder.out; + curr_trnsfr_count.write_en = 1'b1; + incr_curr_trnsfr_count[done] = curr_trnsfr_count.done; + } + + } + control{ + seq{ + + reset_curr_addr; + //end writing to internal mem + init_n_finished_last_trnsfr; + while n_finished_last_trnsfr.out{ + seq{ + reset_bt; + do_write_transfer; + par{ + incr_curr_addr; + incr_curr_trnsfr_count; + } + } + } + } + } +} + + +//We assume that all responses are OKAY because we dont have any error handling. +//So basically this just sets BREADY high then lowers it +component m_bresp_channel( + ARESET : 1, + BVALID : 1, + // We assume all writes are valid. + //BRESP : 2, +) -> ( + // NOTE: In general, according to ZipCPU we want xREADY signals to be registered + // because (IIRC) it helps avoid combinational loops between READY and VALID. + BREADY : 1, +) { + cells{ + bready = std_reg(1); + bt_reg = std_reg(1); + + } + wires{ + BREADY = bready.out; + group reset_bt_reg{ + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt_reg[done] = bt_reg.done; + } + + // TODO(nathanielnrn): This is probably very unoptimal and takes multiple + // cycles to simply do a handshake. Can probably be much better + group block_transfer{ + bready.in = !(BVALID & bready.out) ? 1'b1; + bready.in = BVALID & bready.out ? 1'b0; + bready.write_en = 1'b1; + + bt_reg.in = bready.out & BVALID ? 1'b1; + bt_reg.in = !(bready.out & BVALID) ? 1'b0; + bt_reg.write_en = 1'b1; + block_transfer[done] = bt_reg.out; + } + + } + control{ + seq{ + reset_bt_reg; + block_transfer; + } + } +} + + + +//TODO(nathanielnrn): this is axi_wrapper, prefer to use @toplevel attribute but its not working +// See individual channel components for explanations of signals +component main( + m0_ARESET : 1, + + m0_ARREADY : 1, + + m0_RVALID : 1, + m0_RLAST : 1, + m0_RDATA : 32, + m0_RRESP : 2, + + m0_AWREADY : 1, + + m0_WRESP : 2, + m0_WREADY : 1, + + m0_BVALID : 1, + // Used only for waveform tracing. Not sent anywhere + // Note AXI4 has this at 2 bits, while latest has it at 3. + m0_BRESP : 2, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m0_RID : 1, + + m1_ARESET : 1, + + m1_ARREADY : 1, + + m1_RVALID : 1, + m1_RLAST : 1, + m1_RDATA : 32, + m1_RRESP : 2, + + m1_AWREADY : 1, + + m1_WRESP : 2, + m1_WREADY : 1, + + m1_BVALID : 1, + // Used only for waveform tracing. Not sent anywhere + // Note AXI4 has this at 2 bits, while latest has it at 3. + m1_BRESP : 2, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m1_RID : 1, + + + m2_ARESET : 1, + + m2_ARREADY : 1, + + m2_RVALID : 1, + m2_RLAST : 1, + m2_RDATA : 32, + m2_RRESP : 2, + + m2_AWREADY : 1, + + m2_WRESP : 2, + m2_WREADY : 1, + + m2_BVALID : 1, + // Used only for waveform tracing. Not sent anywhere + // Note AXI4 has this at 2 bits, while latest has it at 3. + m2_BRESP : 2, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m2_RID : 1 +) -> ( + m0_ARVALID : 1, + m0_ARADDR : 64, + m0_ARSIZE : 3, + m0_ARLEN : 8, + m0_ARBURST : 2, + + m0_RREADY : 1, + + m0_AWVALID : 1, + m0_AWADDR : 64, + m0_AWSIZE : 3, + m0_AWLEN : 8, + m0_AWBURST : 2, + m0_AWPROT : 3, + + m0_WVALID : 1, + m0_WLAST : 1, + m0_WDATA : 32, + + m0_BREADY : 1, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m0_ARID : 1, + m0_AWID : 1, + m0_WID : 1, + m0_BID : 1, + + m1_ARVALID : 1, + m1_ARADDR : 64, + m1_ARSIZE : 3, + m1_ARLEN : 8, + m1_ARBURST : 2, + + m1_RREADY : 1, + + m1_AWVALID : 1, + m1_AWADDR : 64, + m1_AWSIZE : 3, + m1_AWLEN : 8, + m1_AWBURST : 2, + m1_AWPROT : 3, + + m1_WVALID : 1, + m1_WLAST : 1, + m1_WDATA : 32, + + m1_BREADY : 1, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m1_ARID : 1, + m1_AWID : 1, + m1_WID : 1, + m1_BID : 1, + + + m2_ARVALID : 1, + m2_ARADDR : 64, + m2_ARSIZE : 3, + m2_ARLEN : 8, + m2_ARBURST : 2, + + m2_RREADY : 1, + + m2_AWVALID : 1, + m2_AWADDR : 64, + m2_AWSIZE : 3, + m2_AWLEN : 8, + m2_AWBURST : 2, + m2_AWPROT : 3, + + m2_WVALID : 1, + m2_WLAST : 1, + m2_WDATA : 32, + + m2_BREADY : 1, + + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m2_ARID : 1, + m2_AWID : 1, + m2_WID : 1, + m2_BID : 1 +) { + cells{ + + + //original read stuff + + curr_addr_A0 = std_reg(64); + base_addr_A0 = std_reg(64); + curr_addr_B0 = std_reg(64); + base_addr_B0 = std_reg(64); + curr_addr_Sum0 = std_reg(64); + base_addr_Sum0 = std_reg(64); + + A0_read_channel = m_read_channel(); + A0_arread_channel = m_arread_channel(); + B0_read_channel = m_read_channel(); + B0_arread_channel = m_arread_channel(); + Sum0_read_channel = m_read_channel(); + Sum0_arread_channel = m_arread_channel(); + //end read stuff + + + // TODO(nathanielnrn):Do we need to mark these extrenal? they were in + // original vec_add and we raised them to top level. + A0 = seq_mem_d1(32,8,64); + B0 = seq_mem_d1(32,8,64); + Sum0 = seq_mem_d1(32,8,64); + + vec_add_cell = vec_add();//end vec add stuff + + + //original write stuff + max_trnsfrs = std_reg(8); + + A0_awwrite_channel = m_awwrite_channel(); + A0_write_channel = m_write_channel(); + A0_bresp_channel = m_bresp_channel(); + + B0_awwrite_channel = m_awwrite_channel(); + B0_write_channel = m_write_channel(); + B0_bresp_channel = m_bresp_channel(); + + Sum0_awwrite_channel = m_awwrite_channel(); + Sum0_write_channel = m_write_channel(); + Sum0_bresp_channel = m_bresp_channel(); + //end original write stuff + + } + + wires{ + //these are tied low because cocotb expects them, not actually required for + // axi spec AFAIK + m0_ARID = 1'b0; + m0_AWID = 1'b0; + m0_WID = 1'b0; + m0_BID = 1'b0; + m1_ARID = 1'b0; + m1_AWID = 1'b0; + m1_WID = 1'b0; + m1_BID = 1'b0; + m2_ARID = 1'b0; + m2_AWID = 1'b0; + m2_WID = 1'b0; + m2_BID = 1'b0; + + group set_curr_to_base_addr_A0{ + curr_addr_A0.in = base_addr_A0.out; + curr_addr_A0.write_en = 1'b1; + set_curr_to_base_addr_A0[done] = curr_addr_A0.done; + } + + group init_base_addr_A0{ + base_addr_A0.in = 64'b0; + base_addr_A0.write_en = 1'b1; + init_base_addr_A0[done] = base_addr_A0.done; + } + + group set_curr_to_base_addr_B0{ + curr_addr_B0.in = base_addr_B0.out; + curr_addr_B0.write_en = 1'b1; + set_curr_to_base_addr_B0[done] = curr_addr_B0.done; + } + + group init_base_addr_B0{ + base_addr_B0.in = 64'b0; + base_addr_B0.write_en = 1'b1; + init_base_addr_B0[done] = base_addr_B0.done; + } + + group set_curr_to_base_addr_Sum0{ + curr_addr_Sum0.in = base_addr_Sum0.out; + curr_addr_Sum0.write_en = 1'b1; + set_curr_to_base_addr_Sum0[done] = curr_addr_Sum0.done; + } + + group init_base_addr_Sum0{ + base_addr_Sum0.in = 64'b0; + base_addr_Sum0.write_en = 1'b1; + init_base_addr_Sum0[done] = base_addr_Sum0.done; + } + } + control{ + seq{ + //read stuff + par{ + init_base_addr_A0; + init_base_addr_B0; + init_base_addr_Sum0; + } + par{ + seq{ + //A0 reads + invoke A0_arread_channel[base_addr = base_addr_A0] + ( + ARESET = m0_ARESET, + ARREADY = m0_ARREADY + ) + ( + ARVALID = m0_ARVALID, + ARADDR = m0_ARADDR, + ARSIZE = m0_ARSIZE, + ARLEN = m0_ARLEN, + ARBURST = m0_ARBURST + ); + + set_curr_to_base_addr_A0; + + invoke A0_read_channel[data_received = A0, curr_addr = curr_addr_A0] + ( + ARESET = m0_ARESET, + RVALID = m0_RVALID, + RLAST = m0_RLAST, + RDATA = m0_RDATA, + RRESP = m0_RRESP + ) + ( + RREADY = m0_RREADY + ); + } + + + seq{ //B0 reads + invoke B0_arread_channel[base_addr = base_addr_B0] + ( + ARESET = m1_ARESET, + ARREADY = m1_ARREADY + ) + ( + ARVALID = m1_ARVALID, + ARADDR = m1_ARADDR, + ARSIZE = m1_ARSIZE, + ARLEN = m1_ARLEN, + ARBURST = m1_ARBURST + ); + + set_curr_to_base_addr_B0; + + invoke B0_read_channel[data_received = B0, curr_addr = curr_addr_B0] + ( + ARESET = m1_ARESET, + RVALID = m1_RVALID, + RLAST = m1_RLAST, + RDATA = m1_RDATA, + RRESP = m1_RRESP + ) + ( + RREADY = m1_RREADY + ); + } + seq{ //Sum0 reads + invoke Sum0_arread_channel[base_addr = base_addr_Sum0] + ( + ARESET = m2_ARESET, + ARREADY = m2_ARREADY + ) + ( + ARVALID = m2_ARVALID, + ARADDR = m2_ARADDR, + ARSIZE = m2_ARSIZE, + ARLEN = m2_ARLEN, + ARBURST = m2_ARBURST + ); + + set_curr_to_base_addr_Sum0; + + invoke Sum0_read_channel[data_received = Sum0, curr_addr = curr_addr_Sum0] + ( + ARESET = m2_ARESET, + RVALID = m2_RVALID, + RLAST = m2_RLAST, + RDATA = m2_RDATA, + RRESP = m2_RRESP + ) + ( + RREADY = m2_RREADY + ); + } + } //end read stuff + + + + //compute stuff + invoke vec_add_cell[A0 = A0, B0 = B0, Sum0 = Sum0]()(); + //end comput stuff + + + + //write stuff + par { + seq { //A0 writes + invoke A0_awwrite_channel[base_addr = base_addr_A0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m0_ARESET, + AWREADY = m0_AWREADY + ) + ( + AWVALID = m0_AWVALID, + AWADDR = m0_AWADDR, + AWSIZE = m0_AWSIZE, + AWLEN = m0_AWLEN, + AWBURST = m0_AWBURST, + AWPROT = m0_AWPROT + ); + + set_curr_to_base_addr_A0; + + invoke A0_write_channel[internal_mem = A0, curr_addr = curr_addr_A0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m0_ARESET, + WREADY = m0_WREADY + ) + ( + WVALID = m0_WVALID, + WLAST = m0_WLAST, + WDATA = m0_WDATA + ); + + invoke A0_bresp_channel(BVALID = m0_BVALID)(BREADY = m0_BREADY); + } + seq { //B0 writes + invoke B0_awwrite_channel[base_addr = base_addr_B0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m1_ARESET, + AWREADY = m1_AWREADY + ) + ( + AWVALID = m1_AWVALID, + AWADDR = m1_AWADDR, + AWSIZE = m1_AWSIZE, + AWLEN = m1_AWLEN, + AWBURST = m1_AWBURST, + AWPROT = m1_AWPROT + ); + + set_curr_to_base_addr_B0; + + invoke B0_write_channel[internal_mem = B0, curr_addr = curr_addr_B0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m1_ARESET, + WREADY = m1_WREADY + ) + ( + WVALID = m1_WVALID, + WLAST = m1_WLAST, + WDATA = m1_WDATA + ); + + invoke B0_bresp_channel(BVALID = m1_BVALID)(BREADY = m1_BREADY); + } + + seq { //Sum0 writes + invoke Sum0_awwrite_channel[base_addr = base_addr_Sum0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m2_ARESET, + AWREADY = m2_AWREADY + ) + ( + AWVALID = m2_AWVALID, + AWADDR = m2_AWADDR, + AWSIZE = m2_AWSIZE, + AWLEN = m2_AWLEN, + AWBURST = m2_AWBURST, + AWPROT = m2_AWPROT + ); + + set_curr_to_base_addr_Sum0; + + invoke Sum0_write_channel[internal_mem = Sum0, curr_addr = curr_addr_Sum0, max_trnsfrs = max_trnsfrs] + ( + ARESET = m2_ARESET, + WREADY = m2_WREADY + ) + ( + WVALID = m2_WVALID, + WLAST = m2_WLAST, + WDATA = m2_WDATA + ); + + invoke Sum0_bresp_channel(BVALID = m2_BVALID)(BREADY = m2_BREADY); + } + } + } + } +} + + diff --git a/yxi/axi-calyx/axi-reads-calyx.futil b/yxi/axi-calyx/axi-reads-calyx.futil index 7b5760e72..903b97dd5 100644 --- a/yxi/axi-calyx/axi-reads-calyx.futil +++ b/yxi/axi-calyx/axi-reads-calyx.futil @@ -93,8 +93,7 @@ component m_arread_channel( is_arvalid.in = is_arvalid.out & ARREADY & arvalid_was_high.out ? 1'b0; is_arvalid.write_en = 1'b1; - - arvalid_was_high.in = 1'b1; + arvalid_was_high.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; diff --git a/yxi/axi-calyx/axi-writes-calyx.futil b/yxi/axi-calyx/axi-writes-calyx.futil new file mode 100644 index 000000000..c10e5e095 --- /dev/null +++ b/yxi/axi-calyx/axi-writes-calyx.futil @@ -0,0 +1,521 @@ +// ### +// This file contains the components needed to perform write transacitons via AXI. +// Current goal is to create a cocotb testbench that tests correctness of this. +// See https://github.com/cucapra/calyx/issues/1733 for more information. +// +// This wrapper assumes it is part of a dot product computation with vectors of +// length 16 +// It assumes a bus data width of 32 +// This is largely a work in progress and as of Nov 20 2023 is not intended to +// actually be used for anything +// ### + +import "primitives/core.futil"; +import "primitives/compile.futil"; +import "primitives/math.futil"; +import "primitives/memories.futil"; + + +//this goes m->s +component m_awwrite_channel( + ARESET: 1, + AWREADY: 1 +) -> ( + AWVALID: 1, + // This needs to be 64, see link below `m_axi` section. + AWADDR: 64, + // 2^AWSIZE is bytes used in transfer. For memory-mapped AXI (which is what we + // are doing I believe), should match width of data bus (to shell?, so 32 wide? This + // is 3'b010) + // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements + // for restrictions + AWSIZE: 3, + // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. + AWLEN : 8, + // 00 for fixed, 01 for incrementing, 2 for wrap, + // needs to be incr for RTL kernels (can't use wrapped or fixed) + AWBURST : 2, + // required according to spec. We hardcode this + AWPROT : 3) { + cells{ + is_awvalid = std_reg(1); + + // gets set high with AWVALID and remains high + awvalid_was_high = std_reg(1); + // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` + // but for now will live here. + ref base_addr = std_reg(64); + + //we write to this here and read from it in m_write_channel + ref max_trnsfrs = std_reg(8); + + // number of trasfers in a transaction. This is sent to subordinate + txn_len = std_reg(8); + + // number of txns we want to occur before entire m_awwrite_channel is done + // this is internal to the channel (unlike txn_len) + txn_n = std_const(32,1); + txn_count = std_reg(32); + perform_write_txns = std_neq(32); + txn_adder = std_add(32); + + //"block_transfer" register. need to put into a reg to avoid combinational loops + bt_reg = std_reg(1); + + + } + + wires{ + + AWVALID = is_awvalid.out; + + group deassert_val { + is_awvalid.in = 1'b0; + is_awvalid.write_en = 1'b1; + deassert_val[done] = is_awvalid.done; + } + + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + // this asserts valid and defines all inputs correctly + // because valid should not be deasserted until handshake occurs + // this all needs to be one group + // this contains blocking logic previously in its own group + group do_aw_transfer { + //assert AWVALID + is_awvalid.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + + // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high + // but for now we will be explicit and reduce this in generation maybe. Not sure + // it even matters. + // This makes AWVALID go low after a single cycle. Without it it stays high for 2. + is_awvalid.in = is_awvalid.out & AWREADY & awvalid_was_high.out ? 1'b0; + is_awvalid.write_en = 1'b1; + + awvalid_was_high.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + awvalid_was_high.write_en = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + + + // drive output signals for transfer + AWADDR = base_addr.out; + // see link above, needs to match data width to host. + // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. + AWSIZE = 3'b010; + // For now this can be taken from .yxi, as size of mem, because we are assuming + // data_bus width that matches size of memory cells + // If we want to use bigger mems need to be able to update base addr + AWLEN = txn_len.out; + AWBURST = 2'b01; //incr + // 3'b110 is [privileged access] [Non-secure access] [Data access]] + AWPROT = 3'b110; + + + // TODO(nathanielnrn): This is used to tell write_channel how many transfers to do + // we eventually want this to correspond to AWLEN + // (need a case statement or mux or something) + // for now hardcoding to 15 for 16 transfers + max_trnsfrs.in = 8'd15; + max_trnsfrs.write_en = 1'b1; + + //done when one cycle after handshake (handshake happens for a single cycle) + bt_reg.in = AWREADY & is_awvalid.out ? 1'b1; + bt_reg.in = !(AWREADY & is_awvalid.out) ? 1'b0; + bt_reg.write_en = 1'b1; + do_aw_transfer[done] = bt_reg.out; + } + + + //txn bookkeeping. + //We are done performing reads when txn_count == txn_n + group txn_count_init { + txn_count.in = 32'b0; + txn_count.write_en = 1'b1; + txn_count_init[done] = txn_count.done; + + } + + group txn_len_init { + //TODO(nathanielnrn): 15 is good for word wide data bus. We'd + //expect 16 transfers. Number of transfers that occur is AWLEN + 1 + txn_len.in = 8'd15; + txn_len.write_en = 1'b1; + txn_len_init[done] = txn_len.done; + } + + group txn_incr { + txn_adder.left = txn_count.out; + txn_adder.right = 32'b1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'b1; + txn_incr[done] = txn_count.done; + + } + + comb group check_writes_done { + perform_write_txns.left = txn_count.out; + perform_write_txns.right = txn_n.out; + } + } + + control{ + //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? + seq{ + txn_count_init; + txn_len_init; + while perform_write_txns.out with check_writes_done{ + seq{ + reset_bt; + do_aw_transfer; + deassert_val; + txn_incr; + } + } + } + } +} + + + + +component m_write_channel( + ARESET : 1, + WREADY : 1, +) -> ( + WVALID : 1, + WLAST : 1, + WDATA : 32, +) { + cells { + // 16 is due to dot-product vector length assumption + // For this manual implementation we are just writing into this data based + // on the data we read from cocotb + ref internal_mem = seq_mem_d1(32, 16, 64); + wvalid = std_reg(1); + wvalid_was_high = std_reg(1); + // used internally to access our seq_mem_d1 + ref curr_addr = std_reg(64); + + //this increments + curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count + //this is number of transfer we want to do + ref max_trnsfrs = std_reg(8); + + // registered because wlast is high with last transfer, not after + // before this was registered we were terminating immediately with + // last transfer and not servicing it. This is for while loop in control group + n_finished_last_trnsfr = std_reg(1); + + // TODO: get this width from yxi + //read_data_reg = std_reg(32); + + //used for address of seq_d1_mem we are reading from + curr_addr_adder = std_add(64); + curr_trnsfr_count_adder = std_add(8); + + + // block_transfer reg to avoid combinational loops + bt_reg = std_reg(1); + + + + //write init stuff TODO: delete this + n_init_done = std_reg(1); + curr_addr_slice = std_slice(64,32); + + } + wires{ + + WVALID = wvalid.out; + //internal_mem.write_en = 1'b0; + + + + //stuff for initialization + group reset_curr_addr{ + curr_addr.in = 64'b0; + curr_addr.write_en = 1'b1; + reset_curr_addr[done] = curr_addr.done; + } + + group write_to_internal{ + internal_mem.read_en = 1'b0; + internal_mem.write_en = 1'b1; + internal_mem.addr0 = curr_addr.out; + + curr_addr_slice.in = curr_addr.out; + internal_mem.write_data = curr_addr_slice.out; + write_to_internal[done] = internal_mem.write_done; + } + + group check_if_writes_done{ + n_init_done.in = curr_addr.out == 64'd16 ? 1'b0; + n_init_done.in = !(curr_addr.out == 64'd16) ? 1'b1; + n_init_done.write_en = 1'b1; + check_if_writes_done[done] = n_init_done.done; + } + + group init_done{ + n_init_done.in = 1'b1; + n_init_done.write_en = 1'b1; + init_done[done] = n_init_done.done; + } + //end stuff for initialization + + + group init_n_finished_last_trnsfr { + n_finished_last_trnsfr.in = 1'b1; + n_finished_last_trnsfr.write_en = 1'b1; + init_n_finished_last_trnsfr[done] = n_finished_last_trnsfr.done; + } + + //Used to block any servicing until handshake occurs. + group reset_bt { + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt[done] = bt_reg.done; + } + + //NOTE: xVALID signals must be high until xREADY is high as well, so this works + //because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip + //and group will be done by bt_reg.out + group do_write_transfer { + //set RREADY high + //TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). + //Could we simplify this we just making things ready when we are in + //block_transfer && RVALID? + + //NOTE: is_rdy.in = 1'b1; does not work, it leaves RREADY high for 2 cycles + // this both asserts and deasserts one cycle later + wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; + // TODO(nathanielnrn): Can prob get rid of wvalid_was_high + wvalid.in = wvalid.out & WREADY & wvalid_was_high.out ? 1'b0; + wvalid.write_en = 1'b1; + + //set to 1 after valid has been high even once + wvalid_was_high.in = 1'b1; + wvalid_was_high.write_en = !(wvalid.out & WREADY) & !wvalid_was_high.out ? 1'b1; + + + // set data output based on curr_addr register + internal_mem.addr0 = curr_addr.out; + internal_mem.read_en = 1'b1; + WDATA = internal_mem.read_data; + + //set wlast + WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; + WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; + + //set high only when WLAST is high and a handshake occurs. + n_finished_last_trnsfr.in = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b0; + n_finished_last_trnsfr.write_en = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b1; + + + + // we are done after handshake + bt_reg.in = wvalid.out & WREADY ? 1'b1; + bt_reg.in = !(wvalid.out & WREADY) ? 1'b0; + bt_reg.write_en = 1'b1; + do_write_transfer[done] = bt_reg.out; + } + + group incr_curr_addr{ + curr_addr_adder.left = 64'd1 ; + curr_addr_adder.right = curr_addr.out; + curr_addr.in = curr_addr_adder.out; + curr_addr.write_en = 1'b1; + incr_curr_addr[done] = curr_addr.done; + } + + group incr_curr_trnsfr_count { + curr_trnsfr_count_adder.left = 8'd1; + curr_trnsfr_count_adder.right = curr_trnsfr_count.out; + curr_trnsfr_count.in = curr_trnsfr_count_adder.out; + curr_trnsfr_count.write_en = 1'b1; + incr_curr_trnsfr_count[done] = curr_trnsfr_count.done; + } + + } + control{ + seq{ + + //done for writing to internal mem + init_done; + reset_curr_addr; + while n_init_done.out { + seq{ + write_to_internal; + incr_curr_addr; + check_if_writes_done; + } + } + //end writing to internal mem + reset_curr_addr; + init_n_finished_last_trnsfr; + while n_finished_last_trnsfr.out{ + seq{ + reset_bt; + do_write_transfer; + par{ + incr_curr_addr; + incr_curr_trnsfr_count; + } + } + } + } + } +} + + +//We assume that all responses are OKAY because we dont have any error handling. +//So basically this just sets BREADY high then lowers it +component m_bresp_channel( + ARESET : 1, + BVALID : 1, + // We assume all writes are valid. + //BRESP : 2, +) -> ( + // NOTE: In general, according to ZipCPU we want xREADY signals to be registered + // because (IIRC) it helps avoid combinational loops between READY and VALID. + BREADY : 1, +) { + cells{ + bready = std_reg(1); + bt_reg = std_reg(1); + + } + wires{ + BREADY = bready.out; + group reset_bt_reg{ + bt_reg.in = 1'b0; + bt_reg.write_en = 1'b1; + reset_bt_reg[done] = bt_reg.done; + } + + // TODO(nathanielnrn): This is probably very unoptimal and takes multiple + // cycles to simply do a handshake. Can probably be much better + group block_transfer{ + bready.in = !(BVALID & bready.out) ? 1'b1; + bready.in = BVALID & bready.out ? 1'b0; + bready.write_en = 1'b1; + + bt_reg.in = bready.out & BVALID ? 1'b1; + bt_reg.in = !(bready.out & BVALID) ? 1'b0; + bt_reg.write_en = 1'b1; + block_transfer[done] = bt_reg.out; + } + + } + control{ + seq{ + reset_bt_reg; + block_transfer; + } + } +} + + + +//TODO(nathanielnrn): this is axi_wrapper, prefer to use @toplevel attribute but its not working +// See individual channel components for explanations of signals +component main( + m_ARESET : 1, + m_AWREADY : 1, + + m_WRESP : 2, + m_WREADY : 1, + + m_BVALID : 1, + // Used only for waveform tracing. Not sent anywhere + // Note this AXI4 has this at 2 bits, while latest has it at 3. + m_BRESP : 2, +) -> ( + + m_AWVALID : 1, + m_AWADDR: 64, + m_AWSIZE: 3, + m_AWLEN : 8, + m_AWBURST : 2, + m_AWPROT : 3, + + m_WVALID : 1, + m_WLAST : 1, + m_WDATA : 32, + + m_BREADY : 1, + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. + m_AWID : 1, + m_WID : 1, + m_BID : 1, +) { + cells{ + vec1_data = seq_mem_d1(32,16,64); + output_data = seq_mem_d1(32,1,0); + + curr_addr = std_reg(64); + base_addr = std_reg(64); + + max_trnsfrs = std_reg(8); + + awwrite_channel = m_awwrite_channel(); + write_channel = m_write_channel(); + bresp_channel = m_bresp_channel(); + + } + + wires{ + + m_AWID = 1'b0; + m_WID = 1'b0; + m_BID = 1'b0; + + group set_curr_to_base_addr{ + curr_addr.in = base_addr.out; + curr_addr.write_en = 1'b1; + set_curr_to_base_addr[done] = curr_addr.done; + } + } + control{ + seq{ + invoke awwrite_channel[base_addr = base_addr, max_trnsfrs = max_trnsfrs] + ( + ARESET = m_ARESET, + AWREADY = m_AWREADY + ) + ( + AWVALID = m_AWVALID, + AWADDR = m_AWADDR, + AWSIZE = m_AWSIZE, + AWLEN = m_AWLEN, + AWBURST = m_AWBURST, + AWPROT = m_AWPROT + ); + + set_curr_to_base_addr; + + invoke write_channel[internal_mem = vec1_data, curr_addr = curr_addr, max_trnsfrs = max_trnsfrs] + ( + ARESET = m_ARESET, + WREADY = m_WREADY + ) + ( + WVALID = m_WVALID, + WLAST = m_WLAST, + WDATA = m_WDATA + ); + + invoke bresp_channel + ( + BVALID = m_BVALID + ) + ( + BREADY = m_BREADY + ); + } + } + + +} diff --git a/yxi/axi-calyx/cocotb/Makefile b/yxi/axi-calyx/cocotb/Makefile index 3ae9a87d4..dc468c6d5 100644 --- a/yxi/axi-calyx/cocotb/Makefile +++ b/yxi/axi-calyx/cocotb/Makefile @@ -7,16 +7,16 @@ TOPLEVEL_LANG ?= verilog #Needed to extract desired test from runt invocation -VERILOG_SOURCES += $(PWD)/../outputs/axi-reads.v +VERILOG_SOURCES += $(PWD)/../outputs/axi-combined.v #Defines build directory, if left to default only a single computation is run -SIM_BUILD=sim_build/axi-reads +SIM_BUILD=sim_build/axi-combined # TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file TOPLEVEL = main # MODULE is the basename of the Python test file -MODULE = axi-read-tests +MODULE = axi-combined-tests # include cocotb's make rules to take care of the simulator setup diff --git a/yxi/axi-calyx/cocotb/axi-combined-tests.py b/yxi/axi-calyx/cocotb/axi-combined-tests.py new file mode 100644 index 000000000..9b4a619a1 --- /dev/null +++ b/yxi/axi-calyx/cocotb/axi-combined-tests.py @@ -0,0 +1,230 @@ +import cocotb +from cocotb.clock import Clock +from cocotbext.axi import AxiBus, AxiRam +from cocotb.triggers import Timer, ClockCycles +import mmap +import struct +from typing import Union, Literal, List + +# TODO(nathanielnrn): If optional signals like WSTRB are not recognized, +# install cocotb-bus directly from github, as 0.2.1 has a bug + + +debug = False + + +# Reads 8 elements from mmap of 8*4 bytes. Writes these elements to 8 cells in calyx defined seq_d1 mem. +@cocotb.test() +async def read_channels_happy_path(main): + A0_in = [1, 2, 4, 8, 16, 32, 64, 128] + B0_in = [126, 62, 30, 14, 6, 2, 0, 1] + expected_sum = [A0_in[i] + B0_in[i] for i in range(len(B0_in))] + await run_module(main, A0_in, B0_in, expected_sum) # checks cocotb axi rams + await assert_mem_content(main.A0, A0_in) # checks in module, as opposed to axiram + await assert_mem_content(main.B0, B0_in) + await assert_mem_content(main.Sum0, expected_sum) + + +# Adding extra data to backing mmap does not ruin reading of 8 elements and writing them correctly. +@cocotb.test() +async def read_channels_extra_mmap_data(main): + A0_in = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 2**32 - 1, + ] + B0_in = [127, 63, 31, 15, 7, 3, 1, 0, 2**32 - 1] + expected_sum = [A0_in[i] + B0_in[i] for i in range(len(B0_in))] + + await run_module(main, A0_in, B0_in, expected_sum) + await assert_mem_content(main.Sum0, expected_sum[0:8]) + await assert_mem_content(main.A0, A0_in[0:8]) + await assert_mem_content(main.B0, B0_in[0:8]) + + +################## +# Helper functions# +################## + + +async def assert_mem_content(mem, expected: List[int]): + """Checks that `mem` content inside the verilog module (as opposed to + cocotb axi-ram matches expected + """ + if debug: + print(f"DEBUG: assert_mem_content: {cocotb_mem_to_ints(mem)}") + assert ( + cocotb_mem_to_ints(mem) == expected + ), f":mem {cocotb_mem_to_ints(mem)} does not contain the data in expected: {expected}." + + +async def assert_axi_ram_content( + axi_ram, expected: List[int], length=8 * 4, address=0x0000 +): + """Checks that `mem` content inside the cocotb (as opposed to + verilog module matches expected + """ + if debug: + print(f"DEBUG: axi_ram.read: {axi_ram.read(address,length)}") + print( + f"DEBUG: assert_axi_ram_content: {bytes_to_int(axi_ram.read(address,length))}" + ) + assert ( + bytes_to_int(axi_ram.read(address, length)) == expected + ), f"The axi_ram {axi_ram} contained {bytes_to_int(axi_ram.read(address,length))} not {expected}." + + +async def run_module( + module, + A0_data: List[int], + B0_data: List[int], + Sum0_expected: List[int], +): + """Create an mmap with data of `data_vec` and use this to initialize + a cocotb-axi-ram (read only) with this data. Assert that the data that + our AXI program reads has been written to the memory inside our Calyx program + correctly and matches `expected.` + + mmap_size is in bytes. + + """ + cocotb.start_soon(Clock(module.clk, 2, units="ns").start()) + + # Assert reset for 5 cycles (required for Calyx interfacing) + module.reset.value = 1 + await ClockCycles(module.clk, 5) # wait a bit + module.reset.value = 0 + + # Start the execution + module.go.value = 1 + + # 4 bytes per integer + A0_size = len(A0_data) * 4 + B0_size = len(B0_data) * 4 + Sum0_size = 8 * 4 # hardcoded + # anonymous mmep for now to back axiram + A0_memmap = mmap.mmap(-1, A0_size) + B0_memmap = mmap.mmap(-1, B0_size) + Sum0_memmap = mmap.mmap(-1, Sum0_size) + + A0 = AxiRam( + # NOTE: prefix should not contain the final "_" + AxiBus.from_prefix(module, "m0"), + module.clk, + module.reset, + # size in bytes + size=A0_size, + mem=A0_memmap, + ) + + B0 = AxiRam( + # NOTE: prefix should not contain the final "_" + AxiBus.from_prefix(module, "m1"), + module.clk, + module.reset, + # size in bytes + size=B0_size, + mem=B0_memmap, + ) + + Sum0 = AxiRam( + # NOTE: prefix should not contain the final "_" + AxiBus.from_prefix(module, "m2"), + module.clk, + module.reset, + # size in bytes + size=Sum0_size, + mem=Sum0_memmap, + ) + + A0_bytes = int_to_bytes(A0_data) + B0_bytes = int_to_bytes(B0_data) + + A0_memmap.seek(0) + A0_memmap.write(A0_bytes) + A0_memmap.seek(0) + + B0_memmap.seek(0) + B0_memmap.write(B0_bytes) + B0_memmap.seek(0) + + Sum0_memmap.seek(0) + + await Timer(20, "ns") + if debug: + A0.hexdump(0x0000, A0_size, prefix="A0 RAM") + B0.hexdump(0x0000, B0_size, prefix="B0 RAM") + Sum0.hexdump(0x0000, Sum0_size, prefix="Sum0 RAM") + + await Timer(1000, "ns") + if debug: + A0.hexdump(0x0000, A0_size, prefix="A0 RAM post") + B0.hexdump(0x0000, B0_size, prefix="B0 RAM post") + Sum0.hexdump(0x0000, Sum0_size, prefix="Sum0 RAM post") + + await assert_axi_ram_content(A0, A0_data[0:8]) + await assert_axi_ram_content(B0, B0_data[0:8]) + await assert_axi_ram_content(Sum0, Sum0_expected[0:8]) + + if debug: + print(f"A0 is: {module.A0.mem.value}") + print(f"B0 is: {module.B0.mem.value}") + print(f"Sum0 is: {module.Sum0.mem.value}") + + +# TODO(nathanielnrn): Decide between these and xilinx cocotb tests, refactor out +# after determining which is better + + +# Returns 4-byte representation of an integer +# Does not yet support unsigned, can be changed by changing to `i` as opposed to `I`. +# Not supported cause haven't yet thought about how AXI is affected +def int_to_bytes( + integers, byteorder: Union[Literal["little"], Literal["big"]] = "little" +): + frmt = get_format(byteorder, integers) + return struct.pack(frmt, *integers) + + +# returns iterable of ints or a single int depending on size of bytes argument +def bytes_to_int(bytes, byteorder="little"): + assert len(bytes) % 4 == 0, "bytes length not divisble by 4." + frmt = get_format(byteorder, bytes) + ints = struct.unpack(frmt, bytes) + if len(ints) == 1: + return ints[0] + return list(ints) + + +# Returns format used by Struct, assuming we are interested in integers (so 4 bytes) +def get_format(byteorder: Union[Literal["little"], Literal["big"]], input_list): + frmt = "" + if byteorder == "little": + frmt += "<" + elif byteorder == "big": + frmt += ">" + else: + raise ValueError("byteorder must be 'little' or 'big'.") + + if type(input_list) is bytes: + assert len(input_list) % 4 == 0, "input_list length not divisble by 4." + frmt += f"{len(input_list)//4}" + elif type(input_list[0]) is int: + frmt += f"{len(input_list)}" + + frmt += "I" + return frmt + + +# Takes in top level cocotb memory structure and returns integers of bytes contained in it. +def cocotb_mem_to_ints(memory) -> List[int]: + integers = list(map(lambda e: e.integer, memory.mem.value)) + # Cocotb mem.value seems to store integers in reverse order? So memory cell 0 is + # at index -1 and memory cell n-1 is at index 0 + return integers[::-1] diff --git a/yxi/axi-calyx/cocotb/axi-write-tests.py b/yxi/axi-calyx/cocotb/axi-write-tests.py new file mode 100644 index 000000000..9c9c56503 --- /dev/null +++ b/yxi/axi-calyx/cocotb/axi-write-tests.py @@ -0,0 +1,171 @@ +import cocotb +from cocotb.clock import Clock +from cocotbext.axi import AxiWriteBus, AxiRamWrite +from cocotb.triggers import Timer, ClockCycles +import mmap +import struct +from typing import Union, Literal, List + +# TODO(nathanielnrn): If optional signals like WSTRB are not recognized, +# install cocotb-bus directly from github, as 0.2.1 has a bug + + +# Reads 16 elements from mmap of 16*4 bytes. Writes these elements to 16 cells in calyx defined seq_d1 mem. +@cocotb.test() +async def write_channels_happy_path(main): + happy_data_vec = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384, + 32768, + ] + # Expected is from hardcoded initialization of writing in axi-writes-calyx.futil + expected = [i for i in range(16)] + await write_axi_test_helper(main, happy_data_vec, expected) + + +# Adding extra data to backing mmap does not ruin reading of 16 elements and writing them correctly. +@cocotb.test() +async def write_channels_extra_mmap_data(main): + large_data_vec = [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, + 1024, + 2048, + 4096, + 8192, + 16384, + 32768, + 2**32 - 1, + ] + expected = [i for i in range(16)] + expected.append(2**32 - 1) + await write_axi_test_helper(main, large_data_vec, expected) + + +async def write_axi_test_helper( + module, data_vec: List[int], expected: List[int], mmap_size: int = None +): + """Create an mmap with data of `data_vec` and use this to initialize + a cocotb-axi-ram (write only) with this data. Assert that the data in this + cocotb AXI Ram matches expected at the end of writing (currently expect 16 zeroes) + correctly and matches `expected.` + + mmap_size is in bytes. + + """ + + cocotb.start_soon(Clock(module.clk, 2, units="ns").start()) + + # Assert reset for 5 cycles (reuqired for Calyx interfacing) + module.reset.value = 1 + await ClockCycles(module.clk, 5) # wait a bit + module.reset.value = 0 + + # Start the execution + module.go.value = 1 + + if mmap_size is None: + # 4 bytes per integer + mmap_size = len(data_vec) * 4 + # anonymous mmep for now to back axiram + memmap = mmap.mmap(-1, mmap_size) + axi_ram_write = AxiRamWrite( + # NOTE: prefix should not contain the final "_" + AxiWriteBus.from_prefix(module, "m"), + module.clk, + module.reset, + # size in bytes + size=mmap_size, + mem=memmap, + ) + + data_vec_bytes = int_to_bytes(data_vec) + memmap.seek(0) + memmap.write(data_vec_bytes) + memmap.seek(0) + + await Timer(20, "ns") + # axi_ram_read.hexdump(0x0000, mmap_size, prefix="RAM") + + await Timer(500, "ns") + # assert ( + # cocotb_mem_to_ints(module.vec1_data) == expected + # ), f"Internal memory is not {expected}, instead is {cocotb_mem_to_ints(module.vec1_data)}" + + axi_ram_mem_ints = bytes_to_int(axi_ram_write.read(0x0000, mmap_size)) + assert ( + axi_ram_mem_ints == expected + ), f"The AXI ram: {axi_ram_mem_ints} does not contain the data in expected: {expected}." + + +# TODO(nathanielnrn): Decide between these and xilinx cocotb tests, refactor out +# after determining which is better + + +# Returns 4-byte representation of an integer +# Does not yet support unsigned, can be changed by changing to `i` as opposed to `I`. +# Not supported cause haven't yet thought about how AXI is affected +def int_to_bytes( + integers, byteorder: Union[Literal["little"], Literal["big"]] = "little" +): + frmt = get_format(byteorder, integers) + return struct.pack(frmt, *integers) + + +# returns list of ints or a single int depending on size of bytes argument +def bytes_to_int(bytes, byteorder="little"): + assert len(bytes) % 4 == 0, "bytes length not divisble by 4." + frmt = get_format(byteorder, bytes) + ints = struct.unpack(frmt, bytes) + if len(ints) == 1: + return ints[0] + return list(ints) + + +# Returns format used by Struct, assuming we are interested in integers (so 4 bytes) +def get_format(byteorder: Union[Literal["little"], Literal["big"]], input_list): + frmt = "" + if byteorder == "little": + frmt += "<" + elif byteorder == "big": + frmt += ">" + else: + raise ValueError("byteorder must be 'little' or 'big'.") + + if type(input_list) is bytes: + assert len(input_list) % 4 == 0, "input_list length not divisble by 4." + frmt += f"{len(input_list)//4}" + elif type(input_list[0]) is int: + frmt += f"{len(input_list)}" + + frmt += "I" + return frmt + + +# Takes in top level cocotb memory structure and returns integers of bytes contained in it. +def cocotb_mem_to_ints(memory) -> List[int]: + integers = list(map(lambda e: e.integer, memory.mem.value)) + # Cocotb mem.value seems to store integers in reverse order? So memory cell 0 is + # at index -1 and memory cell n-1 is at index 0 + return integers[::-1] diff --git a/yxi/axi-calyx/cocotb/sim.sh b/yxi/axi-calyx/cocotb/sim.sh new file mode 100644 index 000000000..1e991788f --- /dev/null +++ b/yxi/axi-calyx/cocotb/sim.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Intended to convert from calyx to synthesizable verilog, enable waveform tracing and run tests defined in Makefile +#expects an outputs/ dir one level up from here +fud e ../axi-combined-calyx.futil --from calyx --to synth-verilog -o ../outputs/axi-combined.v \ + && ../vcdump.py ../outputs/axi-combined.v \ + && make WAVES=1 \ + && mv out.vcd axi-combined.fst diff --git a/yxi/axi-calyx/vcdump.py b/yxi/axi-calyx/vcdump.py new file mode 100755 index 000000000..09772d5b2 --- /dev/null +++ b/yxi/axi-calyx/vcdump.py @@ -0,0 +1,40 @@ +#!/usr/bin/python3 +import sys + + +# Usage: `./vcdump.py ` will add dump lines required to get icarus to create vcds + + +def replace_line(file_path, old_line, new_line): + try: + with open(file_path, "r") as file: + lines = file.readlines() + + with open(file_path, "w") as file: + for line in lines: + if line.strip() == old_line.strip(): + file.write(new_line + "\n") + else: + file.write(line) + print(f"Replacement in '{file_path}' successful.") + except Exception as e: + print(f"Error: {e}") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python script.py ") + else: + file_path = sys.argv[1] + old_line = "// COMPONENT END: main" + new_line = """ +`ifdef COCOTB_SIM + initial begin + $dumpfile ("out.vcd"); + $dumpvars (0, main); + #1; + end +`endif +// COMPONENT END: main + """ + replace_line(file_path, old_line, new_line) From be69d537d09d4bddd68201d7155e282397161fb4 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:46:19 -0500 Subject: [PATCH 135/189] Compaction Accounts for Continuous Assignments (#1847) * first pass * code cleaning * documentation * clippy * bug fix * better analyssi * documentation --- calyx-opt/src/analysis/control_order.rs | 91 ++++++++++++++----- calyx-opt/src/analysis/reaching_defns.rs | 2 +- calyx-opt/src/analysis/read_write_set.rs | 65 ++++++++++++- calyx-opt/src/passes/schedule_compaction.rs | 11 ++- .../continuous-compaction.expect | 47 ++++++++++ .../continuous-compaction.futil | 45 +++++++++ .../continuous-no-compaction.expect | 40 ++++++++ .../continuous-no-compaction.futil | 46 ++++++++++ 8 files changed, 318 insertions(+), 29 deletions(-) create mode 100644 tests/passes/schedule-compaction/continuous-compaction.expect create mode 100644 tests/passes/schedule-compaction/continuous-compaction.futil create mode 100644 tests/passes/schedule-compaction/continuous-no-compaction.expect create mode 100644 tests/passes/schedule-compaction/continuous-no-compaction.futil diff --git a/calyx-opt/src/analysis/control_order.rs b/calyx-opt/src/analysis/control_order.rs index 27102ebfe..5edb9a290 100644 --- a/calyx-opt/src/analysis/control_order.rs +++ b/calyx-opt/src/analysis/control_order.rs @@ -7,7 +7,7 @@ use petgraph::{ algo, graph::{DiGraph, NodeIndex}, }; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::fmt::Write as _; /// Extract the dependency order of a list of control programs. @@ -42,21 +42,19 @@ impl ControlOrder { .unique() } - fn get_cells_static_seq( - ports: Vec>, + // Filters out the constants from `cells`, while mapping the remaining `ir:Cell`s + // to their cell name. + fn filter_out_constants( + cells: Vec>, ) -> impl Iterator { - ports + cells .into_iter() - .filter_map(|p| { - let cr = p.borrow().cell_parent(); - let cell = cr.borrow(); - match cell.prototype { - // Ignore constants and _this - ir::CellType::Constant { .. } => None, - ir::CellType::ThisComponent => { - Some(ir::Id::new("this_comp")) - } - _ => Some(cell.name()), + .filter_map(|cell| match cell.borrow().prototype { + ir::CellType::Constant { .. } => None, + ir::CellType::Component { .. } + | ir::CellType::Primitive { .. } + | ir::CellType::ThisComponent { .. } => { + Some(cell.borrow().name()) } }) .unique() @@ -144,16 +142,32 @@ impl ControlOrder { } } - // returns a graph of dependency for input programs - // input control programs are considered to have data dependency if: + // Returns a graph of dependency for input programs. + // Input control programs are considered to have data dependency if: // 1. subsequent program writes to cells that previous program reads from // 2. subsequent program writes to cells that previous program writes to // 3. subsequent program reads from cells that previous program writes to + // Furthermore, we add dependencies due to continuous assignments as well. If: + // 4. Program writes to cell that a continuous assignment writes to or reads from. + // 5. Program reads from a cell that a continuous assignment writes to. + // Then the program "touches" the continuous assignments, and therefore depends + // on all previous programs that "touched" continuous assignments as well. + // In short, we treat continuous assignments as one big cell. pub fn get_dependency_graph_static_seq( stmts: impl Iterator, + (cont_reads, cont_writes): ( + Vec>, + Vec>, + ), dependency: &mut HashMap>, latency_map: &mut HashMap, ) -> DiGraph, ()> { + // The names of the cells that are read/written in continuous assignments + let cont_read_cell_names = + Self::filter_out_constants(cont_reads).collect_vec(); + let cont_write_cell_names = + Self::filter_out_constants(cont_writes).collect_vec(); + // Directed graph where edges means that a control program must be run before. let mut gr: DiGraph, ()> = DiGraph::new(); @@ -161,17 +175,22 @@ impl ControlOrder { let mut reads: HashMap> = HashMap::default(); let mut writes: HashMap> = HashMap::default(); + // Stores the nodes (i.e., control stmts) that are affected by continuous + // assignments + let mut continuous_idxs: HashSet = HashSet::new(); + for c in stmts { - let (port_reads, port_writes) = - ReadWriteSet::control_port_read_write_set_static(&c); - let r_cells = Self::get_cells_static_seq(port_reads); - let w_cells = Self::get_cells_static_seq(port_writes); + let (cell_reads, cell_writes) = + ReadWriteSet::control_read_write_set_static(&c); + let r_cell_names = Self::filter_out_constants(cell_reads); + let w_cell_names = Self::filter_out_constants(cell_writes); let latency = c.get_latency(); let idx = gr.add_node(Some(c)); dependency.insert(idx, Vec::new()); latency_map.insert(idx, latency); - for cell in r_cells { + for cell in r_cell_names { + // Checking: 3. subsequent program reads from cells that previous program writes to if let Some(wr_idxs) = writes.get(&cell) { for wr_idx in wr_idxs { if !wr_idx.eq(&idx) { @@ -180,10 +199,23 @@ impl ControlOrder { } } } + + // Checking: 5. Program reads from a cell that a continuous + // assignment writes to. + if cont_write_cell_names.contains(&cell) { + for cur_idx in continuous_idxs.iter() { + if !cur_idx.eq(&idx) { + gr.add_edge(*cur_idx, idx, ()); + dependency.entry(idx).or_default().push(*cur_idx); + } + } + continuous_idxs.insert(idx); + } reads.entry(cell).or_default().push(idx); } - for cell in w_cells { + for cell in w_cell_names { + // Checking: 2. subsequent program writes to cells that previous program writes to if let Some(wr_idxs) = writes.get(&cell) { for wr_idx in wr_idxs { if !wr_idx.eq(&idx) { @@ -193,6 +225,7 @@ impl ControlOrder { } } + // Checking: 1. subsequent program writes to cells that previous program reads from if let Some(r_idxs) = reads.get(&cell) { for r_idx in r_idxs { if !r_idx.eq(&idx) { @@ -202,6 +235,20 @@ impl ControlOrder { } } + // Checking: 4. Program writes to cell that a continuous assignment + // writes to or reads from. + if cont_write_cell_names.contains(&cell) + || cont_read_cell_names.contains(&cell) + { + for cur_idx in continuous_idxs.iter() { + if !cur_idx.eq(&idx) { + gr.add_edge(*cur_idx, idx, ()); + dependency.entry(idx).or_default().push(*cur_idx); + } + } + continuous_idxs.insert(idx); + } + writes.entry(cell).or_default().push(idx); } } diff --git a/calyx-opt/src/analysis/reaching_defns.rs b/calyx-opt/src/analysis/reaching_defns.rs index 0e2b90874..384cfda85 100644 --- a/calyx-opt/src/analysis/reaching_defns.rs +++ b/calyx-opt/src/analysis/reaching_defns.rs @@ -143,8 +143,8 @@ impl DefSet { set: self .set .iter() + .filter(|&(name, _)| !killset.contains(name)) .cloned() - .filter(|(name, _)| !killset.contains(name)) .collect(), } } diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index de1103e7b..544a17d88 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -120,7 +120,8 @@ impl ReadWriteSet { } impl ReadWriteSet { - /// Returns the ports that are read by the given control program. + /// Returns the ports that are read and written, respectively, + /// by the given static control program. pub fn control_port_read_write_set_static( scon: &ir::StaticControl, ) -> (Vec>, Vec>) { @@ -193,7 +194,27 @@ impl ReadWriteSet { } } - /// Returns the ports that are read by the given control program. + /// Returns the cells that are read and written, respectively, + /// by the given static control program. + pub fn control_read_write_set_static( + scon: &ir::StaticControl, + ) -> (Vec>, Vec>) { + let (port_reads, port_writes) = + Self::control_port_read_write_set_static(scon); + ( + port_reads + .into_iter() + .map(|p| p.borrow().cell_parent()) + .collect(), + port_writes + .into_iter() + .map(|p| p.borrow().cell_parent()) + .collect(), + ) + } + + /// Returns the ports that are read and written, respectively, + /// by the given control program. pub fn control_port_read_write_set( con: &ir::Control, ) -> (Vec>, Vec>) { @@ -305,4 +326,44 @@ impl ReadWriteSet { } } } + + /// Returns the cells that are read and written, respectively, + /// by the given control program. + pub fn control_read_write_set( + con: &ir::Control, + ) -> (Vec>, Vec>) { + let (port_reads, port_writes) = Self::control_port_read_write_set(con); + ( + port_reads + .into_iter() + .map(|p| p.borrow().cell_parent()) + .collect(), + port_writes + .into_iter() + .map(|p| p.borrow().cell_parent()) + .collect(), + ) + } + + /// Returns the ports that are read and written, respectively, + /// in the continuous assignments of the given component. + pub fn cont_ports_read_write_set( + comp: &mut calyx_ir::Component, + ) -> (Vec>, Vec>) { + ( + Self::port_read_set(comp.continuous_assignments.iter()).collect(), + Self::port_write_set(comp.continuous_assignments.iter()).collect(), + ) + } + + /// Returns the cells that are read and written, respectively, + /// in the continuous assignments of the given component. + pub fn cont_read_write_set( + comp: &mut calyx_ir::Component, + ) -> (Vec>, Vec>) { + ( + Self::read_set(comp.continuous_assignments.iter()).collect(), + Self::write_set(comp.continuous_assignments.iter()).collect(), + ) + } } diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index c18bca763..ec440da8e 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -1,3 +1,4 @@ +use crate::analysis::ReadWriteSet; use crate::traversal::Action; use crate::{ analysis, @@ -8,10 +9,10 @@ use petgraph::{algo, graph::NodeIndex}; use std::collections::HashMap; #[derive(Default)] -/// for static seqs that are statically promoted by the compiler, -/// aggressively compacts the execution schedule so that the execution +/// For static seqs that are statically promoted by the compiler. +/// Aggressively compacts the execution schedule so that the execution /// order of control operators still respects data dependency -/// Example: see tests/passes/schedule-compaction/schedule-compaction.rs +/// Example: see tests/passes/schedule-compaction/schedule-compaction.futil pub struct ScheduleCompaction; impl Named for ScheduleCompaction { @@ -47,11 +48,14 @@ impl Visitor for ScheduleCompaction { // records the scheduled start time of corresponding control operator for each node index let mut schedule: HashMap = HashMap::new(); + let (cont_reads, cont_writes) = ReadWriteSet::cont_read_write_set(comp); + let mut builder = ir::Builder::new(comp, sigs); let mut total_order = analysis::ControlOrder::::get_dependency_graph_static_seq( s.stmts.drain(..), + (cont_reads, cont_writes), &mut dependency, &mut latency_map, ); @@ -60,7 +64,6 @@ impl Visitor for ScheduleCompaction { let mut total_time: u64 = 0; // First we build the schedule. - for i in order { // Start time is when the latest dependency finishes let start = dependency diff --git a/tests/passes/schedule-compaction/continuous-compaction.expect b/tests/passes/schedule-compaction/continuous-compaction.expect new file mode 100644 index 000000000..1ccd2ef0f --- /dev/null +++ b/tests/passes/schedule-compaction/continuous-compaction.expect @@ -0,0 +1,47 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + r2 = std_reg(8); + r3 = std_reg(8); + add = std_add(8); + } + wires { + static<1> group write_r0 { + r0.in = 8'd1; + r0.write_en = 1'd1; + } + static<1> group write_r1 { + r1.in = add.out; + r1.write_en = 1'd1; + } + static<1> group write_r2 { + r2.in = 8'd3; + r2.write_en = 1'd1; + } + static<1> group write_r3 { + r3.in = 8'd3; + r3.write_en = 1'd1; + } + out = r1.out; + add.right = 8'd1; + add.left = r0.out; + } + control { + seq { + static<2> par { + static<2> seq { + write_r0; + write_r1; + } + static<1> seq { + write_r2; + } + static<1> seq { + write_r3; + } + } + } + } +} diff --git a/tests/passes/schedule-compaction/continuous-compaction.futil b/tests/passes/schedule-compaction/continuous-compaction.futil new file mode 100644 index 000000000..017c13cda --- /dev/null +++ b/tests/passes/schedule-compaction/continuous-compaction.futil @@ -0,0 +1,45 @@ +// -p validate -p schedule-compaction + +import "primitives/core.futil"; + +component main() -> (out: 8) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + r2 = std_reg(8); + r3 = std_reg(8); + add = std_add(8); + } + wires { + static<1> group write_r0 { + r0.write_en = 1'd1; + r0.in = 8'd1; + } + static<1> group write_r1 { + r1.write_en = 1'd1; + r1.in = add.out; + } + static<1> group write_r2 { + r2.write_en = 1'd1; + r2.in = 8'd3; + } + static<1> group write_r3 { + r3.write_en = 1'd1; + r3.in = 8'd3; + } + add.left = r0.out; + add.right = 8'd1; + out = r1.out; + } + control { + seq { + @compactable static seq { + write_r0; + // Continuous assignments to add.left and add.right prevent compation. + write_r1; + write_r2; + write_r3; + } + } + } +} \ No newline at end of file diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.expect b/tests/passes/schedule-compaction/continuous-no-compaction.expect new file mode 100644 index 000000000..b61eaf801 --- /dev/null +++ b/tests/passes/schedule-compaction/continuous-no-compaction.expect @@ -0,0 +1,40 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + r2 = std_reg(8); + add = std_add(8); + add1 = std_add(8); + } + wires { + static<1> group write_r0 { + r0.in = 8'd1; + r0.write_en = 1'd1; + } + static<1> group write_r1 { + r1.in = add.out; + r1.write_en = 1'd1; + } + static<1> group write_add1 { + add1.right = 8'd4; + add1.left = 8'd1; + } + out = r1.out; + add.right = 8'd1; + add.left = r0.out; + r2.in = add1.out; + } + control { + seq { + static<2> seq { + write_r0; + write_r1; + } + static<2> seq { + write_r0; + write_add1; + } + } + } +} diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.futil b/tests/passes/schedule-compaction/continuous-no-compaction.futil new file mode 100644 index 000000000..c69eb1a3f --- /dev/null +++ b/tests/passes/schedule-compaction/continuous-no-compaction.futil @@ -0,0 +1,46 @@ +// -p validate -p schedule-compaction + +import "primitives/core.futil"; + +component main() -> (out: 8) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + r2 = std_reg(8); + add = std_add(8); + add1 = std_add(8); + } + wires { + static<1> group write_r0 { + r0.write_en = 1'd1; + r0.in = 8'd1; + } + static<1> group write_r1 { + r1.write_en = 1'd1; + r1.in = add.out; + } + static<1> group write_add1 { + add1.left = 8'd1; + add1.right = 8'd4; + } + r2.in = add1.out; + add.left = r0.out; + add.right = 8'd1; + out = r1.out; + } + control { + seq { + @compactable static seq { + write_r0; + // Continuous assignments to add.left and add.right prevent compation. + write_r1; + } + @compactable static seq { + write_r0; + // Continuous assignment r2.in = add1.out prevents compaction. + // This is overly conservative. + write_add1; + } + } + } +} \ No newline at end of file From 192d8f09019be09805f2db74eaabafae2053c6b0 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Tue, 16 Jan 2024 14:47:06 -0500 Subject: [PATCH 136/189] Document Calyx RTL interface requirements (#1843) * move docs into running-calyx dir * add interfacing.md documenting how to interface with RTL designs * remove old directory * update summary.md with interfacing.md * fix link * Update docs/running-calyx/interfacing.md Co-authored-by: Adrian Sampson * Update docs/running-calyx/interfacing.md Co-authored-by: Adrian Sampson * Update docs/running-calyx/interfacing.md Co-authored-by: Adrian Sampson * Polish and PR feedback --------- Co-authored-by: Adrian Sampson --- docs/SUMMARY.md | 19 +++--- docs/{ => running-calyx}/fud/axi-gen.md | 0 docs/{ => running-calyx}/fud/circt.md | 0 docs/{ => running-calyx}/fud/examples.md | 0 docs/{ => running-calyx}/fud/external.md | 0 docs/{ => running-calyx}/fud/index.md | 0 .../{ => running-calyx}/fud/multiple-paths.md | 0 .../fud/resource-estimation.md | 0 docs/{ => running-calyx}/fud/xilinx.md | 0 docs/running-calyx/interfacing.md | 65 +++++++++++++++++++ docs/{ => running-calyx}/interpreter.md | 0 11 files changed, 75 insertions(+), 9 deletions(-) rename docs/{ => running-calyx}/fud/axi-gen.md (100%) rename docs/{ => running-calyx}/fud/circt.md (100%) rename docs/{ => running-calyx}/fud/examples.md (100%) rename docs/{ => running-calyx}/fud/external.md (100%) rename docs/{ => running-calyx}/fud/index.md (100%) rename docs/{ => running-calyx}/fud/multiple-paths.md (100%) rename docs/{ => running-calyx}/fud/resource-estimation.md (100%) rename docs/{ => running-calyx}/fud/xilinx.md (100%) create mode 100644 docs/running-calyx/interfacing.md rename docs/{ => running-calyx}/interpreter.md (100%) diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 76595ae44..aedda9c6c 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -14,15 +14,16 @@ # Running Calyx Programs -- [`fud`: The Calyx Driver](./fud/index.md) - - [Examples](./fud/examples.md) - - [Xilinx Tools](./fud/xilinx.md) - - [AXI Generation](./fud/axi-gen.md) - - [External Stages](./fud/external.md) - - [Multiple Paths](./fud/multiple-paths.md) - - [CIRCT](./fud/circt.md) - - [Resource Estimation](./fud/resource-estimation.md) -- [The Calyx Interpreter](./interpreter.md) +- [`fud`: The Calyx Driver](./running-calyx/fud/index.md) + - [Examples](./running-calyx/fud/examples.md) + - [Xilinx Tools](./running-calyx/fud/xilinx.md) + - [AXI Generation](./running-calyx/fud/axi-gen.md) + - [External Stages](./running-calyx/fud/external.md) + - [Multiple Paths](./running-calyx/fud/multiple-paths.md) + - [CIRCT](./running-calyx/fud/circt.md) + - [Resource Estimation](./running-calyx/fud/resource-estimation.md) +- [Interfacing with Calyx RTL](./running-calyx/interfacing.md) +- [The Calyx Interpreter](./running-calyx/interpreter.md) # Compiler Development Guide diff --git a/docs/fud/axi-gen.md b/docs/running-calyx/fud/axi-gen.md similarity index 100% rename from docs/fud/axi-gen.md rename to docs/running-calyx/fud/axi-gen.md diff --git a/docs/fud/circt.md b/docs/running-calyx/fud/circt.md similarity index 100% rename from docs/fud/circt.md rename to docs/running-calyx/fud/circt.md diff --git a/docs/fud/examples.md b/docs/running-calyx/fud/examples.md similarity index 100% rename from docs/fud/examples.md rename to docs/running-calyx/fud/examples.md diff --git a/docs/fud/external.md b/docs/running-calyx/fud/external.md similarity index 100% rename from docs/fud/external.md rename to docs/running-calyx/fud/external.md diff --git a/docs/fud/index.md b/docs/running-calyx/fud/index.md similarity index 100% rename from docs/fud/index.md rename to docs/running-calyx/fud/index.md diff --git a/docs/fud/multiple-paths.md b/docs/running-calyx/fud/multiple-paths.md similarity index 100% rename from docs/fud/multiple-paths.md rename to docs/running-calyx/fud/multiple-paths.md diff --git a/docs/fud/resource-estimation.md b/docs/running-calyx/fud/resource-estimation.md similarity index 100% rename from docs/fud/resource-estimation.md rename to docs/running-calyx/fud/resource-estimation.md diff --git a/docs/fud/xilinx.md b/docs/running-calyx/fud/xilinx.md similarity index 100% rename from docs/fud/xilinx.md rename to docs/running-calyx/fud/xilinx.md diff --git a/docs/running-calyx/interfacing.md b/docs/running-calyx/interfacing.md new file mode 100644 index 000000000..706667da0 --- /dev/null +++ b/docs/running-calyx/interfacing.md @@ -0,0 +1,65 @@ +# Interfacing with Calyx Programs + +To run RTL designs created from Calyx programs, top-level `reset`, `go`, and `done` +signals must be interfaced with correctly. +Interfacing with RTL designs in this way becomes relevant when writing harnesses/testbenches +to execute programs created with Calyx. + +Namely, the client for a Calyx top-level module must: +1. Assert the `reset` signal and then deassert it, to initialize the state inside +control registers correctly. +2. Assert the `go` signal, and keep it asserted as long as the module is running. +3. Wait for the `done` signal to be asserted while keeping `go` high. Deasserting +the `go` signal before a component deasserts its `done` signal will lead to +[undefined behavior][go-done]. + +Asserting the `reset` and `go` signals in this order is important. Otherwise the top-level +component will begin running with garbage data inside of control registers. + + +## Cocotb + +As a concrete example, consider using [cocotb][] +to test a Calyx-generated Verilog design. + +If we imagine a simple Calyx program that contains a simple toplevel module named `main`: + +``` +component main()->() { + cells { + reg = std_reg(4); + } + group write_to_reg { + reg.in = 4'd3; + reg.write_en = 1'b1; + write_to_reg[done] = reg.done; + } + control{ + seq{ + write_to_reg; + } + } +} +``` + +In order to be able to actually write to our register, we need to drive our `reset` and +`go` signals in our cocotb test: + +```python +# Required for all cocotb testbenches. Included for completeness. +cocotb.start_soon(Clock(module.clk, 2, units="ns").start()) + +# Reset Calyx-generated control registers +main.reset.value = 1 +await ClockCycles(main.clk, 5) #wait a bit +module.reset.value = 0 + +# Start execution of control sequence +module.go.value = 1 + +#At this point our Calyx program is done +await RisingEdge(main.done) +``` + +[go-done]: ../lang/ref.md#the-go-done-interface +[cocotb]: https://www.cocotb.org/ diff --git a/docs/interpreter.md b/docs/running-calyx/interpreter.md similarity index 100% rename from docs/interpreter.md rename to docs/running-calyx/interpreter.md From 6c2af3481b0dcb830578c348c2d0d5172a470893 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Wed, 17 Jan 2024 13:40:05 -0500 Subject: [PATCH 137/189] Fix read channel data_received write_en (#1851) --- yxi/axi-calyx/axi-combined-calyx.futil | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index 78ef049b4..2c62a258e 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -204,7 +204,7 @@ component m_read_channel( RREADY : 1, ) { cells { - // 16 is due to dot-product vector length assumption + // 8 is due to vector_add length assumption // For this manual implementation we are just writing into this data based // on the data we read from cocotb ref data_received = seq_mem_d1(32, 8, 64); @@ -267,7 +267,9 @@ component m_read_channel( //store the data we want to write read_data_reg.in = RDATA; - read_data_reg.write_en = is_rdy.out; + //read_data_reg.write_en = is_rdy.out; + read_data_reg.write_en = !(RVALID & is_rdy.out) ? 1'b0; + read_data_reg.write_en = RVALID & is_rdy.out ? 1'b1; //update n_RLAST reg n_RLAST.in = RLAST ? 1'b0; From d9061fdb3c905c29af77b64ef8ee41eb4c740b4f Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Thu, 18 Jan 2024 14:06:49 -0500 Subject: [PATCH 138/189] Simplify Calyx AXI wrapper -- `xVALID` signals and reg `invokes` (#1846) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * simplify valid.in signals * WIP: replace groups with reg invokes * add python file that enables waveform (vcd/fst) generation * formatting * simplify valid.in signals * WIP: replace groups with reg invokes * Replaces register-init groups with invokes * Formatting of invokes * Replace reg groups with invokes in main --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-combined-calyx.futil | 213 +++++-------------------- 1 file changed, 36 insertions(+), 177 deletions(-) diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index 2c62a258e..39eac8abd 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -72,32 +72,13 @@ component m_arread_channel( ARVALID = is_arvalid.out; - group deassert_val { - is_arvalid.in = 1'b0; - is_arvalid.write_en = 1'b1; - deassert_val[done] = is_arvalid.done; - } - - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - group reset_was_high { - arvalid_was_high.in = 1'b0; - arvalid_was_high.write_en = 1'b1; - reset_was_high[done] = arvalid_was_high.done; - } - // this asserts valid and defines all inputs correctly // because valid should not be deasserted until handshake occurs // this all needs to be one group // this contains blocking logic previously in its own group group do_ar_transfer { - //assert ARVALID - - is_arvalid.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + //assert ARVALID as long as this is the first time we are asserting it + is_arvalid.in = !arvalid_was_high.out ? 1'b1; // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high // but for now we will be explicit and reduce this in generation maybe. Not sure @@ -134,25 +115,6 @@ component m_arread_channel( do_ar_transfer[done] = bt_reg.out; } - - //txn bookkeeping. - //We are done performing reads when txn_count == txn_n - group txn_count_init { - txn_count.in = 32'b0; - txn_count.write_en = 1'b1; - txn_count_init[done] = txn_count.done; - - } - - group txn_len_init { - // TODO(nathanielnrn):Parametrize this. - // 7 is good for word wide data bus and 8 element vec_add We'd - // expect 8 transfers. Number of transfers that occur is ARLEN + 1 - txn_len.in = 8'd7; - txn_len.write_en = 1'b1; - txn_len_init[done] = txn_len.done; - } - group txn_incr { txn_adder.left = txn_count.out; txn_adder.right = 32'b1; @@ -172,16 +134,19 @@ component m_arread_channel( control{ //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? seq{ - txn_count_init; - txn_len_init; + invoke txn_count(in=32'b0)(); + // TODO(nathanielnrn):Parametrize this. + // 7 is good for word wide data bus and 8 element vec_add We'd + // expect 8 transfers. Number of transfers that occur is ARLEN + 1 + invoke txn_len(in=8'd7)(); while perform_reads.out with check_reads_done{ seq{ par { - reset_bt; - reset_was_high; + invoke bt_reg(in=1'b0)(); + invoke arvalid_was_high(in=1'b0)(); } do_ar_transfer; - deassert_val; + invoke is_arvalid(in=1'b0)(); txn_incr; } } @@ -223,6 +188,7 @@ component m_read_channel( curr_addr_adder = std_add(64); // block_transfer reg to avoid combinational loops + // Used to block any servicing until handshake occurs. bt_reg = std_reg(1); } @@ -231,19 +197,6 @@ component m_read_channel( RREADY = is_rdy.out; data_received.read_en = 1'b0; - group init_n_RLAST { - n_RLAST.in = 1'b1; - n_RLAST.write_en = 1'b1; - init_n_RLAST[done] = n_RLAST.done; - } - - // Used to block any servicing until handshake occurs. - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - // NOTE: xVALID signals must be high until xREADY is high as well, so this works // because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip // and group will be done by bt_reg.out @@ -306,10 +259,10 @@ component m_read_channel( } } control{ - init_n_RLAST; + invoke n_RLAST(in=1'b1)(); //init n_RLAST while n_RLAST.out{ seq{ - reset_bt; + invoke bt_reg(in=1'b0)(); //reset bt_reg block_transfer; receive_r_transfer; incr_curr_addr; @@ -473,32 +426,13 @@ component m_awwrite_channel( AWVALID = is_awvalid.out; - group deassert_val { - is_awvalid.in = 1'b0; - is_awvalid.write_en = 1'b1; - deassert_val[done] = is_awvalid.done; - } - - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - - group reset_was_high { - awvalid_was_high.in = 1'b0; - awvalid_was_high.write_en = 1'b1; - reset_was_high[done] = awvalid_was_high.done; - } - // this asserts valid and defines all inputs correctly // because valid should not be deasserted until handshake occurs // this all needs to be one group // this contains blocking logic previously in its own group group do_aw_transfer { //assert AWVALID - is_awvalid.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + is_awvalid.in = !awvalid_was_high.out ? 1'b1; // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high // but for now we will be explicit and reduce this in generation maybe. Not sure @@ -540,22 +474,6 @@ component m_awwrite_channel( } - //txn bookkeeping. - //We are done performing reads when txn_count == txn_n - group txn_count_init { - txn_count.in = 32'b0; - txn_count.write_en = 1'b1; - txn_count_init[done] = txn_count.done; - - } - - group txn_len_init { - //TODO(nathanielnrn): 15 is good for word wide data bus. We'd - //expect 16 transfers. Number of transfers that occur is AWLEN + 1 - txn_len.in = 8'd7; - txn_len.write_en = 1'b1; - txn_len_init[done] = txn_len.done; - } group txn_incr { txn_adder.left = txn_count.out; @@ -575,16 +493,17 @@ component m_awwrite_channel( control{ //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? seq{ - txn_count_init; - txn_len_init; + invoke txn_count(in=32'b0)(); + //TODO(nathanielnrn):parameterize this number. 7(+1) gives us 8 elements + invoke txn_len(in=8'd7)(); while perform_write_txns.out with check_writes_done{ seq{ par { - reset_bt; - reset_was_high; + invoke bt_reg(in=1'b0)(); + invoke awvalid_was_high(in=1'b0)(); } do_aw_transfer; - deassert_val; + invoke is_awvalid(in=1'b0)(); txn_incr; } } @@ -638,25 +557,6 @@ component m_write_channel( WVALID = wvalid.out; - group reset_curr_addr{ - curr_addr.in = 64'b0; - curr_addr.write_en = 1'b1; - reset_curr_addr[done] = curr_addr.done; - } - - group init_n_finished_last_trnsfr { - n_finished_last_trnsfr.in = 1'b1; - n_finished_last_trnsfr.write_en = 1'b1; - init_n_finished_last_trnsfr[done] = n_finished_last_trnsfr.done; - } - - //Used to block any servicing until handshake occurs. - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - //NOTE: xVALID signals must be high until xREADY is high as well, so this works //because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip //and group will be done by bt_reg.out @@ -664,9 +564,8 @@ component m_write_channel( //set RREADY high //TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). //Could we simplify this we just making things ready when we are in - //block_transfer && RVALID? - //NOTE: wvalid.in = 1'b1; does not work, it leaves RREADY high for 2 cycles + //NOTE: wvalid.in = 1'b1; does not work, it leaves WVALID high for 2 cycles // this both asserts and deasserts one cycle later wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; // TODO(nathanielnrn): Can prob get rid of wvalid_was_high @@ -675,7 +574,7 @@ component m_write_channel( //set to 1 after valid has been high even once wvalid_was_high.in = 1'b1; - wvalid_was_high.write_en = !(wvalid.out & WREADY) & !wvalid_was_high.out ? 1'b1; + wvalid_was_high.write_en = !(wvalid.out & WREADY & !wvalid_was_high.out) ? 1'b1; // set data output based on curr_addr register @@ -720,12 +619,11 @@ component m_write_channel( control{ seq{ - reset_curr_addr; - //end writing to internal mem - init_n_finished_last_trnsfr; + invoke curr_addr(in=64'b0)(); //reset curr_addr + invoke n_finished_last_trnsfr(in=1'b1)(); //init reg while n_finished_last_trnsfr.out{ seq{ - reset_bt; + invoke bt_reg(in=1'b0)(); do_write_transfer; par{ incr_curr_addr; @@ -757,11 +655,6 @@ component m_bresp_channel( } wires{ BREADY = bready.out; - group reset_bt_reg{ - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt_reg[done] = bt_reg.done; - } // TODO(nathanielnrn): This is probably very unoptimal and takes multiple // cycles to simply do a handshake. Can probably be much better @@ -779,7 +672,7 @@ component m_bresp_channel( } control{ seq{ - reset_bt_reg; + invoke bt_reg(in=1'b0)(); block_transfer; } } @@ -1003,49 +896,15 @@ component main( m2_WID = 1'b0; m2_BID = 1'b0; - group set_curr_to_base_addr_A0{ - curr_addr_A0.in = base_addr_A0.out; - curr_addr_A0.write_en = 1'b1; - set_curr_to_base_addr_A0[done] = curr_addr_A0.done; - } - - group init_base_addr_A0{ - base_addr_A0.in = 64'b0; - base_addr_A0.write_en = 1'b1; - init_base_addr_A0[done] = base_addr_A0.done; - } - - group set_curr_to_base_addr_B0{ - curr_addr_B0.in = base_addr_B0.out; - curr_addr_B0.write_en = 1'b1; - set_curr_to_base_addr_B0[done] = curr_addr_B0.done; - } - - group init_base_addr_B0{ - base_addr_B0.in = 64'b0; - base_addr_B0.write_en = 1'b1; - init_base_addr_B0[done] = base_addr_B0.done; - } - - group set_curr_to_base_addr_Sum0{ - curr_addr_Sum0.in = base_addr_Sum0.out; - curr_addr_Sum0.write_en = 1'b1; - set_curr_to_base_addr_Sum0[done] = curr_addr_Sum0.done; - } - - group init_base_addr_Sum0{ - base_addr_Sum0.in = 64'b0; - base_addr_Sum0.write_en = 1'b1; - init_base_addr_Sum0[done] = base_addr_Sum0.done; - } } control{ seq{ //read stuff par{ - init_base_addr_A0; - init_base_addr_B0; - init_base_addr_Sum0; + //init base_addresses + invoke base_addr_A0(in = 64'b0)(); + invoke base_addr_B0(in = 64'b0)(); + invoke base_addr_Sum0(in = 64'b0)(); } par{ seq{ @@ -1063,7 +922,7 @@ component main( ARBURST = m0_ARBURST ); - set_curr_to_base_addr_A0; + invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address invoke A0_read_channel[data_received = A0, curr_addr = curr_addr_A0] ( @@ -1093,7 +952,7 @@ component main( ARBURST = m1_ARBURST ); - set_curr_to_base_addr_B0; + invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address invoke B0_read_channel[data_received = B0, curr_addr = curr_addr_B0] ( @@ -1121,7 +980,7 @@ component main( ARBURST = m2_ARBURST ); - set_curr_to_base_addr_Sum0; + invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address invoke Sum0_read_channel[data_received = Sum0, curr_addr = curr_addr_Sum0] ( @@ -1162,7 +1021,7 @@ component main( AWPROT = m0_AWPROT ); - set_curr_to_base_addr_A0; + invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address invoke A0_write_channel[internal_mem = A0, curr_addr = curr_addr_A0, max_trnsfrs = max_trnsfrs] ( @@ -1192,7 +1051,7 @@ component main( AWPROT = m1_AWPROT ); - set_curr_to_base_addr_B0; + invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address invoke B0_write_channel[internal_mem = B0, curr_addr = curr_addr_B0, max_trnsfrs = max_trnsfrs] ( @@ -1223,7 +1082,7 @@ component main( AWPROT = m2_AWPROT ); - set_curr_to_base_addr_Sum0; + invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address invoke Sum0_write_channel[internal_mem = Sum0, curr_addr = curr_addr_Sum0, max_trnsfrs = max_trnsfrs] ( From c918bb3094a02673c5c7c74ee69685d95f87350f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 19 Jan 2024 13:51:41 -0500 Subject: [PATCH 139/189] Add parens around guard exprs (#1858) --- calyx-py/calyx/py_ast.py | 4 ++-- calyx-py/test/builder_example.expect | 2 +- calyx-py/test/example.expect | 2 +- tests/frontend/exp/degree-2-unsigned.expect | 4 ++-- tests/frontend/exp/degree-4-signed.expect | 4 ++-- tests/frontend/exp/degree-4-unsigned.expect | 4 ++-- tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect | 8 ++++---- tests/frontend/ntt-pipeline/ntt-4.expect | 8 ++++---- tests/frontend/relay/softmax.expect | 4 ++-- tests/frontend/systolic/array-1.expect | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index d1eedcb2e..3605f9278 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -276,7 +276,7 @@ class And(GuardExpr): right: GuardExpr def doc(self) -> str: - return f"{self.left.doc()} & {self.right.doc()}" + return f"({self.left.doc()} & {self.right.doc()})" @dataclass @@ -285,7 +285,7 @@ class Or(GuardExpr): right: GuardExpr def doc(self) -> str: - return f"{self.left.doc()} | {self.right.doc()}" + return f"({self.left.doc()} | {self.right.doc()})" @dataclass diff --git a/calyx-py/test/builder_example.expect b/calyx-py/test/builder_example.expect index 7ed951b27..cb0a7426c 100644 --- a/calyx-py/test/builder_example.expect +++ b/calyx-py/test/builder_example.expect @@ -13,7 +13,7 @@ component main(in: 32) -> (out: 32) { rhs.write_en = 1'd1; lhs.in = 32'd1; rhs.in = 32'd41; - update_operands[done] = lhs.done & rhs.done ? 1'd1; + update_operands[done] = (lhs.done & rhs.done) ? 1'd1; } group compute_sum { add.left = lhs.out; diff --git a/calyx-py/test/example.expect b/calyx-py/test/example.expect index 1ed815072..62fc8a0d0 100644 --- a/calyx-py/test/example.expect +++ b/calyx-py/test/example.expect @@ -13,7 +13,7 @@ component main() -> () { rhs.in = 32'd41; lhs.write_en = 1'd1; rhs.write_en = 1'd1; - update_operands[done] = lhs.done & rhs.done ? 1'd1; + update_operands[done] = (lhs.done & rhs.done) ? 1'd1; } group compute_sum { add.left = lhs.out; diff --git a/tests/frontend/exp/degree-2-unsigned.expect b/tests/frontend/exp/degree-2-unsigned.expect index b6ef1de1e..786d17ac9 100644 --- a/tests/frontend/exp/degree-2-unsigned.expect +++ b/tests/frontend/exp/degree-2-unsigned.expect @@ -39,7 +39,7 @@ component exp(x: 32) -> (out: 32) { frac_x.write_en = 1'd1; int_x.in = rsh.out; frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; + split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } group consume_pow2<"static"=1> { p2.write_en = 1'd1; @@ -114,7 +114,7 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow.write_en = 1'd1; count.in = 32'd0; count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; + init[done] = (pow.done & count.done) ? 1'd1; } group execute_mul { mul.left = base; diff --git a/tests/frontend/exp/degree-4-signed.expect b/tests/frontend/exp/degree-4-signed.expect index c530c34b2..0a6a19d0e 100644 --- a/tests/frontend/exp/degree-4-signed.expect +++ b/tests/frontend/exp/degree-4-signed.expect @@ -56,7 +56,7 @@ component exp(x: 16) -> (out: 16) { frac_x.write_en = 1'd1; int_x.in = rsh.out; frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; + split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } group negate { mult_pipe1.left = exponent_value.out; @@ -207,7 +207,7 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow.write_en = 1'd1; count.in = 16'd0; count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; + init[done] = (pow.done & count.done) ? 1'd1; } group execute_mul { mul.left = base; diff --git a/tests/frontend/exp/degree-4-unsigned.expect b/tests/frontend/exp/degree-4-unsigned.expect index 91fa24244..3c8962a8d 100644 --- a/tests/frontend/exp/degree-4-unsigned.expect +++ b/tests/frontend/exp/degree-4-unsigned.expect @@ -53,7 +53,7 @@ component exp(x: 16) -> (out: 16) { frac_x.write_en = 1'd1; int_x.in = rsh.out; frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; + split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } group consume_pow2<"static"=1> { p2.write_en = 1'd1; @@ -178,7 +178,7 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { pow.write_en = 1'd1; count.in = 16'd0; count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; + init[done] = (pow.done & count.done) ? 1'd1; } group execute_mul { mul.left = base; diff --git a/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect b/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect index 90c47326e..bb67b80c7 100644 --- a/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect +++ b/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect @@ -45,7 +45,7 @@ component main() -> () { r0.in = a.read_data; phi0.write_en = 1'd1; phi0.in = phis.read_data; - preamble_0[done] = r0.done & phi0.done ? 1'd1; + preamble_0[done] = (r0.done & phi0.done) ? 1'd1; } group preamble_1 { a.addr0 = 3'd1; @@ -54,7 +54,7 @@ component main() -> () { r1.in = a.read_data; phi1.write_en = 1'd1; phi1.in = phis.read_data; - preamble_1[done] = r1.done & phi1.done ? 1'd1; + preamble_1[done] = (r1.done & phi1.done) ? 1'd1; } group preamble_2 { a.addr0 = 3'd2; @@ -63,7 +63,7 @@ component main() -> () { r2.in = a.read_data; phi2.write_en = 1'd1; phi2.in = phis.read_data; - preamble_2[done] = r2.done & phi2.done ? 1'd1; + preamble_2[done] = (r2.done & phi2.done) ? 1'd1; } group preamble_3 { a.addr0 = 3'd3; @@ -72,7 +72,7 @@ component main() -> () { r3.in = a.read_data; phi3.write_en = 1'd1; phi3.in = phis.read_data; - preamble_3[done] = r3.done & phi3.done ? 1'd1; + preamble_3[done] = (r3.done & phi3.done) ? 1'd1; } group precursor_0 { r0.in = A0.out; diff --git a/tests/frontend/ntt-pipeline/ntt-4.expect b/tests/frontend/ntt-pipeline/ntt-4.expect index d6fceb91b..881c1b991 100644 --- a/tests/frontend/ntt-pipeline/ntt-4.expect +++ b/tests/frontend/ntt-pipeline/ntt-4.expect @@ -45,7 +45,7 @@ component main() -> () { r0.in = a.read_data; phi0.write_en = 1'd1; phi0.in = phis.read_data; - preamble_0[done] = r0.done & phi0.done ? 1'd1; + preamble_0[done] = (r0.done & phi0.done) ? 1'd1; } group preamble_1 { a.addr0 = 3'd1; @@ -54,7 +54,7 @@ component main() -> () { r1.in = a.read_data; phi1.write_en = 1'd1; phi1.in = phis.read_data; - preamble_1[done] = r1.done & phi1.done ? 1'd1; + preamble_1[done] = (r1.done & phi1.done) ? 1'd1; } group preamble_2 { a.addr0 = 3'd2; @@ -63,7 +63,7 @@ component main() -> () { r2.in = a.read_data; phi2.write_en = 1'd1; phi2.in = phis.read_data; - preamble_2[done] = r2.done & phi2.done ? 1'd1; + preamble_2[done] = (r2.done & phi2.done) ? 1'd1; } group preamble_3 { a.addr0 = 3'd3; @@ -72,7 +72,7 @@ component main() -> () { r3.in = a.read_data; phi3.write_en = 1'd1; phi3.in = phis.read_data; - preamble_3[done] = r3.done & phi3.done ? 1'd1; + preamble_3[done] = (r3.done & phi3.done) ? 1'd1; } group precursor_0 { r0.in = A0.out; diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index e1186d3ba..d5302ee3a 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -379,7 +379,7 @@ component exp(x: 32) -> (out: 32) { frac_x.write_en = 1'd1; int_x.in = rsh.out; frac_x.in = and1.out; - split_bits[done] = int_x.done & frac_x.done ? 1'd1; + split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } group negate { mult_pipe1.left = exponent_value.out; @@ -628,7 +628,7 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { pow.write_en = 1'd1; count.in = 32'd0; count.write_en = 1'd1; - init[done] = pow.done & count.done ? 1'd1; + init[done] = (pow.done & count.done) ? 1'd1; } group execute_mul { mul.left = base; diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index a0a53c6bf..506285de2 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -148,7 +148,7 @@ component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: } static<1> group write_done_cond { delay_reg.in = 1'd1; - delay_reg.write_en = r0_valid & r0_idx == 1'd0 ? 1'd1; + delay_reg.write_en = (r0_valid & r0_idx == 1'd0) ? 1'd1; computation_done = delay_reg.done ? 1'd1; } } @@ -184,7 +184,7 @@ component main() -> () { post_op_component.r0_idx = systolic_array_component.r0_idx; systolic_done.write_en = systolic_array_component.done ? 1'd1; systolic_done.in = systolic_array_component.done ? 1'd1; - systolic_done_wire.in = systolic_array_component.done | systolic_done.out ? 1'd1; + systolic_done_wire.in = (systolic_array_component.done | systolic_done.out) ? 1'd1; systolic_array_component.go = !systolic_done_wire.out ? 1'd1; systolic_array_component.depth = 32'd3; post_op_component.go = 1'd1; From ebdc28de0f45c0a22fe0d82c1abdf2af6c561c52 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Sat, 20 Jan 2024 22:25:27 -0500 Subject: [PATCH 140/189] Add support for using python builder `invoke` with integer literals (#1849) * Add support for invoking with integer literals * Update invoke example to have consts * Change example to have a literal instead of const --- calyx-py/calyx/builder.py | 11 ++++++++++- docs/builder/ref.md | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index e95d18fa8..2b444a499 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -836,7 +836,16 @@ def invoke(cell: CellBuilder, **kwargs) -> ast.Invoke: return ast.Invoke( cell._cell.id, [ - (k[3:], ExprBuilder.unwrap(v)) + ( + k[3:], + ( + ( + const(cell.infer_width(k[3:]), v).expr + if isinstance(v, int) + else ExprBuilder.unwrap(v) + ) + ), + ) for (k, v) in kwargs.items() if k.startswith("in_") ], diff --git a/docs/builder/ref.md b/docs/builder/ref.md index f695d26b6..423da6db8 100644 --- a/docs/builder/ref.md +++ b/docs/builder/ref.md @@ -309,7 +309,8 @@ See the language reference for [`invoke`][invoke]. ```python # invoke(cell, **kwargs) -my_invoke = invoke(my_cell, in_arg1=my_cell_arg1_reg.out, in_arg2=my_cell_arg2_reg.out) +my_invoke = invoke(my_cell, in_arg1=my_cell_arg1_reg.out, in_arg2=1) + ``` ## Miscellaneous Tips + Tricks From 201735c4a65febbe0991506f0edee052375f5ab4 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Sat, 20 Jan 2024 22:25:41 -0500 Subject: [PATCH 141/189] Decouple AXI `base_addr` and calyx memories' `curr_addr` in hardcoded AXI implementation (#1854) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * simplify valid.in signals * WIP: replace groups with reg invokes * add python file that enables waveform (vcd/fst) generation * formatting * simplify valid.in signals * WIP: replace groups with reg invokes * Replaces register-init groups with invokes * Formatting of invokes * Replace reg groups with invokes in main * Modify tests to account for base address != 0 * Separate base-address calyx-mem-address dependency This solution, made for our load->compute->store scheme, simply increments the base_addr and curr_addr differently. This should make it easy to have multiple transactions, which this hardcoded does not support * move incrs into par block * fix was_valid signal in write channel --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-combined-calyx.futil | 84 +++++++++++++++------- yxi/axi-calyx/cocotb/axi-combined-tests.py | 41 ++++++----- 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index 39eac8abd..0782cf03d 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -174,7 +174,9 @@ component m_read_channel( // on the data we read from cocotb ref data_received = seq_mem_d1(32, 8, 64); is_rdy = std_reg(1); - ref curr_addr = std_reg(64); + ref curr_addr = std_reg(64); + //need to increment this + ref base_addr = std_reg(64); // registered because RLAST is high with last transfer, not after // before this was registered we were terminating immediately with @@ -186,6 +188,7 @@ component m_read_channel( //address of seq_d1_mem we are writing to curr_addr_adder = std_add(64); + base_addr_adder = std_add(64); // block_transfer reg to avoid combinational loops // Used to block any servicing until handshake occurs. @@ -257,6 +260,14 @@ component m_read_channel( curr_addr.write_en = 1'b1; incr_curr_addr[done] = curr_addr.done; } + + group incr_base_addr{ + base_addr_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width + base_addr_adder.right = base_addr.out; + base_addr.in = base_addr_adder.out; + base_addr.write_en= 1'b1; + incr_base_addr[done] = base_addr.done; + } } control{ invoke n_RLAST(in=1'b1)(); //init n_RLAST @@ -265,7 +276,10 @@ component m_read_channel( invoke bt_reg(in=1'b0)(); //reset bt_reg block_transfer; receive_r_transfer; - incr_curr_addr; + par{ + incr_curr_addr; + incr_base_addr; + } } } } @@ -528,7 +542,8 @@ component m_write_channel( wvalid = std_reg(1); wvalid_was_high = std_reg(1); // used internally to access our seq_mem_d1 - ref curr_addr = std_reg(64); + ref curr_addr = std_reg(64); + ref base_addr = std_reg(64); //this increments curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count @@ -542,6 +557,7 @@ component m_write_channel( //used for address of seq_d1_mem we are reading from curr_addr_adder = std_add(64); + base_addr_adder = std_add(64); curr_trnsfr_count_adder = std_add(8); @@ -549,9 +565,6 @@ component m_write_channel( bt_reg = std_reg(1); - - curr_addr_slice = std_slice(64,32); - } wires{ @@ -569,12 +582,12 @@ component m_write_channel( // this both asserts and deasserts one cycle later wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; // TODO(nathanielnrn): Can prob get rid of wvalid_was_high - wvalid.in = wvalid.out & WREADY & wvalid_was_high.out ? 1'b0; + wvalid.in = (wvalid.out & WREADY) & wvalid_was_high.out ? 1'b0; wvalid.write_en = 1'b1; //set to 1 after valid has been high even once - wvalid_was_high.in = 1'b1; - wvalid_was_high.write_en = !(wvalid.out & WREADY & !wvalid_was_high.out) ? 1'b1; + wvalid_was_high.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; + wvalid_was_high.write_en = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; // set data output based on curr_addr register @@ -606,6 +619,14 @@ component m_write_channel( curr_addr.write_en = 1'b1; incr_curr_addr[done] = curr_addr.done; } + + group incr_base_addr{ + base_addr_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width + base_addr_adder.right = base_addr.out; + base_addr.in = base_addr_adder.out; + base_addr.write_en= 1'b1; + incr_base_addr[done] = base_addr.done; + } group incr_curr_trnsfr_count { curr_trnsfr_count_adder.left = 8'd1; @@ -628,6 +649,7 @@ component m_write_channel( par{ incr_curr_addr; incr_curr_trnsfr_count; + incr_base_addr; } } } @@ -902,9 +924,13 @@ component main( //read stuff par{ //init base_addresses - invoke base_addr_A0(in = 64'b0)(); - invoke base_addr_B0(in = 64'b0)(); - invoke base_addr_Sum0(in = 64'b0)(); + //TODO: get this from kernel.xml + invoke base_addr_A0(in = 64'x1000)(); + invoke base_addr_B0(in = 64'x1000)(); + invoke base_addr_Sum0(in = 64'x1000)(); + invoke curr_addr_A0(in = 64'x0000)(); + invoke curr_addr_B0(in = 64'x0000)(); + invoke curr_addr_Sum0(in = 64'x0000)(); } par{ seq{ @@ -922,9 +948,9 @@ component main( ARBURST = m0_ARBURST ); - invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address + //invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address - invoke A0_read_channel[data_received = A0, curr_addr = curr_addr_A0] + invoke A0_read_channel[data_received = A0, curr_addr = curr_addr_A0, base_addr = base_addr_A0] ( ARESET = m0_ARESET, RVALID = m0_RVALID, @@ -952,9 +978,9 @@ component main( ARBURST = m1_ARBURST ); - invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address + //invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address - invoke B0_read_channel[data_received = B0, curr_addr = curr_addr_B0] + invoke B0_read_channel[data_received = B0, curr_addr = curr_addr_B0, base_addr = base_addr_B0] ( ARESET = m1_ARESET, RVALID = m1_RVALID, @@ -980,9 +1006,9 @@ component main( ARBURST = m2_ARBURST ); - invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address + //invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address - invoke Sum0_read_channel[data_received = Sum0, curr_addr = curr_addr_Sum0] + invoke Sum0_read_channel[data_received = Sum0, curr_addr = curr_addr_Sum0, base_addr = base_addr_Sum0] ( ARESET = m2_ARESET, RVALID = m2_RVALID, @@ -1000,10 +1026,14 @@ component main( //compute stuff invoke vec_add_cell[A0 = A0, B0 = B0, Sum0 = Sum0]()(); - //end comput stuff - - + //end compute stuff + //reset base_addr registers before writing + par{ + invoke base_addr_A0(in = 64'x1000)(); + invoke base_addr_B0(in = 64'x1000)(); + invoke base_addr_Sum0(in = 64'x1000)(); + } //write stuff par { seq { //A0 writes @@ -1021,9 +1051,9 @@ component main( AWPROT = m0_AWPROT ); - invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address + //invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address - invoke A0_write_channel[internal_mem = A0, curr_addr = curr_addr_A0, max_trnsfrs = max_trnsfrs] + invoke A0_write_channel[internal_mem = A0, curr_addr = curr_addr_A0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_A0] ( ARESET = m0_ARESET, WREADY = m0_WREADY @@ -1051,9 +1081,9 @@ component main( AWPROT = m1_AWPROT ); - invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address + //invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address - invoke B0_write_channel[internal_mem = B0, curr_addr = curr_addr_B0, max_trnsfrs = max_trnsfrs] + invoke B0_write_channel[internal_mem = B0, curr_addr = curr_addr_B0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_B0] ( ARESET = m1_ARESET, WREADY = m1_WREADY @@ -1082,9 +1112,9 @@ component main( AWPROT = m2_AWPROT ); - invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address + //invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address - invoke Sum0_write_channel[internal_mem = Sum0, curr_addr = curr_addr_Sum0, max_trnsfrs = max_trnsfrs] + invoke Sum0_write_channel[internal_mem = Sum0, curr_addr = curr_addr_Sum0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_Sum0] ( ARESET = m2_ARESET, WREADY = m2_WREADY diff --git a/yxi/axi-calyx/cocotb/axi-combined-tests.py b/yxi/axi-calyx/cocotb/axi-combined-tests.py index 9b4a619a1..f99782174 100644 --- a/yxi/axi-calyx/cocotb/axi-combined-tests.py +++ b/yxi/axi-calyx/cocotb/axi-combined-tests.py @@ -20,7 +20,7 @@ async def read_channels_happy_path(main): B0_in = [126, 62, 30, 14, 6, 2, 0, 1] expected_sum = [A0_in[i] + B0_in[i] for i in range(len(B0_in))] await run_module(main, A0_in, B0_in, expected_sum) # checks cocotb axi rams - await assert_mem_content(main.A0, A0_in) # checks in module, as opposed to axiram + await assert_mem_content(main.A0, A0_in) # checks in verilog module, as opposed to axiram await assert_mem_content(main.B0, B0_in) await assert_mem_content(main.Sum0, expected_sum) @@ -65,10 +65,10 @@ async def assert_mem_content(mem, expected: List[int]): async def assert_axi_ram_content( - axi_ram, expected: List[int], length=8 * 4, address=0x0000 + axi_ram, expected: List[int], address=0x0000, length=8 * 4 ): """Checks that `mem` content inside the cocotb (as opposed to - verilog module matches expected + verilog module matches expected starting at address for length bytes """ if debug: print(f"DEBUG: axi_ram.read: {axi_ram.read(address,length)}") @@ -104,10 +104,12 @@ async def run_module( # Start the execution module.go.value = 1 + #Used to test byte-addressable to calyx-width-addressable + base_address = 0x1000 # 4 bytes per integer - A0_size = len(A0_data) * 4 - B0_size = len(B0_data) * 4 - Sum0_size = 8 * 4 # hardcoded + A0_size = len(A0_data) * 4 + base_address + B0_size = len(B0_data) * 4 + base_address + Sum0_size = 8 * 4 + base_address # hardcoded because we dont pass in any sum data # anonymous mmep for now to back axiram A0_memmap = mmap.mmap(-1, A0_size) B0_memmap = mmap.mmap(-1, B0_size) @@ -146,31 +148,32 @@ async def run_module( A0_bytes = int_to_bytes(A0_data) B0_bytes = int_to_bytes(B0_data) - A0_memmap.seek(0) + A0_memmap.seek(base_address) A0_memmap.write(A0_bytes) A0_memmap.seek(0) - B0_memmap.seek(0) + B0_memmap.seek(base_address) B0_memmap.write(B0_bytes) B0_memmap.seek(0) - Sum0_memmap.seek(0) + Sum0_memmap.seek(base_address) await Timer(20, "ns") if debug: - A0.hexdump(0x0000, A0_size, prefix="A0 RAM") - B0.hexdump(0x0000, B0_size, prefix="B0 RAM") - Sum0.hexdump(0x0000, Sum0_size, prefix="Sum0 RAM") + A0.hexdump(base_address, A0_size - base_address , prefix="A0 RAM") + B0.hexdump(base_address, B0_size - base_address, prefix="B0 RAM") + Sum0.hexdump(base_address, Sum0_size - base_address, prefix="Sum0 RAM") await Timer(1000, "ns") if debug: - A0.hexdump(0x0000, A0_size, prefix="A0 RAM post") - B0.hexdump(0x0000, B0_size, prefix="B0 RAM post") - Sum0.hexdump(0x0000, Sum0_size, prefix="Sum0 RAM post") - - await assert_axi_ram_content(A0, A0_data[0:8]) - await assert_axi_ram_content(B0, B0_data[0:8]) - await assert_axi_ram_content(Sum0, Sum0_expected[0:8]) + A0.hexdump(base_address, A0_size - base_address, prefix="A0 RAM post") + B0.hexdump(base_address, B0_size - base_address, prefix="B0 RAM post") + Sum0.hexdump(base_address, Sum0_size - base_address, prefix="Sum0 RAM post") + + #TODO(nathanielnrn): dynamically pass in `length` currently uses default 8*4 for vec_add test + await assert_axi_ram_content(A0, A0_data[0:8], base_address) + await assert_axi_ram_content(B0, B0_data[0:8], base_address) + await assert_axi_ram_content(Sum0, Sum0_expected[0:8], base_address) if debug: print(f"A0 is: {module.A0.mem.value}") From 97ba200e53842d22a5f63e99d89f3061de2e0d1c Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Sat, 20 Jan 2024 22:25:56 -0500 Subject: [PATCH 142/189] Add parentheses around `==` and `!=` in builder (#1859) * Add parens to `eq` and `neq` in builder * runt tests --- calyx-py/calyx/py_ast.py | 4 ++-- tests/frontend/systolic/array-1.expect | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index 3605f9278..5b91d42c5 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -294,7 +294,7 @@ class Eq(GuardExpr): right: GuardExpr def doc(self) -> str: - return f"{self.left.doc()} == {self.right.doc()}" + return f"({self.left.doc()} == {self.right.doc()})" @dataclass @@ -303,7 +303,7 @@ class Neq(GuardExpr): right: GuardExpr def doc(self) -> str: - return f"{self.left.doc()} != {self.right.doc()}" + return f"({self.left.doc()} != {self.right.doc()})" # Control diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 506285de2..332495f07 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -148,7 +148,7 @@ component default_post_op(out_mem_0_done: 1, r0_valid: 1, r0_value: 32, r0_idx: } static<1> group write_done_cond { delay_reg.in = 1'd1; - delay_reg.write_en = (r0_valid & r0_idx == 1'd0) ? 1'd1; + delay_reg.write_en = (r0_valid & (r0_idx == 1'd0)) ? 1'd1; computation_done = delay_reg.done ? 1'd1; } } From 1992a46ae9ad25567f825f3eed79593cd75b6505 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Mon, 22 Jan 2024 14:20:03 -0500 Subject: [PATCH 143/189] [Docs] tiny addition about github practices (#1840) * tiny addition about github practices * Change the title * rachit notes * Update docs/github.md Co-authored-by: Adrian Sampson * Update docs/github.md Co-authored-by: Adrian Sampson * Update docs/github.md Co-authored-by: Adrian Sampson * Update docs/github.md Co-authored-by: Adrian Sampson --------- Co-authored-by: Adrian Sampson --- docs/SUMMARY.md | 1 + docs/github.md | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 docs/github.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index aedda9c6c..aa7899c04 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -35,6 +35,7 @@ - [Debugging](./debug/index.md) - [Logical Bugs](./debug/cider.md) - [Compilation Bugs](./debug/debug.md) +- [Contributing to Calyx](./github.md) # Generating Calyx diff --git a/docs/github.md b/docs/github.md new file mode 100644 index 000000000..013c48ec0 --- /dev/null +++ b/docs/github.md @@ -0,0 +1,38 @@ +# Contributing to Calyx + +## Github Workflow +The current home of the Calyx repo can be found [here][calyx_repo]. As with many +large projects, we protect the main branch of the repo so that updates can only +be made via pull requests. So the development cycle tends to look like: +``` +checkout main -> develop code -> open PR -> revise -> merge PR +``` + +For legibility of commits, we squash all commits in a PR down to a single commit +and merge the composite commit to the main branch. This helps keep the commit +count of the main branch lower than it would otherwise be; however, it can make +using commands like `git bisect` more challenging for large branches. For that +reason we tend to recommend more frequent PRs to avoid large deltas. + +Once your PR has been merged, be sure to ***check out the updated main branch*** +for future changes. If you branch off the merged branch or continue with it, +there will be extensive merge conflicts due to the squash and merge tactic. For +this reason we always recommend creating branches off of the main branch if you +intend to have them merged into it. + +### CI Behavior +The CI runs a number of tests including ensuring that Rust and Python code has +been formatted. For Python we use the [Black](https://github.com/psf/black) formatter and for Rust we use the +standard `cargo fmt`. + +For Rust further linting is done via [`clippy`][clippy] to ensure that there are +no warnings. In situations where warnings are expected, such as code that is +only part way through development, you can opt to add `#[allow]` annotations +within Rust to suppress the lint. + +If changes are made to the `Dockerfile` then the CI will automatically rebuild +the Docker image and run your tests on it. + + +[calyx_repo]: https://github.com/calyxir/calyx +[clippy]: https://github.com/rust-lang/rust-clippy From f478b493a9327ee81c0e8b109f1f53fe23cfa25b Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:36:44 -0500 Subject: [PATCH 144/189] Backend for listing instantiations of primitives (#1860) * First pass for backend to produce json file containing primitive instantiation info * pretty print the json * Map from param names to values * Fix clippy error * usage message * Fix doc comments * Change JSON format for parameter names and values * Fix formatting error * Changed naming and fixed unchanged name * Make parameter collection functional * Make fixes from PR comments --- calyx-backend/src/backend_opt.rs | 3 + calyx-backend/src/lib.rs | 2 + calyx-backend/src/primitive_uses.rs | 110 ++++++++++++++++++++++++++++ src/cmdline.rs | 8 +- 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 calyx-backend/src/primitive_uses.rs diff --git a/calyx-backend/src/backend_opt.rs b/calyx-backend/src/backend_opt.rs index 166189fb1..f11c73374 100644 --- a/calyx-backend/src/backend_opt.rs +++ b/calyx-backend/src/backend_opt.rs @@ -14,6 +14,7 @@ pub enum BackendOpt { Sexp, Yxi, Firrtl, + PrimitiveUses, None, } @@ -30,6 +31,7 @@ fn backends() -> Vec<(&'static str, BackendOpt)> { ("sexp", BackendOpt::Sexp), ("yxi", BackendOpt::Yxi), ("firrtl", BackendOpt::Firrtl), + ("primitive-uses", BackendOpt::PrimitiveUses), ("none", BackendOpt::None), ] } @@ -74,6 +76,7 @@ impl ToString for BackendOpt { Self::Yxi => "yxi", Self::Calyx => "calyx", Self::Firrtl => "firrtl", + Self::PrimitiveUses => "primitive-uses", Self::None => "none", } .to_string() diff --git a/calyx-backend/src/lib.rs b/calyx-backend/src/lib.rs index 2701920db..e2b9bf2f5 100644 --- a/calyx-backend/src/lib.rs +++ b/calyx-backend/src/lib.rs @@ -1,12 +1,14 @@ //! Backends for the Calyx compiler. mod backend_opt; mod firrtl; +mod primitive_uses; mod traits; mod verilog; mod yxi; pub use backend_opt::BackendOpt; pub use firrtl::FirrtlBackend; +pub use primitive_uses::PrimitiveUsesBackend; pub use traits::Backend; pub use verilog::VerilogBackend; pub use yxi::YxiBackend; diff --git a/calyx-backend/src/primitive_uses.rs b/calyx-backend/src/primitive_uses.rs new file mode 100644 index 000000000..8867e2f0d --- /dev/null +++ b/calyx-backend/src/primitive_uses.rs @@ -0,0 +1,110 @@ +//! Primitive instantiations backend for the Calyx compiler. +//! +//! Transforms an [`ir::Context`](crate::ir::Context) into a JSON file that +//! records the unique primitive instantiations in a program. +//! Usage: -b primitive-inst [-o ] +//! Adapted from resources.rs. + +use std::{collections::HashSet, io}; + +use crate::traits::Backend; +use calyx_ir as ir; +use calyx_utils::{CalyxResult, OutputFile}; +use serde::{Deserialize, Serialize}; + +#[derive(Default)] +pub struct PrimitiveUsesBackend; + +impl Backend for PrimitiveUsesBackend { + fn name(&self) -> &'static str { + "primitive_uses" + } + + /// OK to run this analysis on any Calyx program + fn validate(_ctx: &ir::Context) -> CalyxResult<()> { + Ok(()) + } + + /// Don't need to take care of this for this pass + fn link_externs( + _ctx: &ir::Context, + _file: &mut OutputFile, + ) -> CalyxResult<()> { + Ok(()) + } + + fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { + let main_comp = ctx.entrypoint(); + + let mut primitive_set: HashSet = HashSet::new(); + + gen_primitive_set(ctx, main_comp, &mut primitive_set); + + write_json(primitive_set.clone(), file)?; + + Ok(()) + } +} + +#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] +struct PrimitiveUse { + name: String, + params: Vec, +} + +#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] +struct PrimitiveParam { + param_name: String, + param_value: u64, +} + +/// Accumulates a set with each primitive with a given set of parameters +/// in the program with entrypoint `main_comp`. +fn gen_primitive_set( + ctx: &ir::Context, + main_comp: &ir::Component, + primitive_set: &mut HashSet, +) { + for cell in main_comp.cells.iter() { + let cell_ref = cell.borrow(); + match &cell_ref.prototype { + ir::CellType::Primitive { + name, + param_binding, + .. + } => { + let curr_params = param_binding + .iter() + .map(|(param_name, param_size)| PrimitiveParam { + param_name: param_name.to_string(), + param_value: *param_size, + }) + .collect(); + let curr_primitive = PrimitiveUse { + name: name.to_string(), + params: curr_params, + }; + (*primitive_set).insert(curr_primitive); + } + ir::CellType::Component { name } => { + let component = ctx + .components + .iter() + .find(|comp| comp.name == name) + .unwrap(); + gen_primitive_set(ctx, component, primitive_set); + } + _ => (), + } + } +} + +/// Write the collected set of primitive instantiations to a JSON file. +fn write_json( + primitive_set: HashSet, + file: &mut OutputFile, +) -> Result<(), io::Error> { + let created_vec: Vec = primitive_set.into_iter().collect(); + serde_json::to_writer_pretty(file.get_write(), &created_vec)?; + Ok(()) +} diff --git a/src/cmdline.rs b/src/cmdline.rs index 61cb1fb4f..93d9f5b01 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -4,8 +4,8 @@ use argh::FromArgs; use calyx_backend::SexpBackend; use calyx_backend::{ xilinx::{XilinxInterfaceBackend, XilinxXmlBackend}, - Backend, BackendOpt, FirrtlBackend, MlirBackend, ResourcesBackend, - VerilogBackend, YxiBackend, + Backend, BackendOpt, FirrtlBackend, MlirBackend, PrimitiveUsesBackend, + ResourcesBackend, VerilogBackend, YxiBackend, }; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error, OutputFile}; @@ -170,6 +170,10 @@ impl Opts { let backend = FirrtlBackend; backend.run(context, self.output) } + BackendOpt::PrimitiveUses => { + let backend = PrimitiveUsesBackend; + backend.run(context, self.output) + } BackendOpt::Calyx => { ir::Printer::write_context( &context, From 8e2fe15ce31ad4ce353c85f0603834d226e283d0 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Tue, 23 Jan 2024 10:41:05 -0500 Subject: [PATCH 145/189] Add `calyx-py` AXI generator address channels (#1855) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * simplify valid.in signals * WIP: replace groups with reg invokes * add python file that enables waveform (vcd/fst) generation * formatting * simplify valid.in signals * WIP: replace groups with reg invokes * Replaces register-init groups with invokes * Formatting of invokes * Replace reg groups with invokes in main * Modify tests to account for base address != 0 * Separate base-address calyx-mem-address dependency This solution, made for our load->compute->store scheme, simply increments the base_addr and curr_addr differently. This should make it easy to have multiple transactions, which this hardcoded does not support * move incrs into par block * iitial axi-generator commit * WIP get arread-channel working * Finished ARREAD channel. TODO: Compare two, look at getting binary built. Look at improving *_use/modifying to fit needs better * Create m_to_s_address_channel for {AR,AW} channels * WIP: Add read channel * Finished read_channel. Still need to fix #1850 * Finished read channels * Remove read channel to break up into multiple PRs --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-generator.py | 208 +++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 yxi/axi-calyx/axi-generator.py diff --git a/yxi/axi-calyx/axi-generator.py b/yxi/axi-calyx/axi-generator.py new file mode 100644 index 000000000..e93411528 --- /dev/null +++ b/yxi/axi-calyx/axi-generator.py @@ -0,0 +1,208 @@ +from calyx.builder import ( + Builder, + add_comp_params, + invoke, + while_with, + par, +) +from typing import Literal +from math import log2 +import json + +# In general, ports to the wrapper are uppercase, internal registers are lower case. + +yxi_input = """ +{ + "toplevel": "main", + "memories": [ + { + "name": "A0", + "width": 32, + "size": 8 + }, + { + "name": "B0", + "width": 32, + "size": 8 + }, + { + "name": "v0", + "width": 32, + "size": 1 + } + ] +} +""" + +yxi = json.loads(yxi_input) +mems = yxi["memories"] + + +def add_arread_channel(prog, mem): + _add_m_to_s_address_channel(prog, mem, "AR") + + +def add_awwrite_channel(prog, mem): + awwrite_channel = _add_m_to_s_address_channel(prog, mem, "AW") + max_transfers = awwrite_channel.reg("max_transfers", 8, is_ref=True) + + # TODO(nathanielnrn): We eventually want to move beyond + # the implicit 1 transaction that is the size of the memory + # How should we store this? + # Recall this goes to write channel as number of transfers it expectes to do before + # setting WLAST high + with awwrite_channel.get_group("do_aw_transfer"): + max_transfers.in_ = mem["size"] - 1 + max_transfers.write_en = 1 + + +def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): + """Adds a manager to subordinate + channel to the program. Uses `prefix` to name the channels + appropriately. Expected to be either "AW" or "AR." + Contains all of the channels shared between AW and AR channels. + + Returns a component builder in case there are additional + cells/wires/groups that need to be added to the component. + """ + + assert prefix in ["AW", "AR"], "Prefix must be either AW or AR." + + # Following Arm's notation of denoting `xVALID` and `xREADY` signals + # `x` stands for the prefix of the channel, i.e. `AW` or `AR` + lc_x = prefix.lower() + x = prefix + # Inputs/outputs + m_to_s_address_channel = prog.component(f"m_{lc_x}_channel") + channel_inputs = [("ARESETn", 1), (f"{x}READY", 1)] + channel_outputs = [ + (f"{x}VALID", 1), + (f"{x}ADDR", 64), + (f"{x}SIZE", 3), # bytes used in transfer + (f"{x}LEN", 8), # number of transfers in transaction + (f"{x}BURST", 2), # for XRT should be tied to 2'b01 for WRAP burst + (f"{x}PROT", 3), # tied to be priviliged, nonsecure, data access request + ] + add_comp_params(m_to_s_address_channel, channel_inputs, channel_outputs) + + # Cells + xvalid = m_to_s_address_channel.reg(f"{lc_x}valid", 1) + xvalid_was_high = m_to_s_address_channel.reg(f"{lc_x}valid_was_high", 1) + base_addr = m_to_s_address_channel.reg("base_addr", 64, is_ref=True) + xlen = m_to_s_address_channel.reg(f"{lc_x}len", 8) + + # Number of txns we want to occur before m_arread_channel is done + # TODO: parameterize + txn_n = m_to_s_address_channel.const("txn_n", 32, 1) + txn_count = m_to_s_address_channel.reg("txn_count", 32) + txn_adder = m_to_s_address_channel.add(32, "txn_adder") + + # Need to put block_transfer register here to avoid combinational loops + bt_reg = m_to_s_address_channel.reg("bt_reg", 1) + + # Wires + with m_to_s_address_channel.continuous: + m_to_s_address_channel.this()[f"{x}VALID"] = xvalid.out + + # Groups + # Responsible for asserting ARVALID, and deasserting it a cycle after the handshake. + # This is necesarry because of the way transitions between groups work. + # See #1828 https://github.com/calyxir/calyx/issues/1828 + with m_to_s_address_channel.group(f"do_{lc_x}_transfer") as do_x_transfer: + xREADY = m_to_s_address_channel.this()[f"{x}READY"] + # TODO: Can we simplify this? + # See comments #1846 https://github.com/calyxir/calyx/pull/1846 + # Assert arvalid if it was not previously high + xvalid.in_ = ~xvalid_was_high.out @ 1 + # Deassert in the next cycle once it is high + xvalid.in_ = (xvalid.out & xREADY & xvalid_was_high.out) @ 0 + xvalid.write_en = 1 + + xvalid_was_high.in_ = (~(xvalid.out & xREADY) & ~xvalid_was_high.out) @ 1 + xvalid_was_high.write_en = (~(xvalid.out & xREADY) & ~xvalid_was_high.out) @ 1 + + # Drive output signals for transfer + m_to_s_address_channel.this()[f"{x}ADDR"] = base_addr.out + # This is taken from mem size, we assume the databus width is the size + # of our memory cell and that width is a power of 2 + # TODO(nathanielnrn): convert to binary instead of decimal + m_to_s_address_channel.this()[f"{x}SIZE"] = width_xsize(mem["width"]) + # TODO(nathanielnrn): Figure our how to set arlen. For now set to size of mem. + m_to_s_address_channel.this()[f"{x}LEN"] = xlen.out + m_to_s_address_channel.this()[f"{x}BURST"] = 1 # Must be INCR for XRT + # Required by spec, we hardcode to privileged, non-secure, data access + m_to_s_address_channel.this()[f"{x}PROT"] = 0b110 + + # control block_transfer reg to go low after one cycle + bt_reg.in_ = (xREADY & xvalid.out) @ 1 + bt_reg.in_ = ~(xREADY & xvalid.out) @ 0 + bt_reg.write_en = 1 + do_x_transfer.done = bt_reg.out + + with m_to_s_address_channel.group("incr_txn_count") as incr_txn_count: + txn_adder.left = txn_count.out + txn_adder.right = 1 + txn_count.in_ = txn_adder.out + txn_count.write_en = 1 + incr_txn_count.done = txn_count.done + + # Control + # check if txn_count == txn_n + cellname = "perform_reads" if prefix == "AR" else "perform_writes" + check_transactions_done = m_to_s_address_channel.neq_use( + txn_count.out, txn_n.out, signed=False, cellname=cellname, width=32 + ) + # with arread_channel.comb_group("check_reads_done") as check_reads_done: + # perform_reads.left = txn_count.out + # perform_reads.right = txn_n.out + + invoke_txn_count = invoke(txn_count, in_in=0) + # ARLEN must be between 0-255, make sure to subtract 1 from yxi + # size when assigning to ARLEN + assert mem["size"] < 256, "Memory size must be less than 256" + invoke_xlen = invoke(xlen, in_in=mem["size"] - 1) + + while_body = [ + par( + invoke(bt_reg, in_in=0), + invoke(xvalid_was_high, in_in=0), + ), + do_x_transfer, + invoke(xvalid, in_in=0), + incr_txn_count, + ] + + while_loop = while_with(check_transactions_done, while_body) + m_to_s_address_channel.control += [invoke_txn_count, invoke_xlen, while_loop] + return m_to_s_address_channel + + +# Helper functions +def width_in_bytes(width: int): + assert width % 8 == 0, "Width must be a multiple of 8." + return width // 8 + + +def width_xsize(width: int): + log = log2(width_in_bytes(width)) + assert log.is_integer(), "Width must be a power of 2." + return int(log) + + +def clog2(x): + """Ceiling log2""" + if x <= 0: + raise ValueError("x must be positive") + return (x - 1).bit_length() + + +def build(): + prog = Builder() + # add_arread_channel(prog, mems[0]) + add_awwrite_channel(prog, mems[0]) + # add_read_channel(prog, mems[0]) + return prog.program + + +if __name__ == "__main__": + build().emit() From d08d239d4f7d0672ddab3fdda1e996f5b6896403 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Tue, 23 Jan 2024 15:47:40 -0500 Subject: [PATCH 146/189] Add `calyx-py` AXI generator read channel (#1856) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * simplify valid.in signals * WIP: replace groups with reg invokes * add python file that enables waveform (vcd/fst) generation * formatting * simplify valid.in signals * WIP: replace groups with reg invokes * Replaces register-init groups with invokes * Formatting of invokes * Replace reg groups with invokes in main * Modify tests to account for base address != 0 * Separate base-address calyx-mem-address dependency This solution, made for our load->compute->store scheme, simply increments the base_addr and curr_addr differently. This should make it easy to have multiple transactions, which this hardcoded does not support * move incrs into par block * iitial axi-generator commit * WIP get arread-channel working * Finished ARREAD channel. TODO: Compare two, look at getting binary built. Look at improving *_use/modifying to fit needs better * Create m_to_s_address_channel for {AR,AW} channels * WIP: Add read channel * Finished read_channel. Still need to fix #1850 * Finished read channels * Remove read channel to break up into multiple PRs * Add read channel back --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-generator.py | 125 ++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/yxi/axi-calyx/axi-generator.py b/yxi/axi-calyx/axi-generator.py index e93411528..1c3846c1a 100644 --- a/yxi/axi-calyx/axi-generator.py +++ b/yxi/axi-calyx/axi-generator.py @@ -4,9 +4,10 @@ invoke, while_with, par, + while_, ) from typing import Literal -from math import log2 +from math import log2, ceil import json # In general, ports to the wrapper are uppercase, internal registers are lower case. @@ -177,6 +178,124 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): return m_to_s_address_channel +def add_read_channel(prog, mem): + # Inputs/Outputs + read_channel = prog.component("m_read_channel") + # TODO(nathanielnrn): We currently assume RDATA is the same width as the + # memory. This limits throughput many AXI data busses are much wider + # i.e., 512 bits. + channel_inputs = [ + ("ARESETn", 1), + ("RVALID", 1), + ("RLAST", 1), + ("RDATA", mem["width"]), + ("RRESP", 2), + ] + channel_outputs = [("RREADY", 1)] + add_comp_params(read_channel, channel_inputs, channel_outputs) + + # Cells + + # We assume idx_size is exactly clog2(len). See comment in #1751 + # https://github.com/calyxir/calyx/issues/1751#issuecomment-1778360566 + mem_ref = read_channel.seq_mem_d1( + name="mem_ref", + bitwidth=mem["width"], + len=mem["size"], + idx_size=clog2(mem["size"]), + is_external=False, + is_ref=True, + ) + + # according to zipcpu, rready should be registered + rready = read_channel.reg("rready", 1) + curr_addr = read_channel.reg("curr_addr", clog2(mem["size"]), is_ref=True) + base_addr = read_channel.reg("base_addr", 64, is_ref=True) + # Registed because RLAST is high with laster transfer, not after + # before this we were terminating immediately with + # last transfer and not servicing it + n_RLAST = read_channel.reg("n_RLAST", 1) + # Stores data we want to write to our memory at end of block_transfer group + read_data_reg = read_channel.reg("read_data_reg", mem["width"]) + + bt_reg = read_channel.reg("bt_reg", 1) + + # Groups + with read_channel.continuous: + read_channel.this()["RREADY"] = rready.out + # Tie this low as we are only ever writing to seq_mem + mem_ref.read_en = 0 + + # Wait for handshake. Ensure that when this is done we are ready to write + # (i.e., read_data_reg.write_en = is_rdy.out) + # xVALID signals must be high until xREADY is high too, this works because + # if xREADY is high, then xVALID being high makes 1 flip and group + # is done by bt_reg.out + with read_channel.group("block_transfer") as block_transfer: + RVALID = read_channel.this()["RVALID"] + RDATA = read_channel.this()["RDATA"] + RLAST = read_channel.this()["RLAST"] + # TODO(nathanielnrn): We are allowed to have RREADY depend on RVALID. + # Can we simplify to just RVALID? + + # rready.in = 1 does not work because it leaves RREADY high for 2 cycles. + # The way it is below leaves it high for only 1 cycle. See #1828 + # https://github.com/calyxir/calyx/issues/1828 + + # TODO(nathanielnrn): Spec recommends defaulting xREADY high to get rid + # of extra cycles. Can we do this as opposed to waiting for RVALID? + rready.in_ = ~(rready.out & RVALID) @ 1 + rready.in_ = (rready.out & RVALID) @ 0 + rready.write_en = 1 + + # Store data we want to write + read_data_reg.in_ = RDATA + read_data_reg.write_en = (rready.out & RVALID) @ 1 + read_data_reg.write_en = ~(rready.out & RVALID) @ 0 + + n_RLAST.in_ = RLAST @ 0 + n_RLAST.in_ = ~RLAST @ 1 + n_RLAST.write_en = 1 + + # We are done after handshake + bt_reg.in_ = (rready.out & RVALID) @ 1 + bt_reg.in_ = ~(rready.out & RVALID) @ 0 + bt_reg.write_en = 1 + block_transfer.done = bt_reg.out + + with read_channel.group("service_read_transfer") as service_read_transfer: + # not ready till done servicing + rready.in_ = 0 + rready.write_en = 1 + + # write data we received to mem_ref + mem_ref.addr0 = curr_addr.out + mem_ref.write_data = read_data_reg.out + mem_ref.write_en = 1 + service_read_transfer.done = mem_ref.done + + # creates group that increments curr_addr by 1. Creates adder and wires up correctly + curr_addr_incr = read_channel.incr(curr_addr, 1) + # TODO(nathanielnrn): Currently we assume that width is a power of 2. + # In the future we should allow for non-power of 2 widths, will need some + # splicing for this. + # See https://cucapra.slack.com/archives/C05TRBNKY93/p1705587169286609?thread_ts=1705524171.974079&cid=C05TRBNKY93 # noqa: E501 + base_addr_incr = read_channel.incr(base_addr, ceil(mem["width"] / 8)) + + # Control + invoke_n_RLAST = invoke(n_RLAST, in_in=1) + invoke_bt_reg = invoke(bt_reg, in_in=0) + while_body = [ + invoke_bt_reg, + block_transfer, + service_read_transfer, + par(curr_addr_incr, base_addr_incr), + ] + while_n_RLAST = while_(n_RLAST.out, while_body) + + read_channel.control += [invoke_n_RLAST, while_n_RLAST] + + # Helper functions def width_in_bytes(width: int): assert width % 8 == 0, "Width must be a multiple of 8." @@ -198,9 +317,9 @@ def clog2(x): def build(): prog = Builder() - # add_arread_channel(prog, mems[0]) + add_arread_channel(prog, mems[0]) add_awwrite_channel(prog, mems[0]) - # add_read_channel(prog, mems[0]) + add_read_channel(prog, mems[0]) return prog.program From d8a6af6000474bae4e58773328de7c1a4f02fee5 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Tue, 23 Jan 2024 16:01:18 -0500 Subject: [PATCH 147/189] Add `calyx-py` AXI generator write channel (#1861) * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * update gitignore to get rid of sim_build and other cocotb artifacts * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * init commit of hardcoded axi wrapper for a 'main' kernel * add axi-reads-calix * hook up inputs to channels in the wrapper. tbd if this works * Working calyx verison of AR and R TBD if this actually implements AXI correctly. There are currently some hacks in place (marked with todos) to get this to compile, namely some splicing that doesn't consider what we actually want to splice (it just takes [31:0]) as opposed to dynamically considering actual bits we want. A few other things that should be cleaned up eventually Need to create a cocotb testbench to test correctness * Track output of compiled calyx read channel Maybe this shouldn't be here, but for now (having deleted my working directory earlier) putting it here * Working make files for running cocotb tests Simply run make from the cocotb directory and axi-read-tests will be executed * Add xID signals for cocotb compatability We tie ARID low in our manager * Fix prefix issue on cocotb axi test bench Prefixes should not contain trailing "_" * commit to repro 'make WAVES=1' cocotb error from axi-reads-calyx.futil * axi-reads patch * sync debug * Add txn_len initialization to 16 in calyx program * AXI Read fixed to get to read channel start Got rid of "assert_val" and "block_transfer" groups and instead perform these things inside "do_ar_transfer", this is required because we cant assert valid before we drive the data correctly, so needs to happen in parallel. Currently: This seems to write 16 times to same place, this is due to hardcoding of 16 in ar transfer, not sure why address doesn't increment this is tbd (and next TODO) * Add integer byte conversion for tests on Calyx AXI testharness * WIP get reads to work. Add incr_curr_addr group This is part of read channel control sequence * remove .fst from tracking * Add more data to testbench to make waveform viewing easier * Reads seem to be terminating correctly at RLAST * AR transfers seem to work, valid is high for 1 cycle * Unreduced axi-reads-calyx.futil Also reduces data bus width to 32 * Cocotb testbench now passes * Formatted and passing axi-read-tests * Reduce and comment axi-reads-calyx.futil * remove axi-reads.v from being tracked * add a todo * add required ARPROT signal. This is hardcoded to be priviliged * rename directories to yxi/axi-calyx * initial commit of axi-writes-calyx, a copy of axi-reads-calyx * WIP axi writes * rename directories * WIP imlpementing writes * add testing for writes, note makefile is overwritten so now tests writes, not reads * passing axi writes and testing * Work on full AXI wrapper, reads and compute works * cleaned up combined futil and tests * delete axi-reads* which is subsumed by axi-combined * add axi-combined-tests.py * remove axi-writes as it is subsumed by axi-combined * formatting * Update yxi/axi-calyx/axi-combined-calyx.futil Co-authored-by: Adrian Sampson * formatting * add sim.sh which goes from calyx to running tests * simplify valid.in signals * WIP: replace groups with reg invokes * add python file that enables waveform (vcd/fst) generation * formatting * simplify valid.in signals * WIP: replace groups with reg invokes * Replaces register-init groups with invokes * Formatting of invokes * Replace reg groups with invokes in main * Modify tests to account for base address != 0 * Separate base-address calyx-mem-address dependency This solution, made for our load->compute->store scheme, simply increments the base_addr and curr_addr differently. This should make it easy to have multiple transactions, which this hardcoded does not support * move incrs into par block * iitial axi-generator commit * WIP get arread-channel working * Finished ARREAD channel. TODO: Compare two, look at getting binary built. Look at improving *_use/modifying to fit needs better * Create m_to_s_address_channel for {AR,AW} channels * WIP: Add read channel * Finished read_channel. Still need to fix #1850 * Finished read channels * Remove read channel to break up into multiple PRs * Add read channel back * Create wrtie channel * add some parentheses to fix parsing errors * formating * fix incorrect init of finished_last_trnsfr register * add bresp channel (#1862) --------- Co-authored-by: Rachit Nigam Co-authored-by: Adrian Sampson --- yxi/axi-calyx/axi-generator.py | 166 +++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 6 deletions(-) diff --git a/yxi/axi-calyx/axi-generator.py b/yxi/axi-calyx/axi-generator.py index 1c3846c1a..89e87df33 100644 --- a/yxi/axi-calyx/axi-generator.py +++ b/yxi/axi-calyx/axi-generator.py @@ -153,9 +153,6 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): check_transactions_done = m_to_s_address_channel.neq_use( txn_count.out, txn_n.out, signed=False, cellname=cellname, width=32 ) - # with arread_channel.comb_group("check_reads_done") as check_reads_done: - # perform_reads.left = txn_count.out - # perform_reads.right = txn_n.out invoke_txn_count = invoke(txn_count, in_in=0) # ARLEN must be between 0-255, make sure to subtract 1 from yxi @@ -296,6 +293,161 @@ def add_read_channel(prog, mem): read_channel.control += [invoke_n_RLAST, while_n_RLAST] +def add_write_channel(prog, mem): + # Inputs/Outputs + write_channel = prog.component("m_write_channel") + # We assume idx_size is exactly clog2(len). See comment in #1751 + # https://github.com/calyxir/calyx/issues/1751#issuecomment-1778360566 + channel_inputs = [("ARESETn", 1), ("WREADY", 1)] + # TODO(nathanielnrn): We currently assume WDATA is the same width as the + # memory. This limits throughput many AXI data busses are much wider + # i.e., 512 bits. + channel_outputs = [ + ("WVALID", 1), + ("WLAST", 1), + ("WDATA", mem["width"]), + ] + add_comp_params(write_channel, channel_inputs, channel_outputs) + + # Cells + # We assume idx_size is exactly clog2(len). See comment in #1751 + # https://github.com/calyxir/calyx/issues/1751#issuecomment-1778360566 + mem_ref = write_channel.seq_mem_d1( + name="mem_ref", + bitwidth=mem["width"], + len=mem["size"], + idx_size=clog2(mem["size"]), + is_external=False, + is_ref=True, + ) + + # according to zipcpu, rready should be registered + wvalid = write_channel.reg("wvalid", 1) + wvalid_was_high = write_channel.reg("wvalid_was_high", 1) + # internal calyx memory indexing + curr_addr = write_channel.reg("curr_addr", clog2(mem["size"]), is_ref=True) + # host indexing, must be 64 bits + base_addr = write_channel.reg("base_addr", 64, is_ref=True) + + curr_trsnfr_count = write_channel.reg("curr_trsnfr_count", 8) + # Number of transfers we want to do in current txn + max_trnsfrs = write_channel.reg("max_trnsfrs", 8, is_ref=True) + + # Register because w last is high with last transfer. Before this + # We were terminating immediately with last transfer and not servicing it. + n_finished_last_trnsfr = write_channel.reg("n_finished_last_trnsfr", 1) + + bt_reg = write_channel.reg("bt_reg", 1) + + # Groups + with write_channel.continuous: + write_channel.this()["WVALID"] = wvalid.out + + with write_channel.group("service_write_transfer") as service_write_transfer: + WREADY = write_channel.this()["WREADY"] + + # Assert then deassert. Can maybe getgit right of wvalid_was_high in guard + wvalid.in_ = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 + wvalid.in_ = (wvalid.out & WREADY & wvalid_was_high.out) @ 0 + wvalid.write_en = 1 + + # Set high when wvalid is high even once + # This is just wavlid.in_ guard from above + # TODO: confirm this is correct? + wvalid_was_high.in_ = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 + wvalid_was_high.write_en = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 + + # Set data output based on intermal memory output + mem_ref.addr0 = curr_addr.out + mem_ref.read_en = 1 + write_channel.this()["WDATA"] = mem_ref.read_data + + write_channel.this()["WLAST"] = ( + max_trnsfrs.out == curr_trsnfr_count.out + ) @ 1 + write_channel.this()["WLAST"] = ( + max_trnsfrs.out != curr_trsnfr_count.out + ) @ 0 + + # set high when WLAST is high and a handshake occurs + n_finished_last_trnsfr.in_ = ( + (max_trnsfrs.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) + ) @ 0 + n_finished_last_trnsfr.write_en = ( + (max_trnsfrs.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) + ) @ 1 + + # done after handshake + bt_reg.in_ = (wvalid.out & WREADY) @ 1 + bt_reg.in_ = ~(wvalid.out & WREADY) @ 0 + bt_reg.write_en = 1 + service_write_transfer.done = bt_reg.out + + # creates group that increments curr_addr by 1. + # Creates adder and wires up correctly + curr_addr_incr = write_channel.incr(curr_addr, 1) + # TODO(nathanielnrn): Currently we assume that width is a power of 2. + # In the future we should allow for non-power of 2 widths, will need some + # splicing for this. + # See https://cucapra.slack.com/archives/C05TRBNKY93/p1705587169286609?thread_ts=1705524171.974079&cid=C05TRBNKY93 # noqa: E501 + base_addr_incr = write_channel.incr(base_addr, ceil(mem["width"] / 8)) + curr_trsnfr_count_incr = write_channel.incr(curr_trsnfr_count, 1) + + # Control + init_curr_addr = invoke(curr_addr, in_in=0) + init_n_finished_last_trnsfr = invoke(n_finished_last_trnsfr, in_in=1) + while_n_finished_last_trnsfr_body = [ + invoke(bt_reg, in_in=0), + service_write_transfer, + par(curr_addr_incr, curr_trsnfr_count_incr, base_addr_incr), + ] + while_n_finished_last_trnsfr = while_( + n_finished_last_trnsfr.out, while_n_finished_last_trnsfr_body + ) + write_channel.control += [ + init_curr_addr, + init_n_finished_last_trnsfr, + while_n_finished_last_trnsfr, + ] + + +# For now we assume all responses are OKAY because we don't have any error +# handling logic. So basically this sets BREADY high then lowers it on +# handshake. +def add_bresp_channel(prog, mem): + # Inputs/Outputs + bresp_channel = prog.component("m_bresp_channel") + # No BRESP because it is ignored, i.e we assume it is tied OKAY + channel_inputs = [("ARESETn", 1), ("BVALID", 1)] + channel_outputs = [("BREADY", 1)] + add_comp_params(bresp_channel, channel_inputs, channel_outputs) + + # Cells + bready = bresp_channel.reg("bready", 1) + bt_reg = bresp_channel.reg("bt_reg", 1) + + # Groups + with bresp_channel.continuous: + bresp_channel.this()["BREADY"] = bready.out + + # TODO(nathanielnrn): This is probably unoptimal and takes multiple + # cycles to do a simple handshake which we basically ignore. Can + # probably be much better. + with bresp_channel.group("block_transfer") as block_transfer: + BVALID = bresp_channel.this()["BVALID"] + bready.in_ = ~(bready.out & BVALID) @ 1 + bready.in_ = (bready.out & BVALID) @ 0 + bready.write_en = 1 + + bt_reg.in_ = (bready.out & BVALID) @ 1 + bt_reg.in_ = ~(bready.out & BVALID) @ 0 + bt_reg.write_en = 1 + block_transfer.done = bt_reg.out + + # Control + bresp_channel.control += [invoke(bt_reg, in_in=0), block_transfer] + + # Helper functions def width_in_bytes(width: int): assert width % 8 == 0, "Width must be a multiple of 8." @@ -317,9 +469,11 @@ def clog2(x): def build(): prog = Builder() - add_arread_channel(prog, mems[0]) - add_awwrite_channel(prog, mems[0]) - add_read_channel(prog, mems[0]) + # add_arread_channel(prog, mems[0]) + # add_awwrite_channel(prog, mems[0]) + # add_read_channel(prog, mems[0]) + # add_write_channel(prog, mems[0]) + add_bresp_channel(prog, mems[0]) return prog.program From cfe4c8abfebabbe10b19ea815f6d31b5bcbd27b4 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Wed, 24 Jan 2024 16:34:42 -0500 Subject: [PATCH 148/189] [Cider 2.0] Partial checkpoint (#1868) * add some more doc strings * mod changes * typo * partial checkpoint * words and stuff * sketch out the next_node search * delete * integrate partial use of the next_node fn * partial checkpoint * correct macro after changing names * change the primitive trait * it kinda simulates now * use bitor * Some basics * everything is extremely broken and I need to make new error types * we're compiling again --- interp/src/errors.rs | 23 +- interp/src/flatten/flat_ir/base.rs | 269 ++++-- .../src/flatten/flat_ir/control/structures.rs | 30 + interp/src/flatten/mod.rs | 4 +- interp/src/flatten/primitives/builder.rs | 15 +- .../src/flatten/primitives/combinational.rs | 228 ++++-- interp/src/flatten/primitives/macros.rs | 64 +- interp/src/flatten/primitives/prim_trait.rs | 95 ++- .../flatten/primitives/stateful/memories.rs | 183 +++-- .../structures/environment/assignments.rs | 71 ++ .../src/flatten/structures/environment/env.rs | 760 +++++++++++++++++ .../src/flatten/structures/environment/mod.rs | 774 +----------------- .../structures/environment/program_counter.rs | 173 ++-- interp/src/flatten/structures/mod.rs | 1 - interp/src/flatten/structures/values.rs | 30 - interp/src/logging.rs | 10 +- interp/src/main.rs | 2 +- 17 files changed, 1613 insertions(+), 1119 deletions(-) create mode 100644 interp/src/flatten/structures/environment/assignments.rs create mode 100644 interp/src/flatten/structures/environment/env.rs delete mode 100644 interp/src/flatten/structures/values.rs diff --git a/interp/src/errors.rs b/interp/src/errors.rs index 3ff1e0e34..a6547e962 100644 --- a/interp/src/errors.rs +++ b/interp/src/errors.rs @@ -1,5 +1,7 @@ -use crate::utils::assignment_to_string; use crate::values::Value; +use crate::{ + flatten::flat_ir::prelude::AssignedValue, utils::assignment_to_string, +}; use calyx_ir::{self as ir, Assignment, Id}; use calyx_utils::Error as CalyxError; use rustyline::error::ReadlineError; @@ -99,6 +101,17 @@ pub enum InterpreterError { a2: String, }, + #[error( + "conflicting assigns + 1. {a1} + 2. {a2} + " + )] + FlatConflictingAssignments { + a1: AssignedValue, + a2: AssignedValue, + }, + #[error("unable to find component named \"{0}\"")] UnknownComponent(String), @@ -155,6 +168,14 @@ pub enum InterpreterError { #[error(transparent)] IOError(#[from] std::io::Error), + + //TODO Griffin: Make this more descriptive + #[error("Attempted to write an undefined value to register or memory")] + UndefinedWrite, + + //TODO Griffin: Make this more descriptive + #[error("Attempted to write an undefined memory address")] + UndefinedWriteAddr, } impl InterpreterError { diff --git a/interp/src/flatten/flat_ir/base.rs b/interp/src/flatten/flat_ir/base.rs index 6745bd6d8..e91cd16fa 100644 --- a/interp/src/flatten/flat_ir/base.rs +++ b/interp/src/flatten/flat_ir/base.rs @@ -3,8 +3,11 @@ use std::{ ops::{Add, Sub}, }; -use crate::flatten::structures::index_trait::{ - impl_index, impl_index_nonzero, IndexRange, IndexRef, +use crate::{ + flatten::structures::index_trait::{ + impl_index, impl_index_nonzero, IndexRange, IndexRef, + }, + values::Value, }; use super::{cell_prototype::CellPrototype, prelude::Identifier}; @@ -41,23 +44,23 @@ impl_index!(RefPortDefinitionIdx); /// The index of a port instance in the global value map #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] -pub struct GlobalPortId(NonZeroU32); -impl_index_nonzero!(GlobalPortId); +pub struct GlobalPortIdx(NonZeroU32); +impl_index_nonzero!(GlobalPortIdx); /// The index of a cell instance in the global value map #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] -pub struct GlobalCellId(NonZeroU32); -impl_index_nonzero!(GlobalCellId); +pub struct GlobalCellIdx(NonZeroU32); +impl_index_nonzero!(GlobalCellIdx); /// The index of a ref cell instance in the global value map #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] -pub struct GlobalRefCellId(u32); -impl_index!(GlobalRefCellId); +pub struct GlobalRefCellIdx(u32); +impl_index!(GlobalRefCellIdx); /// The index of a ref port instance in the global value map #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] -pub struct GlobalRefPortId(u32); -impl_index!(GlobalRefPortId); +pub struct GlobalRefPortIdx(u32); +impl_index!(GlobalRefPortIdx); // Offset indices @@ -141,26 +144,35 @@ impl From for PortRef { /// after the relative offsets have been transformed via a component base location pub enum GlobalPortRef { /// A non-ref port with an exact address - Port(GlobalPortId), + Port(GlobalPortIdx), /// A reference port - Ref(GlobalRefPortId), + Ref(GlobalRefPortIdx), } -impl From for GlobalPortRef { - fn from(v: GlobalRefPortId) -> Self { +impl GlobalPortRef { + pub fn from_local(local: PortRef, base_info: &BaseIndices) -> Self { + match local { + PortRef::Local(l) => (base_info + l).into(), + PortRef::Ref(r) => (base_info + r).into(), + } + } +} + +impl From for GlobalPortRef { + fn from(v: GlobalRefPortIdx) -> Self { Self::Ref(v) } } -impl From for GlobalPortRef { - fn from(v: GlobalPortId) -> Self { +impl From for GlobalPortRef { + fn from(v: GlobalPortIdx) -> Self { Self::Port(v) } } impl GlobalPortRef { #[must_use] - pub fn as_port(&self) -> Option<&GlobalPortId> { + pub fn as_port(&self) -> Option<&GlobalPortIdx> { if let Self::Port(v) = self { Some(v) } else { @@ -169,7 +181,7 @@ impl GlobalPortRef { } #[must_use] - pub fn as_ref(&self) -> Option<&GlobalRefPortId> { + pub fn as_ref(&self) -> Option<&GlobalRefPortIdx> { if let Self::Ref(v) = self { Some(v) } else { @@ -243,6 +255,163 @@ impl From for CellRef { pub struct AssignmentIdx(u32); impl_index!(AssignmentIdx); +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AssignmentWinner { + /// Indicates that the "winning" assignment for this port was produced by a + /// cell computation rather than an assignment. Since cells cannot share + /// ports, there is no way for multiple cells to write the same output port, + /// thus we don't need to record the cell that assigned it. + Cell, + /// A concrete value produced by the control program + Implicit, + /// The assignment that produced this value. + Assign(AssignmentIdx), +} + +impl From for AssignmentWinner { + fn from(v: AssignmentIdx) -> Self { + Self::Assign(v) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AssignedValue { + val: Value, + winner: AssignmentWinner, +} + +impl std::fmt::Display for AssignedValue { + // TODO: replace with something more reasonable + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl AssignedValue { + pub fn new>(val: Value, winner: T) -> Self { + Self { + val, + winner: winner.into(), + } + } + + /// Returns true if the two AssignedValues do not have the same winner + pub fn has_conflict_with(&self, other: &Self) -> bool { + self.winner != other.winner + } + + pub fn val(&self) -> &Value { + &self.val + } + + pub fn winner(&self) -> &AssignmentWinner { + &self.winner + } + + pub fn implicit_bit_high() -> Self { + Self { + val: Value::bit_high(), + winner: AssignmentWinner::Implicit, + } + } + + #[inline] + pub fn cell_value(val: Value) -> Self { + Self { + val, + winner: AssignmentWinner::Cell, + } + } + + #[inline] + pub fn implicit_value(val: Value) -> Self { + Self { + val, + winner: AssignmentWinner::Implicit, + } + } + + #[inline] + pub fn cell_b_high() -> Self { + Self::cell_value(Value::bit_high()) + } + + #[inline] + pub fn cell_b_low() -> Self { + Self::cell_value(Value::bit_low()) + } +} + +#[derive(Debug, Clone)] +/// A wrapper struct around an option of an [AssignedValue] +pub struct PortValue(Option); + +impl std::fmt::Display for PortValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl PortValue { + pub fn is_undef(&self) -> bool { + self.0.is_none() + } + + pub fn is_def(&self) -> bool { + self.0.is_some() + } + + pub fn as_option(&self) -> Option<&AssignedValue> { + self.0.as_ref() + } + + pub fn as_bool(&self) -> Option { + self.0.as_ref().map(|x| x.val().as_bool()) + } + + pub fn as_usize(&self) -> Option { + self.0.as_ref().map(|x| x.val().as_usize()) + } + + pub fn val(&self) -> Option<&Value> { + self.0.as_ref().map(|x| &x.val) + } + + pub fn winner(&self) -> Option<&AssignmentWinner> { + self.0.as_ref().map(|x| &x.winner) + } + + pub fn new>(val: T) -> Self { + val.into() + } + + pub fn new_undef() -> Self { + Self(None) + } + + /// Creates a [PortValue] that has the "winner" as a cell + pub fn new_cell(val: Value) -> Self { + Self(Some(AssignedValue::cell_value(val))) + } + + /// Creates a [PortValue] that has the "winner" as implicit + pub fn new_implicit(val: Value) -> Self { + Self(Some(AssignedValue::implicit_value(val))) + } +} + +impl From> for PortValue { + fn from(value: Option) -> Self { + Self(value) + } +} + +impl From for PortValue { + fn from(value: AssignedValue) -> Self { + Self(Some(value)) + } +} + /// A global index for standard groups in the IR #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] pub struct GroupIdx(u32); @@ -339,18 +508,18 @@ mod sealed { #[derive(Debug, Clone)] pub struct BaseIndices { - pub port_base: GlobalPortId, - pub cell_base: GlobalCellId, - pub ref_cell_base: GlobalRefCellId, - pub ref_port_base: GlobalRefPortId, + pub port_base: GlobalPortIdx, + pub cell_base: GlobalCellIdx, + pub ref_cell_base: GlobalRefCellIdx, + pub ref_port_base: GlobalRefPortIdx, } impl BaseIndices { pub fn new( - port_base: GlobalPortId, - cell_base: GlobalCellId, - ref_cell_base: GlobalRefCellId, - ref_port_base: GlobalRefPortId, + port_base: GlobalPortIdx, + cell_base: GlobalCellIdx, + ref_cell_base: GlobalRefCellIdx, + ref_port_base: GlobalRefPortIdx, ) -> Self { Self { port_base, @@ -362,70 +531,70 @@ impl BaseIndices { } impl Add for &BaseIndices { - type Output = GlobalPortId; + type Output = GlobalPortIdx; fn add(self, rhs: LocalPortOffset) -> Self::Output { - GlobalPortId::new(self.port_base.index() + rhs.index()) + GlobalPortIdx::new(self.port_base.index() + rhs.index()) } } impl Add for &BaseIndices { - type Output = GlobalRefPortId; + type Output = GlobalRefPortIdx; fn add(self, rhs: LocalRefPortOffset) -> Self::Output { - GlobalRefPortId::new(self.ref_port_base.index() + rhs.index()) + GlobalRefPortIdx::new(self.ref_port_base.index() + rhs.index()) } } impl Add for &BaseIndices { - type Output = GlobalCellId; + type Output = GlobalCellIdx; fn add(self, rhs: LocalCellOffset) -> Self::Output { - GlobalCellId::new(self.cell_base.index() + rhs.index()) + GlobalCellIdx::new(self.cell_base.index() + rhs.index()) } } impl Add for &BaseIndices { - type Output = GlobalRefCellId; + type Output = GlobalRefCellIdx; fn add(self, rhs: LocalRefCellOffset) -> Self::Output { - GlobalRefCellId::new(self.ref_cell_base.index() + rhs.index()) + GlobalRefCellIdx::new(self.ref_cell_base.index() + rhs.index()) } } impl Add<&LocalPortOffset> for &BaseIndices { - type Output = GlobalPortId; + type Output = GlobalPortIdx; fn add(self, rhs: &LocalPortOffset) -> Self::Output { - GlobalPortId::new(self.port_base.index() + rhs.index()) + GlobalPortIdx::new(self.port_base.index() + rhs.index()) } } impl Add<&LocalRefPortOffset> for &BaseIndices { - type Output = GlobalRefPortId; + type Output = GlobalRefPortIdx; fn add(self, rhs: &LocalRefPortOffset) -> Self::Output { - GlobalRefPortId::new(self.ref_port_base.index() + rhs.index()) + GlobalRefPortIdx::new(self.ref_port_base.index() + rhs.index()) } } impl Add<&LocalCellOffset> for &BaseIndices { - type Output = GlobalCellId; + type Output = GlobalCellIdx; fn add(self, rhs: &LocalCellOffset) -> Self::Output { - GlobalCellId::new(self.cell_base.index() + rhs.index()) + GlobalCellIdx::new(self.cell_base.index() + rhs.index()) } } impl Add<&LocalRefCellOffset> for &BaseIndices { - type Output = GlobalRefCellId; + type Output = GlobalRefCellIdx; fn add(self, rhs: &LocalRefCellOffset) -> Self::Output { - GlobalRefCellId::new(self.ref_cell_base.index() + rhs.index()) + GlobalRefCellIdx::new(self.ref_cell_base.index() + rhs.index()) } } -impl Sub<&BaseIndices> for GlobalPortId { +impl Sub<&BaseIndices> for GlobalPortIdx { type Output = LocalPortOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -433,7 +602,7 @@ impl Sub<&BaseIndices> for GlobalPortId { } } -impl Sub<&BaseIndices> for GlobalRefPortId { +impl Sub<&BaseIndices> for GlobalRefPortIdx { type Output = LocalRefPortOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -441,7 +610,7 @@ impl Sub<&BaseIndices> for GlobalRefPortId { } } -impl Sub<&BaseIndices> for GlobalCellId { +impl Sub<&BaseIndices> for GlobalCellIdx { type Output = LocalCellOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -449,7 +618,7 @@ impl Sub<&BaseIndices> for GlobalCellId { } } -impl Sub<&BaseIndices> for GlobalRefCellId { +impl Sub<&BaseIndices> for GlobalRefCellIdx { type Output = LocalRefCellOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -457,7 +626,7 @@ impl Sub<&BaseIndices> for GlobalRefCellId { } } -impl Sub<&BaseIndices> for &GlobalPortId { +impl Sub<&BaseIndices> for &GlobalPortIdx { type Output = LocalPortOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -465,7 +634,7 @@ impl Sub<&BaseIndices> for &GlobalPortId { } } -impl Sub<&BaseIndices> for &GlobalRefPortId { +impl Sub<&BaseIndices> for &GlobalRefPortIdx { type Output = LocalRefPortOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -473,7 +642,7 @@ impl Sub<&BaseIndices> for &GlobalRefPortId { } } -impl Sub<&BaseIndices> for &GlobalCellId { +impl Sub<&BaseIndices> for &GlobalCellIdx { type Output = LocalCellOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { @@ -481,7 +650,7 @@ impl Sub<&BaseIndices> for &GlobalCellId { } } -impl Sub<&BaseIndices> for &GlobalRefCellId { +impl Sub<&BaseIndices> for &GlobalRefCellIdx { type Output = LocalRefCellOffset; fn sub(self, rhs: &BaseIndices) -> Self::Output { diff --git a/interp/src/flatten/flat_ir/control/structures.rs b/interp/src/flatten/flat_ir/control/structures.rs index beb839775..e802c0c60 100644 --- a/interp/src/flatten/flat_ir/control/structures.rs +++ b/interp/src/flatten/flat_ir/control/structures.rs @@ -48,6 +48,14 @@ impl Seq { pub fn stms(&self) -> &[ControlIdx] { &self.0 } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } } /// Parallel compositions of control nodes @@ -65,6 +73,14 @@ impl Par { pub fn stms(&self) -> &[ControlIdx] { &self.0 } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } } /// An if-then-else control node @@ -201,6 +217,20 @@ pub enum ControlNode { Invoke(Invoke), } +impl ControlNode { + pub fn is_leaf(&self) -> bool { + match self { + ControlNode::While(_) + | ControlNode::Seq(_) + | ControlNode::Par(_) + | ControlNode::If(_) => false, + ControlNode::Enable(_) + | ControlNode::Invoke(_) + | ControlNode::Empty(_) => true, + } + } +} + // --------------------- /// An enum indicating whether an entity is entirely local to the given context diff --git a/interp/src/flatten/mod.rs b/interp/src/flatten/mod.rs index 1cdb5ed86..15c94757b 100644 --- a/interp/src/flatten/mod.rs +++ b/interp/src/flatten/mod.rs @@ -3,9 +3,7 @@ pub mod primitives; mod structures; pub(crate) mod text_utils; -use structures::environment::Environment; - -use self::structures::environment::Simulator; +use structures::environment::{Environment, Simulator}; pub fn flat_main(ctx: &calyx_ir::Context) { let i_ctx = flat_ir::control::translator::translate(ctx); diff --git a/interp/src/flatten/primitives/builder.rs b/interp/src/flatten/primitives/builder.rs index 522694573..f2bbb8e9d 100644 --- a/interp/src/flatten/primitives/builder.rs +++ b/interp/src/flatten/primitives/builder.rs @@ -1,10 +1,7 @@ use crate::{ - flatten::{ - flat_ir::{ - cell_prototype::{CellPrototype, MemType, PrimType1}, - prelude::{CellInfo, GlobalPortId}, - }, - structures::environment::Environment, + flatten::flat_ir::{ + cell_prototype::{CellPrototype, MemType, PrimType1}, + prelude::{CellInfo, GlobalPortIdx}, }, values::Value, }; @@ -13,9 +10,8 @@ use super::{combinational::*, Primitive}; use super::{prim_trait::DummyPrimitive, stateful::*}; pub fn build_primitive( - env: &mut Environment, prim: &CellInfo, - base_port: GlobalPortId, + base_port: GlobalPortIdx, ) -> Box { match &prim.prototype { CellPrototype::Constant { @@ -24,7 +20,8 @@ pub fn build_primitive( c_type: _, } => { let v = Value::from(*val, *width); - env.ports[base_port] = v.clone(); + // TODO griffin: see if it is worth putting the initialization back + // env.ports[base_port] = v.clone(); Box::new(StdConst::new(v, base_port)) } diff --git a/interp/src/flatten/primitives/combinational.rs b/interp/src/flatten/primitives/combinational.rs index cef80fcd6..a1b389949 100644 --- a/interp/src/flatten/primitives/combinational.rs +++ b/interp/src/flatten/primitives/combinational.rs @@ -3,11 +3,12 @@ use std::ops::Not; use bitvec::vec::BitVec; use crate::{ + errors::InterpreterResult, flatten::{ - flat_ir::prelude::GlobalPortId, + flat_ir::prelude::{AssignedValue, GlobalPortIdx, PortValue}, primitives::{ - comb_primitive, declare_ports, output, ports, prim_trait::Results, - Primitive, + all_defined, comb_primitive, declare_ports, ports, + prim_trait::UpdateStatus, Primitive, }, structures::environment::PortMap, }, @@ -15,24 +16,31 @@ use crate::{ values::Value, }; +use super::prim_trait::UpdateResult; + pub struct StdConst { value: Value, - out: GlobalPortId, + out: GlobalPortIdx, } impl StdConst { - pub fn new(value: Value, out: GlobalPortId) -> Self { + pub fn new(value: Value, out: GlobalPortIdx) -> Self { Self { value, out } } } impl Primitive for StdConst { - fn exec_comb(&self, _port_map: &PortMap) -> Results { - Ok(vec![]) + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { + Ok(if port_map[self.out].is_undef() { + port_map[self.out] = PortValue::new_cell(self.value.clone()); + UpdateStatus::Changed + } else { + UpdateStatus::Unchanged + }) } - fn exec_cycle(&mut self, _port_map: &PortMap) -> Results { - Ok(vec![]) + fn exec_cycle(&mut self, _port_map: &mut PortMap) -> UpdateResult { + Ok(UpdateStatus::Unchanged) } fn has_comb(&self) -> bool { @@ -45,29 +53,42 @@ impl Primitive for StdConst { } pub struct StdMux { - base: GlobalPortId, + base: GlobalPortIdx, width: u32, } impl StdMux { declare_ports![ COND: 0, TRU: 1, FAL:2, OUT: 3]; - pub fn new(base: GlobalPortId, width: u32) -> Self { + pub fn new(base: GlobalPortIdx, width: u32) -> Self { Self { base, width } } } impl Primitive for StdMux { - fn exec_comb(&self, port_map: &PortMap) -> Results { + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base; cond: Self::COND, tru: Self::TRU, fal: Self::FAL, out: Self::OUT]; - let out_idx = if port_map[cond].as_bool() { tru } else { fal }; + let winning_idx = + port_map[cond].as_bool().map(|c| if c { tru } else { fal }); - Ok(output![out: port_map[out_idx].clone()]) + if winning_idx.is_some() && port_map[winning_idx.unwrap()].is_def() { + Ok(port_map.insert_val( + out, + AssignedValue::cell_value( + port_map[winning_idx.unwrap()].val().unwrap().clone(), + ), + )?) + } else { + port_map.write_undef(out)?; + Ok(UpdateStatus::Unchanged) + } } - fn reset(&mut self, _: &PortMap) -> Results { + fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { ports![&self.base; out: Self::OUT]; - Ok(output![out: Value::zeroes(self.width)]) + port_map.write_undef_unchecked(out); + + Ok(()) } fn has_stateful(&self) -> bool { @@ -76,15 +97,18 @@ impl Primitive for StdMux { } comb_primitive!(StdNot(input [0]) -> (out [1]) { - Ok(output![out: input.clone_bit_vec().not().into()]) + all_defined!(input); + Ok(Some(input.clone_bit_vec().not().into())) }); comb_primitive!(StdWire(input [0] ) -> (out [1]) { - Ok(output!(out: input.clone())) + Ok(input.val().cloned()) }); // ===================== Unsigned binary operations ====================== comb_primitive!(StdAdd(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); let mut c_in = false; @@ -102,16 +126,18 @@ comb_primitive!(StdAdd(left [0], right [1]) -> (out [2]) { let tr: Value = sum.into(); //as a sanity check, check tr has same width as left debug_assert_eq!(tr.width(), left.width()); - Ok(output![out: tr]) + Ok(Some(tr)) }); comb_primitive!(StdSub(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); // TODO griffin: the old approach is not possible with the way primitives work let result = Value::from(left.as_unsigned() - right.as_unsigned(), left.width()); - Ok(output![out: result]) + Ok(Some(result)) }); // TODO (Griffin): Make these wrappers around the normal add comb_primitive!(StdFpAdd(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); let a_iter = left.iter(); let b_iter = right.iter(); let mut c_in = false; @@ -129,17 +155,19 @@ comb_primitive!(StdFpAdd(left [0], right [1]) -> (out [2]) { //as a sanity check, check tr has same width as left debug_assert_eq!(tr.width(), left.width()); - Ok(output![out: tr]) + Ok(Some(tr)) }); comb_primitive!(StdFpSub(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); let result = Value::from(left.as_unsigned() - right.as_unsigned(), left.width()); - Ok(output![out: result]) + Ok(Some(result)) }); // ===================== Shift Operations ====================== comb_primitive!(StdLsh[WIDTH](left [0], right [1]) -> (out [2]) { + all_defined!(left, right); //to avoid the casting overflow, //we know that [left], [right], and [self] //are capped at bitwidths as large as largest u64 (2^64 - 1 = 1.84 * 10^19 ...) @@ -152,7 +180,7 @@ comb_primitive!(StdLsh[WIDTH](left [0], right [1]) -> (out [2]) { for bit in right.iter().by_ref().skip(64) { if bit { - return Ok(output![out: Value::zeroes(WIDTH as usize)]); + return Ok( Some(Value::zeroes(WIDTH as usize))); } } } @@ -186,10 +214,12 @@ comb_primitive!(StdLsh[WIDTH](left [0], right [1]) -> (out [2]) { let tr = Value::from_bv(tr); debug_assert_eq!(tr.width(), WIDTH as u64); //sanity check the widths - Ok(output![out: tr]) + Ok(Some(tr)) }); comb_primitive!(StdRsh[WIDTH](left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + //remove [right] bits from index 0 //extend to proper size @@ -198,7 +228,7 @@ comb_primitive!(StdRsh[WIDTH](left [0], right [1]) -> (out [2]) { //check if right is greater than or equal to 2 ^ 64 for bit in right.iter().skip(64) { if bit { - return Ok(output![out: Value::zeroes(WIDTH as usize)]); + return Ok( Some(Value::zeroes(WIDTH as usize))); } } } @@ -219,19 +249,23 @@ comb_primitive!(StdRsh[WIDTH](left [0], right [1]) -> (out [2]) { let tr = Value::from_bv(tr); debug_assert_eq!(tr.width(), WIDTH as u64); //sanity check the widths - Ok(output![out: tr]) + Ok(Some(tr)) }); // ===================== Signed Shift Operations ====================== comb_primitive!(StdSlsh(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let shift_amount = right.as_usize(); let mut val = left.clone_bit_vec(); val.shift_right(shift_amount); let result: Value = val.into(); - Ok(output![out: result]) + Ok(Some(result)) }); comb_primitive!(StdSrsh(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let shift_amount = right.as_usize(); let sign: bool = left[left.len()-1]; //msb let mut val = left.clone_bit_vec(); @@ -242,24 +276,32 @@ comb_primitive!(StdSrsh(left [0], right [1]) -> (out [2]) { } } let result: Value = val.into(); - Ok(output![out: result]) + Ok(Some(result)) }); // ===================== Logial Operations ====================== comb_primitive!(StdAnd(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let result: Value = (left.clone_bit_vec() & right.clone_bit_vec()).into(); - Ok(output![out: result]) + Ok(Some(result)) }); comb_primitive!(StdOr(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let result: Value = (left.clone_bit_vec() | right.clone_bit_vec()).into(); - Ok(output![out: result]) + Ok(Some(result)) }); comb_primitive!(StdXor(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let result: Value = (left.clone_bit_vec() ^ right.clone_bit_vec()).into(); - Ok(output![out: result]) + Ok(Some(result)) }); // ===================== Comparison Operations ====================== comb_primitive!(StdGt(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); let mut tr = false; @@ -271,13 +313,15 @@ comb_primitive!(StdGt(left [0], right [1]) -> (out [2]) { tr = ai & !bi || tr & !bi || tr & ai; } - Ok(output![out: if tr { + Ok(Some(if tr { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdLt(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); let mut tr = false; @@ -289,13 +333,15 @@ comb_primitive!(StdLt(left [0], right [1]) -> (out [2]) { //same as gt, just reverse the if. //but actually not so if they are equal... should change the loop - Ok(output![out: if tr { + Ok(Some(if tr { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdGe(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); let mut tr = true; //diff between gt and ge is just assume they r equal @@ -307,13 +353,15 @@ comb_primitive!(StdGe(left [0], right [1]) -> (out [2]) { tr = ai & !bi || tr & !bi || tr & ai; } - Ok(output![out: if tr { + Ok(Some(if tr { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdLe(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); let mut tr = true; //diff between le and lt is just assume they are equal @@ -325,142 +373,180 @@ comb_primitive!(StdLe(left [0], right [1]) -> (out [2]) { //same as gt, just reverse the if. //but actually not so if they are equal... should change the loop - Ok(output![out: if tr { + Ok(Some(if tr { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdEq(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); //tr represents a = b for (ai, bi) in a_iter.zip(b_iter) { if !ai & bi || !bi & ai { - return Ok(output![out: Value::bit_low()]); + return Ok(Some(Value::bit_low())); } } - Ok(output![out: Value::bit_high()]) + Ok(Some(Value::bit_high())) }); comb_primitive!(StdNeq(left [0], right [1]) -> (out [2]) { + all_defined!(left, right); + let a_iter = left.iter(); let b_iter = right.iter(); //tr represents a = b for (ai, bi) in a_iter.zip(b_iter) { if bi & !ai || !bi & ai { - return Ok(output![out: Value::bit_high()]); + return Ok(Some(Value::bit_high())); } } - Ok(output![out:Value::bit_low()]) + Ok(Some(Value::bit_low())) }); // ===================== Signed Comparison Operations ====================== comb_primitive!(StdSgt(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() > right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() > right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdSlt(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() < right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() < right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdSge(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() >= right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() >= right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdSle(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() <= right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() <= right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdSeq(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() == right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() == right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdSneq(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() != right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() != right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); // ===================== Unsigned FP Comparison Operators ====================== comb_primitive!(StdFpGt(left [0], right [1]) -> (out [2]) { - Ok(output![out: - if left.as_unsigned() > right.as_unsigned() { + all_defined!(left, right); + + Ok( + Some(if left.as_unsigned() > right.as_unsigned() { Value::bit_high() } else { Value::bit_low() - }] + }) ) }); // ===================== Signed FP Comparison Operators ====================== comb_primitive!(StdFpSgt(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() > right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() > right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); comb_primitive!(StdFpSlt(left [0], right [1]) -> (out [2]) { - Ok(output![out: if left.as_signed() < right.as_signed() { + all_defined!(left, right); + + Ok( Some(if left.as_signed() < right.as_signed() { Value::bit_high() } else { Value::bit_low() - }]) + })) }); // ===================== Resizing Operations ====================== comb_primitive!(StdSlice[OUT_WIDTH](input [0]) -> (out [1]) { - Ok(output![out: input.truncate(OUT_WIDTH as usize)]) + all_defined!(input); + + Ok( Some(input.truncate(OUT_WIDTH as usize))) }); comb_primitive!(StdPad[OUT_WIDTH](input [0]) -> (out [1]) { - Ok(output![out: input.ext(OUT_WIDTH as usize)]) + all_defined!(input); + + Ok( Some(input.ext(OUT_WIDTH as usize))) }); // ===================== Unsynthesizeable Operations ====================== comb_primitive!(StdUnsynMult[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_unsigned() * right.as_unsigned(), WIDTH)]) + all_defined!(left, right); + + Ok( Some(Value::from(left.as_unsigned() * right.as_unsigned(), WIDTH))) }); comb_primitive!(StdUnsynDiv[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_unsigned() / right.as_unsigned(), WIDTH)]) + all_defined!(left, right); + + Ok( Some(Value::from(left.as_unsigned() / right.as_unsigned(), WIDTH))) }); comb_primitive!(StdUnsynSmult[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_signed() * right.as_signed(), WIDTH)]) + all_defined!(left, right); + + Ok( Some(Value::from(left.as_signed() * right.as_signed(), WIDTH))) }); comb_primitive!(StdUnsynSdiv[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_signed() / right.as_signed(), WIDTH)]) + all_defined!(left, right); + + Ok( Some(Value::from(left.as_signed() / right.as_signed(), WIDTH))) }); comb_primitive!(StdUnsynMod[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_unsigned() % right.as_unsigned(), WIDTH)]) + all_defined!(left, right); + + Ok( Some(Value::from(left.as_unsigned() % right.as_unsigned(), WIDTH))) }); comb_primitive!(StdUnsynSmod[WIDTH](left [0], right [1]) -> (out [2]) { - Ok(output![out: Value::from(left.as_signed() - right.as_signed() * floored_division( + all_defined!(left, right); + + Ok( Some(Value::from(left.as_signed() - right.as_signed() * floored_division( &left.as_signed(), - &right.as_signed()), WIDTH)]) + &right.as_signed()), WIDTH))) }); diff --git a/interp/src/flatten/primitives/macros.rs b/interp/src/flatten/primitives/macros.rs index 0c068d7b8..79162465f 100644 --- a/interp/src/flatten/primitives/macros.rs +++ b/interp/src/flatten/primitives/macros.rs @@ -1,6 +1,6 @@ macro_rules! ports { ($base:expr; $( $port:ident : $offset:expr ),+ ) => { - $(let $port: $crate::flatten::flat_ir::prelude::GlobalPortId = ($crate::flatten::structures::index_trait::IndexRef::index($base) + $offset).into();)+ + $(let $port: $crate::flatten::flat_ir::prelude::GlobalPortIdx = ($crate::flatten::structures::index_trait::IndexRef::index($base) + $offset).into();)+ } } @@ -14,17 +14,11 @@ macro_rules! declare_ports { } } -macro_rules! output { - ( $( $port:ident : $value:expr ),+ $(,)? ) => { - vec![$( ($port, $value).into(),)+] - } -} - macro_rules! make_getters { ($base:ident; $( $port:ident : $offset:expr ),+ ) => { $( #[inline] - fn $port(&self) -> $crate::flatten::flat_ir::prelude::GlobalPortId { + fn $port(&self) -> $crate::flatten::flat_ir::prelude::GlobalPortIdx { ($crate::flatten::structures::index_trait::IndexRef::index(&self.$base) + $offset).into() } )+ @@ -34,30 +28,30 @@ macro_rules! make_getters { pub(crate) use declare_ports; pub(crate) use make_getters; -pub(crate) use output; + pub(crate) use ports; macro_rules! comb_primitive { ($name:ident$([$($param:ident),+])? ( $($port:ident [$port_idx:expr]),+ ) -> - ($($out_port:ident [$out_port_idx:expr]),+) + ($out_port:ident [$out_port_idx:expr]) $execute:block) => { #[derive(Clone, Debug)] #[allow(non_snake_case)] pub struct $name { $($($param: u32,)+)? - base_port: $crate::flatten::flat_ir::prelude::GlobalPortId + base_port: $crate::flatten::flat_ir::prelude::GlobalPortIdx } impl $name { $crate::flatten::primitives::macros::declare_ports![$($port: $port_idx),+]; - $crate::flatten::primitives::macros::declare_ports![$($out_port: $out_port_idx),+]; + $crate::flatten::primitives::macros::declare_ports![$out_port: $out_port_idx,]; #[allow(non_snake_case)] pub fn new( - base_port: $crate::flatten::flat_ir::prelude::GlobalPortId, + base_port: $crate::flatten::flat_ir::prelude::GlobalPortIdx, $($($param: u32,)+)? ) -> Self { Self { @@ -70,39 +64,63 @@ macro_rules! comb_primitive { impl $crate::flatten::primitives::Primitive for $name { fn exec_comb( &self, - port_map: &$crate::flatten::structures::environment::PortMap, - ) -> $crate::flatten::primitives::prim_trait::Results { + port_map: &mut $crate::flatten::structures::environment::PortMap, + ) -> $crate::flatten::primitives::prim_trait::UpdateResult { $crate::flatten::primitives::macros::ports![&self.base_port; $($port: Self::$port,)+ - $($out_port: Self::$out_port),+ + $out_port: Self::$out_port ]; + #[allow(non_snake_case)] - let exec_func = |$($($param: u32,)+)? $($port: &$crate::values::Value),+, $($out_port:$crate::flatten::flat_ir::prelude::GlobalPortId,)+ | -> $crate::flatten::primitives::prim_trait::Results { + let exec_func = |$($($param: u32,)+)? $($port: &$crate::flatten::flat_ir::prelude::PortValue),+| ->$crate::errors::InterpreterResult> { $execute }; - let out = exec_func( + let output = exec_func( $($(self.$param,)*)? $(&port_map[$port],)+ - $($out_port,)+ - ); - out + )?; + + if let Some(val) = output { + if port_map[$out_port].val().is_some() && *port_map[$out_port].val().unwrap() == val { + Ok($crate::flatten::primitives::prim_trait::UpdateStatus::Unchanged) + } else { + port_map[$out_port] = $crate::flatten::flat_ir::prelude::PortValue::new_cell(val); + Ok($crate::flatten::primitives::prim_trait::UpdateStatus::Changed) + } + } else { + port_map.write_undef($out_port)?; + Ok($crate::flatten::primitives::prim_trait::UpdateStatus::Unchanged) + } } fn has_stateful(&self) -> bool { false } - fn reset(&mut self, map:&$crate::flatten::structures::environment::PortMap) -> $crate::flatten::primitives::prim_trait::Results { - self.exec_comb(map) + fn reset(&mut self, map:&mut $crate::flatten::structures::environment::PortMap) -> $crate::errors::InterpreterResult<()> { + self.exec_comb(map)?; + Ok(()) } } }; } +macro_rules! all_defined { + ($($port_name:ident),+) => { + #[allow(unused_parens)] + let ($($port_name),+) = if [$($port_name),+].iter().all(|x|x.is_def()) { + ($($port_name.val().unwrap()),+) + } else { + return Ok(None); + }; + }; +} + +pub(crate) use all_defined; pub(crate) use comb_primitive; diff --git a/interp/src/flatten/primitives/prim_trait.rs b/interp/src/flatten/primitives/prim_trait.rs index 2d039f87b..d5d22b5bc 100644 --- a/interp/src/flatten/primitives/prim_trait.rs +++ b/interp/src/flatten/primitives/prim_trait.rs @@ -1,48 +1,113 @@ use crate::{ debugger::PrintCode, errors::InterpreterResult, - flatten::{flat_ir::base::GlobalPortId, structures::environment::PortMap}, + flatten::{flat_ir::base::GlobalPortIdx, structures::environment::PortMap}, primitives::Serializable, values::Value, }; pub struct AssignResult { - pub destination: GlobalPortId, + pub destination: GlobalPortIdx, pub value: Value, } impl AssignResult { - pub fn new(destination: GlobalPortId, value: Value) -> Self { + pub fn new(destination: GlobalPortIdx, value: Value) -> Self { Self { destination, value } } } -impl From<(GlobalPortId, Value)> for AssignResult { - fn from(value: (GlobalPortId, Value)) -> Self { +impl From<(GlobalPortIdx, Value)> for AssignResult { + fn from(value: (GlobalPortIdx, Value)) -> Self { Self::new(value.0, value.1) } } -impl From<(Value, GlobalPortId)> for AssignResult { - fn from(value: (Value, GlobalPortId)) -> Self { +impl From<(Value, GlobalPortIdx)> for AssignResult { + fn from(value: (Value, GlobalPortIdx)) -> Self { Self::new(value.1, value.0) } } -/// The return value for evaluating the results of a primitive -pub type Results = InterpreterResult>; +/// An enum used to denote whether or not committed updates changed the state +pub enum UpdateStatus { + Unchanged, + Changed, +} + +impl From for UpdateStatus { + fn from(value: bool) -> Self { + if value { + Self::Changed + } else { + Self::Unchanged + } + } +} + +impl UpdateStatus { + #[inline] + /// If the status is unchanged and other is changed, updates the status of + /// self to changed, otherwise does nothing + pub fn update(&mut self, other: Self) { + if !self.is_changed() && other.is_changed() { + *self = UpdateStatus::Changed; + } + } + + #[inline] + /// Returns `true` if the update status is [`Changed`]. + /// + /// [`Changed`]: UpdateStatus::Changed + #[must_use] + pub fn is_changed(&self) -> bool { + matches!(self, Self::Changed) + } +} + +impl std::ops::BitOr for UpdateStatus { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + if self.is_changed() || rhs.is_changed() { + UpdateStatus::Changed + } else { + UpdateStatus::Unchanged + } + } +} + +impl std::ops::BitOr for &UpdateStatus { + type Output = UpdateStatus; + + fn bitor(self, rhs: Self) -> Self::Output { + if self.is_changed() || rhs.is_changed() { + UpdateStatus::Changed + } else { + UpdateStatus::Unchanged + } + } +} + +impl std::ops::BitOrAssign for UpdateStatus { + fn bitor_assign(&mut self, rhs: Self) { + self.update(rhs) + } +} + +pub type UpdateResult = InterpreterResult; pub trait Primitive { - fn exec_comb(&self, _port_map: &PortMap) -> Results { - Ok(vec![]) + fn exec_comb(&self, _port_map: &mut PortMap) -> UpdateResult { + Ok(UpdateStatus::Unchanged) } - fn exec_cycle(&mut self, _port_map: &PortMap) -> Results { - Ok(vec![]) + fn exec_cycle(&mut self, _port_map: &mut PortMap) -> UpdateResult { + Ok(UpdateStatus::Unchanged) } - fn reset(&mut self, _port_map: &PortMap) -> Results { - Ok(vec![]) + fn reset(&mut self, _port_map: &mut PortMap) -> InterpreterResult<()> { + Ok(()) } fn has_comb(&self) -> bool { diff --git a/interp/src/flatten/primitives/stateful/memories.rs b/interp/src/flatten/primitives/stateful/memories.rs index a6b127af6..9c5c9a98b 100644 --- a/interp/src/flatten/primitives/stateful/memories.rs +++ b/interp/src/flatten/primitives/stateful/memories.rs @@ -1,8 +1,10 @@ use crate::{ + errors::{InterpreterError, InterpreterResult}, flatten::{ - flat_ir::prelude::GlobalPortId, + flat_ir::prelude::{AssignedValue, GlobalPortIdx, PortValue}, primitives::{ - declare_ports, make_getters, output, ports, prim_trait::Results, + declare_ports, make_getters, ports, + prim_trait::{UpdateResult, UpdateStatus}, Primitive, }, structures::environment::PortMap, @@ -12,14 +14,14 @@ use crate::{ }; pub struct StdReg { - base_port: GlobalPortId, + base_port: GlobalPortIdx, internal_state: Value, } impl StdReg { declare_ports![IN: 0, WRITE_EN: 1, CLK: 2, RESET: 3, OUT: 4, DONE: 5]; - pub fn new(base_port: GlobalPortId, width: u32) -> Self { + pub fn new(base_port: GlobalPortIdx, width: u32) -> Self { let internal_state = Value::zeroes(width); Self { base_port, @@ -29,35 +31,52 @@ impl StdReg { } impl Primitive for StdReg { - fn exec_cycle(&mut self, port_map: &PortMap) -> Results { + fn exec_cycle(&mut self, port_map: &mut PortMap) -> UpdateResult { ports![&self.base_port; input: Self::IN, write_en: Self::WRITE_EN, reset: Self::RESET, - out: Self::OUT, + out_idx: Self::OUT, done: Self::DONE ]; - let out = if port_map[reset].as_bool() { + let done_port = if port_map[reset].as_bool().unwrap_or_default() { self.internal_state = Value::zeroes(self.internal_state.width()); - output![ out: self.internal_state.clone(), done: Value::bit_low() ] - } else if port_map[write_en].as_bool() { - self.internal_state = port_map[input].clone(); - output![ out: self.internal_state.clone(), done: Value::bit_high() ] + port_map + .insert_val(done, AssignedValue::cell_value(Value::bit_low())) + } else if port_map[write_en].as_bool().unwrap_or_default() { + self.internal_state = port_map[input] + .as_option() + .ok_or(InterpreterError::UndefinedWrite)? + .val() + .clone(); + + port_map + .insert_val(done, AssignedValue::cell_value(Value::bit_high())) } else { - output![ out: self.internal_state.clone(), done: Value::bit_high() ] - }; - - Ok(out) + port_map + .insert_val(done, AssignedValue::cell_value(Value::bit_low())) + }?; + + Ok(done_port + | port_map.insert_val( + out_idx, + AssignedValue::cell_value(self.internal_state.clone()), + )?) } - fn reset(&mut self, _: &PortMap) -> Results { + fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { ports![&self.base_port; done: Self::DONE]; - Ok(output![done: Value::bit_low()]) + port_map[done] = PortValue::new_cell(Value::bit_low()); + Ok(()) } - fn has_comb(&self) -> bool { - false + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { + ports![&self.base_port; out_idx: Self::OUT]; + port_map.insert_val( + out_idx, + AssignedValue::cell_value(self.internal_state.clone()), + ) } fn serialize( @@ -81,8 +100,8 @@ pub trait MemAddresser { fn calculate_addr( &self, port_map: &PortMap, - base_port: GlobalPortId, - ) -> usize; + base_port: GlobalPortIdx, + ) -> Option; } pub struct MemD1; @@ -91,8 +110,8 @@ impl MemAddresser for MemD1 { fn calculate_addr( &self, port_map: &PortMap, - base_port: GlobalPortId, - ) -> usize { + base_port: GlobalPortIdx, + ) -> Option { let addr0 = if SEQ { ports![&base_port; addr0: Self::SEQ_ADDR0]; addr0 @@ -127,8 +146,8 @@ impl MemAddresser for MemD2 { fn calculate_addr( &self, port_map: &PortMap, - base_port: GlobalPortId, - ) -> usize { + base_port: GlobalPortIdx, + ) -> Option { let (addr0, addr1) = if SEQ { ports![&base_port; addr0: Self::SEQ_ADDR0, @@ -141,10 +160,10 @@ impl MemAddresser for MemD2 { (addr0, addr1) }; - let a0 = port_map[addr0].as_usize(); - let a1 = port_map[addr1].as_usize(); + let a0 = port_map[addr0].as_usize()?; + let a1 = port_map[addr1].as_usize()?; - a0 * self.d1_size + a1 + Some(a0 * self.d1_size + a1) } const NON_ADDRESS_BASE: usize = if SEQ { @@ -169,8 +188,8 @@ impl MemAddresser for MemD3 { fn calculate_addr( &self, port_map: &PortMap, - base_port: GlobalPortId, - ) -> usize { + base_port: GlobalPortIdx, + ) -> Option { let (addr0, addr1, addr2) = if SEQ { ports![&base_port; addr0: Self::SEQ_ADDR0, @@ -188,11 +207,11 @@ impl MemAddresser for MemD3 { (addr0, addr1, addr2) }; - let a0 = port_map[addr0].as_usize(); - let a1 = port_map[addr1].as_usize(); - let a2 = port_map[addr2].as_usize(); + let a0 = port_map[addr0].as_usize()?; + let a1 = port_map[addr1].as_usize()?; + let a2 = port_map[addr2].as_usize()?; - a0 * (self.d1_size * self.d2_size) + a1 * self.d2_size + a2 + Some(a0 * (self.d1_size * self.d2_size) + a1 * self.d2_size + a2) } const NON_ADDRESS_BASE: usize = if SEQ { @@ -221,8 +240,8 @@ impl MemAddresser for MemD4 { fn calculate_addr( &self, port_map: &PortMap, - base_port: GlobalPortId, - ) -> usize { + base_port: GlobalPortIdx, + ) -> Option { let (addr0, addr1, addr2, addr3) = if SEQ { ports![&base_port; addr0: Self::SEQ_ADDR0, @@ -242,15 +261,17 @@ impl MemAddresser for MemD4 { (addr0, addr1, addr2, addr3) }; - let a0 = port_map[addr0].as_usize(); - let a1 = port_map[addr1].as_usize(); - let a2 = port_map[addr2].as_usize(); - let a3 = port_map[addr3].as_usize(); + let a0 = port_map[addr0].as_usize()?; + let a1 = port_map[addr1].as_usize()?; + let a2 = port_map[addr2].as_usize()?; + let a3 = port_map[addr3].as_usize()?; - a0 * (self.d1_size * self.d2_size * self.d3_size) - + a1 * (self.d2_size * self.d3_size) - + a2 * self.d3_size - + a3 + Some( + a0 * (self.d1_size * self.d2_size * self.d3_size) + + a1 * (self.d2_size * self.d3_size) + + a2 * self.d3_size + + a3, + ) } const NON_ADDRESS_BASE: usize = if SEQ { @@ -261,7 +282,7 @@ impl MemAddresser for MemD4 { } pub struct StdMem { - base_port: GlobalPortId, + base_port: GlobalPortIdx, internal_state: Vec, allow_invalid_access: bool, width: u32, @@ -288,41 +309,63 @@ impl StdMem { } impl Primitive for StdMem { - fn exec_comb(&self, port_map: &PortMap) -> Results { + fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { let addr = self.addresser.calculate_addr(port_map, self.base_port); let read_data = self.read_data(); - if addr < self.internal_state.len() { - Ok(output![read_data: self.internal_state[addr].clone()]) - } else { + + if addr.is_some() && addr.unwrap() < self.internal_state.len() { + Ok(port_map.insert_val( + read_data, + AssignedValue::cell_value( + self.internal_state[addr.unwrap()].clone(), + ), + )?) + } + // either the address is undefined or it is outside the range of valid addresses + else { // throw error on cycle boundary rather than here - Ok(output![read_data: Value::zeroes(self.width)]) + port_map.write_undef(read_data)?; + Ok(UpdateStatus::Unchanged) } } - fn exec_cycle(&mut self, port_map: &PortMap) -> Results { - let reset = port_map[self.reset_port()].as_bool(); - let write_en = port_map[self.write_en()].as_bool(); + fn exec_cycle(&mut self, port_map: &mut PortMap) -> UpdateResult { + // These two behave like false when undefined + let reset = port_map[self.reset_port()].as_bool().unwrap_or_default(); + let write_en = port_map[self.write_en()].as_bool().unwrap_or_default(); + let addr = self.addresser.calculate_addr(port_map, self.base_port); let (read_data, done) = (self.read_data(), self.done()); - if write_en && !reset { - let write_data = port_map[self.write_data()].clone(); - self.internal_state[addr] = write_data; - Ok( - output![read_data: self.internal_state[addr].clone(), done: Value::bit_high()], - ) + let done = if write_en && !reset { + let addr = addr.ok_or(InterpreterError::UndefinedWriteAddr)?; + + let write_data = port_map[self.write_data()] + .as_option() + .ok_or(InterpreterError::UndefinedWrite)?; + self.internal_state[addr] = write_data.val().clone(); + port_map.insert_val(done, AssignedValue::cell_b_high())? + } else { + port_map.insert_val(done, AssignedValue::cell_b_low())? + }; + + if let Some(addr) = addr { + Ok(port_map.insert_val( + read_data, + AssignedValue::cell_value(self.internal_state[addr].clone()), + )? | done) } else { - Ok( - output![read_data: self.internal_state[addr].clone(), done: Value::bit_low()], - ) + Ok(done) } } - fn reset(&mut self, _port_map: &PortMap) -> Results { + fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { let (read_data, done) = (self.read_data(), self.done()); - Ok( - output![read_data: Value::zeroes(self.width), done: Value::bit_low()], - ) + + port_map.write_undef_unchecked(read_data); + port_map[done] = PortValue::new_cell(Value::bit_low()); + + Ok(()) } fn serialize( @@ -345,7 +388,7 @@ pub type StdMemD4 = StdMem>; impl StdMemD1 { pub fn new( - base: GlobalPortId, + base: GlobalPortIdx, width: u32, allow_invalid: bool, size: usize, @@ -364,7 +407,7 @@ impl StdMemD1 { impl StdMemD2 { pub fn new( - base: GlobalPortId, + base: GlobalPortIdx, width: u32, allow_invalid: bool, size: (usize, usize), @@ -383,7 +426,7 @@ impl StdMemD2 { impl StdMemD3 { pub fn new( - base: GlobalPortId, + base: GlobalPortIdx, width: u32, allow_invalid: bool, size: (usize, usize, usize), @@ -406,7 +449,7 @@ impl StdMemD3 { impl StdMemD4 { pub fn new( - base: GlobalPortId, + base: GlobalPortIdx, width: u32, allow_invalid: bool, size: (usize, usize, usize, usize), diff --git a/interp/src/flatten/structures/environment/assignments.rs b/interp/src/flatten/structures/environment/assignments.rs new file mode 100644 index 000000000..895eaa7da --- /dev/null +++ b/interp/src/flatten/structures/environment/assignments.rs @@ -0,0 +1,71 @@ +use crate::flatten::{ + flat_ir::prelude::{Assignment, AssignmentIdx, GlobalCellIdx}, + structures::context::Context, +}; + +use super::env::AssignmentRange; + +/// A collection of assignments represented using a series of half-open ranges +/// via [AssignmentRange] +#[derive(Debug)] +pub(crate) struct AssignmentBundle { + assigns: Vec<(GlobalCellIdx, AssignmentRange)>, +} + +impl AssignmentBundle { + pub fn new() -> Self { + Self { + assigns: Vec::new(), + } + } + + pub fn with_capacity(size: usize) -> Self { + Self { + assigns: Vec::with_capacity(size), + } + } + + #[inline] + pub fn push(&mut self, value: (GlobalCellIdx, AssignmentRange)) { + self.assigns.push(value) + } + + pub fn iter( + &self, + ) -> impl Iterator { + self.assigns.iter() + } + + pub fn iter_over_indices( + &self, + ) -> impl Iterator + '_ { + self.assigns + .iter() + .flat_map(|(c, x)| x.iter().map(|y| (*c, y))) + } + + pub fn iter_over_assignments<'a>( + &'a self, + ctx: &'a Context, + ) -> impl Iterator { + self.iter_over_indices() + .map(|(c, idx)| (c, &ctx.primary[idx])) + } + + /// The total number of assignments. Not the total number of index ranges! + pub fn len(&self) -> usize { + self.assigns + .iter() + .fold(0, |acc, (_, range)| acc + range.size()) + } +} + +impl FromIterator<(GlobalCellIdx, AssignmentRange)> for AssignmentBundle { + fn from_iter>( + iter: T, + ) -> Self { + Self { + assigns: iter.into_iter().collect(), + } + } +} diff --git a/interp/src/flatten/structures/environment/env.rs b/interp/src/flatten/structures/environment/env.rs new file mode 100644 index 000000000..78ae6132e --- /dev/null +++ b/interp/src/flatten/structures/environment/env.rs @@ -0,0 +1,760 @@ +use ahash::HashSet; +use itertools::Itertools; + +use super::{assignments::AssignmentBundle, program_counter::ProgramCounter}; + +use super::super::{ + context::Context, index_trait::IndexRange, indexed_map::IndexedMap, +}; +use crate::{ + errors::{InterpreterError, InterpreterResult}, + flatten::{ + flat_ir::{ + prelude::{ + AssignedValue, AssignmentIdx, BaseIndices, ComponentIdx, + ControlIdx, ControlNode, GlobalCellIdx, GlobalPortIdx, + GlobalPortRef, GlobalRefCellIdx, GlobalRefPortIdx, GuardIdx, + PortRef, PortValue, + }, + wires::guards::Guard, + }, + primitives::{self, prim_trait::UpdateStatus, Primitive}, + structures::{ + environment::program_counter::{ControlPoint, SearchPath}, + index_trait::IndexRef, + }, + }, +}; +use std::{collections::VecDeque, fmt::Debug}; + +pub type PortMap = IndexedMap; + +impl PortMap { + /// Essentially asserts that the port given is undefined, it errors out if + /// the port is defined and otherwise does nothing + pub fn write_undef( + &mut self, + target: GlobalPortIdx, + ) -> InterpreterResult<()> { + if self[target].is_def() { + todo!("raise error") + } else { + Ok(()) + } + } + + /// Sets the given index to undefined without checking whether or not it was + /// already defined + #[inline] + pub fn write_undef_unchecked(&mut self, target: GlobalPortIdx) { + self[target] = PortValue::new_undef(); + } + + pub fn insert_val( + &mut self, + target: GlobalPortIdx, + val: AssignedValue, + ) -> InterpreterResult { + match self[target].as_option() { + // unchanged + Some(t) if *t == val => Ok(UpdateStatus::Unchanged), + // conflict + // TODO: Fix to make the error more helpful + Some(t) if t.has_conflict_with(&val) => InterpreterResult::Err( + InterpreterError::FlatConflictingAssignments { + a1: t.clone(), + a2: val, + } + .into(), + ), + // changed + Some(_) | None => { + self[target] = PortValue::new(val); + Ok(UpdateStatus::Changed) + } + } + } +} + +pub(crate) type CellMap = IndexedMap; +pub(crate) type RefCellMap = + IndexedMap>; +pub(crate) type RefPortMap = + IndexedMap>; +pub(crate) type AssignmentRange = IndexRange; + +pub(crate) struct ComponentLedger { + pub(crate) index_bases: BaseIndices, + pub(crate) comp_id: ComponentIdx, +} + +impl ComponentLedger { + /// Convert a relative offset to a global one. Perhaps should take an owned + /// value rather than a pointer + pub fn convert_to_global(&self, port: &PortRef) -> GlobalPortRef { + match port { + PortRef::Local(l) => (&self.index_bases + l).into(), + PortRef::Ref(r) => (&self.index_bases + r).into(), + } + } +} + +/// An enum encapsulating cell functionality. It is either a pointer to a +/// primitive or information about a calyx component instance +pub(crate) enum CellLedger { + Primitive { + // wish there was a better option with this one + cell_dyn: Box, + }, + Component(ComponentLedger), +} + +impl CellLedger { + fn new_comp(idx: ComponentIdx, env: &Environment) -> Self { + Self::Component(ComponentLedger { + index_bases: BaseIndices::new( + env.ports.peek_next_idx(), + (env.cells.peek_next_idx().index() + 1).into(), + env.ref_cells.peek_next_idx(), + env.ref_ports.peek_next_idx(), + ), + comp_id: idx, + }) + } + + pub fn as_comp(&self) -> Option<&ComponentLedger> { + match self { + Self::Component(comp) => Some(comp), + _ => None, + } + } + + #[inline] + pub fn unwrap_comp(&self) -> &ComponentLedger { + self.as_comp() + .expect("Unwrapped cell ledger as component but received primitive") + } +} + +impl Debug for CellLedger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Primitive { .. } => f.debug_struct("Primitive").finish(), + Self::Component(ComponentLedger { + index_bases, + comp_id, + }) => f + .debug_struct("Component") + .field("index_bases", index_bases) + .field("comp_id", comp_id) + .finish(), + } + } +} + +#[derive(Debug)] +pub struct Environment<'a> { + /// A map from global port IDs to their current values. + pub(crate) ports: PortMap, + /// A map from global cell IDs to their current state and execution info. + cells: CellMap, + /// A map from global ref cell IDs to the cell they reference, if any. + ref_cells: RefCellMap, + /// A map from global ref port IDs to the port they reference, if any. + ref_ports: RefPortMap, + + /// The program counter for the whole program execution. + pc: ProgramCounter, + + /// The immutable context. This is retained for ease of use. + ctx: &'a Context, +} + +impl<'a> Environment<'a> { + pub fn new(ctx: &'a Context) -> Self { + let root = ctx.entry_point; + let aux = &ctx.secondary[root]; + + let mut env = Self { + ports: PortMap::with_capacity(aux.port_offset_map.count()), + cells: CellMap::with_capacity(aux.cell_offset_map.count()), + ref_cells: RefCellMap::with_capacity( + aux.ref_cell_offset_map.count(), + ), + ref_ports: RefPortMap::with_capacity( + aux.ref_port_offset_map.count(), + ), + pc: ProgramCounter::new(ctx), + ctx, + }; + + let root_node = CellLedger::new_comp(root, &env); + let root = env.cells.push(root_node); + env.layout_component(root); + + env + } + + /// Internal function used to layout a given component from a cell id + /// + /// Layout is handled in the following order: + /// 1. component signature (input/output) + /// 2. group hole ports + /// 3. cells + ports, primitive + /// 4. sub-components + /// 5. ref-cells & ports + fn layout_component(&mut self, comp: GlobalCellIdx) { + let ComponentLedger { + index_bases, + comp_id, + } = self.cells[comp] + .as_comp() + .expect("Called layout component with a non-component cell."); + let comp_aux = &self.ctx.secondary[*comp_id]; + + // first layout the signature + for sig_port in comp_aux.signature.iter() { + let idx = self.ports.push(PortValue::new_undef()); + debug_assert_eq!(index_bases + sig_port, idx); + } + // second group ports + for group_idx in comp_aux.definitions.groups() { + //go + let go = self.ports.push(PortValue::new_undef()); + + //done + let done = self.ports.push(PortValue::new_undef()); + + // quick sanity check asserts + let go_actual = index_bases + self.ctx.primary[group_idx].go; + let done_actual = index_bases + self.ctx.primary[group_idx].done; + // Case 1 - Go defined before done + if self.ctx.primary[group_idx].go < self.ctx.primary[group_idx].done + { + debug_assert_eq!(done, done_actual); + debug_assert_eq!(go, go_actual); + } + // Case 2 - Done defined before go + else { + // in this case go is defined after done, so our variable names + // are backward, but this is not a problem since they are + // initialized to the same value + debug_assert_eq!(go, done_actual); + debug_assert_eq!(done, go_actual); + } + } + + for (cell_off, def_idx) in comp_aux.cell_offset_map.iter() { + let info = &self.ctx.secondary[*def_idx]; + if !info.prototype.is_component() { + let port_base = self.ports.peek_next_idx(); + for port in info.ports.iter() { + let idx = self.ports.push(PortValue::new_undef()); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + port, + idx + ); + } + let cell_dyn = primitives::build_primitive(info, port_base); + let cell = self.cells.push(CellLedger::Primitive { cell_dyn }); + + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + cell_off, + cell + ); + } else { + let child_comp = info.prototype.as_component().unwrap(); + let child_comp = CellLedger::new_comp(*child_comp, self); + + let cell = self.cells.push(child_comp); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + cell_off, + cell + ); + + self.layout_component(cell); + } + } + + // ref cells and ports are initialized to None + for (ref_cell, def_idx) in comp_aux.ref_cell_offset_map.iter() { + let info = &self.ctx.secondary[*def_idx]; + for port_idx in info.ports.iter() { + let port_actual = self.ref_ports.push(None); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + port_idx, + port_actual + ) + } + let cell_actual = self.ref_cells.push(None); + debug_assert_eq!( + &self.cells[comp].as_comp().unwrap().index_bases + ref_cell, + cell_actual + ) + } + } +} + +// ===================== Environment print implementations ===================== +impl<'a> Environment<'a> { + pub fn print_env(&self) { + let root_idx = GlobalCellIdx::new(0); + let mut hierarchy = Vec::new(); + self.print_component(root_idx, &mut hierarchy) + } + + fn print_component( + &self, + target: GlobalCellIdx, + hierarchy: &mut Vec, + ) { + let info = self.cells[target].as_comp().unwrap(); + let comp = &self.ctx.secondary[info.comp_id]; + hierarchy.push(target); + + // This funky iterator chain first pulls the first element (the + // entrypoint) and extracts its name. Subsequent element are pairs of + // global offsets produced by a staggered iteration, yielding `(root, + // child)` then `(child, grandchild)` and so on. All the strings are + // finally collected and concatenated with a `.` separator to produce + // the fully qualified name prefix for the given component instance. + let name_prefix = hierarchy + .first() + .iter() + .map(|x| { + let info = self.cells[**x].as_comp().unwrap(); + let prior_comp = &self.ctx.secondary[info.comp_id]; + &self.ctx.secondary[prior_comp.name] + }) + .chain(hierarchy.iter().zip(hierarchy.iter().skip(1)).map( + |(l, r)| { + let info = self.cells[*l].as_comp().unwrap(); + let prior_comp = &self.ctx.secondary[info.comp_id]; + let local_target = r - (&info.index_bases); + + let def_idx = &prior_comp.cell_offset_map[local_target]; + + let id = &self.ctx.secondary[*def_idx]; + &self.ctx.secondary[id.name] + }, + )) + .join("."); + + for (cell_off, def_idx) in comp.cell_offset_map.iter() { + let definition = &self.ctx.secondary[*def_idx]; + + println!("{}.{}", name_prefix, self.ctx.secondary[definition.name]); + for port in definition.ports.iter() { + let definition = + &self.ctx.secondary[comp.port_offset_map[port]]; + println!( + " {}: {}", + self.ctx.secondary[definition.name], + self.ports[&info.index_bases + port] + ); + } + + if definition.prototype.is_component() { + let child_target = &info.index_bases + cell_off; + self.print_component(child_target, hierarchy); + } + } + + hierarchy.pop(); + } + + pub fn print_env_stats(&self) { + println!("Environment Stats:"); + println!(" Ports: {}", self.ports.len()); + println!(" Cells: {}", self.cells.len()); + println!(" Ref Cells: {}", self.ref_cells.len()); + println!(" Ref Ports: {}", self.ref_ports.len()); + } + + pub fn print_pc(&self) { + println!("{:?}", self.pc) + } +} + +/// A wrapper struct for the environment that provides the functions used to +/// simulate the actual program +pub struct Simulator<'a> { + env: Environment<'a>, +} + +impl<'a> Simulator<'a> { + pub fn new(env: Environment<'a>) -> Self { + Self { env } + } + + pub fn print_env(&self) { + self.env.print_env() + } + + pub fn ctx(&self) -> &Context { + self.env.ctx + } +} + +// =========================== simulation functions =========================== +impl<'a> Simulator<'a> { + /// pull out the next nodes to search when + fn extract_next_search(&self, idx: ControlIdx) -> VecDeque { + match &self.env.ctx.primary[idx] { + ControlNode::Seq(s) => s.stms().iter().copied().collect(), + ControlNode::Par(p) => p.stms().iter().copied().collect(), + ControlNode::If(i) => vec![i.tbranch(), i.fbranch()].into(), + ControlNode::While(w) => vec![w.body()].into(), + _ => VecDeque::new(), + } + } + + #[inline] + fn lookup_global_port_id(&self, port: GlobalPortRef) -> GlobalPortIdx { + match port { + GlobalPortRef::Port(p) => p, + // TODO Griffin: Please make sure this error message is correct with + // respect to the compiler + GlobalPortRef::Ref(r) => self.env.ref_ports[r].expect("A ref port is being queried without a supplied ref-cell. This is an error?"), + } + } + + #[inline] + fn get_global_idx( + &self, + port: &PortRef, + comp: GlobalCellIdx, + ) -> GlobalPortIdx { + let ledger = self.env.cells[comp].unwrap_comp(); + self.lookup_global_port_id(ledger.convert_to_global(port)) + } + + #[inline] + fn get_value(&self, port: &PortRef, comp: GlobalCellIdx) -> &PortValue { + let port_idx = self.get_global_idx(port, comp); + &self.env.ports[port_idx] + } + + /// Attempt to find the parent cell for a port. If no such cell exists (i.e. + /// it is a hole port, then it returns None) + fn get_parent_cell( + &self, + port: PortRef, + comp: GlobalCellIdx, + ) -> Option { + let component = self.env.cells[comp].unwrap_comp(); + let comp_info = &self.env.ctx.secondary[component.comp_id]; + + match port { + PortRef::Local(l) => { + for (cell_offset, cell_def_idx) in + comp_info.cell_offset_map.iter() + { + if self.env.ctx.secondary[*cell_def_idx].ports.contains(l) { + return Some(&component.index_bases + cell_offset); + } + } + } + PortRef::Ref(r) => { + for (cell_offset, cell_def_idx) in + comp_info.ref_cell_offset_map.iter() + { + if self.env.ctx.secondary[*cell_def_idx].ports.contains(r) { + let ref_cell_idx = &component.index_bases + cell_offset; + return Some( + self.env.ref_cells[ref_cell_idx] + .expect("Ref cell has not been instantiated"), + ); + } + } + } + } + + None + } + + // may want to make this iterate directly if it turns out that the vec + // allocation is too expensive in this context + fn get_assignments( + &self, + control_points: &[ControlPoint], + ) -> AssignmentBundle { + control_points + .iter() + .map(|node| { + match &self.ctx().primary[node.control_node] { + ControlNode::Enable(e) => { + (node.comp, self.ctx().primary[e.group()].assignments) + } + + ControlNode::Invoke(_) => { + todo!("invokes not yet implemented") + } + + ControlNode::Empty(_) => { + unreachable!( + "called `get_assignments` with an empty node" + ) + } + // non-leaf nodes + ControlNode::If(_) + | ControlNode::While(_) + | ControlNode::Seq(_) + | ControlNode::Par(_) => { + unreachable!( + "Called `get_assignments` with non-leaf nodes" + ) + } + } + }) + .collect() + } + + pub fn step(&mut self) -> InterpreterResult<()> { + /// attempts to get the next node for the given control point, if found + /// it replaces the given node. Returns true if the node was found and + /// replaced, returns false otherwise + fn get_next(node: &mut ControlPoint, ctx: &Context) -> bool { + let path = SearchPath::find_path_from_root(node.control_node, ctx); + let next = path.next_node(&ctx.primary.control); + if let Some(next) = next { + *node = node.new_w_comp(next); + true + } else { + //need to remove the node from the list now + false + } + } + + // place to keep track of what groups we need to conclude at the end of + // this step. These are indices into the program counter + + let mut leaf_nodes = vec![]; + + self.env.pc.vec_mut().retain_mut(|node| { + // just considering a single node case for the moment + match &self.env.ctx.primary[node.control_node] { + ControlNode::Seq(seq) => { + if !seq.is_empty() { + let next = seq.stms()[0]; + *node = node.new_w_comp(next); + true + } else { + get_next(node, self.env.ctx) + } + } + ControlNode::Par(_par) => todo!("not ready for par yet"), + ControlNode::If(i) => { + if i.cond_group().is_some() { + todo!("if statement has a with clause") + } + + let target = GlobalPortRef::from_local( + i.cond_port(), + &self.env.cells[node.comp].unwrap_comp().index_bases, + ); + + let result = match target { + GlobalPortRef::Port(p) => self.env.ports[p] + .as_bool() + .expect("if condition is undefined"), + GlobalPortRef::Ref(r) => { + let index = self.env.ref_ports[r].unwrap(); + self.env.ports[index] + .as_bool() + .expect("if condition is undefined") + } + }; + + let target = if result { i.tbranch() } else { i.fbranch() }; + *node = node.new_w_comp(target); + true + } + ControlNode::While(w) => { + if w.cond_group().is_some() { + todo!("while statement has a with clause") + } + + let target = GlobalPortRef::from_local( + w.cond_port(), + &self.env.cells[node.comp].unwrap_comp().index_bases, + ); + + let result = match target { + GlobalPortRef::Port(p) => self.env.ports[p] + .as_bool() + .expect("while condition is undefined"), + GlobalPortRef::Ref(r) => { + let index = self.env.ref_ports[r].unwrap(); + self.env.ports[index] + .as_bool() + .expect("while condition is undefined") + } + }; + + if result { + // enter the body + *node = node.new_w_comp(w.body()); + true + } else { + // ascend the tree + get_next(node, self.env.ctx) + } + } + + // ===== leaf nodes ===== + ControlNode::Empty(_) => get_next(node, self.env.ctx), + ControlNode::Enable(_) => { + leaf_nodes.push(node.clone()); + true + } + ControlNode::Invoke(_) => todo!("invokes not implemented yet"), + } + }); + + self.simulate_combinational(&leaf_nodes)?; + + let parent_cells: HashSet = self + .get_assignments(&leaf_nodes) + .iter() + .flat_map(|(cell, assigns)| { + assigns.iter().map(|x| { + let assign = &self.env.ctx.primary[x]; + self.get_parent_cell(assign.dst, *cell) + }) + }) + .flatten() + .collect(); + + for cell in parent_cells { + match &mut self.env.cells[cell] { + CellLedger::Primitive { cell_dyn } => { + cell_dyn.exec_cycle(&mut self.env.ports)?; + } + CellLedger::Component(_) => todo!(), + } + } + + Ok(()) + } + + fn evaluate_guard( + &self, + guard: GuardIdx, + comp: GlobalCellIdx, + ) -> Option { + let guard = &self.ctx().primary[guard]; + match guard { + Guard::True => Some(true), + Guard::Or(a, b) => { + let g1 = self.evaluate_guard(*a, comp)?; + let g2 = self.evaluate_guard(*b, comp)?; + Some(g1 || g2) + } + Guard::And(a, b) => { + let g1 = self.evaluate_guard(*a, comp)?; + let g2 = self.evaluate_guard(*b, comp)?; + Some(g1 && g2) + } + Guard::Not(n) => Some(!self.evaluate_guard(*n, comp)?), + Guard::Comp(c, a, b) => { + let comp_v = self.env.cells[comp].unwrap_comp(); + + let a = self.lookup_global_port_id(comp_v.convert_to_global(a)); + let b = self.lookup_global_port_id(comp_v.convert_to_global(b)); + + let a_val = self.env.ports[a].val()?; + let b_val = self.env.ports[b].val()?; + match c { + calyx_ir::PortComp::Eq => a_val == b_val, + calyx_ir::PortComp::Neq => a_val != b_val, + calyx_ir::PortComp::Gt => a_val > b_val, + calyx_ir::PortComp::Lt => a_val < b_val, + calyx_ir::PortComp::Geq => a_val >= b_val, + calyx_ir::PortComp::Leq => a_val <= b_val, + } + .into() + } + Guard::Port(p) => { + let comp_v = self.env.cells[comp].unwrap_comp(); + let p_idx = + self.lookup_global_port_id(comp_v.convert_to_global(p)); + self.env.ports[p_idx].as_bool() + } + } + } + + fn simulate_combinational( + &mut self, + control_points: &[ControlPoint], + ) -> InterpreterResult<()> { + let assigns_bundle = self.get_assignments(control_points); + let mut has_changed = true; + + let parent_cells: HashSet = assigns_bundle + .iter() + .flat_map(|(cell, assigns)| { + assigns.iter().map(|x| { + let assign = &self.env.ctx.primary[x]; + self.get_parent_cell(assign.dst, *cell) + }) + }) + .flatten() + .collect(); + + while has_changed { + has_changed = false; + + // evaluate all the assignments and make updates + for (cell, assigns) in assigns_bundle.iter() { + for assign_idx in assigns { + let assign = &self.env.ctx.primary[assign_idx]; + + // TODO griffin: Come back to this unwrap default later + // since we may want to do something different if the guard + // does not have a defined value + if self.evaluate_guard(assign.guard, *cell).unwrap_or(false) + { + let val = self.get_value(&assign.src, *cell); + let dest = self.get_global_idx(&assign.dst, *cell); + if let Some(v) = val.as_option() { + self.env.ports.insert_val( + dest, + AssignedValue::new(v.val().clone(), assign_idx), + )?; + } else if self.env.ports[dest].is_def() { + todo!("Raise an error here since this assignment is undefining things") + } + } + } + } + + // Run all the primitives + let changed: bool = parent_cells + .iter() + .map(|x| match &mut self.env.cells[*x] { + CellLedger::Primitive { cell_dyn } => { + cell_dyn.exec_comb(&mut self.env.ports) + } + CellLedger::Component(_) => todo!(), + }) + .fold_ok(false, |has_changed, update| { + has_changed | update.is_changed() + })?; + + has_changed |= changed; + } + + Ok(()) + } + + pub fn _main_test(&mut self) { + self.env.print_pc(); + for _x in self.env.pc.iter() { + // println!("{:?} next {:?}", x, self.find_next_control_point(x)) + } + self.env.print_pc(); + self.print_env(); + // println!("{:?}", self.get_assignments()) + } +} diff --git a/interp/src/flatten/structures/environment/mod.rs b/interp/src/flatten/structures/environment/mod.rs index 781456769..bfce4ff9c 100644 --- a/interp/src/flatten/structures/environment/mod.rs +++ b/interp/src/flatten/structures/environment/mod.rs @@ -1,773 +1,5 @@ +mod assignments; +mod env; mod program_counter; -use itertools::Itertools; - -use self::program_counter::ProgramCounter; - -use super::{ - context::Context, index_trait::IndexRange, indexed_map::IndexedMap, -}; -use crate::{ - errors::InterpreterResult, - flatten::{ - flat_ir::{ - prelude::{ - Assignment, AssignmentIdx, BaseIndices, ComponentIdx, - ControlIdx, ControlNode, GlobalCellId, GlobalPortId, - GlobalPortRef, GlobalRefCellId, GlobalRefPortId, GuardIdx, - PortRef, - }, - wires::guards::Guard, - }, - primitives::{self, Primitive}, - structures::index_trait::IndexRef, - }, - values::Value, -}; -use std::{collections::VecDeque, fmt::Debug}; - -pub(crate) type PortMap = IndexedMap; -pub(crate) type CellMap = IndexedMap; -pub(crate) type RefCellMap = IndexedMap>; -pub(crate) type RefPortMap = IndexedMap>; -type AssignmentRange = IndexRange; - -pub(crate) struct ComponentLedger { - pub(crate) index_bases: BaseIndices, - pub(crate) comp_id: ComponentIdx, -} - -impl ComponentLedger { - /// Convert a relative offset to a global one. Perhaps should take an owned - /// value rather than a pointer - pub fn convert_to_global(&self, port: &PortRef) -> GlobalPortRef { - match port { - PortRef::Local(l) => (&self.index_bases + l).into(), - PortRef::Ref(r) => (&self.index_bases + r).into(), - } - } -} - -/// An enum encapsulating cell functionality. It is either a pointer to a -/// primitive or information about a calyx component instance -pub(crate) enum CellLedger { - Primitive { - // wish there was a better option with this one - cell_dyn: Box, - }, - Component(ComponentLedger), -} - -impl CellLedger { - fn new_comp(idx: ComponentIdx, env: &Environment) -> Self { - Self::Component(ComponentLedger { - index_bases: BaseIndices::new( - env.ports.peek_next_idx(), - (env.cells.peek_next_idx().index() + 1).into(), - env.ref_cells.peek_next_idx(), - env.ref_ports.peek_next_idx(), - ), - comp_id: idx, - }) - } - - pub fn as_comp(&self) -> Option<&ComponentLedger> { - match self { - Self::Component(comp) => Some(comp), - _ => None, - } - } - - #[inline] - pub fn unwrap_comp(&self) -> &ComponentLedger { - self.as_comp() - .expect("Unwrapped cell ledger as component but received primitive") - } -} - -impl Debug for CellLedger { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Primitive { .. } => f.debug_struct("Primitive").finish(), - Self::Component(ComponentLedger { - index_bases, - comp_id, - }) => f - .debug_struct("Component") - .field("index_bases", index_bases) - .field("comp_id", comp_id) - .finish(), - } - } -} - -#[derive(Debug)] -pub struct Environment<'a> { - /// A map from global port IDs to their current values. - pub(crate) ports: PortMap, - /// A map from global cell IDs to their current state and execution info. - cells: CellMap, - /// A map from global ref cell IDs to the cell they reference, if any. - ref_cells: RefCellMap, - /// A map from global ref port IDs to the port they reference, if any. - ref_ports: RefPortMap, - - /// The program counter for the whole program execution. - pc: ProgramCounter, - - /// The immutable context. This is retained for ease of use. - ctx: &'a Context, -} - -impl<'a> Environment<'a> { - pub fn new(ctx: &'a Context) -> Self { - let root = ctx.entry_point; - let aux = &ctx.secondary[root]; - - let mut env = Self { - ports: PortMap::with_capacity(aux.port_offset_map.count()), - cells: CellMap::with_capacity(aux.cell_offset_map.count()), - ref_cells: RefCellMap::with_capacity( - aux.ref_cell_offset_map.count(), - ), - ref_ports: RefPortMap::with_capacity( - aux.ref_port_offset_map.count(), - ), - pc: ProgramCounter::new(ctx), - ctx, - }; - - let root_node = CellLedger::new_comp(root, &env); - let root = env.cells.push(root_node); - env.layout_component(root); - - env - } - - /// Internal function used to layout a given component from a cell id - /// - /// Layout is handled in the following order: - /// 1. component signature (input/output) - /// 2. group hole ports - /// 3. cells + ports, primitive - /// 4. sub-components - /// 5. ref-cells & ports - fn layout_component(&mut self, comp: GlobalCellId) { - let ComponentLedger { - index_bases, - comp_id, - } = self.cells[comp] - .as_comp() - .expect("Called layout component with a non-component cell."); - let comp_aux = &self.ctx.secondary[*comp_id]; - - let comp_id = *comp_id; - - // first layout the signature - for sig_port in comp_aux.signature.iter() { - let width = self.ctx.lookup_port_def(&comp_id, sig_port).width; - let idx = self.ports.push(Value::zeroes(width)); - debug_assert_eq!(index_bases + sig_port, idx); - } - // second group ports - for group_idx in comp_aux.definitions.groups() { - //go - let go = self.ports.push(Value::bit_low()); - - //done - let done = self.ports.push(Value::bit_low()); - - // quick sanity check asserts - let go_actual = index_bases + self.ctx.primary[group_idx].go; - let done_actual = index_bases + self.ctx.primary[group_idx].done; - // Case 1 - Go defined before done - if self.ctx.primary[group_idx].go < self.ctx.primary[group_idx].done - { - debug_assert_eq!(done, done_actual); - debug_assert_eq!(go, go_actual); - } - // Case 2 - Done defined before go - else { - // in this case go is defined after done, so our variable names - // are backward, but this is not a problem since they are - // initialized to the same value - debug_assert_eq!(go, done_actual); - debug_assert_eq!(done, go_actual); - } - } - - for (cell_off, def_idx) in comp_aux.cell_offset_map.iter() { - let info = &self.ctx.secondary[*def_idx]; - if !info.prototype.is_component() { - let port_base = self.ports.peek_next_idx(); - for port in info.ports.iter() { - let width = self.ctx.lookup_port_def(&comp_id, port).width; - let idx = self.ports.push(Value::zeroes(width)); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + port, - idx - ); - } - let cell_dyn = - primitives::build_primitive(self, info, port_base); - let cell = self.cells.push(CellLedger::Primitive { cell_dyn }); - - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + cell_off, - cell - ); - } else { - let child_comp = info.prototype.as_component().unwrap(); - let child_comp = CellLedger::new_comp(*child_comp, self); - - let cell = self.cells.push(child_comp); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + cell_off, - cell - ); - - self.layout_component(cell); - } - } - - // ref cells and ports are initialized to None - for (ref_cell, def_idx) in comp_aux.ref_cell_offset_map.iter() { - let info = &self.ctx.secondary[*def_idx]; - for port_idx in info.ports.iter() { - let port_actual = self.ref_ports.push(None); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + port_idx, - port_actual - ) - } - let cell_actual = self.ref_cells.push(None); - debug_assert_eq!( - &self.cells[comp].as_comp().unwrap().index_bases + ref_cell, - cell_actual - ) - } - } -} - -// ===================== Environment print implementations ===================== -impl<'a> Environment<'a> { - pub fn print_env(&self) { - let root_idx = GlobalCellId::new(0); - let mut hierarchy = Vec::new(); - self.print_component(root_idx, &mut hierarchy) - } - - fn print_component( - &self, - target: GlobalCellId, - hierarchy: &mut Vec, - ) { - let info = self.cells[target].as_comp().unwrap(); - let comp = &self.ctx.secondary[info.comp_id]; - hierarchy.push(target); - - // This funky iterator chain first pulls the first element (the - // entrypoint) and extracts its name. Subsequent element are pairs of - // global offsets produced by a staggered iteration, yielding `(root, - // child)` then `(child, grandchild)` and so on. All the strings are - // finally collected and concatenated with a `.` separator to produce - // the fully qualified name prefix for the given component instance. - let name_prefix = hierarchy - .first() - .iter() - .map(|x| { - let info = self.cells[**x].as_comp().unwrap(); - let prior_comp = &self.ctx.secondary[info.comp_id]; - &self.ctx.secondary[prior_comp.name] - }) - .chain(hierarchy.iter().zip(hierarchy.iter().skip(1)).map( - |(l, r)| { - let info = self.cells[*l].as_comp().unwrap(); - let prior_comp = &self.ctx.secondary[info.comp_id]; - let local_target = r - (&info.index_bases); - - let def_idx = &prior_comp.cell_offset_map[local_target]; - - let id = &self.ctx.secondary[*def_idx]; - &self.ctx.secondary[id.name] - }, - )) - .join("."); - - for (cell_off, def_idx) in comp.cell_offset_map.iter() { - let definition = &self.ctx.secondary[*def_idx]; - - println!("{}.{}", name_prefix, self.ctx.secondary[definition.name]); - for port in definition.ports.iter() { - let definition = - &self.ctx.secondary[comp.port_offset_map[port]]; - println!( - " {}: {}", - self.ctx.secondary[definition.name], - self.ports[&info.index_bases + port] - ); - } - - if definition.prototype.is_component() { - let child_target = &info.index_bases + cell_off; - self.print_component(child_target, hierarchy); - } - } - - hierarchy.pop(); - } - - pub fn print_env_stats(&self) { - println!("Environment Stats:"); - println!(" Ports: {}", self.ports.len()); - println!(" Cells: {}", self.cells.len()); - println!(" Ref Cells: {}", self.ref_cells.len()); - println!(" Ref Ports: {}", self.ref_ports.len()); - } - - pub fn print_pc(&self) { - println!("{:?}", self.pc) - } -} - -/// A wrapper struct for the environment that provides the functions used to -/// simulate the actual program -pub struct Simulator<'a> { - env: Environment<'a>, -} - -impl<'a> Simulator<'a> { - pub fn new(env: Environment<'a>) -> Self { - Self { env } - } - - pub fn print_env(&self) { - self.env.print_env() - } - - pub fn ctx(&self) -> &Context { - self.env.ctx - } -} - -// =========================== simulation functions =========================== -impl<'a> Simulator<'a> { - /// Finds the next control point from a finished control point. If there is - /// no next control point, returns None. - /// - /// If given an If/While statement this will assume the entire if/while node - /// is finished executing and will ascend to the parent context. Evaluating - /// the if/while condition and moving to the appropriate body must be - /// handled elsewhere. - // fn find_next_control_point( - // &self, - // target: &ControlPoint, - // ) -> NextControlPoint { - // let comp = target.comp; - // let comp_idx = self.env.cells[comp].as_comp().unwrap().comp_id; - // let root_ctrl = self.env.ctx.primary[comp_idx].control.expect( - // "Called `find_next_control_point` on a component with no control. This is an error, please report it", - // ); - - // // here's the goal: - // // we want to first walk the control tree for this component and find - // // the given control point and the path through the tree to get there. - // // Once we have this, we move back along the path to find the next - // // node to run (either a terminal node in an `invoke` or `enable` or a - // // non-terminal while/if condition check). Since this involves - // // backtracking, in the limit this means backtracking all the way to the - // // root of the component in which case the component has finished - // // executing. - - // let cont = self.extract_next_search(root_ctrl); - - // let mut search_stack = Vec::from([SearchNode { - // node: root_ctrl, - // next: cont, - // }]); - - // while let Some(mut node) = search_stack.pop() { - // if node.node == target.control_leaf { - // // found the node! we return it to the stack which is now the - // // path from the root to our finished node - // search_stack.push(node); - // break; - // } else if let Some(next_node) = node.next.pop_front() { - // let next_search_node = SearchNode { - // node: next_node, - // next: self.extract_next_search(next_node), - // }; - // // return the now modified original - // search_stack.push(node); - // // push the descendent next, so that the search continues - // // depth first - // search_stack.push(next_search_node); - // } else { - // // This node was not the one we wanted and none of its - // // children (if any) were either, we must return to the - // // parent which means dropping the node, i.e. doing nothing here - // } - // } - - // if search_stack.is_empty() { - // // The reason this should never happen is that this implies a - // // controlpoint was constructed for a fully-structural component - // // instance which means something went wrong with the construction - // // as such an instance could not have a control program to reference - // panic!("Could not find control point in component, this should never happen. Please report this error.") - // } - - // // phase two, backtrack to find the next node to run - - // // remove the deepest node (i.e. our target) - // search_stack.pop(); - - // let mut immediate_next_node = None; - - // while let Some(node) = search_stack.pop() { - // match &self.ctx().primary[node.node] { - // ControlNode::Seq(_) => { - // if let Some(next) = node.next.get(0) { - // // the target node will have been popped off the - // // list during the search meaning the next node left - // // over from the search is the next node to run - // immediate_next_node = Some(*next); - // // exit to descend the list - // break; - // } else { - // // no next node, go to parent context - // } - // }, - // ControlNode::Par(_) => { - // // par arm needs to wait until all arms are finished - // return NextControlPoint::FinishedParChild(ControlPoint::new(comp, node.node)); - // }, - // ControlNode::If(_) => { - // // do nothing, go to parent context - // }, - // ControlNode::While(_) => { - // // need to recheck condition so the while itself is next - // return NextControlPoint::Next(ControlPoint::new(comp, node.node)); - // }, - // // - // ControlNode::Empty(_) - // | ControlNode::Enable(_) - // | ControlNode::Invoke(_) => unreachable!("terminal nodes cannot be the parents of a node. If this happens something has gone horribly wrong and should be reported"), - // } - // } - - // // phase 3, take the immediate next node and descend to find its leaf - - // if let Some(node) = immediate_next_node { - // // we reuse the existing search stack without resetting it to allow - // // backtracking further if the immediate next node has no actual - // // leaves under it, e.g. a seq of empty seqs - // // TODO Griffin: double check this aspect later as it might - // // complicate things or introduce errors - // self.descend_to_leaf(node, &mut search_stack, comp) - // } else { - // // if we exit without finding the next node then it does not exist - // NextControlPoint::None - // } - // } - - /// pull out the next nodes to search when - fn extract_next_search(&self, idx: ControlIdx) -> VecDeque { - match &self.env.ctx.primary[idx] { - ControlNode::Seq(s) => s.stms().iter().copied().collect(), - ControlNode::Par(p) => p.stms().iter().copied().collect(), - ControlNode::If(i) => vec![i.tbranch(), i.fbranch()].into(), - ControlNode::While(w) => vec![w.body()].into(), - _ => VecDeque::new(), - } - } - - fn lookup_global_port_id(&self, port: GlobalPortRef) -> GlobalPortId { - match port { - GlobalPortRef::Port(p) => p, - // TODO Griffin: Please make sure this error message is correct with - // respect to the compiler - GlobalPortRef::Ref(r) => self.env.ref_ports[r].expect("A ref port is being queried without a supplied ref-cell. This is an error?"), - } - } - - fn get_global_idx( - &self, - port: &PortRef, - comp: GlobalCellId, - ) -> GlobalPortId { - let ledger = self.env.cells[comp].unwrap_comp(); - self.lookup_global_port_id(ledger.convert_to_global(port)) - } - - fn get_value(&self, port: &PortRef, comp: GlobalCellId) -> &Value { - let port_idx = self.get_global_idx(port, comp); - &self.env.ports[port_idx] - } - - // fn descend_to_leaf( - // &self, - // // the node (possibly terminal) which we want to start evaluating - // immediate_next_node: ControlIdx, - // search_stack: &mut Vec, - // comp: GlobalCellId, - // ) -> NextControlPoint { - // search_stack.push(SearchNode { - // node: immediate_next_node, - // next: self.extract_next_search(immediate_next_node), - // }); - - // while let Some(mut node) = search_stack.pop() { - // match &self.ctx().primary[node.node] { - // ControlNode::Seq(_) => { - // if let Some(next) = node.next.pop_front() { - // search_stack.push(node); - // let next_search_node = SearchNode { - // node: next, - // next: self.extract_next_search(next), - // }; - // search_stack.push(next_search_node); - // } else { - // // this seq does not contain any more nodes. - // // Currently only possible if the seq is empty - // } - // }, - - // ControlNode::Par(p) => { - // let mut ctrl_points = vec![]; - // let mut pars_activated = vec![]; - - // let mut this_par = (ControlPoint::new(comp, node.node), p.stms().len() as u32); - - // // TODO Griffin: Maybe consider making this not - // // recursive in the future - // for arm in p.stms().iter().map( |x| { - // self.descend_to_leaf(*x, &mut vec![], comp) - // }) { - // match arm { - // NextControlPoint::None => { - // this_par.1 -= 1; - // }, - // NextControlPoint::Next(c) => ctrl_points.push(c), - // NextControlPoint::FinishedParChild(_) => unreachable!("I think this impossible"), - // NextControlPoint::StartedParChild(nodes, pars) => { - // ctrl_points.extend(nodes); - // pars_activated.extend(pars); - // }, - // } - // } - - // if this_par.1 != 0 { - // pars_activated.push(this_par); - // return NextControlPoint::StartedParChild(ctrl_points, pars_activated) - // } else { - // // there were no next nodes under this par, so we - // // ascend the search tree and continue - // } - // } - - // // functionally terminals for the purposes of needing to be - // // seen in the control program and given extra treatment - // ControlNode::If(_) - // | ControlNode::While(_) - // // actual terminals - // | ControlNode::Invoke(_) - // | ControlNode::Enable(_) - // // might not want this here in the future, but makes sense - // // if we think about annotations on empty groups. - // | ControlNode::Empty(_)=> { - // return NextControlPoint::Next(ControlPoint::new(comp, node.node)) - // } - // } - // } - // NextControlPoint::None - // } - - // may want to make this iterate directly if it turns out that the vec - // allocation is too expensive in this context - fn get_assignments(&self) -> AssignmentBundle { - // maybe should give this a capacity equivalent to the number of - // elements in the program counter? It would be a bit of an over - // approximation - let mut out = AssignmentBundle::new(); - for node in self.env.pc.iter() { - match &self.ctx().primary[node.control_leaf] { - ControlNode::Empty(_) => { - // don't need to add any assignments here - } - ControlNode::Enable(e) => { - out.assigns.push((node.comp, self.ctx().primary[e.group()].assignments)) - } - - ControlNode::Invoke(_) => todo!("invokes not yet implemented"), - // The reason this shouldn't happen is that the program counter - // should've processed these nodes into their children and - // stored the needed auxillary data for par structures - ControlNode::If(_) | ControlNode::While(_) => panic!("If/While nodes are present in the control program when `get_assignments` is called. This is an error, please report it."), - ControlNode::Seq(_) | ControlNode::Par(_) => unreachable!(), - } - } - - out - } - - pub fn step(&mut self) -> InterpreterResult<()> { - // place to keep track of what groups we need to conclude at the end of - // this step. These are indices into the program counter - - // we want to iterate through all the nodes present in the program counter - - // first we need to check for conditional control nodes - - self.simulate_combinational(); - - todo!() - } - - fn evaluate_guard(&self, guard: GuardIdx, comp: GlobalCellId) -> bool { - let guard = &self.ctx().primary[guard]; - match guard { - Guard::True => true, - Guard::Or(a, b) => { - self.evaluate_guard(*a, comp) || self.evaluate_guard(*b, comp) - } - Guard::And(a, b) => { - self.evaluate_guard(*a, comp) || self.evaluate_guard(*b, comp) - } - Guard::Not(n) => !self.evaluate_guard(*n, comp), - Guard::Comp(c, a, b) => { - let comp_v = self.env.cells[comp].unwrap_comp(); - - let a = self.lookup_global_port_id(comp_v.convert_to_global(a)); - let b = self.lookup_global_port_id(comp_v.convert_to_global(b)); - - let a_val = &self.env.ports[a]; - let b_val = &self.env.ports[b]; - match c { - calyx_ir::PortComp::Eq => a_val == b_val, - calyx_ir::PortComp::Neq => a_val != b_val, - calyx_ir::PortComp::Gt => a_val > b_val, - calyx_ir::PortComp::Lt => a_val < b_val, - calyx_ir::PortComp::Geq => a_val >= b_val, - calyx_ir::PortComp::Leq => a_val <= b_val, - } - } - Guard::Port(p) => { - let comp_v = self.env.cells[comp].unwrap_comp(); - let p_idx = - self.lookup_global_port_id(comp_v.convert_to_global(p)); - self.env.ports[p_idx].as_bool() - } - } - } - - fn simulate_combinational(&mut self) { - let assigns = self.get_assignments(); - let mut has_changed = true; - - // This is an upper-bound, i.e. if every assignment succeeds then there - // will be this many entries - let mut updates_vec: Vec<(GlobalPortId, Value)> = - Vec::with_capacity(assigns.len()); - - while has_changed { - let updates = assigns.iter_over_assignments(self.ctx()).filter_map( - |(comp_idx, assign)| { - if self.evaluate_guard(assign.guard, comp_idx) { - let val = self.get_value(&assign.src, comp_idx); - Some(( - self.get_global_idx(&assign.dst, comp_idx), - val.clone(), - )) - } else { - None - } - }, - ); - - // want to buffer all updates before committing. It's not ideal to - // be doing this in a tight loop. - updates_vec.extend(updates); - - for (dest, val) in updates_vec.drain(..) { - if self.env.ports[dest] != val { - has_changed = true - } - self.env.ports[dest] = val; - } - } - } - - pub fn _main_test(&mut self) { - self.env.print_pc(); - for _x in self.env.pc.iter() { - // println!("{:?} next {:?}", x, self.find_next_control_point(x)) - } - println!("{:?}", self.get_assignments()) - } -} - -/// A collection of assignments represented using a series of half-open ranges -/// via [AssignmentRange] -#[derive(Debug)] -struct AssignmentBundle { - assigns: Vec<(GlobalCellId, AssignmentRange)>, -} - -impl AssignmentBundle { - fn new() -> Self { - Self { - assigns: Vec::new(), - } - } - - fn with_capacity(size: usize) -> Self { - Self { - assigns: Vec::with_capacity(size), - } - } - - #[inline] - pub fn push(&mut self, value: (GlobalCellId, AssignmentRange)) { - self.assigns.push(value) - } - - pub fn iter( - &self, - ) -> impl Iterator { - self.assigns.iter() - } - - pub fn iter_over_indices( - &self, - ) -> impl Iterator + '_ { - self.assigns - .iter() - .flat_map(|(c, x)| x.iter().map(|y| (*c, y))) - } - - pub fn iter_over_assignments<'a>( - &'a self, - ctx: &'a Context, - ) -> impl Iterator { - self.iter_over_indices() - .map(|(c, idx)| (c, &ctx.primary[idx])) - } - - /// The total number of assignments. Not the total number of index ranges! - pub fn len(&self) -> usize { - self.assigns - .iter() - .fold(0, |acc, (_, range)| acc + range.size()) - } -} - -impl FromIterator<(GlobalCellId, AssignmentRange)> for AssignmentBundle { - fn from_iter>( - iter: T, - ) -> Self { - Self { - assigns: iter.into_iter().collect(), - } - } -} +pub use env::{Environment, PortMap, Simulator}; diff --git a/interp/src/flatten/structures/environment/program_counter.rs b/interp/src/flatten/structures/environment/program_counter.rs index 190e78936..90ed42195 100644 --- a/interp/src/flatten/structures/environment/program_counter.rs +++ b/interp/src/flatten/structures/environment/program_counter.rs @@ -4,7 +4,7 @@ use ahash::{HashMap, HashMapExt}; use super::super::context::Context; use crate::flatten::{ - flat_ir::prelude::{ControlIdx, ControlNode, GlobalCellId}, + flat_ir::prelude::{ControlIdx, ControlMap, ControlNode, GlobalCellIdx}, structures::index_trait::{impl_index_nonzero, IndexRef}, }; @@ -12,29 +12,28 @@ use itertools::{FoldWhile, Itertools}; /// Simple struct containing both the component instance and the active leaf /// node in the component -#[derive(Debug, Hash, Eq, PartialEq)] +#[derive(Debug, Hash, Eq, PartialEq, Clone)] pub struct ControlPoint { - pub comp: GlobalCellId, - pub control_leaf: ControlIdx, + pub comp: GlobalCellIdx, + pub control_node: ControlIdx, } impl ControlPoint { - pub fn new(comp: GlobalCellId, control_leaf: ControlIdx) -> Self { - Self { comp, control_leaf } + pub fn new(comp: GlobalCellIdx, control_leaf: ControlIdx) -> Self { + Self { + comp, + control_node: control_leaf, + } } -} -#[derive(Debug)] -enum NextControlPoint { - /// no - None, - /// This is the node to run next. The nice friendly singular case - Next(ControlPoint), - /// We just finished the child of this par block and need to decrement its - /// count - FinishedParChild(ControlPoint), - /// We passed through one or more par nodes to reach this leaf (or leaves) - StartedParChild(Vec, Vec<(ControlPoint, u32)>), + /// Constructs a new [ControlPoint] from an existing one by copying over the + /// component identifier but changing the leaf node + pub fn new_w_comp(&self, target: ControlIdx) -> Self { + Self { + comp: self.comp, + control_node: target, + } + } } /// An index for searching up and down a tree. This is used to index into @@ -91,6 +90,73 @@ impl SearchPath { self.path.is_empty() } + /// Assuming the current node (i.e. the end of this path) has finished + /// executing, this ascends the path to the parent node and then proceeds to + /// it's next child, if no such child exists, it ascends again and repeats + /// the process. If no next node is found, it returns None, indicating that + /// there is nothing new to evaluate on the path. + pub fn next_node(&self, control_map: &ControlMap) -> Option { + // Case A: Path is empty? Or has exactly 1 node, so there is no next + if self.len() < 2 { + None + } + // Case B: We have an actual search to do + else { + // minus 2 gets us the second to last node index + for search_head in (0..=self.len() - 2).rev() { + let SearchNode { node, search_index } = &self.path[search_head]; + match &control_map[*node] { + ControlNode::Seq(s) => { + let current_child = search_index.expect( + "search index should be present in active seq", + ); + // We still have children to iterate through in this composition + if current_child.index() < (s.stms().len() - 1) { + let next_child = + s.stms()[current_child.index() + 1]; + return Some(next_child); + } + // we finished this seq node and need to ascend further + else { + continue; + } + } + ControlNode::Par(_) => { + // the challenge here is that we currently don't know if + // the par is done executing. probably this means we + // should return None and wait until the entire par is + // done? or return a third value indicating that the + // par's child count should be decremented. The latter + // seems more promising but I need to think on it more + + todo!("need to deal with par") + } + ControlNode::If(_) => { + // there is nothing to do when ascending to an if as it + // is already done once the body is done + continue; + } + ControlNode::While(_) => { + // we need to re-check the conditional, so this is our + // next node + return Some(*node); + } + + // none of these three should be possible as a non-leaf node + // which is what we are currently searching through on the + // path, so this is definitely an error + ControlNode::Invoke(_) + | ControlNode::Empty(_) + | ControlNode::Enable(_) => { + unreachable!("SearchPath is malformed. This is an error and should be reported") + } + } + } + + None + } + } + pub fn find_path_to_node( start: ControlIdx, target: ControlIdx, @@ -174,6 +240,8 @@ impl SearchPath { current_path } + /// find a path to the target node from the root of it's control tree. This + /// automatically finds the root node and invokes [find_path_to_node]. pub fn find_path_from_root(target: ControlIdx, context: &Context) -> Self { let root = context .primary @@ -219,66 +287,25 @@ impl ProgramCounter { let root = ctx.entry_point; // this relies on the fact that we construct the root cell-ledger // as the first possible cell in the program. If that changes this will break. - let root_cell = GlobalCellId::new(0); - let mut par_map: HashMap = HashMap::new(); + let root_cell = GlobalCellIdx::new(0); let mut vec = Vec::with_capacity(CONTROL_POINT_PREALLOCATE); - if let Some(current) = ctx.primary[root].control { - let mut work_queue: Vec = Vec::from([current]); - let mut backtrack_map = HashMap::new(); - while let Some(current) = work_queue.pop() { - match &ctx.primary[current] { - ControlNode::Empty(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Enable(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Seq(s) => match s - .stms() - .iter() - .find(|&x| !backtrack_map.contains_key(x)) - { - Some(n) => { - backtrack_map.insert(*n, current); - work_queue.push(*n); - } - None => { - if let Some(b) = backtrack_map.get(¤t) { - work_queue.push(*b) - } - } - }, - ControlNode::Par(p) => { - par_map.insert( - ControlPoint::new(root_cell, current), - p.stms().len().try_into().expect( - "number of par arms does not fit into the default size value. Please let us know so that we can adjust the datatype accordingly", - ), - ); - for node in p.stms() { - work_queue.push(*node); - } - } - ControlNode::If(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::While(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - ControlNode::Invoke(_) => { - vec.push(ControlPoint::new(root_cell, current)) - } - } - } + if let Some(current) = ctx.primary[root].control { + vec.push(ControlPoint { + comp: root_cell, + control_node: current, + }) } else { todo!( "Flat interpreter does not support control-less components yet" ) } - Self { vec, par_map } + Self { + vec, + par_map: HashMap::new(), + } } pub fn iter(&self) -> std::slice::Iter<'_, ControlPoint> { @@ -288,6 +315,14 @@ impl ProgramCounter { pub fn is_done(&self) -> bool { self.vec.is_empty() } + + pub fn iter_mut(&mut self) -> impl Iterator { + self.vec.iter_mut() + } + + pub(crate) fn vec_mut(&mut self) -> &mut Vec { + &mut self.vec + } } impl<'a> IntoIterator for &'a ProgramCounter { diff --git a/interp/src/flatten/structures/mod.rs b/interp/src/flatten/structures/mod.rs index feccaf3e8..af7edb104 100644 --- a/interp/src/flatten/structures/mod.rs +++ b/interp/src/flatten/structures/mod.rs @@ -4,4 +4,3 @@ pub mod index_trait; pub mod indexed_map; mod printer; pub mod sparse_map; -pub mod values; diff --git a/interp/src/flatten/structures/values.rs b/interp/src/flatten/structures/values.rs deleted file mode 100644 index 0c4b5ee6d..000000000 --- a/interp/src/flatten/structures/values.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::values::Value as BvValue; - -pub enum Value { - /// An undefined value from which it is dangerous to read. - Undefined, - /// A defined value that can be computed with - Defined(DefinedValue), -} - -pub enum DefinedValue { - Large(BvValue), -} - -impl Value { - /// Returns `true` if the value is [`Undefined`]. - /// - /// [`Undefined`]: Value::Undefined - #[must_use] - pub fn is_undefined(&self) -> bool { - matches!(self, Self::Undefined) - } - - /// Returns `true` if the value is [`Defined`]. - /// - /// [`Defined`]: Value::Defined - #[must_use] - pub fn is_defined(&self) -> bool { - matches!(self, Self::Defined(..)) - } -} diff --git a/interp/src/logging.rs b/interp/src/logging.rs index 9698f29a0..64dd1ce23 100644 --- a/interp/src/logging.rs +++ b/interp/src/logging.rs @@ -9,11 +9,11 @@ use slog::{Drain, Level}; static ROOT_LOGGER: OnceCell = OnceCell::new(); -pub fn initialze_default_logger() { - initialze_logger(false); +pub fn initialize_default_logger() { + initialize_logger(false); } -pub fn initialze_logger(quiet: bool) { +pub fn initialize_logger(quiet: bool) { let decorator = slog_term::TermDecorator::new().stderr().build(); let drain = slog_term::FullFormat::new(decorator).build(); let filter_level = if quiet { Level::Error } else { Level::Trace }; @@ -31,13 +31,13 @@ pub fn initialze_logger(quiet: bool) { pub fn root() -> &'static Logger { ROOT_LOGGER.get().unwrap_or_else(|| { - initialze_default_logger(); + initialize_default_logger(); ROOT_LOGGER.get().unwrap() }) } /// Utility method for creating subloggers for components/primitives/etc. This -/// is the prefered method for getting a logger. Initializes the source key with +/// is the preferred method for getting a logger. Initializes the source key with /// the supplied name. pub fn new_sublogger>(source_name: S) -> Logger { root().new(o!("source" => String::from(source_name.as_ref()))) diff --git a/interp/src/main.rs b/interp/src/main.rs index 883907acb..ee8d7f51a 100644 --- a/interp/src/main.rs +++ b/interp/src/main.rs @@ -135,7 +135,7 @@ fn main() -> InterpreterResult<()> { .allow_par_conflicts(opts.allow_par_conflicts) .build(); - interp::logging::initialze_logger(config.quiet); + interp::logging::initialize_logger(config.quiet); let log = interp::logging::root(); From 33311777e7a3687d3f62262762e1e87ba3479e54 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Wed, 24 Jan 2024 17:19:30 -0500 Subject: [PATCH 149/189] [Cider-dap] Fix cider extension (#1869) * add the compiled extension for ease of use and restore tsconfig * some cleanup to get it working * add a helpful note to the configuration * add an exclusion --- .gitignore | 1 + .vscode/launch.json | 29 +++- cider-dap/calyxDebug/built/extension.js | 195 ++++++++++++++++++++++++ cider-dap/calyxDebug/extension.ts | 3 + cider-dap/calyxDebug/package.json | 4 + cider-dap/calyxDebug/tsconfig.json | 10 ++ 6 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 cider-dap/calyxDebug/built/extension.js create mode 100644 cider-dap/calyxDebug/tsconfig.json diff --git a/.gitignore b/.gitignore index ccf0b37de..223c98004 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ results.xml !cider-dap/calyxDebug/package.json +!cider-dap/calyxDebug/tsconfig.json diff --git a/.vscode/launch.json b/.vscode/launch.json index f7eb3af4e..77d62526a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -32,7 +32,9 @@ "program": "${workspaceFolder}/target/debug/calyx", "cwd": "${workspaceFolder}", "stopOnEntry": false, - "sourceLanguages": ["rust"], + "sourceLanguages": [ + "rust" + ], "preLaunchTask": "Cargo Build", "console": "integratedTerminal" }, @@ -40,27 +42,39 @@ "type": "lldb", "request": "launch", "name": "Debug Interpreter", - "args": ["${input:target}", "-l", "${workspaceFolder}"], + "args": [ + "${input:target}", + "-l", + "${workspaceFolder}" + ], "program": "${workspaceFolder}/target/debug/cider", "windows": { "program": "${workspaceFolder}/target/debug/cider.exe" }, "cwd": "${workspaceFolder}", "stopOnEntry": false, - "sourceLanguages": ["rust"] + "sourceLanguages": [ + "rust" + ] }, { "type": "lldb", "request": "launch", "name": "Debug Interpreter on current file", - "args": ["${file}", "-l", "${workspaceFolder}"], + "args": [ + "${file}", + "-l", + "${workspaceFolder}" + ], "program": "${workspaceFolder}/target/debug/cider", "windows": { "program": "${workspaceFolder}/target/debug/cider.exe" }, "cwd": "${workspaceFolder}", "stopOnEntry": false, - "sourceLanguages": ["rust"] + "sourceLanguages": [ + "rust" + ] } ], "inputs": [ @@ -79,7 +93,10 @@ "id": "backend", "type": "pickString", "description": "Backend to be used by the compiler", - "options": ["verilog", "calyx"] + "options": [ + "verilog", + "calyx" + ] } ] } diff --git a/cider-dap/calyxDebug/built/extension.js b/cider-dap/calyxDebug/built/extension.js new file mode 100644 index 000000000..8e0d515db --- /dev/null +++ b/cider-dap/calyxDebug/built/extension.js @@ -0,0 +1,195 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var vscode = require("vscode"); +var cp = require("child_process"); +// Hold the debug adapter instance +var debugAdapter = null; +var programName = null; // Store the program name +// Create output channel +var outputChannel = vscode.window.createOutputChannel("Cider dap"); +function logToPanel(message) { + console.log("inside logPanel"); + outputChannel.appendLine(message); +} +// Function to get the program name from the user +function getProgramName() { + return __awaiter(this, void 0, void 0, function () { + var fileName, path; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, vscode.window.showInputBox({ + placeHolder: "Please enter the name of a futil file in the workspace folder", + value: "default.futil", + })]; + case 1: + fileName = _a.sent(); + if (fileName) { + if (!fileName.startsWith("/")) { + path = require("path"); + return [2 /*return*/, path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, fileName)]; + } + return [2 /*return*/, fileName]; + } + else { + return [2 /*return*/, null]; + } + return [2 /*return*/]; + } + }); + }); +} +// Factory for multi-session +var CiderDebugAdapterDescriptorFactoryServer = /** @class */ (function () { + function CiderDebugAdapterDescriptorFactoryServer(adapterPath, workspace, outputChannel) { + logToPanel("inside constructor"); + this.adapter = new CiderDebugAdapter(adapterPath, workspace, outputChannel); + this.adapterPath = adapterPath; + this.workspace = workspace; + this.outputChannel = outputChannel; + } + CiderDebugAdapterDescriptorFactoryServer.prototype.createDebugAdapterDescriptor = function (session) { + // Return a new debug adapter descriptor + logToPanel("creating adapter descriptor"); + return new vscode.DebugAdapterServer(this._startDebugServer(session)); + }; + CiderDebugAdapterDescriptorFactoryServer.prototype._startDebugServer = function (session) { + logToPanel("start of startDebugServer"); + // default port: 8888 + var port = vscode.workspace.getConfiguration("cider-dap").port; + if (!this.adapter.isServerRunning()) { + logToPanel("server is not running"); + this.adapter.start(port); + logToPanel("started dap-server"); + } + logToPanel("exiting startDebugging"); + return port; + }; + return CiderDebugAdapterDescriptorFactoryServer; +}()); +var CiderDebugAdapter = /** @class */ (function () { + function CiderDebugAdapter(adapterPath, cwd, outputChannel) { + logToPanel("inside CiderDebugAdapter"); + this.adapterPath = adapterPath; + this.cwd = cwd; + this.outputChannel = outputChannel; + this.adapterProcess = null; + logToPanel("at the end of ciderDebugAdapter"); + } + CiderDebugAdapter.prototype.isServerRunning = function () { + logToPanel("checking if server is running"); + return this.adapterProcess != null && this.adapterProcess.exitCode == null; + }; + // Start the debug adapter process + CiderDebugAdapter.prototype.start = function (port) { + logToPanel("beginning of start"); + // Spawn a new child process for the debug adapter + // Include the port as a command line argument + this.adapterProcess = cp.spawn(this.adapterPath, ["--port", port, "--tcp"], { cwd: this.cwd }); + // Attach event listener to capture standard output of the adapter process and log it to the output channel + this.adapterProcess.stdout.on("data", function (data) { + logToPanel(data.toString()); + }); + // Attach event listener to capture standard error of the adapter process and log it to the output channel + this.adapterProcess.stderr.on("data", function (data) { + logToPanel(data.toString()); + }); + this.adapterProcess.on("spawn", function () { + logToPanel("Debugger started on port " + port + "!"); + }); + }; + CiderDebugAdapter.prototype.stop = function () { + if (this.adapterProcess) { + this.adapterProcess.kill(); + this.adapterProcess = null; + this.isRunning = false; + logToPanel("Debugger stopped."); + } + else { + logToPanel("No running debug adapter to stop."); + } + }; + return CiderDebugAdapter; +}()); +// Factory for single-session +var CiderDebugAdapterDescriptorFactoryExecutable = /** @class */ (function () { + function CiderDebugAdapterDescriptorFactoryExecutable() { + } + CiderDebugAdapterDescriptorFactoryExecutable.prototype.createDebugAdapterDescriptor = function (_session) { + // Use the DebugAdapterExecutable as the debug adapter descriptor + console.log("inside adapter factory"); + console.log(vscode.workspace.getConfiguration("cider-dap").path); + return new vscode.DebugAdapterExecutable(vscode.workspace.getConfiguration("cider-dap").path, [], { cwd: vscode.workspace.rootPath }); + }; + return CiderDebugAdapterDescriptorFactoryExecutable; +}()); +function activate(context) { + logToPanel("Extension activated!"); + var factory; + // Get session type (multi or single) from package.json configuration + logToPanel("setting up with configuration '" + vscode.workspace.getConfiguration("cider-dap").sessionType + "'. You will need to reload after changing the settings if a different mode is desired."); + switch (vscode.workspace.getConfiguration("cider-dap").sessionType) { + case "Multi-Session": + factory = new CiderDebugAdapterDescriptorFactoryServer(vscode.workspace.getConfiguration("cider-dap").path, vscode.workspace.rootPath, outputChannel); + break; + case "Single-Session": + default: + factory = new CiderDebugAdapterDescriptorFactoryExecutable(); + break; + } + context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory("cider-dap", factory)); + logToPanel("after start server"); + // Update the adapter path with the serverPort and use it for starting the debug adapter + logToPanel("before startDebugging"); + logToPanel("Hello, your extension is now activated!"); +} +function stopDebugging() { + if (debugAdapter) { + debugAdapter.stop(); + } + else { + logToPanel("No running debug adapter to stop."); + } +} +function deactivate() { + logToPanel("deactivate"); +} +module.exports = { + activate: activate, + deactivate: deactivate, +}; diff --git a/cider-dap/calyxDebug/extension.ts b/cider-dap/calyxDebug/extension.ts index 62ffbf2a7..c0074d810 100644 --- a/cider-dap/calyxDebug/extension.ts +++ b/cider-dap/calyxDebug/extension.ts @@ -150,6 +150,9 @@ function activate(context) { let factory: vscode.DebugAdapterDescriptorFactory; // Get session type (multi or single) from package.json configuration + + logToPanel("setting up with configuration '" + vscode.workspace.getConfiguration("cider-dap").sessionType + "'. You will need to reload after changing the settings if a different mode is desired.") + switch (vscode.workspace.getConfiguration("cider-dap").sessionType) { case "Multi-Session": factory = new CiderDebugAdapterDescriptorFactoryServer( diff --git a/cider-dap/calyxDebug/package.json b/cider-dap/calyxDebug/package.json index b6bf43bd0..c73ec1dcc 100644 --- a/cider-dap/calyxDebug/package.json +++ b/cider-dap/calyxDebug/package.json @@ -65,5 +65,9 @@ ], "scripts": { "vscode:prepublish": "npx tsc" + }, + "devDependencies": { + "@types/node": "^20.11.6", + "@types/vscode": "^1.54.0" } } diff --git a/cider-dap/calyxDebug/tsconfig.json b/cider-dap/calyxDebug/tsconfig.json new file mode 100644 index 000000000..2ad65eb2d --- /dev/null +++ b/cider-dap/calyxDebug/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "built", + "allowJs": true, + "target": "es5" + }, + "include": [ + "extension.ts" + ] +} From 017a37ad2c11472a5019b2a90496b46f58b0c66f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 28 Jan 2024 23:50:58 +0530 Subject: [PATCH 150/189] Dont panic if insufficient parameters provided (#1876) --- calyx-frontend/src/common.rs | 2 +- calyx-ir/src/builder.rs | 22 ++++++++++++++++++---- calyx-ir/src/from_ast.rs | 18 +++++++++++------- tests/errors/insufficient-params.expect | 7 ++++--- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/calyx-frontend/src/common.rs b/calyx-frontend/src/common.rs index 78dbe363a..5f595459f 100644 --- a/calyx-frontend/src/common.rs +++ b/calyx-frontend/src/common.rs @@ -45,7 +45,7 @@ impl Primitive { ) -> CalyxResult<(SmallVec<[(Id, u64); 5]>, Vec>)> { if self.params.len() != parameters.len() { let msg = format!( - "Invalid parameter binding for primitive `{}`. Requires {} parameters but provided with {}.", + "primitive `{}` requires {} parameters but instantiation provides {} parameters", self.name.clone(), self.params.len(), parameters.len(), diff --git a/calyx-ir/src/builder.rs b/calyx-ir/src/builder.rs index 547533e53..bb65e6513 100644 --- a/calyx-ir/src/builder.rs +++ b/calyx-ir/src/builder.rs @@ -2,6 +2,7 @@ //! representation. use crate::{self as ir, LibrarySignatures, Nothing, RRC, WRC}; use calyx_frontend::BoolAttr; +use calyx_utils::CalyxResult; use std::{cmp, rc::Rc}; use super::{CellType, PortDef}; @@ -213,15 +214,28 @@ impl<'a> Builder<'a> { primitive: Prim, param_values: &[u64], ) -> RRC + where + Pre: Into + ToString + Clone, + Prim: Into, + { + self.try_add_primitive(prefix, primitive, param_values) + .expect("failed to add primitive:") + } + + /// Result variant of [[ir::Builder::add_primitive()]]. + pub fn try_add_primitive( + &mut self, + prefix: Pre, + primitive: Prim, + param_values: &[u64], + ) -> CalyxResult> where Pre: Into + ToString + Clone, Prim: Into, { let prim_id = primitive.into(); let prim = &self.lib.get_primitive(prim_id); - let (param_binding, ports) = prim - .resolve(param_values) - .expect("Failed to add primitive."); + let (param_binding, ports) = prim.resolve(param_values)?; let name = self.component.generate_name(prefix); let cell = Self::cell_from_signature( @@ -238,7 +252,7 @@ impl<'a> Builder<'a> { cell.borrow_mut().add_attribute(BoolAttr::Generated, 1); } self.component.cells.add(Rc::clone(&cell)); - cell + Ok(cell) } /// Add a component instance to this component using its name and port diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index 619c5ab31..7479045c5 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -269,7 +269,7 @@ fn build_component( // required information. comp.cells .into_iter() - .for_each(|cell| add_cell(cell, sig_ctx, &mut builder)); + .try_for_each(|cell| add_cell(cell, sig_ctx, &mut builder))?; comp.groups .into_iter() @@ -301,15 +301,17 @@ fn build_component( ///////////////// Cell Construction ///////////////////////// -fn add_cell(cell: ast::Cell, sig_ctx: &SigCtx, builder: &mut Builder) { +fn add_cell( + cell: ast::Cell, + sig_ctx: &SigCtx, + builder: &mut Builder, +) -> CalyxResult<()> { let proto_name = cell.prototype.name; let res = if sig_ctx.lib.find_primitive(proto_name).is_some() { - let c = builder.add_primitive( - cell.name, - proto_name, - &cell.prototype.params, - ); + let c = builder + .try_add_primitive(cell.name, proto_name, &cell.prototype.params) + .map_err(|e| e.with_pos(&cell.attributes))?; c.borrow_mut().set_reference(cell.reference); c } else { @@ -328,6 +330,8 @@ fn add_cell(cell: ast::Cell, sig_ctx: &SigCtx, builder: &mut Builder) { // Add attributes to the built cell res.borrow_mut().attributes = cell.attributes; + + Ok(()) } ///////////////// Group Construction ///////////////////////// diff --git a/tests/errors/insufficient-params.expect b/tests/errors/insufficient-params.expect index 09ebb3bff..96605cfd2 100644 --- a/tests/errors/insufficient-params.expect +++ b/tests/errors/insufficient-params.expect @@ -1,5 +1,6 @@ ---CODE--- -101 +1 ---STDERR--- -thread 'main' panicked at 'Failed to add primitive.: Malformed Structure: Invalid parameter binding for primitive `std_fp_div_pipe`. Requires 3 parameters but provided with 1.', calyx-ir/src/builder.rs:224:14 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +Error: tests/errors/insufficient-params.futil +5 | d = std_fp_div_pipe(32); + | ^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: primitive `std_fp_div_pipe` requires 3 parameters but instantiation provides 1 parameters From 59a581ba669738fce6f38c1bd91d4fe0a03b6b70 Mon Sep 17 00:00:00 2001 From: Nathaniel Navarro Date: Sun, 28 Jan 2024 15:16:20 -0500 Subject: [PATCH 151/189] Clean up AXI generator channels (#1867) * Clean up AXI generator channels Renamed some registers, simplified/corrected(?) the was_high signals Assert a few properties we expect from our yxi input. Still TODO: refactor out shared channels/code * Rename `*_addr` registers in hardcoded axi --- yxi/axi-calyx/axi-combined-calyx.futil | 200 ++++++++++++------------- yxi/axi-calyx/axi-generator.py | 81 +++++----- 2 files changed, 140 insertions(+), 141 deletions(-) diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index 0782cf03d..f28f30d2d 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -47,10 +47,10 @@ component m_arread_channel( is_arvalid = std_reg(1); // gets set high with ARVALID and remains high - arvalid_was_high = std_reg(1); + ar_handshake_occurred = std_reg(1); // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` // but for now will live here. - ref base_addr = std_reg(64); + ref curr_addr_axi = std_reg(64); // number of trasfers in a transaction. This is sent to subordinate txn_len = std_reg(8); @@ -78,24 +78,21 @@ component m_arread_channel( // this contains blocking logic previously in its own group group do_ar_transfer { //assert ARVALID as long as this is the first time we are asserting it - is_arvalid.in = !arvalid_was_high.out ? 1'b1; + is_arvalid.in = !ar_handshake_occurred.out ? 1'b1; - // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high - // but for now we will be explicit and reduce this in generation maybe. Not sure - // it even matters. // This makes ARVALID go low after a single cycle. // Without it it stays high for 2 cycles // See issue #1828: https://github.com/calyxir/calyx/issues/1828 - is_arvalid.in = is_arvalid.out & ARREADY & arvalid_was_high.out ? 1'b0; + is_arvalid.in = is_arvalid.out & ARREADY & ar_handshake_occurred.out ? 1'b0; is_arvalid.write_en = 1'b1; - arvalid_was_high.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; + ar_handshake_occurred.in = !(is_arvalid.out & ARREADY) & !ar_handshake_occurred.out ? 1'b1; + ar_handshake_occurred.write_en = !(is_arvalid.out & ARREADY) & !ar_handshake_occurred.out ? 1'b1; // drive output signals for transfer - ARADDR = base_addr.out; + ARADDR = curr_addr_axi.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. ARSIZE = 3'b010; @@ -143,7 +140,7 @@ component m_arread_channel( seq{ par { invoke bt_reg(in=1'b0)(); - invoke arvalid_was_high(in=1'b0)(); + invoke ar_handshake_occurred(in=1'b0)(); } do_ar_transfer; invoke is_arvalid(in=1'b0)(); @@ -174,9 +171,9 @@ component m_read_channel( // on the data we read from cocotb ref data_received = seq_mem_d1(32, 8, 64); is_rdy = std_reg(1); - ref curr_addr = std_reg(64); + ref curr_addr_internal_mem = std_reg(64); //need to increment this - ref base_addr = std_reg(64); + ref curr_addr_axi = std_reg(64); // registered because RLAST is high with last transfer, not after // before this was registered we were terminating immediately with @@ -187,8 +184,8 @@ component m_read_channel( read_data_reg = std_reg(32); //address of seq_d1_mem we are writing to - curr_addr_adder = std_add(64); - base_addr_adder = std_add(64); + curr_addr_internal_mem_adder = std_add(64); + curr_addr_axi_adder = std_add(64); // block_transfer reg to avoid combinational loops // Used to block any servicing until handshake occurs. @@ -246,27 +243,27 @@ component m_read_channel( is_rdy.write_en = 1'b1; //write the data we received during transfer to seq_d1_mem - data_received.addr0 = curr_addr.out; + data_received.addr0 = curr_addr_internal_mem.out; data_received.write_en = 1'b1; data_received.write_data = read_data_reg.out; receive_r_transfer[done] = data_received.write_done; } - group incr_curr_addr{ - curr_addr_adder.left = 64'd1 ; - curr_addr_adder.right = curr_addr.out; - curr_addr.in = curr_addr_adder.out; - curr_addr.write_en = 1'b1; - incr_curr_addr[done] = curr_addr.done; + group incr_curr_addr_internal_mem{ + curr_addr_internal_mem_adder.left = 64'd1 ; + curr_addr_internal_mem_adder.right = curr_addr_internal_mem.out; + curr_addr_internal_mem.in = curr_addr_internal_mem_adder.out; + curr_addr_internal_mem.write_en = 1'b1; + incr_curr_addr_internal_mem[done] = curr_addr_internal_mem.done; } - group incr_base_addr{ - base_addr_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width - base_addr_adder.right = base_addr.out; - base_addr.in = base_addr_adder.out; - base_addr.write_en= 1'b1; - incr_base_addr[done] = base_addr.done; + group incr_curr_addr_axi{ + curr_addr_axi_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width + curr_addr_axi_adder.right = curr_addr_axi.out; + curr_addr_axi.in = curr_addr_axi_adder.out; + curr_addr_axi.write_en= 1'b1; + incr_curr_addr_axi[done] = curr_addr_axi.done; } } control{ @@ -277,8 +274,8 @@ component m_read_channel( block_transfer; receive_r_transfer; par{ - incr_curr_addr; - incr_base_addr; + incr_curr_addr_internal_mem; + incr_curr_addr_axi; } } } @@ -412,10 +409,10 @@ component m_awwrite_channel( is_awvalid = std_reg(1); // gets set high with AWVALID and remains high - awvalid_was_high = std_reg(1); + aw_handshake_occurred = std_reg(1); // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` // but for now will live here. - ref base_addr = std_reg(64); + ref curr_addr_axi = std_reg(64); //we write to this here and read from it in m_write_channel ref max_trnsfrs = std_reg(8); @@ -446,21 +443,21 @@ component m_awwrite_channel( // this contains blocking logic previously in its own group group do_aw_transfer { //assert AWVALID - is_awvalid.in = !awvalid_was_high.out ? 1'b1; + is_awvalid.in = !(is_awvalid.out & AWREADY) & !aw_handshake_occurred.out ? 1'b1; - // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high + // TODO(nathanielnrn): in theory should be able to get rid of aw_handshake_occurred // but for now we will be explicit and reduce this in generation maybe. Not sure // it even matters. // This makes AWVALID go low after a single cycle. Without it it stays high for 2. - is_awvalid.in = is_awvalid.out & AWREADY & awvalid_was_high.out ? 1'b0; + is_awvalid.in = (is_awvalid.out & AWREADY) | aw_handshake_occurred.out ? 1'b0; is_awvalid.write_en = 1'b1; - awvalid_was_high.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - awvalid_was_high.write_en = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; + aw_handshake_occurred.in = is_awvalid.out & AWREADY ? 1'b1; + aw_handshake_occurred.write_en = !aw_handshake_occurred.out ? 1'b1; // drive output signals for transfer - AWADDR = base_addr.out; + AWADDR = curr_addr_axi.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. AWSIZE = 3'b010; @@ -514,7 +511,7 @@ component m_awwrite_channel( seq{ par { invoke bt_reg(in=1'b0)(); - invoke awvalid_was_high(in=1'b0)(); + invoke aw_handshake_occurred(in=1'b0)(); } do_aw_transfer; invoke is_awvalid(in=1'b0)(); @@ -540,10 +537,10 @@ component m_write_channel( // on the data we read from cocotb ref internal_mem = seq_mem_d1(32, 8, 64); wvalid = std_reg(1); - wvalid_was_high = std_reg(1); + w_handshake_occurred = std_reg(1); // used internally to access our seq_mem_d1 - ref curr_addr = std_reg(64); - ref base_addr = std_reg(64); + ref curr_addr_internal_mem = std_reg(64); + ref curr_addr_axi = std_reg(64); //this increments curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count @@ -556,8 +553,8 @@ component m_write_channel( n_finished_last_trnsfr = std_reg(1); //used for address of seq_d1_mem we are reading from - curr_addr_adder = std_add(64); - base_addr_adder = std_add(64); + curr_addr_internal_mem_adder = std_add(64); + curr_addr_axi_adder = std_add(64); curr_trnsfr_count_adder = std_add(8); @@ -580,18 +577,18 @@ component m_write_channel( //NOTE: wvalid.in = 1'b1; does not work, it leaves WVALID high for 2 cycles // this both asserts and deasserts one cycle later - wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; - // TODO(nathanielnrn): Can prob get rid of wvalid_was_high - wvalid.in = (wvalid.out & WREADY) & wvalid_was_high.out ? 1'b0; + wvalid.in = !(wvalid.out & WREADY) & !w_handshake_occurred.out ? 1'b1; + // TODO(nathanielnrn): Can prob get rid of w_handshake_occurred + wvalid.in = (wvalid.out & WREADY) | w_handshake_occurred.out ? 1'b0; wvalid.write_en = 1'b1; //set to 1 after valid has been high even once - wvalid_was_high.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; - wvalid_was_high.write_en = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; + w_handshake_occurred.in = wvalid.out & WREADY ? 1'b1; + w_handshake_occurred.write_en = !w_handshake_occurred.out ? 1'b1; - // set data output based on curr_addr register - internal_mem.addr0 = curr_addr.out; + // set data output based on curr_addr_internal_mem register + internal_mem.addr0 = curr_addr_internal_mem.out; internal_mem.read_en = 1'b1; WDATA = internal_mem.read_data; @@ -612,20 +609,20 @@ component m_write_channel( do_write_transfer[done] = bt_reg.out; } - group incr_curr_addr{ - curr_addr_adder.left = 64'd1 ; - curr_addr_adder.right = curr_addr.out; - curr_addr.in = curr_addr_adder.out; - curr_addr.write_en = 1'b1; - incr_curr_addr[done] = curr_addr.done; + group incr_curr_addr_internal_mem{ + curr_addr_internal_mem_adder.left = 64'd1 ; + curr_addr_internal_mem_adder.right = curr_addr_internal_mem.out; + curr_addr_internal_mem.in = curr_addr_internal_mem_adder.out; + curr_addr_internal_mem.write_en = 1'b1; + incr_curr_addr_internal_mem[done] = curr_addr_internal_mem.done; } - group incr_base_addr{ - base_addr_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width - base_addr_adder.right = base_addr.out; - base_addr.in = base_addr_adder.out; - base_addr.write_en= 1'b1; - incr_base_addr[done] = base_addr.done; + group incr_curr_addr_axi{ + curr_addr_axi_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width + curr_addr_axi_adder.right = curr_addr_axi.out; + curr_addr_axi.in = curr_addr_axi_adder.out; + curr_addr_axi.write_en= 1'b1; + incr_curr_addr_axi[done] = curr_addr_axi.done; } group incr_curr_trnsfr_count { @@ -640,16 +637,17 @@ component m_write_channel( control{ seq{ - invoke curr_addr(in=64'b0)(); //reset curr_addr + invoke curr_addr_internal_mem(in=64'b0)(); //reset curr_addr_internal_mem invoke n_finished_last_trnsfr(in=1'b1)(); //init reg while n_finished_last_trnsfr.out{ seq{ invoke bt_reg(in=1'b0)(); do_write_transfer; par{ - incr_curr_addr; + incr_curr_addr_internal_mem; incr_curr_trnsfr_count; - incr_base_addr; + incr_curr_addr_axi; + invoke w_handshake_occurred(in=1'b0)(); } } } @@ -859,12 +857,12 @@ component main( //original read stuff - curr_addr_A0 = std_reg(64); - base_addr_A0 = std_reg(64); - curr_addr_B0 = std_reg(64); - base_addr_B0 = std_reg(64); - curr_addr_Sum0 = std_reg(64); - base_addr_Sum0 = std_reg(64); + curr_addr_internal_mem_A0 = std_reg(64); + curr_addr_axi_A0 = std_reg(64); + curr_addr_internal_mem_B0 = std_reg(64); + curr_addr_axi_B0 = std_reg(64); + curr_addr_internal_mem_Sum0 = std_reg(64); + curr_addr_axi_Sum0 = std_reg(64); A0_read_channel = m_read_channel(); A0_arread_channel = m_arread_channel(); @@ -923,19 +921,19 @@ component main( seq{ //read stuff par{ - //init base_addresses + //init curr_addr_axiesses //TODO: get this from kernel.xml - invoke base_addr_A0(in = 64'x1000)(); - invoke base_addr_B0(in = 64'x1000)(); - invoke base_addr_Sum0(in = 64'x1000)(); - invoke curr_addr_A0(in = 64'x0000)(); - invoke curr_addr_B0(in = 64'x0000)(); - invoke curr_addr_Sum0(in = 64'x0000)(); + invoke curr_addr_axi_A0(in = 64'x1000)(); + invoke curr_addr_axi_B0(in = 64'x1000)(); + invoke curr_addr_axi_Sum0(in = 64'x1000)(); + invoke curr_addr_internal_mem_A0(in = 64'x0000)(); + invoke curr_addr_internal_mem_B0(in = 64'x0000)(); + invoke curr_addr_internal_mem_Sum0(in = 64'x0000)(); } par{ seq{ //A0 reads - invoke A0_arread_channel[base_addr = base_addr_A0] + invoke A0_arread_channel[curr_addr_axi = curr_addr_axi_A0] ( ARESET = m0_ARESET, ARREADY = m0_ARREADY @@ -948,9 +946,9 @@ component main( ARBURST = m0_ARBURST ); - //invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_A0(in = curr_addr_axi_A0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke A0_read_channel[data_received = A0, curr_addr = curr_addr_A0, base_addr = base_addr_A0] + invoke A0_read_channel[data_received = A0, curr_addr_internal_mem = curr_addr_internal_mem_A0, curr_addr_axi = curr_addr_axi_A0] ( ARESET = m0_ARESET, RVALID = m0_RVALID, @@ -965,7 +963,7 @@ component main( seq{ //B0 reads - invoke B0_arread_channel[base_addr = base_addr_B0] + invoke B0_arread_channel[curr_addr_axi = curr_addr_axi_B0] ( ARESET = m1_ARESET, ARREADY = m1_ARREADY @@ -978,9 +976,9 @@ component main( ARBURST = m1_ARBURST ); - //invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_B0(in = curr_addr_axi_B0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke B0_read_channel[data_received = B0, curr_addr = curr_addr_B0, base_addr = base_addr_B0] + invoke B0_read_channel[data_received = B0, curr_addr_internal_mem = curr_addr_internal_mem_B0, curr_addr_axi = curr_addr_axi_B0] ( ARESET = m1_ARESET, RVALID = m1_RVALID, @@ -993,7 +991,7 @@ component main( ); } seq{ //Sum0 reads - invoke Sum0_arread_channel[base_addr = base_addr_Sum0] + invoke Sum0_arread_channel[curr_addr_axi = curr_addr_axi_Sum0] ( ARESET = m2_ARESET, ARREADY = m2_ARREADY @@ -1006,9 +1004,9 @@ component main( ARBURST = m2_ARBURST ); - //invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_Sum0(in = curr_addr_axi_Sum0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke Sum0_read_channel[data_received = Sum0, curr_addr = curr_addr_Sum0, base_addr = base_addr_Sum0] + invoke Sum0_read_channel[data_received = Sum0, curr_addr_internal_mem = curr_addr_internal_mem_Sum0, curr_addr_axi = curr_addr_axi_Sum0] ( ARESET = m2_ARESET, RVALID = m2_RVALID, @@ -1028,16 +1026,16 @@ component main( invoke vec_add_cell[A0 = A0, B0 = B0, Sum0 = Sum0]()(); //end compute stuff - //reset base_addr registers before writing + //reset curr_addr_axi registers before writing par{ - invoke base_addr_A0(in = 64'x1000)(); - invoke base_addr_B0(in = 64'x1000)(); - invoke base_addr_Sum0(in = 64'x1000)(); + invoke curr_addr_axi_A0(in = 64'x1000)(); + invoke curr_addr_axi_B0(in = 64'x1000)(); + invoke curr_addr_axi_Sum0(in = 64'x1000)(); } //write stuff par { seq { //A0 writes - invoke A0_awwrite_channel[base_addr = base_addr_A0, max_trnsfrs = max_trnsfrs] + invoke A0_awwrite_channel[curr_addr_axi = curr_addr_axi_A0, max_trnsfrs = max_trnsfrs] ( ARESET = m0_ARESET, AWREADY = m0_AWREADY @@ -1051,9 +1049,9 @@ component main( AWPROT = m0_AWPROT ); - //invoke curr_addr_A0(in = base_addr_A0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_A0(in = curr_addr_axi_A0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke A0_write_channel[internal_mem = A0, curr_addr = curr_addr_A0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_A0] + invoke A0_write_channel[internal_mem = A0, curr_addr_internal_mem = curr_addr_internal_mem_A0, max_trnsfrs = max_trnsfrs, curr_addr_axi = curr_addr_axi_A0] ( ARESET = m0_ARESET, WREADY = m0_WREADY @@ -1067,7 +1065,7 @@ component main( invoke A0_bresp_channel(BVALID = m0_BVALID)(BREADY = m0_BREADY); } seq { //B0 writes - invoke B0_awwrite_channel[base_addr = base_addr_B0, max_trnsfrs = max_trnsfrs] + invoke B0_awwrite_channel[curr_addr_axi = curr_addr_axi_B0, max_trnsfrs = max_trnsfrs] ( ARESET = m1_ARESET, AWREADY = m1_AWREADY @@ -1081,9 +1079,9 @@ component main( AWPROT = m1_AWPROT ); - //invoke curr_addr_B0(in = base_addr_B0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_B0(in = curr_addr_axi_B0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke B0_write_channel[internal_mem = B0, curr_addr = curr_addr_B0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_B0] + invoke B0_write_channel[internal_mem = B0, curr_addr_internal_mem = curr_addr_internal_mem_B0, max_trnsfrs = max_trnsfrs, curr_addr_axi = curr_addr_axi_B0] ( ARESET = m1_ARESET, WREADY = m1_WREADY @@ -1098,7 +1096,7 @@ component main( } seq { //Sum0 writes - invoke Sum0_awwrite_channel[base_addr = base_addr_Sum0, max_trnsfrs = max_trnsfrs] + invoke Sum0_awwrite_channel[curr_addr_axi = curr_addr_axi_Sum0, max_trnsfrs = max_trnsfrs] ( ARESET = m2_ARESET, AWREADY = m2_AWREADY @@ -1112,9 +1110,9 @@ component main( AWPROT = m2_AWPROT ); - //invoke curr_addr_Sum0(in = base_addr_Sum0.out)(); //set curr_addr to base_address + //invoke curr_addr_internal_mem_Sum0(in = curr_addr_axi_Sum0.out)(); //set curr_addr_internal_mem to curr_addr_axiess - invoke Sum0_write_channel[internal_mem = Sum0, curr_addr = curr_addr_Sum0, max_trnsfrs = max_trnsfrs, base_addr = base_addr_Sum0] + invoke Sum0_write_channel[internal_mem = Sum0, curr_addr_internal_mem = curr_addr_internal_mem_Sum0, max_trnsfrs = max_trnsfrs, curr_addr_axi = curr_addr_axi_Sum0] ( ARESET = m2_ARESET, WREADY = m2_WREADY diff --git a/yxi/axi-calyx/axi-generator.py b/yxi/axi-calyx/axi-generator.py index 89e87df33..21e61eade 100644 --- a/yxi/axi-calyx/axi-generator.py +++ b/yxi/axi-calyx/axi-generator.py @@ -88,8 +88,8 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): # Cells xvalid = m_to_s_address_channel.reg(f"{lc_x}valid", 1) - xvalid_was_high = m_to_s_address_channel.reg(f"{lc_x}valid_was_high", 1) - base_addr = m_to_s_address_channel.reg("base_addr", 64, is_ref=True) + xhandshake_occurred = m_to_s_address_channel.reg(f"{lc_x}_handshake_occurred", 1) + curr_addr_axi = m_to_s_address_channel.reg("curr_addr_axi", 64, is_ref=True) xlen = m_to_s_address_channel.reg(f"{lc_x}len", 8) # Number of txns we want to occur before m_arread_channel is done @@ -111,19 +111,16 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): # See #1828 https://github.com/calyxir/calyx/issues/1828 with m_to_s_address_channel.group(f"do_{lc_x}_transfer") as do_x_transfer: xREADY = m_to_s_address_channel.this()[f"{x}READY"] - # TODO: Can we simplify this? - # See comments #1846 https://github.com/calyxir/calyx/pull/1846 - # Assert arvalid if it was not previously high - xvalid.in_ = ~xvalid_was_high.out @ 1 + xvalid.in_ = (~(xvalid.out & xREADY) & ~xhandshake_occurred.out) @ 1 # Deassert in the next cycle once it is high - xvalid.in_ = (xvalid.out & xREADY & xvalid_was_high.out) @ 0 + xvalid.in_ = ((xvalid.out & xREADY) | xhandshake_occurred.out) @ 0 xvalid.write_en = 1 - xvalid_was_high.in_ = (~(xvalid.out & xREADY) & ~xvalid_was_high.out) @ 1 - xvalid_was_high.write_en = (~(xvalid.out & xREADY) & ~xvalid_was_high.out) @ 1 + xhandshake_occurred.in_ = (xvalid.out & xREADY) @ 1 + xhandshake_occurred.write_en = (~xhandshake_occurred.out) @ 1 # Drive output signals for transfer - m_to_s_address_channel.this()[f"{x}ADDR"] = base_addr.out + m_to_s_address_channel.this()[f"{x}ADDR"] = curr_addr_axi.out # This is taken from mem size, we assume the databus width is the size # of our memory cell and that width is a power of 2 # TODO(nathanielnrn): convert to binary instead of decimal @@ -163,7 +160,7 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): while_body = [ par( invoke(bt_reg, in_in=0), - invoke(xvalid_was_high, in_in=0), + invoke(xhandshake_occurred, in_in=0), ), do_x_transfer, invoke(xvalid, in_in=0), @@ -206,8 +203,8 @@ def add_read_channel(prog, mem): # according to zipcpu, rready should be registered rready = read_channel.reg("rready", 1) - curr_addr = read_channel.reg("curr_addr", clog2(mem["size"]), is_ref=True) - base_addr = read_channel.reg("base_addr", 64, is_ref=True) + curr_addr_internal_mem = read_channel.reg("curr_addr_internal_mem", clog2(mem["size"]), is_ref=True) + curr_addr_axi = read_channel.reg("curr_addr_axi", 64, is_ref=True) # Registed because RLAST is high with laster transfer, not after # before this we were terminating immediately with # last transfer and not servicing it @@ -266,18 +263,18 @@ def add_read_channel(prog, mem): rready.write_en = 1 # write data we received to mem_ref - mem_ref.addr0 = curr_addr.out + mem_ref.addr0 = curr_addr_internal_mem.out mem_ref.write_data = read_data_reg.out mem_ref.write_en = 1 service_read_transfer.done = mem_ref.done - # creates group that increments curr_addr by 1. Creates adder and wires up correctly - curr_addr_incr = read_channel.incr(curr_addr, 1) - # TODO(nathanielnrn): Currently we assume that width is a power of 2. + # creates group that increments curr_addr_internal_mem by 1. Creates adder and wires up correctly + curr_addr_internal_mem_incr = read_channel.incr(curr_addr_internal_mem, 1) + # TODO(nathanielnrn): Currently we assume that width is a power of 2 due to xSIZE. # In the future we should allow for non-power of 2 widths, will need some # splicing for this. # See https://cucapra.slack.com/archives/C05TRBNKY93/p1705587169286609?thread_ts=1705524171.974079&cid=C05TRBNKY93 # noqa: E501 - base_addr_incr = read_channel.incr(base_addr, ceil(mem["width"] / 8)) + curr_addr_axi_incr = read_channel.incr(curr_addr_axi, width_in_bytes(mem["width"])) # Control invoke_n_RLAST = invoke(n_RLAST, in_in=1) @@ -286,7 +283,7 @@ def add_read_channel(prog, mem): invoke_bt_reg, block_transfer, service_read_transfer, - par(curr_addr_incr, base_addr_incr), + par(curr_addr_internal_mem_incr, curr_addr_axi_incr), ] while_n_RLAST = while_(n_RLAST.out, while_body) @@ -296,8 +293,6 @@ def add_read_channel(prog, mem): def add_write_channel(prog, mem): # Inputs/Outputs write_channel = prog.component("m_write_channel") - # We assume idx_size is exactly clog2(len). See comment in #1751 - # https://github.com/calyxir/calyx/issues/1751#issuecomment-1778360566 channel_inputs = [("ARESETn", 1), ("WREADY", 1)] # TODO(nathanielnrn): We currently assume WDATA is the same width as the # memory. This limits throughput many AXI data busses are much wider @@ -323,11 +318,11 @@ def add_write_channel(prog, mem): # according to zipcpu, rready should be registered wvalid = write_channel.reg("wvalid", 1) - wvalid_was_high = write_channel.reg("wvalid_was_high", 1) + w_handshake_occurred = write_channel.reg("w_handshake_occurred", 1) # internal calyx memory indexing - curr_addr = write_channel.reg("curr_addr", clog2(mem["size"]), is_ref=True) + curr_addr_internal_mem = write_channel.reg("curr_addr_internal_mem", clog2(mem["size"]), is_ref=True) # host indexing, must be 64 bits - base_addr = write_channel.reg("base_addr", 64, is_ref=True) + curr_addr_axi = write_channel.reg("curr_addr_axi", 64, is_ref=True) curr_trsnfr_count = write_channel.reg("curr_trsnfr_count", 8) # Number of transfers we want to do in current txn @@ -346,19 +341,19 @@ def add_write_channel(prog, mem): with write_channel.group("service_write_transfer") as service_write_transfer: WREADY = write_channel.this()["WREADY"] - # Assert then deassert. Can maybe getgit right of wvalid_was_high in guard - wvalid.in_ = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 - wvalid.in_ = (wvalid.out & WREADY & wvalid_was_high.out) @ 0 + # Assert then deassert. Can maybe getgit right of w_handshake_occurred in guard + wvalid.in_ = (~(wvalid.out & WREADY) & ~w_handshake_occurred.out) @ 1 + wvalid.in_ = ((wvalid.out & WREADY) | w_handshake_occurred.out) @ 0 wvalid.write_en = 1 # Set high when wvalid is high even once # This is just wavlid.in_ guard from above # TODO: confirm this is correct? - wvalid_was_high.in_ = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 - wvalid_was_high.write_en = ~(wvalid.out & WREADY & wvalid_was_high.out) @ 1 + w_handshake_occurred.in_ = (wvalid.out & WREADY) @ 1 + w_handshake_occurred.write_en = (~w_handshake_occurred.out) @ 1 # Set data output based on intermal memory output - mem_ref.addr0 = curr_addr.out + mem_ref.addr0 = curr_addr_internal_mem.out mem_ref.read_en = 1 write_channel.this()["WDATA"] = mem_ref.read_data @@ -383,29 +378,28 @@ def add_write_channel(prog, mem): bt_reg.write_en = 1 service_write_transfer.done = bt_reg.out - # creates group that increments curr_addr by 1. # Creates adder and wires up correctly - curr_addr_incr = write_channel.incr(curr_addr, 1) + curr_addr_internal_mem_incr = write_channel.incr(curr_addr_internal_mem, 1) # TODO(nathanielnrn): Currently we assume that width is a power of 2. # In the future we should allow for non-power of 2 widths, will need some # splicing for this. # See https://cucapra.slack.com/archives/C05TRBNKY93/p1705587169286609?thread_ts=1705524171.974079&cid=C05TRBNKY93 # noqa: E501 - base_addr_incr = write_channel.incr(base_addr, ceil(mem["width"] / 8)) + curr_addr_axi_incr = write_channel.incr(curr_addr_axi, ceil(mem["width"] / 8)) curr_trsnfr_count_incr = write_channel.incr(curr_trsnfr_count, 1) # Control - init_curr_addr = invoke(curr_addr, in_in=0) + init_curr_addr_internal_mem = invoke(curr_addr_internal_mem, in_in=0) init_n_finished_last_trnsfr = invoke(n_finished_last_trnsfr, in_in=1) while_n_finished_last_trnsfr_body = [ invoke(bt_reg, in_in=0), service_write_transfer, - par(curr_addr_incr, curr_trsnfr_count_incr, base_addr_incr), + par(curr_addr_internal_mem_incr, curr_trsnfr_count_incr, curr_addr_axi_incr, invoke(w_handshake_occurred, in_in=0)), ] while_n_finished_last_trnsfr = while_( n_finished_last_trnsfr.out, while_n_finished_last_trnsfr_body ) write_channel.control += [ - init_curr_addr, + init_curr_addr_internal_mem, init_n_finished_last_trnsfr, while_n_finished_last_trnsfr, ] @@ -469,13 +463,20 @@ def clog2(x): def build(): prog = Builder() - # add_arread_channel(prog, mems[0]) - # add_awwrite_channel(prog, mems[0]) - # add_read_channel(prog, mems[0]) - # add_write_channel(prog, mems[0]) + check_mems_welformed(mems) + add_arread_channel(prog, mems[0]) + add_awwrite_channel(prog, mems[0]) + add_read_channel(prog, mems[0]) + add_write_channel(prog, mems[0]) add_bresp_channel(prog, mems[0]) return prog.program +def check_mems_welformed(mems): + """Checks if memories from yxi are well formed. Returns true if they are, false otherwise.""" + for mem in mems: + assert mem["width"] % 8 == 0, "Width must be a multiple of 8 to alow byte addressing to host" + assert log2(mem["width"]).is_integer(), "Width must be a power of 2 to be correctly described by xSIZE" + assert mem["size"] > 0, "Memory size must be greater than 0" if __name__ == "__main__": build().emit() From 766c47285d9b3d47bd7f6231cdda0d6bab63d32a Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 28 Jan 2024 18:07:56 -0500 Subject: [PATCH 152/189] Initial fud2 import (#1877) * Import code for fud2 & fake A snapshot of sampsyo/fake, at commit 8365aa3946d78076ad7c11a972fe2b3ff1a1c420. * Bare-bones fud2 docs * Format * Also format the fake crate --- Cargo.lock | 137 ++++++++++ Cargo.toml | 3 + docs/SUMMARY.md | 3 +- docs/running-calyx/fud2.md | 78 ++++++ fud2/Cargo.toml | 8 + fud2/data/gen_xo.tcl | 46 ++++ fud2/data/get-ports.py | 12 + fud2/data/interp-dat.py | 43 +++ fud2/data/json-dat.py | 54 ++++ fud2/data/primitives-for-firrtl.sv | 330 +++++++++++++++++++++++ fud2/data/tb.sv | 77 ++++++ fud2/data/xrt.ini | 4 + fud2/data/xrt_trace.ini | 7 + fud2/fake/Cargo.toml | 13 + fud2/fake/src/cli.rs | 187 +++++++++++++ fud2/fake/src/config.rs | 42 +++ fud2/fake/src/driver.rs | 400 +++++++++++++++++++++++++++ fud2/fake/src/lib.rs | 6 + fud2/fake/src/run.rs | 391 +++++++++++++++++++++++++++ fud2/src/main.rs | 416 +++++++++++++++++++++++++++++ 20 files changed, 2256 insertions(+), 1 deletion(-) create mode 100644 docs/running-calyx/fud2.md create mode 100644 fud2/Cargo.toml create mode 100644 fud2/data/gen_xo.tcl create mode 100644 fud2/data/get-ports.py create mode 100644 fud2/data/interp-dat.py create mode 100644 fud2/data/json-dat.py create mode 100644 fud2/data/primitives-for-firrtl.sv create mode 100644 fud2/data/tb.sv create mode 100644 fud2/data/xrt.ini create mode 100644 fud2/data/xrt_trace.ini create mode 100644 fud2/fake/Cargo.toml create mode 100644 fud2/fake/src/cli.rs create mode 100644 fud2/fake/src/config.rs create mode 100644 fud2/fake/src/driver.rs create mode 100644 fud2/fake/src/lib.rs create mode 100644 fud2/fake/src/run.rs create mode 100644 fud2/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 17bf05397..85f15cfac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,6 +49,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "argh" version = "0.1.12" @@ -86,6 +92,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + [[package]] name = "atty" version = "0.2.14" @@ -169,6 +184,12 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "bytemuck" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9" + [[package]] name = "byteorder" version = "1.4.3" @@ -300,6 +321,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + [[package]] name = "cast" version = "0.3.0" @@ -396,6 +423,12 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-entity" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7" + [[package]] name = "criterion" version = "0.3.6" @@ -701,6 +734,19 @@ dependencies = [ "str-buf", ] +[[package]] +name = "fake" +version = "0.6.1" +dependencies = [ + "anyhow", + "argh", + "camino", + "cranelift-entity", + "figment", + "pathdiff", + "serde", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -718,6 +764,19 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "figment" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6e5bc7bd59d60d0d45a6ccab6cf0f4ce28698fb4e81e750ddf229c9b824026" +dependencies = [ + "atomic", + "serde", + "toml", + "uncased", + "version_check 0.9.4", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -742,6 +801,14 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "fud2" +version = "0.6.1" +dependencies = [ + "anyhow", + "fake", +] + [[package]] name = "funty" version = "2.0.0" @@ -1155,6 +1222,15 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +dependencies = [ + "camino", +] + [[package]] name = "pest" version = "2.7.2" @@ -1598,6 +1674,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_with" version = "1.14.0" @@ -1905,6 +1990,40 @@ dependencies = [ "serde_json", ] +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -1929,6 +2048,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check 0.9.4", +] + [[package]] name = "unicode-ident" version = "1.0.11" @@ -2172,6 +2300,15 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winnow" +version = "0.5.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d" +dependencies = [ + "memchr", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index ca029447d..3482ad8d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ members = [ "web/rust", "tools/data_gen", "cider-dap", + "fud2", + "fud2/fake", ] exclude = ["site"] @@ -43,6 +45,7 @@ pest = "2" pest_derive = "2" pest_consume = "1" argh = "0.1" +anyhow = "1" calyx-utils = { path = "calyx-utils", version = "0.6.1" } calyx-ir = { path = "calyx-ir", version = "0.6.1" } calyx-frontend = { path = "calyx-frontend", version = "0.6.1" } diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index aa7899c04..e10bfa6d1 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -14,7 +14,7 @@ # Running Calyx Programs -- [`fud`: The Calyx Driver](./running-calyx/fud/index.md) +- [fud: The Calyx Driver](./running-calyx/fud/index.md) - [Examples](./running-calyx/fud/examples.md) - [Xilinx Tools](./running-calyx/fud/xilinx.md) - [AXI Generation](./running-calyx/fud/axi-gen.md) @@ -22,6 +22,7 @@ - [Multiple Paths](./running-calyx/fud/multiple-paths.md) - [CIRCT](./running-calyx/fud/circt.md) - [Resource Estimation](./running-calyx/fud/resource-estimation.md) +- [fud2: Experimental Driver](./running-calyx/fud2.md) - [Interfacing with Calyx RTL](./running-calyx/interfacing.md) - [The Calyx Interpreter](./running-calyx/interpreter.md) diff --git a/docs/running-calyx/fud2.md b/docs/running-calyx/fud2.md new file mode 100644 index 000000000..4e80ab028 --- /dev/null +++ b/docs/running-calyx/fud2.md @@ -0,0 +1,78 @@ +# fud2: An Experimental Successor to fud + +[fud][] is the compiler driver tool for orchestrating the Calyx ecosystem. +fud2 is an experiment in building a new driver that works like fud that adds some fundamental new capabilities and resolves some underlying problems. + +"Original" fud is still the right tool for almost all jobs; fud2 is in an experimental phase and does not support everything fud can do. +Someday, fud2 may supplant fud, but it needs more work before it is ready to do that. +Until then, fud remains your first choice for all your build-related needs. + +[fud]: ./fud/index.md + +## Set Up + +fud2 is a Rust tool, so you can build it along with everything else in this monorepo with `cargo build`. +You might then want to do something like ``ln -s `pwd`/target/debug/fud2 ~/.local/bin`` for easy access to the `fud2` binary. + +fud2 depends on [Ninja][]. +Install it using your OS package manager or by downloading a binary. + +Create a configuration file at `~/.config/fud2.toml`, using the path to your checkout of the Calyx git repository: + +```toml +data = ".../calyx/fud2/data" + +[calyx] +base = ".../calyx" +``` + +Now you're ready to use fud2. + +[ninja]: https://ninja-build.org + +## General Use + +You can see complete command-line documentation with `fud2 --help`. +But generally, you want to do something like this: + + $ fud2 -o + +For example, use this to compile a Calyx program to Verilog: + + $ fud2 foo.futil -o bar.sv + +fud2 tries to automatically guess the input and output formats using filename extensions. +If that doesn't work, you can choose for it with `--from ` and `--to `; +for example, this is a more explicit version of the above: + + $ fud2 foo.futil -o bar.sv --from calyx --to verilog + +You can also omit the input and output filenames to instead use stdin and stdout. +In that case, `--from` and `--to` respectively are required. +So here's yet another way to do the same thing: + + $ fud2 --from calyx --to verilog < foo.futil > bar.sv + +This is handy if you just want to print the result of a build to the console: + + $ fud2 foo.futil --to verilog + +Some operations use other configuration options, which can come from either your `fud2.toml` or the command line. +Use `--set key=value` to override any such option. + +## Advanced Options + +Here are some options you might need: + +* By default, fud2 runs the build in a directory called `.fud2` within the working directory. It automatically deletes this directory when the build is done. + * It can be useful to keep this build directory around for debugging or as a "cache" for future builds. Use `--keep` to prevent fud2 from deleting the build directory. + * You can also tell fud2 to use a different build directory with `--dir`. If you give it an existing directory, it will never be deleted, even without `--keep`. (Only "fresh" build directories are automatically cleaned up.) +* If you don't like the operation path that fud2 selected for your build, you can control it with `--through `. fud2 will search the operation graph for a path that contains that op. You can provide this option multiple times; fud2 will look for paths that contain *all* these operations, in order. +* You can choose one of several modes with `-m `: + * `run`: Actually execute a build. The default. + * `gen`: Generate the Ninja build file in the build directory, but don't actually run the build. The default `run` mode is therefore approximately like doing `fud2 -m gen && ninja -C .fud2`. + * `emit`: Just print the Ninja build file to stdout. The `gen` mode is therefore approximately `fud2 -m emit > .fud2/build.ninja`. + * `plan`: Print a brief description of the plan, i.e., the sequence of operations that the build would run. + * `dot`: Print a [GraphViz][] depiction of the plan. Try `fud2 -m dot | dot -Tpdf > graph.pdf` and take a look. + +[graphviz]: https://graphviz.org diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml new file mode 100644 index 000000000..31e4c39a3 --- /dev/null +++ b/fud2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "fud2" +version.workspace = true +edition.workspace = true + +[dependencies] +fake = { path = "fake" } +anyhow.workspace = true diff --git a/fud2/data/gen_xo.tcl b/fud2/data/gen_xo.tcl new file mode 100644 index 000000000..dbe328b6d --- /dev/null +++ b/fud2/data/gen_xo.tcl @@ -0,0 +1,46 @@ +if { $::argc < 1 } { + #puts "ERROR: Program \"$::argv0\" requires 1 argument!\n" + puts "ERROR: Executable name unspecified\n" + puts "Usage: $::argv0 $::argv \n" + exit +} + +# Define a process that pops an element off of the list +proc lvarpop {upVar {index 0}} { + upvar $upVar list; + if {![info exists list]} { return "-1" } + set top [lindex $list $index]; + set list [concat [lrange $list 0 [expr $index - 1]] [lrange $list [expr $index +1] end]] + return $top; +} + +set xoname [lindex $::argv 0] +set path_to_packaged "./packaged_kernel" + +# Make a temporary Vivado project. +create_project -force kernel_pack "./tmp_kernel_pack" + +# Add all Verilog files in the current working directory. +add_files -norecurse [glob *.v *.sv] + +# I don't really understand any of this. +ipx::package_project -root_dir $path_to_packaged -vendor capra.cs.cornell.edu -library RTLKernel -taxonomy /KernelIP -import_files -set_current false +ipx::unload_core $path_to_packaged/component.xml +ipx::edit_ip_in_project -upgrade true -name tmp_edit_project -directory $path_to_packaged $path_to_packaged/component.xml +set_property sdx_kernel true [ipx::current_core] +set_property sdx_kernel_type rtl [ipx::current_core] + +# Declare bus interfaces. +ipx::associate_bus_interfaces -busif s_axi_control -clock ap_clk [ipx::current_core] +lvarpop argv +foreach busname $argv { + ipx::associate_bus_interfaces -busif $busname -clock ap_clk [ipx::current_core] +} + +# Close & save the temporary project. +ipx::update_checksums [ipx::current_core] +ipx::save_core [ipx::current_core] +close_project -delete + +# Package the project as an .xo file. +package_xo -xo_path ${xoname} -kernel_name Toplevel -ip_directory ${path_to_packaged} -kernel_xml ./kernel.xml diff --git a/fud2/data/get-ports.py b/fud2/data/get-ports.py new file mode 100644 index 000000000..1302c69c6 --- /dev/null +++ b/fud2/data/get-ports.py @@ -0,0 +1,12 @@ +import xml.etree.ElementTree as ET +import sys + + +def get_ports(kernel_xml): + tree = ET.parse(kernel_xml) + for port in tree.findall(".//port[@mode='master']"): + yield port.attrib["name"] + + +if __name__ == "__main__": + print(' '.join(get_ports(sys.argv[1]))) diff --git a/fud2/data/interp-dat.py b/fud2/data/interp-dat.py new file mode 100644 index 000000000..c783a08a5 --- /dev/null +++ b/fud2/data/interp-dat.py @@ -0,0 +1,43 @@ +import simplejson +import sys +import pathlib +from fud.stages.interpreter import convert_to_json, parse_from_json + + +def data2interp(in_file): + """Convert a fud-style JSON data file to Cider-ready JSON. + + The output file is hard-coded to be `data.json`. + """ + round_float_to_fixed = True + with open(in_file) as f: + convert_to_json( + '.', + simplejson.load(f, use_decimal=True), + round_float_to_fixed, + ) + + +def interp2data(in_file, orig_file): + """Convert the Cider's output JSON to fud-style JSON. + + Print the result to stdout. + """ + with open(in_file) as f: + out = parse_from_json(f, pathlib.Path(orig_file)) + simplejson.dump( + out, + sys.stdout, + indent=2, + sort_keys=True, + use_decimal=True, + ) + + +if __name__ == "__main__": + if sys.argv[1] == '--to-interp': + data2interp(*sys.argv[2:]) + elif sys.argv[1] == '--from-interp': + interp2data(*sys.argv[2:]) + else: + print("specify --to-interp or --from-interp", file=sys.stderr) diff --git a/fud2/data/json-dat.py b/fud2/data/json-dat.py new file mode 100644 index 000000000..b6e6d7d37 --- /dev/null +++ b/fud2/data/json-dat.py @@ -0,0 +1,54 @@ +"""Convert between fud-style JSON and hex data files. + +Use the machinery from "old fud" to convert a JSON data file into a +directory of flat hex-encoded files, suitable for loading into a +hardware simulator, and back again. +""" +from fud.stages.verilator.json_to_dat import convert2dat, convert2json +import simplejson +import sys +import os +import re + + +def json2dat(in_file, out_dir): + os.makedirs(out_dir, exist_ok=True) + round_float_to_fixed = True + with open(in_file) as json: + convert2dat( + out_dir, + simplejson.load(json, use_decimal=True), + "dat", + round_float_to_fixed, + ) + + +def dat2json(out_file, in_dir, sim_log=None): + mem = convert2json(in_dir, "out") + + if sim_log: + cycles = 0 + with open(sim_log) as f: + for line in f: + match = re.search(r"Simulated\s+((-)?\d+) cycles", line) + if match: + cycles = int(match.group(1)) + break + out = { + "cycles": cycles, + "memories": mem, + } + else: + out = mem + + with open(out_file, 'w') as f: + simplejson.dump(out, f, indent=2, sort_keys=True, use_decimal=True) + + +if __name__ == '__main__': + if sys.argv[1] == '--from-json': + json2dat(*sys.argv[2:]) + elif sys.argv[1] == '--to-json': + dat2json(*sys.argv[2:]) + else: + print("specify --from-json or --to-json", file=sys.stderr) diff --git a/fud2/data/primitives-for-firrtl.sv b/fud2/data/primitives-for-firrtl.sv new file mode 100644 index 000000000..6335c649a --- /dev/null +++ b/fud2/data/primitives-for-firrtl.sv @@ -0,0 +1,330 @@ +module std_mem_d1 #( + parameter WIDTH = 32, + parameter SIZE = 16, + parameter IDX_SIZE = 4 +) ( + input wire logic [IDX_SIZE-1:0] addr0, + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en, + input wire logic clk, + input wire logic reset, + output logic [ WIDTH-1:0] read_data, + output logic done +); + + logic [WIDTH-1:0] mem[SIZE-1:0]; + + initial begin + $readmemh({"sim_data/mem.dat"}, mem); + end + final begin + $writememh({"sim_data/mem.out"}, mem); + end + + /* verilator lint_off WIDTH */ + assign read_data = mem[addr0]; + + always_ff @(posedge clk) begin + if (reset) + done <= '0; + else if (write_en) + done <= '1; + else + done <= '0; + end + + always_ff @(posedge clk) begin + if (!reset && write_en) + mem[addr0] <= write_data; + end + + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (addr0 >= SIZE) + $error( + "std_mem_d1: Out of bounds access\n", + "addr0: %0d\n", addr0, + "SIZE: %0d", SIZE + ); + end + `endif +endmodule + +/** + * Core primitives for Calyx. + * Implements core primitives used by the compiler. + * + * Conventions: + * - All parameter names must be SNAKE_CASE and all caps. + * - Port names must be snake_case, no caps. + */ +`default_nettype none + +module std_slice #( + parameter IN_WIDTH = 32, + parameter OUT_WIDTH = 32 +) ( + input wire logic [ IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + assign out = in[OUT_WIDTH-1:0]; + + `ifdef VERILATOR + always_comb begin + if (IN_WIDTH < OUT_WIDTH) + $error( + "std_slice: Input width less than output width\n", + "IN_WIDTH: %0d", IN_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_pad #( + parameter IN_WIDTH = 32, + parameter OUT_WIDTH = 32 +) ( + input wire logic [IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + localparam EXTEND = OUT_WIDTH - IN_WIDTH; + assign out = { {EXTEND {1'b0}}, in}; + + `ifdef VERILATOR + always_comb begin + if (IN_WIDTH > OUT_WIDTH) + $error( + "std_pad: Output width less than input width\n", + "IN_WIDTH: %0d", IN_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_cat #( + parameter LEFT_WIDTH = 32, + parameter RIGHT_WIDTH = 32, + parameter OUT_WIDTH = 64 +) ( + input wire logic [LEFT_WIDTH-1:0] left, + input wire logic [RIGHT_WIDTH-1:0] right, + output logic [OUT_WIDTH-1:0] out +); + assign out = {left, right}; + + `ifdef VERILATOR + always_comb begin + if (LEFT_WIDTH + RIGHT_WIDTH != OUT_WIDTH) + $error( + "std_cat: Output width must equal sum of input widths\n", + "LEFT_WIDTH: %0d", LEFT_WIDTH, + "RIGHT_WIDTH: %0d", RIGHT_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_not #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] in, + output logic [WIDTH-1:0] out +); + assign out = ~in; +endmodule + +module std_and #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left & right; +endmodule + +module std_or #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left | right; +endmodule + +module std_xor #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left ^ right; +endmodule + +module std_sub #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left - right; +endmodule + +module std_gt #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left > right; +endmodule + +module std_lt #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left < right; +endmodule + +module std_eq #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left == right; +endmodule + +module std_neq #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left != right; +endmodule + +module std_ge #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left >= right; +endmodule + +module std_le #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left <= right; +endmodule + +module std_lsh #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left << right; +endmodule + +module std_rsh #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left >> right; +endmodule + +/// this primitive is intended to be used +/// for lowering purposes (not in source programs) +module std_mux #( + parameter WIDTH = 32 +) ( + input wire logic cond, + input wire logic [WIDTH-1:0] tru, + input wire logic [WIDTH-1:0] fal, + output logic [WIDTH-1:0] out +); + assign out = cond ? tru : fal; +endmodule + +`default_nettype wire + +module undef #( + parameter WIDTH = 32 +) ( + output logic [WIDTH-1:0] out +); +assign out = 'x; +endmodule + +module std_const #( + parameter WIDTH = 32, + parameter VALUE = 32 +) ( + output logic [WIDTH-1:0] out +); +assign out = VALUE; +endmodule + +module std_wire #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] in, + output logic [WIDTH-1:0] out +); +assign out = in; +endmodule + +module std_add #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] left, + input logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); +assign out = left + right; +endmodule + +module std_reg #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] in, + input logic write_en, + input logic clk, + input logic reset, + output logic [WIDTH-1:0] out, + output logic done +); +always_ff @(posedge clk) begin + if (reset) begin + out <= 0; + done <= 0; + end else if (write_en) begin + out <= in; + done <= 1'd1; + end else done <= 1'd0; + end +endmodule diff --git a/fud2/data/tb.sv b/fud2/data/tb.sv new file mode 100644 index 000000000..c1631bef6 --- /dev/null +++ b/fud2/data/tb.sv @@ -0,0 +1,77 @@ +module TOP; + +// Signals for the main module. +logic go, done, clk, reset; +main #() main ( + .go(go), + .clk(clk), + .reset(reset), + .done(done) +); + +localparam RESET_CYCLES = 3; + +// Cycle counter. Make this signed to catch errors with cycle simulation +// counts. +logic signed [63:0] cycle_count; + +always_ff @(posedge clk) begin + cycle_count <= cycle_count + 1; +end + +always_ff @(posedge clk) begin + // Reset the design for a few cycles + if (cycle_count < RESET_CYCLES) begin + reset <= 1; + go <= 0; + end else begin + reset <= 0; + go <= 1; + end +end + +// Output location of the VCD file +string OUT; +// Disable VCD tracing +int NOTRACE; +// Maximum number of cycles to simulate +longint CYCLE_LIMIT; +// Dummy variable to track value returned by $value$plusargs +int CODE; + +initial begin + CODE = $value$plusargs("OUT=%s", OUT); + CODE = $value$plusargs("CYCLE_LIMIT=%d", CYCLE_LIMIT); + if (CYCLE_LIMIT != 0) begin + $display("cycle limit set to %d", CYCLE_LIMIT); + end + CODE = $value$plusargs("NOTRACE=%d", NOTRACE); + if (NOTRACE == 0) begin + $display("VCD tracing enabled"); + $dumpfile(OUT); + $dumpvars(0,main); + end else begin + $display("VCD tracing disabled"); + end + + // Initial values + go = 0; + clk = 0; + reset = 1; + cycle_count = 0; + + forever begin + #10 clk = ~clk; + if (cycle_count > RESET_CYCLES && done == 1) begin + // Subtract 1 because the cycle counter is incremented at the end of the + // cycle. + $display("Simulated %d cycles", cycle_count - RESET_CYCLES - 1); + $finish; + end else if (cycle_count != 0 && cycle_count == CYCLE_LIMIT + RESET_CYCLES) begin + $display("reached limit of %d cycles", CYCLE_LIMIT); + $finish; + end + end +end + +endmodule diff --git a/fud2/data/xrt.ini b/fud2/data/xrt.ini new file mode 100644 index 000000000..2f2b8e589 --- /dev/null +++ b/fud2/data/xrt.ini @@ -0,0 +1,4 @@ +[Runtime] +runtime_log=xrt.log +[Emulation] +print_infos_in_console=true diff --git a/fud2/data/xrt_trace.ini b/fud2/data/xrt_trace.ini new file mode 100644 index 000000000..21c2738cd --- /dev/null +++ b/fud2/data/xrt_trace.ini @@ -0,0 +1,7 @@ +[Runtime] +runtime_log=xrt.log +[Emulation] +print_infos_in_console=true +debug_mode=batch +user_pre_sim_script=pre_sim.tcl +user_post_sim_script=post_sim.tcl diff --git a/fud2/fake/Cargo.toml b/fud2/fake/Cargo.toml new file mode 100644 index 000000000..cd6e35746 --- /dev/null +++ b/fud2/fake/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fake" +version.workspace = true +edition.workspace = true + +[dependencies] +argh.workspace = true +cranelift-entity = "0.103.0" +serde.workspace = true +figment = { version = "0.10.12", features = ["toml"] } +pathdiff = { version = "0.2.1", features = ["camino"] } +camino = "1.1.6" +anyhow.workspace = true diff --git a/fud2/fake/src/cli.rs b/fud2/fake/src/cli.rs new file mode 100644 index 000000000..5d1547096 --- /dev/null +++ b/fud2/fake/src/cli.rs @@ -0,0 +1,187 @@ +use crate::driver::{Driver, Request, StateRef}; +use crate::run::Run; +use anyhow::{anyhow, bail}; +use argh::FromArgs; +use camino::{Utf8Path, Utf8PathBuf}; +use std::fmt::Display; +use std::str::FromStr; + +enum Mode { + EmitNinja, + ShowPlan, + ShowDot, + Generate, + Run, +} + +impl FromStr for Mode { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "emit" => Ok(Mode::EmitNinja), + "plan" => Ok(Mode::ShowPlan), + "gen" => Ok(Mode::Generate), + "run" => Ok(Mode::Run), + "dot" => Ok(Mode::ShowDot), + _ => Err("unknown mode".to_string()), + } + } +} + +impl Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Mode::EmitNinja => write!(f, "emit"), + Mode::ShowPlan => write!(f, "plan"), + Mode::Generate => write!(f, "gen"), + Mode::Run => write!(f, "run"), + Mode::ShowDot => write!(f, "dot"), + } + } +} + +#[derive(FromArgs)] +/// A generic compiler driver. +struct FakeArgs { + /// the input file + #[argh(positional)] + input: Option, + + /// the output file + #[argh(option, short = 'o')] + output: Option, + + /// the state to start from + #[argh(option)] + from: Option, + + /// the state to produce + #[argh(option)] + to: Option, + + /// execution mode (run, plan, emit, gen, dot) + #[argh(option, short = 'm', default = "Mode::Run")] + mode: Mode, + + /// working directory for the build + #[argh(option)] + dir: Option, + + /// in run mode, keep the temporary directory + #[argh(switch)] + keep: Option, + + /// set a configuration variable (key=value) + #[argh(option, short = 's')] + set: Vec, + + /// route the conversion through a specific operation + #[argh(option)] + through: Vec, + + /// verbose ouput + #[argh(switch, short = 'v')] + verbose: Option, +} + +fn from_state(driver: &Driver, args: &FakeArgs) -> anyhow::Result { + match &args.from { + Some(name) => driver + .get_state(name) + .ok_or(anyhow!("unknown --from state")), + None => match args.input { + Some(ref input) => driver + .guess_state(input) + .ok_or(anyhow!("could not infer input state")), + None => bail!("specify an input file or use --from"), + }, + } +} + +fn to_state(driver: &Driver, args: &FakeArgs) -> anyhow::Result { + match &args.to { + Some(name) => { + driver.get_state(name).ok_or(anyhow!("unknown --to state")) + } + None => match &args.output { + Some(out) => driver + .guess_state(out) + .ok_or(anyhow!("could not infer output state")), + None => Err(anyhow!("specify an output file or use --to")), + }, + } +} + +fn get_request(driver: &Driver, args: &FakeArgs) -> anyhow::Result { + // The default working directory (if not specified) depends on the mode. + let default_workdir = driver.default_workdir(); + let workdir = args.dir.as_deref().unwrap_or_else(|| match args.mode { + Mode::Generate | Mode::Run => default_workdir.as_ref(), + _ => Utf8Path::new("."), + }); + + // Find all the operations to route through. + let through: Result, _> = args + .through + .iter() + .map(|s| { + driver + .get_op(s) + .ok_or(anyhow!("unknown --through op {}", s)) + }) + .collect(); + + Ok(Request { + start_file: args.input.clone(), + start_state: from_state(driver, args)?, + end_file: args.output.clone(), + end_state: to_state(driver, args)?, + through: through?, + workdir: workdir.into(), + }) +} + +pub fn cli(driver: &Driver) -> anyhow::Result<()> { + let args: FakeArgs = argh::from_env(); + + // Make a plan. + let req = get_request(driver, &args)?; + let workdir = req.workdir.clone(); + let plan = driver.plan(req).ok_or(anyhow!("could not find path"))?; + + // Configure. + let mut run = Run::new(driver, plan); + + // Override some global config options. + if let Some(keep) = args.keep { + run.global_config.keep_build_dir = keep; + } + if let Some(verbose) = args.verbose { + run.global_config.verbose = verbose; + } + + // Use `--set` arguments to override configuration values. + for set in args.set { + let mut parts = set.splitn(2, '='); + let key = parts.next().unwrap(); + let value = parts + .next() + .ok_or(anyhow!("--set arguments must be in key=value form"))?; + let dict = figment::util::nest(key, value.into()); + run.config_data = run + .config_data + .merge(figment::providers::Serialized::defaults(dict)); + } + + // Execute. + match args.mode { + Mode::ShowPlan => run.show(), + Mode::ShowDot => run.show_dot(), + Mode::EmitNinja => run.emit_to_stdout()?, + Mode::Generate => run.emit_to_dir(&workdir)?, + Mode::Run => run.emit_and_run(&workdir)?, + } + + Ok(()) +} diff --git a/fud2/fake/src/config.rs b/fud2/fake/src/config.rs new file mode 100644 index 000000000..437445539 --- /dev/null +++ b/fud2/fake/src/config.rs @@ -0,0 +1,42 @@ +use figment::{ + providers::{Format, Serialized, Toml}, + Figment, +}; +use serde::{Deserialize, Serialize}; +use std::{env, path::Path}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct GlobalConfig { + /// The `ninja` command to execute in `run` mode. + pub ninja: String, + + /// Never delete the temporary directory used to execute ninja in `run` mode. + pub keep_build_dir: bool, + + /// Enable verbose output. + pub verbose: bool, +} + +impl Default for GlobalConfig { + fn default() -> Self { + Self { + ninja: "ninja".to_string(), + keep_build_dir: false, + verbose: false, + } + } +} + +/// Load configuration data from the standard config file location. +pub(crate) fn load_config(name: &str) -> Figment { + // The configuration is usually at `~/.config/driver_name.toml`. + let config_base = env::var("XDG_CONFIG_HOME").unwrap_or_else(|_| { + let home = env::var("HOME").expect("$HOME not set"); + home + "/.config" + }); + let config_path = Path::new(&config_base).join(name).with_extension("toml"); + + // Use our defaults, overridden by the TOML config file. + Figment::from(Serialized::defaults(GlobalConfig::default())) + .merge(Toml::file(config_path)) +} diff --git a/fud2/fake/src/driver.rs b/fud2/fake/src/driver.rs new file mode 100644 index 000000000..ee4945909 --- /dev/null +++ b/fud2/fake/src/driver.rs @@ -0,0 +1,400 @@ +use crate::run; +use camino::{Utf8Path, Utf8PathBuf}; +use cranelift_entity::{entity_impl, PrimaryMap, SecondaryMap}; +use pathdiff::diff_utf8_paths; + +/// A State is a type of file that Operations produce or consume. +pub struct State { + /// The name of the state, for the UI. + pub name: String, + + /// The file extensions that this state can be represented by. + /// + /// The first extension in the list is used when generating a new filename for the state. If + /// the list is empty, this is a "pseudo-state" that doesn't correspond to an actual file. + /// Pseudo-states can only be final outputs; they are appropraite for representing actions that + /// interact directly with the user, for example. + pub extensions: Vec, +} + +/// A reference to a State. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct StateRef(u32); +entity_impl!(StateRef, "state"); + +/// An Operation transforms files from one State to another. +pub struct Operation { + pub name: String, + pub input: StateRef, + pub output: StateRef, + pub setups: Vec, + pub emit: Box, +} + +/// A reference to an Operation. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct OpRef(u32); +entity_impl!(OpRef, "op"); + +/// A Setup runs at configuration time and produces Ninja machinery for Operations. +pub struct Setup { + pub name: String, + pub emit: Box, +} + +/// A reference to a Setup. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct SetupRef(u32); +entity_impl!(SetupRef, "setup"); + +impl State { + /// Check whether a filename extension indicates this state. + fn ext_matches(&self, ext: &str) -> bool { + self.extensions.iter().any(|e| e == ext) + } + + /// Is this a "pseudo-state": doesn't correspond to an actual file, and must be an output state? + fn is_pseudo(&self) -> bool { + self.extensions.is_empty() + } +} + +/// Get a version of `path` that works when the working directory is `base`. This is +/// opportunistically a relative path, but we can always fall back to an absolute path to make sure +/// the path still works. +pub fn relative_path(path: &Utf8Path, base: &Utf8Path) -> Utf8PathBuf { + match diff_utf8_paths(path, base) { + Some(p) => p, + None => path + .canonicalize_utf8() + .expect("could not get absolute path"), + } +} + +#[derive(PartialEq)] +enum Destination { + State(StateRef), + Op(OpRef), +} + +/// A Driver encapsulates a set of States and the Operations that can transform between them. It +/// contains all the machinery to perform builds in a given ecosystem. +pub struct Driver { + pub name: String, + pub setups: PrimaryMap, + pub states: PrimaryMap, + pub ops: PrimaryMap, +} + +impl Driver { + /// Find a chain of Operations from the `start` state to the `end`, which may be a state or the + /// final operation in the chain. + fn find_path_segment( + &self, + start: StateRef, + end: Destination, + ) -> Option> { + // Our start state is the input. + let mut visited = SecondaryMap::::new(); + visited[start] = true; + + // Build the incoming edges for each vertex. + let mut breadcrumbs = SecondaryMap::>::new(); + + // Breadth-first search. + let mut state_queue: Vec = vec![start]; + while !state_queue.is_empty() { + let cur_state = state_queue.remove(0); + + // Finish when we reach the goal vertex. + if end == Destination::State(cur_state) { + break; + } + + // Traverse any edge from the current state to an unvisited state. + for (op_ref, op) in self.ops.iter() { + if op.input == cur_state && !visited[op.output] { + state_queue.push(op.output); + visited[op.output] = true; + breadcrumbs[op.output] = Some(op_ref); + } + + // Finish when we reach the goal edge. + if end == Destination::Op(op_ref) { + break; + } + } + } + + // Traverse the breadcrumbs backward to build up the path back from output to input. + let mut op_path: Vec = vec![]; + let mut cur_state = match end { + Destination::State(state) => state, + Destination::Op(op) => { + op_path.push(op); + self.ops[op].input + } + }; + while cur_state != start { + match breadcrumbs[cur_state] { + Some(op) => { + op_path.push(op); + cur_state = self.ops[op].input; + } + None => return None, + } + } + op_path.reverse(); + + Some(op_path) + } + + /// Find a chain of operations from the `start` state to the `end` state, passing through each + /// `through` operation in order. + pub fn find_path( + &self, + start: StateRef, + end: StateRef, + through: &[OpRef], + ) -> Option> { + let mut cur_state = start; + let mut op_path: Vec = vec![]; + + // Build path segments through each through required operation. + for op in through { + let segment = + self.find_path_segment(cur_state, Destination::Op(*op))?; + op_path.extend(segment); + cur_state = self.ops[*op].output; + } + + // Build the final path segment to the destination state. + let segment = + self.find_path_segment(cur_state, Destination::State(end))?; + op_path.extend(segment); + + Some(op_path) + } + + /// Generate a filename with an extension appropriate for the given State. + fn gen_name(&self, stem: &str, state: StateRef) -> Utf8PathBuf { + let state = &self.states[state]; + if state.is_pseudo() { + Utf8PathBuf::from(format!("_pseudo_{}", state.name)) + } else { + // TODO avoid collisions in case we reuse extensions... + Utf8PathBuf::from(stem).with_extension(&state.extensions[0]) + } + } + + pub fn plan(&self, req: Request) -> Option { + // Find a path through the states. + let path = + self.find_path(req.start_state, req.end_state, &req.through)?; + + let mut steps: Vec<(OpRef, Utf8PathBuf)> = vec![]; + + // Get the initial input filename and the stem to use to generate all intermediate filenames. + let (stdin, start_file) = match req.start_file { + Some(path) => (false, relative_path(&path, &req.workdir)), + None => (true, "stdin".into()), + }; + let stem = start_file.file_stem().unwrap(); + + // Generate filenames for each step. + steps.extend(path.into_iter().map(|op| { + let filename = self.gen_name(stem, self.ops[op].output); + (op, filename) + })); + + // If we have a specified output filename, use that instead of the generated one. + let stdout = if let Some(end_file) = req.end_file { + // TODO Can we just avoid generating the unused filename in the first place? + let last_step = steps.last_mut().expect("no steps"); + last_step.1 = relative_path(&end_file, &req.workdir); + false + } else { + // Print to stdout if the last state is a real (non-pseudo) state. + !self.states[req.end_state].is_pseudo() + }; + + Some(Plan { + start: start_file, + steps, + workdir: req.workdir, + stdin, + stdout, + }) + } + + pub fn guess_state(&self, path: &Utf8Path) -> Option { + let ext = path.extension()?; + self.states + .iter() + .find(|(_, state_data)| state_data.ext_matches(ext)) + .map(|(state, _)| state) + } + + pub fn get_state(&self, name: &str) -> Option { + self.states + .iter() + .find(|(_, state_data)| state_data.name == name) + .map(|(state, _)| state) + } + + pub fn get_op(&self, name: &str) -> Option { + self.ops + .iter() + .find(|(_, op_data)| op_data.name == name) + .map(|(op, _)| op) + } + + /// The working directory to use when running a build. + pub fn default_workdir(&self) -> Utf8PathBuf { + format!(".{}", &self.name).into() + } +} + +pub struct DriverBuilder { + name: String, + setups: PrimaryMap, + states: PrimaryMap, + ops: PrimaryMap, +} + +impl DriverBuilder { + pub fn new(name: &str) -> Self { + Self { + name: name.to_string(), + setups: Default::default(), + states: Default::default(), + ops: Default::default(), + } + } + + pub fn state(&mut self, name: &str, extensions: &[&str]) -> StateRef { + self.states.push(State { + name: name.to_string(), + extensions: extensions.iter().map(|s| s.to_string()).collect(), + }) + } + + fn add_op( + &mut self, + name: &str, + setups: &[SetupRef], + input: StateRef, + output: StateRef, + emit: T, + ) -> OpRef { + self.ops.push(Operation { + name: name.into(), + setups: setups.into(), + input, + output, + emit: Box::new(emit), + }) + } + + pub fn add_setup( + &mut self, + name: &str, + emit: T, + ) -> SetupRef { + self.setups.push(Setup { + name: name.into(), + emit: Box::new(emit), + }) + } + + pub fn setup(&mut self, name: &str, func: run::EmitSetupFn) -> SetupRef { + self.add_setup(name, func) + } + + pub fn op( + &mut self, + name: &str, + setups: &[SetupRef], + input: StateRef, + output: StateRef, + build: run::EmitBuildFn, + ) -> OpRef { + self.add_op(name, setups, input, output, build) + } + + pub fn rule( + &mut self, + setups: &[SetupRef], + input: StateRef, + output: StateRef, + rule_name: &str, + ) -> OpRef { + self.add_op( + rule_name, + setups, + input, + output, + run::EmitRuleBuild { + rule_name: rule_name.to_string(), + }, + ) + } + + pub fn build(self) -> Driver { + Driver { + name: self.name, + setups: self.setups, + states: self.states, + ops: self.ops, + } + } +} + +/// A request to the Driver directing it what to build. +#[derive(Debug)] +pub struct Request { + /// The input format. + pub start_state: StateRef, + + /// The output format to produce. + pub end_state: StateRef, + + /// The filename to read the input from, or None to read from stdin. + pub start_file: Option, + + /// The filename to write the output to, or None to print to stdout. + pub end_file: Option, + + /// A sequence of operators to route the conversion through. + pub through: Vec, + + /// The working directory for the build. + pub workdir: Utf8PathBuf, +} + +#[derive(Debug)] +pub struct Plan { + /// The input to the first step. + pub start: Utf8PathBuf, + + /// The chain of operations to run and each step's output file. + pub steps: Vec<(OpRef, Utf8PathBuf)>, + + /// The directory that the build will happen in. + pub workdir: Utf8PathBuf, + + /// Read the first input from stdin. + pub stdin: bool, + + /// Write the final output to stdout. + pub stdout: bool, +} + +impl Plan { + pub fn end(&self) -> &Utf8Path { + match self.steps.last() { + Some((_, path)) => path, + None => &self.start, + } + } +} diff --git a/fud2/fake/src/lib.rs b/fud2/fake/src/lib.rs new file mode 100644 index 000000000..2e2faa0a1 --- /dev/null +++ b/fud2/fake/src/lib.rs @@ -0,0 +1,6 @@ +pub mod cli; +pub mod config; +pub mod driver; +pub mod run; + +pub use driver::{Driver, DriverBuilder}; diff --git a/fud2/fake/src/run.rs b/fud2/fake/src/run.rs new file mode 100644 index 000000000..780c62f53 --- /dev/null +++ b/fud2/fake/src/run.rs @@ -0,0 +1,391 @@ +use crate::config; +use crate::driver::{relative_path, Driver, OpRef, Plan, SetupRef, StateRef}; +use camino::{Utf8Path, Utf8PathBuf}; +use std::collections::{HashMap, HashSet}; +use std::io::Write; +use std::process::Command; + +/// An error that arises while emitting the Ninja file. +#[derive(Debug)] +pub enum EmitError { + Io(std::io::Error), + MissingConfig(String), +} + +impl From for EmitError { + fn from(e: std::io::Error) -> Self { + Self::Io(e) + } +} + +impl std::fmt::Display for EmitError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + EmitError::Io(e) => write!(f, "{}", e), + EmitError::MissingConfig(s) => { + write!(f, "missing required config key: {}", s) + } + } + } +} + +impl std::error::Error for EmitError {} + +pub type EmitResult = std::result::Result<(), EmitError>; + +/// Code to emit a Ninja `build` command. +pub trait EmitBuild { + fn build( + &self, + emitter: &mut Emitter, + input: &str, + output: &str, + ) -> EmitResult; +} + +pub type EmitBuildFn = fn(&mut Emitter, &str, &str) -> EmitResult; + +impl EmitBuild for EmitBuildFn { + fn build( + &self, + emitter: &mut Emitter, + input: &str, + output: &str, + ) -> EmitResult { + self(emitter, input, output) + } +} + +// TODO make this unnecessary... +/// A simple `build` emitter that just runs a Ninja rule. +pub struct EmitRuleBuild { + pub rule_name: String, +} + +impl EmitBuild for EmitRuleBuild { + fn build( + &self, + emitter: &mut Emitter, + input: &str, + output: &str, + ) -> EmitResult { + emitter.build(&self.rule_name, input, output)?; + Ok(()) + } +} + +/// Code to emit Ninja code at the setup stage. +pub trait EmitSetup { + fn setup(&self, emitter: &mut Emitter) -> EmitResult; +} + +pub type EmitSetupFn = fn(&mut Emitter) -> EmitResult; + +impl EmitSetup for EmitSetupFn { + fn setup(&self, emitter: &mut Emitter) -> EmitResult { + self(emitter) + } +} + +pub struct Run<'a> { + pub driver: &'a Driver, + pub plan: Plan, + pub config_data: figment::Figment, + pub global_config: config::GlobalConfig, +} + +impl<'a> Run<'a> { + pub fn new(driver: &'a Driver, plan: Plan) -> Self { + let config_data = config::load_config(&driver.name); + let global_config: config::GlobalConfig = + config_data.extract().expect("failed to load config"); + Self { + driver, + plan, + config_data, + global_config, + } + } + + /// Just print the plan for debugging purposes. + pub fn show(self) { + if self.plan.stdin { + println!("(stdin) -> {}", self.plan.start); + } else { + println!("start: {}", self.plan.start); + } + for (op, file) in self.plan.steps { + println!("{}: {} -> {}", op, self.driver.ops[op].name, file); + } + if self.plan.stdout { + println!("-> (stdout)"); + } + } + + /// Print a GraphViz representation of the plan. + pub fn show_dot(self) { + println!("digraph plan {{"); + println!(" rankdir=LR;"); + println!(" node[shape=box];"); + + // Record the states and ops that are actually used in the plan. + let mut states: HashMap = HashMap::new(); + let mut ops: HashSet = HashSet::new(); + let first_op = self.plan.steps[0].0; + states.insert( + self.driver.ops[first_op].input, + self.plan.start.to_string(), + ); + for (op, file) in &self.plan.steps { + states.insert(self.driver.ops[*op].output, file.to_string()); + ops.insert(*op); + } + + // Show all states. + for (state_ref, state) in self.driver.states.iter() { + print!(" {} [", state_ref); + if let Some(filename) = states.get(&state_ref) { + print!( + "label=\"{}\n{}\" penwidth=3 fillcolor=gray style=filled", + state.name, filename + ); + } else { + print!("label=\"{}\"", state.name); + } + println!("];"); + } + + // Show all operations. + for (op_ref, op) in self.driver.ops.iter() { + print!(" {} -> {} [label=\"{}\"", op.input, op.output, op.name); + if ops.contains(&op_ref) { + print!(" penwidth=3"); + } + println!("];"); + } + + println!("}}"); + } + + /// Print the `build.ninja` file to stdout. + pub fn emit_to_stdout(&self) -> EmitResult { + self.emit(std::io::stdout()) + } + + /// Ensure that a directory exists and write `build.ninja` inside it. + pub fn emit_to_dir(&self, dir: &Utf8Path) -> EmitResult { + std::fs::create_dir_all(dir)?; + let ninja_path = dir.join("build.ninja"); + let ninja_file = std::fs::File::create(ninja_path)?; + + self.emit(ninja_file) + } + + /// Emit `build.ninja` to a temporary directory and then actually execute ninja. + pub fn emit_and_run(&self, dir: &Utf8Path) -> EmitResult { + // Emit the Ninja file. + let stale_dir = dir.exists(); + self.emit_to_dir(dir)?; + + // Capture stdin. + if self.plan.stdin { + let stdin_file = std::fs::File::create( + self.plan.workdir.join(&self.plan.start), + )?; + std::io::copy( + &mut std::io::stdin(), + &mut std::io::BufWriter::new(stdin_file), + )?; + } + + // Run `ninja` in the working directory. + let mut cmd = Command::new(&self.global_config.ninja); + cmd.current_dir(dir); + if self.plan.stdout && !self.global_config.verbose { + // When we're printing to stdout, suppress Ninja's output by default. + cmd.stdout(std::process::Stdio::null()); + } + cmd.status()?; + + // Emit stdout. + if self.plan.stdout { + let stdout_file = + std::fs::File::open(self.plan.workdir.join(self.plan.end()))?; + std::io::copy( + &mut std::io::BufReader::new(stdout_file), + &mut std::io::stdout(), + )?; + } + + // Remove the temporary directory unless it already existed at the start *or* the user specified `--keep`. + if !self.global_config.keep_build_dir && !stale_dir { + std::fs::remove_dir_all(dir)?; + } + + Ok(()) + } + + fn emit(&self, out: T) -> EmitResult { + let mut emitter = Emitter::new( + out, + self.config_data.clone(), + self.plan.workdir.clone(), + ); + + // Emit the setup for each operation used in the plan, only once. + let mut done_setups = HashSet::::new(); + for (op, _) in &self.plan.steps { + for setup in &self.driver.ops[*op].setups { + if done_setups.insert(*setup) { + let setup = &self.driver.setups[*setup]; + writeln!(emitter.out, "# {}", setup.name)?; + setup.emit.setup(&mut emitter)?; + writeln!(emitter.out)?; + } + } + } + + // Emit the build commands for each step in the plan. + emitter.comment("build targets")?; + let mut last_file = &self.plan.start; + for (op, out_file) in &self.plan.steps { + let op = &self.driver.ops[*op]; + op.emit.build( + &mut emitter, + last_file.as_str(), + out_file.as_str(), + )?; + last_file = out_file; + } + writeln!(emitter.out)?; + + // Mark the last file as the default target. + writeln!(emitter.out, "default {}", last_file)?; + + Ok(()) + } +} + +pub struct Emitter { + pub out: Box, + pub config_data: figment::Figment, + pub workdir: Utf8PathBuf, +} + +impl Emitter { + fn new( + out: T, + config_data: figment::Figment, + workdir: Utf8PathBuf, + ) -> Self { + Self { + out: Box::new(out), + config_data, + workdir, + } + } + + /// Fetch a configuration value, or panic if it's missing. + pub fn config_val(&self, key: &str) -> Result { + self.config_data + .extract_inner::(key) + .map_err(|_| EmitError::MissingConfig(key.to_string())) + } + + /// Fetch a configuration value, using a default if it's missing. + pub fn config_or(&self, key: &str, default: &str) -> String { + self.config_data + .extract_inner::(key) + .unwrap_or_else(|_| default.into()) + } + + /// Emit a Ninja variable declaration for `name` based on the configured value for `key`. + pub fn config_var(&mut self, name: &str, key: &str) -> EmitResult { + self.var(name, &self.config_val(key)?)?; + Ok(()) + } + + /// Emit a Ninja variable declaration for `name` based on the configured value for `key`, or a + /// default value if it's missing. + pub fn config_var_or( + &mut self, + name: &str, + key: &str, + default: &str, + ) -> std::io::Result<()> { + self.var(name, &self.config_or(key, default)) + } + + /// Emit a Ninja variable declaration. + pub fn var(&mut self, name: &str, value: &str) -> std::io::Result<()> { + writeln!(self.out, "{} = {}", name, value) + } + + /// Emit a Ninja rule definition. + pub fn rule(&mut self, name: &str, command: &str) -> std::io::Result<()> { + writeln!(self.out, "rule {}", name)?; + writeln!(self.out, " command = {}", command) + } + + /// Emit a simple Ninja build command with one dependency. + pub fn build( + &mut self, + rule: &str, + input: &str, + output: &str, + ) -> std::io::Result<()> { + self.build_cmd(&[output], rule, &[input], &[]) + } + + /// Emit a Ninja build command. + pub fn build_cmd( + &mut self, + targets: &[&str], + rule: &str, + deps: &[&str], + implicit_deps: &[&str], + ) -> std::io::Result<()> { + write!(self.out, "build")?; + for target in targets { + write!(self.out, " {}", target)?; + } + write!(self.out, ": {}", rule)?; + for dep in deps { + write!(self.out, " {}", dep)?; + } + if !implicit_deps.is_empty() { + write!(self.out, " |")?; + for dep in implicit_deps { + write!(self.out, " {}", dep)?; + } + } + writeln!(self.out)?; + Ok(()) + } + + /// Emit a Ninja comment. + pub fn comment(&mut self, text: &str) -> std::io::Result<()> { + writeln!(self.out, "# {}", text)?; + Ok(()) + } + + /// Add a file to the build directory. + pub fn add_file(&self, name: &str, contents: &[u8]) -> std::io::Result<()> { + let path = self.workdir.join(name); + std::fs::write(path, contents)?; + Ok(()) + } + + /// Get a path to an external file. The input `path` may be relative to our original + /// invocation; we make it relative to the build directory so it can safely be used in the + /// Ninja file. + pub fn external_path(&self, path: &Utf8Path) -> Utf8PathBuf { + relative_path(path, &self.workdir) + } + + /// Add a variable parameter to a rule or build command. + pub fn arg(&mut self, name: &str, value: &str) -> std::io::Result<()> { + writeln!(self.out, " {} = {}", name, value)?; + Ok(()) + } +} diff --git a/fud2/src/main.rs b/fud2/src/main.rs new file mode 100644 index 000000000..866e99df6 --- /dev/null +++ b/fud2/src/main.rs @@ -0,0 +1,416 @@ +use fake::{ + cli, + run::{EmitResult, Emitter}, + Driver, DriverBuilder, +}; + +fn build_driver() -> Driver { + let mut bld = DriverBuilder::new("fud2"); + + // Calyx. + let calyx = bld.state("calyx", &["futil"]); + let verilog = bld.state("verilog", &["sv", "v"]); + let calyx_setup = bld.setup("Calyx compiler", |e| { + e.config_var("calyx_base", "calyx.base")?; + e.config_var_or( + "calyx_exe", + "calyx.exe", + "$calyx_base/target/debug/calyx", + )?; + e.rule( + "calyx", + "$calyx_exe -l $calyx_base -b $backend $args $in > $out", + )?; + Ok(()) + }); + bld.op( + "calyx-to-verilog", + &[calyx_setup], + calyx, + verilog, + |e, input, output| { + e.build_cmd(&[output], "calyx", &[input], &[])?; + e.arg("backend", "verilog")?; + Ok(()) + }, + ); + + // Dahlia. + let dahlia = bld.state("dahlia", &["fuse"]); + let dahlia_setup = bld.setup("Dahlia compiler", |e| { + e.var("dahlia_exec", "/Users/asampson/cu/research/dahlia/fuse")?; + e.rule( + "dahlia-to-calyx", + "$dahlia_exec -b calyx --lower -l error $in -o $out", + )?; + Ok(()) + }); + bld.rule(&[dahlia_setup], dahlia, calyx, "dahlia-to-calyx"); + + // MrXL. + let mrxl = bld.state("mrxl", &["mrxl"]); + let mrxl_setup = bld.setup("MrXL compiler", |e| { + e.var("mrxl_exec", "mrxl")?; + e.rule("mrxl-to-calyx", "$mrxl_exec $in > $out")?; + Ok(()) + }); + bld.rule(&[mrxl_setup], mrxl, calyx, "mrxl-to-calyx"); + + // Shared machinery for RTL simulators. + let dat = bld.state("dat", &["json"]); + let vcd = bld.state("vcd", &["vcd"]); + let simulator = bld.state("sim", &["exe"]); + let sim_setup = bld.setup("RTL simulation", |e| { + // Data conversion to and from JSON. + e.config_var_or("python", "python", "python3")?; + e.var( + "json_dat", + &format!("$python {}/json-dat.py", e.config_val("data")?), + )?; + e.rule("hex-data", "$json_dat --from-json $in $out")?; + e.rule("json-data", "$json_dat --to-json $out $in")?; + + // The Verilog testbench. + e.var("testbench", &format!("{}/tb.sv", e.config_val("data")?))?; + + // The input data file. `sim.data` is required. + let data_name = e.config_val("sim.data")?; + let data_path = e.external_path(data_name.as_ref()); + e.var("sim_data", data_path.as_str())?; + + // Produce the data directory. + e.var("datadir", "sim_data")?; + e.build("hex-data", "$sim_data", "$datadir")?; + + // Rule for simulation execution. + e.rule( + "sim-run", + "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle_limit $args > $out", + )?; + + // More shared configuration. + e.config_var_or("cycle_limit", "sim.cycle_limit", "500000000")?; + + Ok(()) + }); + bld.op( + "simulate", + &[sim_setup], + simulator, + dat, + |e, input, output| { + e.build_cmd(&["sim.log"], "sim-run", &[input, "$datadir"], &[])?; + e.arg("bin", input)?; + e.arg("args", "+NOTRACE=1")?; + e.build_cmd(&[output], "json-data", &["$datadir", "sim.log"], &[])?; + Ok(()) + }, + ); + bld.op("trace", &[sim_setup], simulator, vcd, |e, input, output| { + e.build_cmd( + &["sim.log", output], + "sim-run", + &[input, "$datadir"], + &[], + )?; + e.arg("bin", input)?; + e.arg("args", &format!("+NOTRACE=0 +OUT={}", output))?; + Ok(()) + }); + + // Icarus Verilog. + let verilog_noverify = bld.state("verilog-noverify", &["sv"]); + let icarus_setup = bld.setup("Icarus Verilog", |e| { + e.var("iverilog", "iverilog")?; + e.rule("icarus-compile", "$iverilog -g2012 -o $out $testbench $in")?; + Ok(()) + }); + bld.op( + "calyx-noverify", + &[calyx_setup], + calyx, + verilog_noverify, + |e, input, output| { + // Icarus requires a special --disable-verify version of Calyx code. + e.build_cmd(&[output], "calyx", &[input], &[])?; + e.arg("backend", "verilog")?; + e.arg("args", "--disable-verify")?; + Ok(()) + }, + ); + bld.op( + "icarus", + &[sim_setup, icarus_setup], + verilog_noverify, + simulator, + |e, input, output| { + e.build("icarus-compile", input, output)?; + Ok(()) + }, + ); + + // Calyx to FIRRTL. + let firrtl = bld.state("firrtl", &["fir"]); + bld.op( + "calyx-to-firrtl", + &[calyx_setup], + calyx, + firrtl, + |e, input, output| { + e.build_cmd(&[output], "calyx", &[input], &[])?; + e.arg("backend", "firrtl")?; + Ok(()) + }, + ); + + // The FIRRTL compiler. + let firrtl_setup = bld.setup("Firrtl to Verilog compiler", |e| { + e.config_var("firrtl_exe", "firrtl.exe")?; + e.rule("firrtl", "$firrtl_exe -i $in -o $out -X sverilog")?; + + e.var( + "primitives-for-firrtl", + &format!("{}/primitives-for-firrtl.sv", e.config_val("data")?), + )?; + e.rule("add-firrtl-prims", "cat $primitives-for-firrtl $in > $out")?; + + Ok(()) + }); + fn firrtl_compile( + e: &mut Emitter, + input: &str, + output: &str, + ) -> EmitResult { + let tmp_verilog = "partial.sv"; + e.build_cmd(&[tmp_verilog], "firrtl", &[input], &[])?; + e.build_cmd(&[output], "add-firrtl-prims", &[tmp_verilog], &[])?; + Ok(()) + } + bld.op("firrtl", &[firrtl_setup], firrtl, verilog, firrtl_compile); + // This is a bit of a hack, but the Icarus-friendly "noverify" state is identical for this path + // (since FIRRTL compilation doesn't come with verification). + bld.op( + "firrtl-noverify", + &[firrtl_setup], + firrtl, + verilog_noverify, + firrtl_compile, + ); + + // primitive-uses backend + let primitive_uses_json = bld.state("primitive-uses-json", &["json"]); + bld.op( + "primitive-uses", + &[calyx_setup], + calyx, + primitive_uses_json, + |e, input, output| { + e.build_cmd(&[output], "calyx", &[input], &[])?; + e.arg("backend", "primitive-uses")?; + Ok(()) + }, + ); + + // Verilator. + let verilator_setup = bld.setup("Verilator", |e| { + e.config_var_or("verilator", "verilator.exe", "verilator")?; + e.config_var_or("cycle_limit", "sim.cycle_limit", "500000000")?; + e.rule( + "verilator-compile", + "$verilator $in $testbench --trace --binary --top-module TOP -fno-inline -Mdir $out_dir", + )?; + e.rule("cp", "cp $in $out")?; + Ok(()) + }); + bld.op( + "verilator", + &[sim_setup, verilator_setup], + verilog, + simulator, + |e, input, output| { + let out_dir = "verilator-out"; + let sim_bin = format!("{}/VTOP", out_dir); + e.build("verilator-compile", input, &sim_bin)?; + e.arg("out_dir", out_dir)?; + e.build("cp", &sim_bin, output)?; + Ok(()) + }, + ); + + // Interpreter. + let debug = bld.state("debug", &[]); // A pseudo-state. + let cider_setup = bld.setup("Cider interpreter", |e| { + e.config_var_or( + "cider", + "cider.exe", + "$calyx_base/target/debug/cider", + )?; + e.rule( + "cider", + "$cider -l $calyx_base --raw --data data.json $in > $out", + )?; + e.rule( + "cider-debug", + "$cider -l $calyx_base --data data.json $in debug || true", + )?; + e.arg("pool", "console")?; + + // TODO Can we reduce the duplication around `rsrc_dir` and `$python`? + let rsrc_dir = e.config_val("data")?; + e.var("interp-dat", &format!("{}/interp-dat.py", rsrc_dir))?; + e.config_var_or("python", "python", "python3")?; + e.rule("dat-to-interp", "$python $interp-dat --to-interp $in")?; + e.rule( + "interp-to-dat", + "$python $interp-dat --from-interp $in $sim_data > $out", + )?; + e.build_cmd(&["data.json"], "dat-to-interp", &["$sim_data"], &[])?; + Ok(()) + }); + bld.op( + "interp", + &[sim_setup, calyx_setup, cider_setup], + calyx, + dat, + |e, input, output| { + let out_file = "interp_out.json"; + e.build_cmd(&[out_file], "cider", &[input], &["data.json"])?; + e.build_cmd( + &[output], + "interp-to-dat", + &[out_file], + &["$sim_data"], + )?; + Ok(()) + }, + ); + bld.op( + "debug", + &[sim_setup, calyx_setup, cider_setup], + calyx, + debug, + |e, input, output| { + e.build_cmd(&[output], "cider-debug", &[input], &["data.json"])?; + Ok(()) + }, + ); + + // Xilinx compilation. + let xo = bld.state("xo", &["xo"]); + let xclbin = bld.state("xclbin", &["xclbin"]); + let xilinx_setup = bld.setup("Xilinx tools", |e| { + // Locations for Vivado and Vitis installations. + e.config_var("vivado_dir", "xilinx.vivado")?; + e.config_var("vitis_dir", "xilinx.vitis")?; + + // Package a Verilog program as an `.xo` file. + let rsrc_dir = e.config_val("data")?; + e.var("gen_xo_tcl", &format!("{}/gen_xo.tcl", rsrc_dir))?; + e.var("get_ports", &format!("{}/get-ports.py", rsrc_dir))?; + e.config_var_or("python", "python", "python3")?; + e.rule("gen-xo", "$vivado_dir/bin/vivado -mode batch -source $gen_xo_tcl -tclargs $out `$python $get_ports kernel.xml`")?; + e.arg("pool", "console")?; // Lets Ninja stream the tool output "live." + + // Compile an `.xo` file to an `.xclbin` file, which is where the actual EDA work occurs. + e.config_var_or("xilinx_mode", "xilinx.mode", "hw_emu")?; + e.config_var_or("platform", "xilinx.device", "xilinx_u50_gen3x16_xdma_201920_3")?; + e.rule("compile-xclbin", "$vitis_dir/bin/v++ -g -t $xilinx_mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in")?; + e.arg("pool", "console")?; + + Ok(()) + }); + bld.op( + "xo", + &[calyx_setup, xilinx_setup], + calyx, + xo, + |e, input, output| { + // Emit the Verilog itself in "synthesis mode." + e.build_cmd(&["main.sv"], "calyx", &[input], &[])?; + e.arg("backend", "verilog")?; + e.arg("args", "--synthesis -p external")?; + + // Extra ingredients for the `.xo` package. + e.build_cmd(&["toplevel.v"], "calyx", &[input], &[])?; + e.arg("backend", "xilinx")?; + e.build_cmd(&["kernel.xml"], "calyx", &[input], &[])?; + e.arg("backend", "xilinx-xml")?; + + // Package the `.xo`. + e.build_cmd( + &[output], + "gen-xo", + &[], + &["main.sv", "toplevel.v", "kernel.xml"], + )?; + Ok(()) + }, + ); + bld.op("xclbin", &[xilinx_setup], xo, xclbin, |e, input, output| { + e.build_cmd(&[output], "compile-xclbin", &[input], &[])?; + Ok(()) + }); + + // Xilinx execution. + // TODO Only does `hw_emu` for now... + let xrt_setup = bld.setup("Xilinx execution via XRT", |e| { + // Generate `emconfig.json`. + e.rule("emconfig", "$vitis_dir/bin/emconfigutil --platform $platform")?; + e.build_cmd(&["emconfig.json"], "emconfig", &[], &[])?; + + // Execute via the `xclrun` tool. + e.config_var("xrt_dir", "xilinx.xrt")?; + e.rule("xclrun", "bash -c 'source $vitis_dir/settings64.sh ; source $xrt_dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx_mode $python -m fud.xclrun --out $out $in'")?; + e.arg("pool", "console")?; + + // "Pre-sim" and "post-sim" scripts for simulation. + e.rule("echo", "echo $contents > $out")?; + e.build_cmd(&["pre_sim.tcl"], "echo", &[""], &[""])?; + e.arg("contents", "open_vcd\\\\nlog_vcd *\\\\n")?; + e.build_cmd(&["post_sim.tcl"], "echo", &[""], &[""])?; + e.arg("contents", "close_vcd\\\\n")?; + + Ok(()) + }); + bld.op( + "xrt", + &[xilinx_setup, sim_setup, xrt_setup], + xclbin, + dat, + |e, input, output| { + e.build_cmd( + &[output], + "xclrun", + &[input, "$sim_data"], + &["emconfig.json"], + )?; + let rsrc_dir = e.config_val("data")?; + e.arg("xrt_ini", &format!("{}/xrt.ini", rsrc_dir))?; + Ok(()) + }, + ); + bld.op( + "xrt-trace", + &[xilinx_setup, sim_setup, xrt_setup], + xclbin, + vcd, + |e, input, output| { + e.build_cmd( + &[output], // TODO not the VCD, yet... + "xclrun", + &[input, "$sim_data"], + &["emconfig.json", "pre_sim.tcl", "post_sim.tcl"], + )?; + let rsrc_dir = e.config_val("data")?; + e.arg("xrt_ini", &format!("{}/xrt_trace.ini", rsrc_dir))?; + Ok(()) + }, + ); + + bld.build() +} + +fn main() -> anyhow::Result<()> { + let driver = build_driver(); + cli::cli(&driver) +} From 20f0dfc0f125043fc93d8c588712389df2a813ae Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 29 Jan 2024 07:57:45 +0530 Subject: [PATCH 153/189] add logging to fud2 (#1881) --- Cargo.lock | 2 ++ Cargo.toml | 12 +++++++----- fud2/fake/Cargo.toml | 2 ++ fud2/fake/src/cli.rs | 11 +++++++++++ fud2/fake/src/config.rs | 1 + fud2/src/main.rs | 1 + 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85f15cfac..e19067059 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -742,7 +742,9 @@ dependencies = [ "argh", "camino", "cranelift-entity", + "env_logger", "figment", + "log", "pathdiff", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 3482ad8d0..189d19015 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,12 @@ version = "0.6" default-features = false features = ["matrix_graph"] +[workspace.dependencies.env_logger] +version = "0.9.0" +features = ["termcolor", "atty"] +default-features = false + + # =========== Package configuration =========== [package] @@ -92,6 +98,7 @@ itertools.workspace = true log.workspace = true serde.workspace = true argh.workspace = true +env_logger.workspace = true calyx-utils.workspace = true calyx-ir.workspace = true @@ -102,11 +109,6 @@ calyx-opt.workspace = true workspace = true features = ["mlir", "resources", "xilinx"] -[dependencies.env_logger] -version = "0.9.0" -features = ["termcolor", "atty"] -default-features = false - [profile.release] lto = "thin" diff --git a/fud2/fake/Cargo.toml b/fud2/fake/Cargo.toml index cd6e35746..021d7cd28 100644 --- a/fud2/fake/Cargo.toml +++ b/fud2/fake/Cargo.toml @@ -11,3 +11,5 @@ figment = { version = "0.10.12", features = ["toml"] } pathdiff = { version = "0.2.1", features = ["camino"] } camino = "1.1.6" anyhow.workspace = true +log.workspace = true +env_logger.workspace = true diff --git a/fud2/fake/src/cli.rs b/fud2/fake/src/cli.rs index 5d1547096..887ee80e5 100644 --- a/fud2/fake/src/cli.rs +++ b/fud2/fake/src/cli.rs @@ -83,6 +83,10 @@ struct FakeArgs { /// verbose ouput #[argh(switch, short = 'v')] verbose: Option, + + /// log level for debugging fud internal + #[argh(option, long = "log", default = "log::LevelFilter::Warn")] + pub log_level: log::LevelFilter, } fn from_state(driver: &Driver, args: &FakeArgs) -> anyhow::Result { @@ -145,6 +149,13 @@ fn get_request(driver: &Driver, args: &FakeArgs) -> anyhow::Result { pub fn cli(driver: &Driver) -> anyhow::Result<()> { let args: FakeArgs = argh::from_env(); + // enable tracing + env_logger::Builder::new() + .format_timestamp(None) + .filter_level(args.log_level) + .target(env_logger::Target::Stderr) + .init(); + // Make a plan. let req = get_request(driver, &args)?; let workdir = req.workdir.clone(); diff --git a/fud2/fake/src/config.rs b/fud2/fake/src/config.rs index 437445539..12d668922 100644 --- a/fud2/fake/src/config.rs +++ b/fud2/fake/src/config.rs @@ -35,6 +35,7 @@ pub(crate) fn load_config(name: &str) -> Figment { home + "/.config" }); let config_path = Path::new(&config_base).join(name).with_extension("toml"); + log::info!("Loading config from {}", config_path.display()); // Use our defaults, overridden by the TOML config file. Figment::from(Serialized::defaults(GlobalConfig::default())) diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 866e99df6..363421b46 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -412,5 +412,6 @@ fn build_driver() -> Driver { fn main() -> anyhow::Result<()> { let driver = build_driver(); + cli::cli(&driver) } From 9527cd9cd7f8d1608058423a021d895748e36dc7 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 29 Jan 2024 08:14:48 +0530 Subject: [PATCH 154/189] Add subcommand to edit configuration (#1882) --- fud2/fake/src/cli.rs | 41 +++++++++++++++++++++++++++++++++++++++++ fud2/fake/src/config.rs | 10 ++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/fud2/fake/src/cli.rs b/fud2/fake/src/cli.rs index 887ee80e5..1af8660f1 100644 --- a/fud2/fake/src/cli.rs +++ b/fud2/fake/src/cli.rs @@ -1,3 +1,4 @@ +use crate::config; use crate::driver::{Driver, Request, StateRef}; use crate::run::Run; use anyhow::{anyhow, bail}; @@ -41,9 +42,29 @@ impl Display for Mode { } } +/// edit the configuration file +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "edit-config")] +pub struct EditConfig { + /// the editor to use + #[argh(option, short = 'e')] + pub editor: Option, +} + +/// supported subcommands +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand)] +pub enum Subcommand { + /// edit the configuration file + EditConfig(EditConfig), +} + #[derive(FromArgs)] /// A generic compiler driver. struct FakeArgs { + #[argh(subcommand)] + pub sub: Option, + /// the input file #[argh(positional)] input: Option, @@ -156,6 +177,26 @@ pub fn cli(driver: &Driver) -> anyhow::Result<()> { .target(env_logger::Target::Stderr) .init(); + // edit the configuration file + if let Some(Subcommand::EditConfig(EditConfig { editor })) = args.sub { + let editor = + if let Some(e) = editor.or_else(|| std::env::var("EDITOR").ok()) { + e + } else { + bail!("$EDITOR not specified. Use -e") + }; + let config_path = config::config_path(&driver.name); + log::info!("Editing config at {}", config_path.display()); + let status = std::process::Command::new(editor) + .arg(config_path) + .status() + .expect("failed to execute editor"); + if !status.success() { + bail!("editor exited with status {}", status); + } + return Ok(()); + } + // Make a plan. let req = get_request(driver, &args)?; let workdir = req.workdir.clone(); diff --git a/fud2/fake/src/config.rs b/fud2/fake/src/config.rs index 12d668922..3e90d83ce 100644 --- a/fud2/fake/src/config.rs +++ b/fud2/fake/src/config.rs @@ -27,8 +27,8 @@ impl Default for GlobalConfig { } } -/// Load configuration data from the standard config file location. -pub(crate) fn load_config(name: &str) -> Figment { +/// Location of the configuration file +pub(crate) fn config_path(name: &str) -> std::path::PathBuf { // The configuration is usually at `~/.config/driver_name.toml`. let config_base = env::var("XDG_CONFIG_HOME").unwrap_or_else(|_| { let home = env::var("HOME").expect("$HOME not set"); @@ -36,6 +36,12 @@ pub(crate) fn load_config(name: &str) -> Figment { }); let config_path = Path::new(&config_base).join(name).with_extension("toml"); log::info!("Loading config from {}", config_path.display()); + config_path +} + +/// Load configuration data from the standard config file location. +pub(crate) fn load_config(name: &str) -> Figment { + let config_path = config_path(name); // Use our defaults, overridden by the TOML config file. Figment::from(Serialized::defaults(GlobalConfig::default())) From 85164eccecaf11ecb6602bf7f70adec2aa012678 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Mon, 29 Jan 2024 08:16:49 +0530 Subject: [PATCH 155/189] Ignore fud2 build folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 223c98004..50e88d317 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,9 @@ tests/xilinx/cocotb/**/hdl sim_build/ results.xml +# Ignore .fud2 cache +.fud2/ + !cider-dap/calyxDebug/package.json !cider-dap/calyxDebug/tsconfig.json From c88c913afb4edb138439225920f8fdc292cf3baf Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:40:54 -0500 Subject: [PATCH 156/189] [Calyx-FIRRTL] Support for template FIRRTL primitives (#1864) * First pass for backend to produce json file containing primitive instantiation info * pretty print the json * Map from param names to values * Fix clippy error * usage message * Fix doc comments * Change JSON format for parameter names and values * First commit of python script to process json and generate primitives * Fix formatting error * Hack to generate module name * Add some primitives * Generate module name + primitive templates for all documented primities * fix comment * Changed naming and fixed unchanged name * Make parameter collection functional * Option for enabling extmodule declarations for primitives * Fix formatting error from extracted function * Fix test configurations to produce extmodule * Rename script and pass in FIRRTL file * Change commandline option to not use -x * Update tests to match new commandline option * Hack to get around problem of subprocess and print output competing in fud2 * Add error message if primitive template file does not exist * Fix bug and added error message. Also added std_reg and undef primitives * Fix script from PR comments * Refactor script to use python to replace strings instead of using m4 subprocess * Remove unnecessary import --- calyx-backend/src/firrtl.rs | 57 +++++++++------- calyx-ir/src/context.rs | 3 + src/cmdline.rs | 5 ++ src/main.rs | 1 + tests/backend/firrtl/basic-cell.futil | 2 +- tests/backend/firrtl/primitive-cells.futil | 2 +- .../firrtl/generate-firrtl-with-primitives.py | 65 +++++++++++++++++++ tools/firrtl/templates/std_add.fir | 6 ++ tools/firrtl/templates/std_and.fir | 6 ++ tools/firrtl/templates/std_const.fir | 3 + tools/firrtl/templates/std_eq.fir | 6 ++ tools/firrtl/templates/std_ge.fir | 6 ++ tools/firrtl/templates/std_gt.fir | 6 ++ tools/firrtl/templates/std_le.fir | 6 ++ tools/firrtl/templates/std_lsh.fir | 6 ++ tools/firrtl/templates/std_lt.fir | 6 ++ tools/firrtl/templates/std_mem_d1.fir | 34 ++++++++++ tools/firrtl/templates/std_neq.fir | 6 ++ tools/firrtl/templates/std_not.fir | 5 ++ tools/firrtl/templates/std_or.fir | 6 ++ tools/firrtl/templates/std_pad.fir | 5 ++ tools/firrtl/templates/std_reg.fir | 19 ++++++ tools/firrtl/templates/std_rsh.fir | 6 ++ tools/firrtl/templates/std_slice.fir | 5 ++ tools/firrtl/templates/std_sub.fir | 6 ++ tools/firrtl/templates/std_wire.fir | 5 ++ tools/firrtl/templates/std_xor.fir | 6 ++ tools/firrtl/templates/undef.fir | 3 + 28 files changed, 266 insertions(+), 26 deletions(-) create mode 100644 tools/firrtl/generate-firrtl-with-primitives.py create mode 100644 tools/firrtl/templates/std_add.fir create mode 100644 tools/firrtl/templates/std_and.fir create mode 100644 tools/firrtl/templates/std_const.fir create mode 100644 tools/firrtl/templates/std_eq.fir create mode 100644 tools/firrtl/templates/std_ge.fir create mode 100644 tools/firrtl/templates/std_gt.fir create mode 100644 tools/firrtl/templates/std_le.fir create mode 100644 tools/firrtl/templates/std_lsh.fir create mode 100644 tools/firrtl/templates/std_lt.fir create mode 100644 tools/firrtl/templates/std_mem_d1.fir create mode 100644 tools/firrtl/templates/std_neq.fir create mode 100644 tools/firrtl/templates/std_not.fir create mode 100644 tools/firrtl/templates/std_or.fir create mode 100644 tools/firrtl/templates/std_pad.fir create mode 100644 tools/firrtl/templates/std_reg.fir create mode 100644 tools/firrtl/templates/std_rsh.fir create mode 100644 tools/firrtl/templates/std_slice.fir create mode 100644 tools/firrtl/templates/std_sub.fir create mode 100644 tools/firrtl/templates/std_wire.fir create mode 100644 tools/firrtl/templates/std_xor.fir create mode 100644 tools/firrtl/templates/undef.fir diff --git a/calyx-backend/src/firrtl.rs b/calyx-backend/src/firrtl.rs index cc03abec2..dabccc39f 100644 --- a/calyx-backend/src/firrtl.rs +++ b/calyx-backend/src/firrtl.rs @@ -36,30 +36,8 @@ impl Backend for FirrtlBackend { fn emit(ctx: &ir::Context, file: &mut OutputFile) -> CalyxResult<()> { let out = &mut file.get_write(); writeln!(out, "circuit {}:", ctx.entrypoint)?; - // Pass to output any necessary extmodule statements (for primitive calls) - let mut extmodule_set: HashSet = HashSet::new(); - for comp in &ctx.components { - for cell in comp.cells.iter() { - let cell_borrowed = cell.as_ref().borrow(); - if let ir::CellType::Primitive { - name, - param_binding, - .. - } = &cell_borrowed.prototype - { - let curr_module_name = - get_primitive_module_name(name, param_binding); - if extmodule_set.insert(curr_module_name.clone()) { - emit_primitive_extmodule( - cell.borrow().ports(), - &curr_module_name, - name, - param_binding, - out, - )?; - } - }; - } + if ctx.bc.emit_primitive_extmodules { + emit_extmodules(ctx, out)?; } for comp in ctx.components.iter() { emit_component(comp, out)? @@ -68,6 +46,37 @@ impl Backend for FirrtlBackend { } } +fn emit_extmodules( + ctx: &ir::Context, + out: &mut F, +) -> Result<(), calyx_utils::Error> { + let mut extmodule_set: HashSet = HashSet::new(); + for comp in &ctx.components { + for cell in comp.cells.iter() { + let cell_borrowed = cell.as_ref().borrow(); + if let ir::CellType::Primitive { + name, + param_binding, + .. + } = &cell_borrowed.prototype + { + let curr_module_name = + get_primitive_module_name(name, param_binding); + if extmodule_set.insert(curr_module_name.clone()) { + emit_primitive_extmodule( + cell.borrow().ports(), + &curr_module_name, + name, + param_binding, + out, + )?; + } + }; + } + } + Ok(()) +} + // TODO: Ask about the other backend configurations in verilog.rs and see if I need any of it fn emit_component( comp: &ir::Component, diff --git a/calyx-ir/src/context.rs b/calyx-ir/src/context.rs index 13df7eac8..cc00e1b86 100644 --- a/calyx-ir/src/context.rs +++ b/calyx-ir/src/context.rs @@ -13,6 +13,9 @@ pub struct BackendConf { pub enable_verification: bool, /// Use flat (ANF) assignments for guards instead of deep expression trees. pub flat_assign: bool, + /// [FIRRTL backend only] Emit extmodule declarations for primtives + /// for use with SystemVerilog implementations + pub emit_primitive_extmodules: bool, } /// The IR Context that represents an entire Calyx program with all of its diff --git a/src/cmdline.rs b/src/cmdline.rs index 93d9f5b01..f8346aa4a 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -68,6 +68,11 @@ pub struct Opts { #[argh(switch, long = "nested")] pub nested_assign: bool, + /// emit extmodules to use with SystemVerilog implementations + /// of primitives (only relevant to the FIRRTL backend) + #[argh(switch, long = "emit-primitive-extmodules")] + pub emit_primitive_extmodules: bool, + /// select a backend #[argh(option, short = 'b', default = "BackendOpt::default()")] pub backend: BackendOpt, diff --git a/src/main.rs b/src/main.rs index 399bc9909..f0e4eb41d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,7 @@ fn main() -> CalyxResult<()> { synthesis_mode: opts.enable_synthesis, enable_verification: !opts.disable_verify, flat_assign: !opts.nested_assign, + emit_primitive_extmodules: opts.emit_primitive_extmodules, }; // Extra options for the passes ctx.extra_opts = opts.extra_opts.drain(..).collect(); diff --git a/tests/backend/firrtl/basic-cell.futil b/tests/backend/firrtl/basic-cell.futil index 1359c6772..09effbe5c 100644 --- a/tests/backend/firrtl/basic-cell.futil +++ b/tests/backend/firrtl/basic-cell.futil @@ -1,4 +1,4 @@ -// -b firrtl +// -b firrtl --emit-primitive-extmodules import "primitives/core.futil"; component identity(in : 32) -> (out : 32) { cells {} diff --git a/tests/backend/firrtl/primitive-cells.futil b/tests/backend/firrtl/primitive-cells.futil index 8bf993496..b8ce90186 100644 --- a/tests/backend/firrtl/primitive-cells.futil +++ b/tests/backend/firrtl/primitive-cells.futil @@ -1,4 +1,4 @@ -// -b firrtl +// -b firrtl --emit-primitive-extmodules import "primitives/core.futil"; component plus_one(in : 32) -> (out : 32) { cells { diff --git a/tools/firrtl/generate-firrtl-with-primitives.py b/tools/firrtl/generate-firrtl-with-primitives.py new file mode 100644 index 000000000..b6d216393 --- /dev/null +++ b/tools/firrtl/generate-firrtl-with-primitives.py @@ -0,0 +1,65 @@ +import json +import os +import sys + +# Generates a map where `key` should be replaced with `value` +def generate_replacement_map(inst): + replacement_map = {} + for param in inst["params"]: + replacement_map[param["param_name"]] = param["param_value"] + + # Special primitives that have a value dependent on their parameters. + if inst["name"] == "std_pad": + replacement_map["DIFF"] = replacement_map["OUT_WIDTH"] - replacement_map["IN_WIDTH"] + elif inst["name"] == "std_slice": + replacement_map["DIFF"] = replacement_map["IN_WIDTH"] - replacement_map["OUT_WIDTH"] + + return replacement_map + +# Retrieves the appropriate template file for the given primitive +def retrieve_firrtl_template(primitive_name): + firrtl_file_path = os.path.join(sys.path[0], "templates", primitive_name + ".fir") + if not(os.path.isfile(firrtl_file_path)): + print(f"{sys.argv[0]}: FIRRTL template file for primitive {primitive_name} does not exist! Exiting...") + sys.exit(1) + return firrtl_file_path + +# Generates a primitive definition from the provided JSON data of a unique primitive use +def generate_primitive_definition(inst): + template_filename = retrieve_firrtl_template(inst["name"]) + replacement_map = generate_replacement_map(inst) + + with open(template_filename, "r") as template_file: + for line in template_file: + for key in replacement_map: + line = line.replace(key, str(replacement_map[key])) + print(line.rstrip()) + print() # whitespace to buffer between modules + +# Generates a complete FIRRTL program with primitives. +def generate(firrtl_filename, primitive_uses_filename): + firrtl_file = open(firrtl_filename) + primitive_uses_file = open(primitive_uses_filename) + # The first line contains the circuit name, which needs to come before the primitives. + print(firrtl_file.readline().rstrip()) + # Display the primitive definitions. + primitive_insts = json.load(primitive_uses_file) + if primitive_insts: + for inst in primitive_insts: + generate_primitive_definition(inst) + # Display the rest of the FIRRTL program. + for line in firrtl_file.readlines(): + print(line.rstrip()) + +def main(): + if len(sys.argv) != 3: + args_desc = [ + "FIRRTL_FILE", + "PRIMITIVE_USES_JSON" + ] + print(f"Usage: {sys.argv[0]} {' '.join(args_desc)}") + return 1 + generate(sys.argv[1], sys.argv[2]) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tools/firrtl/templates/std_add.fir b/tools/firrtl/templates/std_add.fir new file mode 100644 index 000000000..505f569bb --- /dev/null +++ b/tools/firrtl/templates/std_add.fir @@ -0,0 +1,6 @@ + module std_add_WIDTH: + input left : UInt + input right : UInt + output out : UInt + + out <= add(left, right) diff --git a/tools/firrtl/templates/std_and.fir b/tools/firrtl/templates/std_and.fir new file mode 100644 index 000000000..93c46f98b --- /dev/null +++ b/tools/firrtl/templates/std_and.fir @@ -0,0 +1,6 @@ + module std_and_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= and(left, right) diff --git a/tools/firrtl/templates/std_const.fir b/tools/firrtl/templates/std_const.fir new file mode 100644 index 000000000..27a66a93d --- /dev/null +++ b/tools/firrtl/templates/std_const.fir @@ -0,0 +1,3 @@ + module std_const_WIDTH_VAL : + output out : UInt + out <= UInt(VALUE) diff --git a/tools/firrtl/templates/std_eq.fir b/tools/firrtl/templates/std_eq.fir new file mode 100644 index 000000000..8601d9b9d --- /dev/null +++ b/tools/firrtl/templates/std_eq.fir @@ -0,0 +1,6 @@ + module std_eq_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= eq(left, right) diff --git a/tools/firrtl/templates/std_ge.fir b/tools/firrtl/templates/std_ge.fir new file mode 100644 index 000000000..0aace3aed --- /dev/null +++ b/tools/firrtl/templates/std_ge.fir @@ -0,0 +1,6 @@ + module std_ge_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= ge(left, right) diff --git a/tools/firrtl/templates/std_gt.fir b/tools/firrtl/templates/std_gt.fir new file mode 100644 index 000000000..49b9f4ef9 --- /dev/null +++ b/tools/firrtl/templates/std_gt.fir @@ -0,0 +1,6 @@ + module std_gt_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= gt(left, right) diff --git a/tools/firrtl/templates/std_le.fir b/tools/firrtl/templates/std_le.fir new file mode 100644 index 000000000..6550884ad --- /dev/null +++ b/tools/firrtl/templates/std_le.fir @@ -0,0 +1,6 @@ + module std_le_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= le(left, right) diff --git a/tools/firrtl/templates/std_lsh.fir b/tools/firrtl/templates/std_lsh.fir new file mode 100644 index 000000000..934883c08 --- /dev/null +++ b/tools/firrtl/templates/std_lsh.fir @@ -0,0 +1,6 @@ + module std_lsh_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= dshl(left, right) diff --git a/tools/firrtl/templates/std_lt.fir b/tools/firrtl/templates/std_lt.fir new file mode 100644 index 000000000..8c580049e --- /dev/null +++ b/tools/firrtl/templates/std_lt.fir @@ -0,0 +1,6 @@ + module std_lt_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= lt(left, right) diff --git a/tools/firrtl/templates/std_mem_d1.fir b/tools/firrtl/templates/std_mem_d1.fir new file mode 100644 index 000000000..83bbd340b --- /dev/null +++ b/tools/firrtl/templates/std_mem_d1.fir @@ -0,0 +1,34 @@ + module std_mem_d1_WIDTH_SIZE_IDX_SIZE : + input add0 : UInt + input write_data : UInt + input write_en : UInt<1> + input clk : Clock + input reset : UInt<1> + output read_data : UInt + output done : UInt<1> + + mem internal_mem : + data-type => UInt + depth => SIZE + read-latency => 1 + write-latency => 1 + reader => internal_read + writer => internal_write + read-under-write => undefined + + ; read from memory + internal_mem.internal_read.addr <= add0 + internal_mem.internal_read.en <= UInt(1) + internal_mem.internal_read.clk <= clk + read_data <= internal_mem.internal_read.data + + ; write to memory + internal_mem.internal_write.addr <= add0 + internal_mem.internal_write.en <= write_en + internal_mem.internal_write.clk <= clk + internal_mem.internal_write.data <= write_data + internal_mem.internal_write.mask <= UInt(1) ; unclear + when eq(write_en, UInt(1)): + done <= UInt(1) + else: + done <= UInt(0) diff --git a/tools/firrtl/templates/std_neq.fir b/tools/firrtl/templates/std_neq.fir new file mode 100644 index 000000000..7b6d03ada --- /dev/null +++ b/tools/firrtl/templates/std_neq.fir @@ -0,0 +1,6 @@ + module std_neq_WIDTH : + input left : UInt + input right : UInt + output out : UInt<1> + + out <= neq(left, right) diff --git a/tools/firrtl/templates/std_not.fir b/tools/firrtl/templates/std_not.fir new file mode 100644 index 000000000..b0ead9274 --- /dev/null +++ b/tools/firrtl/templates/std_not.fir @@ -0,0 +1,5 @@ + module std_not_WIDTH : + input in : UInt + output out : UInt + + out <= neg(in) diff --git a/tools/firrtl/templates/std_or.fir b/tools/firrtl/templates/std_or.fir new file mode 100644 index 000000000..ab29cf9e6 --- /dev/null +++ b/tools/firrtl/templates/std_or.fir @@ -0,0 +1,6 @@ + module std_or_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= or(left, right) diff --git a/tools/firrtl/templates/std_pad.fir b/tools/firrtl/templates/std_pad.fir new file mode 100644 index 000000000..7d8696d06 --- /dev/null +++ b/tools/firrtl/templates/std_pad.fir @@ -0,0 +1,5 @@ + module std_pad_IN_WIDTH_OUT_WIDTH: + input in : UInt + output out : UInt + + out <= pad(in, DIFF) ; DIFF should be OUT_WIDTH - IN_WIDTH. diff --git a/tools/firrtl/templates/std_reg.fir b/tools/firrtl/templates/std_reg.fir new file mode 100644 index 000000000..fe9a4192f --- /dev/null +++ b/tools/firrtl/templates/std_reg.fir @@ -0,0 +1,19 @@ + module std_reg_WIDTH : + input in : UInt + input write_en : UInt<1> + input clk : Clock + input reset : UInt<1> + output out : UInt + output done : UInt<1> + + reg internal_reg : UInt, clk + out <= UInt(0) + when eq(write_en, UInt(1)): + out <= in + done <= UInt(1) + else: + when eq(reset, UInt(1)): + done <= UInt(0) + out <= UInt(0) + else: + done <= UInt(0) diff --git a/tools/firrtl/templates/std_rsh.fir b/tools/firrtl/templates/std_rsh.fir new file mode 100644 index 000000000..15999fb5b --- /dev/null +++ b/tools/firrtl/templates/std_rsh.fir @@ -0,0 +1,6 @@ + module std_rsh_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= dshr(left, right) diff --git a/tools/firrtl/templates/std_slice.fir b/tools/firrtl/templates/std_slice.fir new file mode 100644 index 000000000..a5bd50943 --- /dev/null +++ b/tools/firrtl/templates/std_slice.fir @@ -0,0 +1,5 @@ + module std_slice_IN_WIDTH_OUT_WIDTH: + input in : UInt + output out : UInt + + out <= head(in, UInt(DIFF)) ; DIFF should be IN_WIDTH - OUT_WIDTH diff --git a/tools/firrtl/templates/std_sub.fir b/tools/firrtl/templates/std_sub.fir new file mode 100644 index 000000000..49523801e --- /dev/null +++ b/tools/firrtl/templates/std_sub.fir @@ -0,0 +1,6 @@ + module std_sub_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= sub(left, right) diff --git a/tools/firrtl/templates/std_wire.fir b/tools/firrtl/templates/std_wire.fir new file mode 100644 index 000000000..e43f57025 --- /dev/null +++ b/tools/firrtl/templates/std_wire.fir @@ -0,0 +1,5 @@ + module std_wire_WIDTH : + input in : UInt + output out : UInt + + out <= in diff --git a/tools/firrtl/templates/std_xor.fir b/tools/firrtl/templates/std_xor.fir new file mode 100644 index 000000000..f7805b537 --- /dev/null +++ b/tools/firrtl/templates/std_xor.fir @@ -0,0 +1,6 @@ + module std_xor_WIDTH : + input left : UInt + input right : UInt + output out : UInt + + out <= xor(left, right) diff --git a/tools/firrtl/templates/undef.fir b/tools/firrtl/templates/undef.fir new file mode 100644 index 000000000..f2d81bec4 --- /dev/null +++ b/tools/firrtl/templates/undef.fir @@ -0,0 +1,3 @@ + module undef_WIDTH : + output out : UInt + out is invalid From ee6ae1e5ab6c22f2d63355391a5209509c055f21 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 29 Jan 2024 02:41:58 -0500 Subject: [PATCH 157/189] Small tweaks to fud2 (#1879) * More consistent Ninja variable names I was inconsistent about whether to use snake_case or kebab-case; this standardizes us on the latter (and brings a few other names in line with each other). * Rename resources directory The old name, `data`, was ridiculously vague and I don't know why I ever thought it was a good idea. `rsrc` is slightly better. This also changes the config option name; if you were using fud2 already, you will need to change this. --- docs/running-calyx/fud2.md | 2 +- fud2/{data => rsrc}/gen_xo.tcl | 0 fud2/{data => rsrc}/get-ports.py | 0 fud2/{data => rsrc}/interp-dat.py | 0 fud2/{data => rsrc}/json-dat.py | 0 fud2/{data => rsrc}/primitives-for-firrtl.sv | 0 fud2/{data => rsrc}/tb.sv | 0 fud2/{data => rsrc}/xrt.ini | 0 fud2/{data => rsrc}/xrt_trace.ini | 0 fud2/src/main.rs | 72 ++++++++++---------- 10 files changed, 37 insertions(+), 37 deletions(-) rename fud2/{data => rsrc}/gen_xo.tcl (100%) rename fud2/{data => rsrc}/get-ports.py (100%) rename fud2/{data => rsrc}/interp-dat.py (100%) rename fud2/{data => rsrc}/json-dat.py (100%) rename fud2/{data => rsrc}/primitives-for-firrtl.sv (100%) rename fud2/{data => rsrc}/tb.sv (100%) rename fud2/{data => rsrc}/xrt.ini (100%) rename fud2/{data => rsrc}/xrt_trace.ini (100%) diff --git a/docs/running-calyx/fud2.md b/docs/running-calyx/fud2.md index 4e80ab028..d847962a2 100644 --- a/docs/running-calyx/fud2.md +++ b/docs/running-calyx/fud2.md @@ -20,7 +20,7 @@ Install it using your OS package manager or by downloading a binary. Create a configuration file at `~/.config/fud2.toml`, using the path to your checkout of the Calyx git repository: ```toml -data = ".../calyx/fud2/data" +rsrc = ".../calyx/fud2/rsrc" [calyx] base = ".../calyx" diff --git a/fud2/data/gen_xo.tcl b/fud2/rsrc/gen_xo.tcl similarity index 100% rename from fud2/data/gen_xo.tcl rename to fud2/rsrc/gen_xo.tcl diff --git a/fud2/data/get-ports.py b/fud2/rsrc/get-ports.py similarity index 100% rename from fud2/data/get-ports.py rename to fud2/rsrc/get-ports.py diff --git a/fud2/data/interp-dat.py b/fud2/rsrc/interp-dat.py similarity index 100% rename from fud2/data/interp-dat.py rename to fud2/rsrc/interp-dat.py diff --git a/fud2/data/json-dat.py b/fud2/rsrc/json-dat.py similarity index 100% rename from fud2/data/json-dat.py rename to fud2/rsrc/json-dat.py diff --git a/fud2/data/primitives-for-firrtl.sv b/fud2/rsrc/primitives-for-firrtl.sv similarity index 100% rename from fud2/data/primitives-for-firrtl.sv rename to fud2/rsrc/primitives-for-firrtl.sv diff --git a/fud2/data/tb.sv b/fud2/rsrc/tb.sv similarity index 100% rename from fud2/data/tb.sv rename to fud2/rsrc/tb.sv diff --git a/fud2/data/xrt.ini b/fud2/rsrc/xrt.ini similarity index 100% rename from fud2/data/xrt.ini rename to fud2/rsrc/xrt.ini diff --git a/fud2/data/xrt_trace.ini b/fud2/rsrc/xrt_trace.ini similarity index 100% rename from fud2/data/xrt_trace.ini rename to fud2/rsrc/xrt_trace.ini diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 363421b46..69da9c974 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -11,15 +11,15 @@ fn build_driver() -> Driver { let calyx = bld.state("calyx", &["futil"]); let verilog = bld.state("verilog", &["sv", "v"]); let calyx_setup = bld.setup("Calyx compiler", |e| { - e.config_var("calyx_base", "calyx.base")?; + e.config_var("calyx-base", "calyx.base")?; e.config_var_or( - "calyx_exe", + "calyx-exe", "calyx.exe", - "$calyx_base/target/debug/calyx", + "$calyx-base/target/debug/calyx", )?; e.rule( "calyx", - "$calyx_exe -l $calyx_base -b $backend $args $in > $out", + "$calyx-exe -l $calyx-base -b $backend $args $in > $out", )?; Ok(()) }); @@ -38,10 +38,10 @@ fn build_driver() -> Driver { // Dahlia. let dahlia = bld.state("dahlia", &["fuse"]); let dahlia_setup = bld.setup("Dahlia compiler", |e| { - e.var("dahlia_exec", "/Users/asampson/cu/research/dahlia/fuse")?; + e.config_var("dahlia-exe", "dahlia")?; e.rule( "dahlia-to-calyx", - "$dahlia_exec -b calyx --lower -l error $in -o $out", + "$dahlia-exe -b calyx --lower -l error $in -o $out", )?; Ok(()) }); @@ -50,8 +50,8 @@ fn build_driver() -> Driver { // MrXL. let mrxl = bld.state("mrxl", &["mrxl"]); let mrxl_setup = bld.setup("MrXL compiler", |e| { - e.var("mrxl_exec", "mrxl")?; - e.rule("mrxl-to-calyx", "$mrxl_exec $in > $out")?; + e.var("mrxl-exe", "mrxl")?; + e.rule("mrxl-to-calyx", "$mrxl-exe $in > $out")?; Ok(()) }); bld.rule(&[mrxl_setup], mrxl, calyx, "mrxl-to-calyx"); @@ -65,13 +65,13 @@ fn build_driver() -> Driver { e.config_var_or("python", "python", "python3")?; e.var( "json_dat", - &format!("$python {}/json-dat.py", e.config_val("data")?), + &format!("$python {}/json-dat.py", e.config_val("rsrc")?), )?; e.rule("hex-data", "$json_dat --from-json $in $out")?; e.rule("json-data", "$json_dat --to-json $out $in")?; // The Verilog testbench. - e.var("testbench", &format!("{}/tb.sv", e.config_val("data")?))?; + e.var("testbench", &format!("{}/tb.sv", e.config_val("rsrc")?))?; // The input data file. `sim.data` is required. let data_name = e.config_val("sim.data")?; @@ -85,11 +85,11 @@ fn build_driver() -> Driver { // Rule for simulation execution. e.rule( "sim-run", - "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle_limit $args > $out", + "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out", )?; // More shared configuration. - e.config_var_or("cycle_limit", "sim.cycle_limit", "500000000")?; + e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000")?; Ok(()) }); @@ -165,12 +165,12 @@ fn build_driver() -> Driver { // The FIRRTL compiler. let firrtl_setup = bld.setup("Firrtl to Verilog compiler", |e| { - e.config_var("firrtl_exe", "firrtl.exe")?; - e.rule("firrtl", "$firrtl_exe -i $in -o $out -X sverilog")?; + e.config_var("firrtl-exe", "firrtl.exe")?; + e.rule("firrtl", "$firrtl-exe -i $in -o $out -X sverilog")?; e.var( "primitives-for-firrtl", - &format!("{}/primitives-for-firrtl.sv", e.config_val("data")?), + &format!("{}/primitives-for-firrtl.sv", e.config_val("rsrc")?), )?; e.rule("add-firrtl-prims", "cat $primitives-for-firrtl $in > $out")?; @@ -214,10 +214,10 @@ fn build_driver() -> Driver { // Verilator. let verilator_setup = bld.setup("Verilator", |e| { e.config_var_or("verilator", "verilator.exe", "verilator")?; - e.config_var_or("cycle_limit", "sim.cycle_limit", "500000000")?; + e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000")?; e.rule( "verilator-compile", - "$verilator $in $testbench --trace --binary --top-module TOP -fno-inline -Mdir $out_dir", + "$verilator $in $testbench --trace --binary --top-module TOP -fno-inline -Mdir $out-dir", )?; e.rule("cp", "cp $in $out")?; Ok(()) @@ -231,7 +231,7 @@ fn build_driver() -> Driver { let out_dir = "verilator-out"; let sim_bin = format!("{}/VTOP", out_dir); e.build("verilator-compile", input, &sim_bin)?; - e.arg("out_dir", out_dir)?; + e.arg("out-dir", out_dir)?; e.build("cp", &sim_bin, output)?; Ok(()) }, @@ -241,22 +241,22 @@ fn build_driver() -> Driver { let debug = bld.state("debug", &[]); // A pseudo-state. let cider_setup = bld.setup("Cider interpreter", |e| { e.config_var_or( - "cider", + "cider-exe", "cider.exe", - "$calyx_base/target/debug/cider", + "$calyx-base/target/debug/cider", )?; e.rule( "cider", - "$cider -l $calyx_base --raw --data data.json $in > $out", + "$cider-exe -l $calyx-base --raw --data data.json $in > $out", )?; e.rule( "cider-debug", - "$cider -l $calyx_base --data data.json $in debug || true", + "$cider-exe -l $calyx-base --data data.json $in debug || true", )?; e.arg("pool", "console")?; // TODO Can we reduce the duplication around `rsrc_dir` and `$python`? - let rsrc_dir = e.config_val("data")?; + let rsrc_dir = e.config_val("rsrc")?; e.var("interp-dat", &format!("{}/interp-dat.py", rsrc_dir))?; e.config_var_or("python", "python", "python3")?; e.rule("dat-to-interp", "$python $interp-dat --to-interp $in")?; @@ -300,21 +300,21 @@ fn build_driver() -> Driver { let xclbin = bld.state("xclbin", &["xclbin"]); let xilinx_setup = bld.setup("Xilinx tools", |e| { // Locations for Vivado and Vitis installations. - e.config_var("vivado_dir", "xilinx.vivado")?; - e.config_var("vitis_dir", "xilinx.vitis")?; + e.config_var("vivado-dir", "xilinx.vivado")?; + e.config_var("vitis-dir", "xilinx.vitis")?; // Package a Verilog program as an `.xo` file. - let rsrc_dir = e.config_val("data")?; - e.var("gen_xo_tcl", &format!("{}/gen_xo.tcl", rsrc_dir))?; - e.var("get_ports", &format!("{}/get-ports.py", rsrc_dir))?; + let rsrc_dir = e.config_val("rsrc")?; + e.var("gen-xo-tcl", &format!("{}/gen_xo.tcl", rsrc_dir))?; + e.var("get-ports", &format!("{}/get-ports.py", rsrc_dir))?; e.config_var_or("python", "python", "python3")?; - e.rule("gen-xo", "$vivado_dir/bin/vivado -mode batch -source $gen_xo_tcl -tclargs $out `$python $get_ports kernel.xml`")?; + e.rule("gen-xo", "$vivado-dir/bin/vivado -mode batch -source $gen-xo-tcl -tclargs $out `$python $get-ports kernel.xml`")?; e.arg("pool", "console")?; // Lets Ninja stream the tool output "live." // Compile an `.xo` file to an `.xclbin` file, which is where the actual EDA work occurs. - e.config_var_or("xilinx_mode", "xilinx.mode", "hw_emu")?; + e.config_var_or("xilinx-mode", "xilinx.mode", "hw_emu")?; e.config_var_or("platform", "xilinx.device", "xilinx_u50_gen3x16_xdma_201920_3")?; - e.rule("compile-xclbin", "$vitis_dir/bin/v++ -g -t $xilinx_mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in")?; + e.rule("compile-xclbin", "$vitis-dir/bin/v++ -g -t $xilinx-mode --platform $platform --save-temps --profile.data all:all:all --profile.exec all:all:all -lo $out $in")?; e.arg("pool", "console")?; Ok(()) @@ -355,12 +355,12 @@ fn build_driver() -> Driver { // TODO Only does `hw_emu` for now... let xrt_setup = bld.setup("Xilinx execution via XRT", |e| { // Generate `emconfig.json`. - e.rule("emconfig", "$vitis_dir/bin/emconfigutil --platform $platform")?; + e.rule("emconfig", "$vitis-dir/bin/emconfigutil --platform $platform")?; e.build_cmd(&["emconfig.json"], "emconfig", &[], &[])?; // Execute via the `xclrun` tool. - e.config_var("xrt_dir", "xilinx.xrt")?; - e.rule("xclrun", "bash -c 'source $vitis_dir/settings64.sh ; source $xrt_dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx_mode $python -m fud.xclrun --out $out $in'")?; + e.config_var("xrt-dir", "xilinx.xrt")?; + e.rule("xclrun", "bash -c 'source $vitis-dir/settings64.sh ; source $xrt-dir/setup.sh ; XRT_INI_PATH=$xrt_ini EMCONFIG_PATH=. XCL_EMULATION_MODE=$xilinx-mode $python -m fud.xclrun --out $out $in'")?; e.arg("pool", "console")?; // "Pre-sim" and "post-sim" scripts for simulation. @@ -384,7 +384,7 @@ fn build_driver() -> Driver { &[input, "$sim_data"], &["emconfig.json"], )?; - let rsrc_dir = e.config_val("data")?; + let rsrc_dir = e.config_val("rsrc")?; e.arg("xrt_ini", &format!("{}/xrt.ini", rsrc_dir))?; Ok(()) }, @@ -401,7 +401,7 @@ fn build_driver() -> Driver { &[input, "$sim_data"], &["emconfig.json", "pre_sim.tcl", "post_sim.tcl"], )?; - let rsrc_dir = e.config_val("data")?; + let rsrc_dir = e.config_val("rsrc")?; e.arg("xrt_ini", &format!("{}/xrt_trace.ini", rsrc_dir))?; Ok(()) }, From f227a93fc869aa2f1de43a0b61b759dbdde7b933 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:06:50 -0500 Subject: [PATCH 158/189] Separate Inference and Promotion into Separate Passes (#1871) * progress * first try at separating passes * use helper function * better tests, cleaner code * existing tests passing * inference * updated code * clippy * clippy is annoying * fixup works now * fixup is fixed up * another fixup test * rewrite tests * cleaner code * commented code --- calyx-opt/src/analysis/compute_static.rs | 60 +- calyx-opt/src/analysis/inference_analysis.rs | 527 ++++++++++ calyx-opt/src/analysis/mod.rs | 3 + calyx-opt/src/default_passes.rs | 8 +- calyx-opt/src/passes/mod.rs | 2 + calyx-opt/src/passes/static_inference.rs | 106 ++ calyx-opt/src/passes/static_promotion.rs | 984 ++++++------------ .../static-control/fixup-necessary.expect | 8 + .../static-control/fixup-necessary.futil | 63 ++ .../static-control/fixup-necessary.futil.data | 12 + tests/passes/cell-share/empty-invoke.expect | 6 +- tests/passes/cell-share/inline.expect | 2 +- .../component.expect | 0 .../component.futil | 35 + .../groups.expect | 4 +- .../static-inference-promotion/groups.futil | 43 + .../if-diff.expect | 2 +- .../if-diff.futil | 2 +- .../if-no-else.expect | 0 .../if-no-else.futil | 24 + .../invoke.expect | 2 +- .../static-inference-promotion/invoke.futil | 52 + .../multi-static.expect | 2 +- .../multi-static.futil | 2 +- .../no_promote_loop.expect | 39 + .../no_promote_loop.futil | 2 +- .../par.expect | 0 .../static-inference-promotion/par.futil | 40 + .../promote-nested.expect | 0 .../promote-nested.futil | 59 ++ .../threshold.expect | 10 +- .../threshold.futil | 2 +- .../upgrade-bound.expect | 0 .../upgrade-bound.futil | 2 +- .../component.expect} | 22 +- .../component.futil | 2 +- tests/passes/static-inference/groups.expect | 40 + .../groups.futil | 2 +- .../passes/static-inference/if-no-else.expect | 19 + .../if-no-else.futil | 2 +- tests/passes/static-inference/invoke.expect | 47 + .../invoke.futil | 2 +- tests/passes/static-inference/par.expect | 37 + .../par.futil | 3 +- .../static-inference/promote-nested.expect | 57 + .../promote-nested.futil | 2 +- .../static-inference/promote-repeat.expect | 48 + .../static-inference/promote-repeat.futil | 43 + .../static-promotion/fixup-necessary.expect | 61 ++ .../static-promotion/fixup-necessary.futil | 64 ++ 50 files changed, 1793 insertions(+), 761 deletions(-) create mode 100644 calyx-opt/src/analysis/inference_analysis.rs create mode 100644 calyx-opt/src/passes/static_inference.rs create mode 100644 tests/correctness/static-control/fixup-necessary.expect create mode 100644 tests/correctness/static-control/fixup-necessary.futil create mode 100644 tests/correctness/static-control/fixup-necessary.futil.data rename tests/passes/{static-promotion => static-inference-promotion}/component.expect (100%) create mode 100644 tests/passes/static-inference-promotion/component.futil rename tests/passes/{static-promotion => static-inference-promotion}/groups.expect (93%) create mode 100644 tests/passes/static-inference-promotion/groups.futil rename tests/passes/{static-promotion => static-inference-promotion}/if-diff.expect (92%) rename tests/passes/{static-promotion => static-inference-promotion}/if-diff.futil (75%) rename tests/passes/{static-promotion => static-inference-promotion}/if-no-else.expect (100%) create mode 100644 tests/passes/static-inference-promotion/if-no-else.futil rename tests/passes/{static-promotion => static-inference-promotion}/invoke.expect (90%) create mode 100644 tests/passes/static-inference-promotion/invoke.futil rename tests/passes/{static-promotion => static-inference-promotion}/multi-static.expect (90%) rename tests/passes/{static-promotion => static-inference-promotion}/multi-static.futil (91%) create mode 100644 tests/passes/static-inference-promotion/no_promote_loop.expect rename tests/passes/{static-promotion => static-inference-promotion}/no_promote_loop.futil (82%) rename tests/passes/{static-promotion => static-inference-promotion}/par.expect (100%) create mode 100644 tests/passes/static-inference-promotion/par.futil rename tests/passes/{static-promotion => static-inference-promotion}/promote-nested.expect (100%) create mode 100644 tests/passes/static-inference-promotion/promote-nested.futil rename tests/passes/{static-promotion => static-inference-promotion}/threshold.expect (80%) rename tests/passes/{static-promotion => static-inference-promotion}/threshold.futil (82%) rename tests/passes/{static-promotion => static-inference-promotion}/upgrade-bound.expect (100%) rename tests/passes/{static-promotion => static-inference-promotion}/upgrade-bound.futil (86%) rename tests/passes/{static-promotion/no_promote_loop.expect => static-inference/component.expect} (60%) rename tests/passes/{static-promotion => static-inference}/component.futil (88%) create mode 100644 tests/passes/static-inference/groups.expect rename tests/passes/{static-promotion => static-inference}/groups.futil (93%) create mode 100644 tests/passes/static-inference/if-no-else.expect rename tests/passes/{static-promotion => static-inference}/if-no-else.futil (81%) create mode 100644 tests/passes/static-inference/invoke.expect rename tests/passes/{static-promotion => static-inference}/invoke.futil (93%) create mode 100644 tests/passes/static-inference/par.expect rename tests/passes/{static-promotion => static-inference}/par.futil (92%) create mode 100644 tests/passes/static-inference/promote-nested.expect rename tests/passes/{static-promotion => static-inference}/promote-nested.futil (89%) create mode 100644 tests/passes/static-inference/promote-repeat.expect create mode 100644 tests/passes/static-inference/promote-repeat.futil create mode 100644 tests/passes/static-promotion/fixup-necessary.expect create mode 100644 tests/passes/static-promotion/fixup-necessary.futil diff --git a/calyx-opt/src/analysis/compute_static.rs b/calyx-opt/src/analysis/compute_static.rs index 67102da2a..0eb965e49 100644 --- a/calyx-opt/src/analysis/compute_static.rs +++ b/calyx-opt/src/analysis/compute_static.rs @@ -24,7 +24,8 @@ where /// **Ensures**: All sub-programs of the type will also be updated. fn update_static(&mut self, extra: &Self::Info) -> Option { if let Some(time) = self.compute_static(extra) { - self.get_mut_attributes().insert(ir::NumAttr::Static, time); + self.get_mut_attributes() + .insert(ir::NumAttr::PromoteStatic, time); Some(time) } else { None @@ -56,30 +57,24 @@ impl WithStatic for ir::Control { } } -impl WithStatic for ir::StaticEnable { - type Info = (); - fn compute_static(&mut self, _: &Self::Info) -> Option { - // Attempt to get the latency from the attribute on the enable first, or - // failing that, from the group. - Some(self.group.borrow().get_latency()) - } -} - impl WithStatic for ir::Enable { type Info = (); fn compute_static(&mut self, _: &Self::Info) -> Option { // Attempt to get the latency from the attribute on the enable first, or // failing that, from the group. - self.attributes - .get(ir::NumAttr::Static) - .or_else(|| self.group.borrow().attributes.get(ir::NumAttr::Static)) + self.attributes.get(ir::NumAttr::PromoteStatic).or_else(|| { + self.group + .borrow() + .attributes + .get(ir::NumAttr::PromoteStatic) + }) } } impl WithStatic for ir::Invoke { type Info = CompTime; fn compute_static(&mut self, extra: &Self::Info) -> Option { - self.attributes.get(ir::NumAttr::Static).or_else(|| { + self.attributes.get(ir::NumAttr::PromoteStatic).or_else(|| { let comp = self.comp.borrow().type_name()?; extra.get(&comp).cloned() }) @@ -89,36 +84,47 @@ impl WithStatic for ir::Invoke { impl WithStatic for ir::Seq { type Info = CompTime; fn compute_static(&mut self, extra: &Self::Info) -> Option { - let mut sum = 0; - for stmt in &mut self.stmts { - sum += stmt.update_static(extra)?; - } - Some(sum) + // Go through each stmt in the seq, and try to calculate the latency. + self.stmts.iter_mut().fold(Some(0), |acc, stmt| { + match (acc, stmt.update_static(extra)) { + (Some(cur_latency), Some(stmt_latency)) => { + Some(cur_latency + stmt_latency) + } + (_, _) => None, + } + }) } } impl WithStatic for ir::Par { type Info = CompTime; fn compute_static(&mut self, extra: &Self::Info) -> Option { - let mut max = 0; - for stmt in &mut self.stmts { - max = std::cmp::max(max, stmt.update_static(extra)?); - } - Some(max) + // Go through each stmt in the par, and try to calculate the latency. + self.stmts.iter_mut().fold(Some(0), |acc, stmt| { + match (acc, stmt.update_static(extra)) { + (Some(cur_latency), Some(stmt_latency)) => { + Some(std::cmp::max(cur_latency, stmt_latency)) + } + (_, _) => None, + } + }) } } impl WithStatic for ir::If { type Info = CompTime; fn compute_static(&mut self, extra: &Self::Info) -> Option { - let t = self.tbranch.update_static(extra)?; - let f = self.fbranch.update_static(extra)?; // Cannot compute latency information for `if`-`with` + let t_latency = self.tbranch.update_static(extra); + let f_latency = self.fbranch.update_static(extra); if self.cond.is_some() { log::debug!("Cannot compute latency for while-with"); return None; } - Some(std::cmp::max(t, f)) + match (t_latency, f_latency) { + (Some(t), Some(f)) => Some(std::cmp::max(t, f)), + (_, _) => None, + } } } diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs new file mode 100644 index 000000000..a7704946c --- /dev/null +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -0,0 +1,527 @@ +use crate::analysis::{ + compute_static::WithStatic, GraphAnalysis, ReadWriteSet, +}; +use calyx_ir::{self as ir, GetAttributes, RRC}; +use ir::CellType; +use itertools::Itertools; +use std::collections::{HashMap, HashSet}; + +/// Struct to store information about the go-done interfaces defined by a primitive. +/// There is no default implementation because it will almost certainly be very +/// unhelpful: you will want to use `from_ctx`. +#[derive(Debug)] +pub struct GoDone { + ports: Vec<(ir::Id, ir::Id, u64)>, +} + +impl GoDone { + pub fn new(ports: Vec<(ir::Id, ir::Id, u64)>) -> Self { + Self { ports } + } + + /// Returns true if this is @go port + pub fn is_go(&self, name: &ir::Id) -> bool { + self.ports.iter().any(|(go, _, _)| name == go) + } + + /// Returns true if this is a @done port + pub fn is_done(&self, name: &ir::Id) -> bool { + self.ports.iter().any(|(_, done, _)| name == done) + } + + /// Returns the latency associated with the provided @go port if present + pub fn get_latency(&self, go_port: &ir::Id) -> Option { + self.ports.iter().find_map(|(go, _, lat)| { + if go == go_port { + Some(*lat) + } else { + None + } + }) + } + + /// Iterate over the defined ports + pub fn iter(&self) -> impl Iterator { + self.ports.iter() + } + + /// Iterate over the defined ports + pub fn is_empty(&self) -> bool { + self.ports.is_empty() + } + + /// Iterate over the defined ports + pub fn len(&self) -> usize { + self.ports.len() + } + + /// Iterate over the defined ports + pub fn get_ports(&self) -> &Vec<(ir::Id, ir::Id, u64)> { + &self.ports + } +} + +impl From<&ir::Primitive> for GoDone { + fn from(prim: &ir::Primitive) -> Self { + let done_ports: HashMap<_, _> = prim + .find_all_with_attr(ir::NumAttr::Done) + .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name())) + .collect(); + + let go_ports = prim + .find_all_with_attr(ir::NumAttr::Go) + .filter_map(|pd| { + pd.attributes.get(ir::NumAttr::Static).and_then(|st| { + done_ports + .get(&pd.attributes.get(ir::NumAttr::Go)) + .map(|done_port| (pd.name(), *done_port, st)) + }) + }) + .collect_vec(); + GoDone::new(go_ports) + } +} + +impl From<&ir::Cell> for GoDone { + fn from(cell: &ir::Cell) -> Self { + let done_ports: HashMap<_, _> = cell + .find_all_with_attr(ir::NumAttr::Done) + .map(|pr| { + let port = pr.borrow(); + (port.attributes.get(ir::NumAttr::Done), port.name) + }) + .collect(); + + let go_ports = cell + .find_all_with_attr(ir::NumAttr::Go) + .filter_map(|pr| { + let port = pr.borrow(); + port.attributes.get(ir::NumAttr::Static).and_then(|st| { + done_ports + .get(&port.attributes.get(ir::NumAttr::Go)) + .map(|done_port| (port.name, *done_port, st)) + }) + }) + .collect_vec(); + GoDone::new(go_ports) + } +} + +#[derive(Debug)] +/// Default implemnetation is not provided, since it is almost certainly more helpful +/// to use `from_ctx` instead. +pub struct InferenceAnalysis { + /// component name -> vec<(go signal, done signal, latency)> + pub latency_data: HashMap, + /// Maps static component names to their latencies, but there can only + /// be one go port on the component. (This is a subset of the information + /// given by latency_data), and is helpful for inferring invokes. + /// Perhaps someday we should get rid of it and only make it one field. + pub static_component_latencies: HashMap, + + updated_components: HashSet, +} + +impl InferenceAnalysis { + /// Builds FixUp struct from a ctx. Looks at all primitives and component + /// signatures to get latency information. + pub fn from_ctx(ctx: &ir::Context) -> Self { + let mut latency_data = HashMap::new(); + let mut static_component_latencies = HashMap::new(); + // Construct latency_data for each primitive + for prim in ctx.lib.signatures() { + let prim_go_done = GoDone::from(prim); + if prim_go_done.len() == 1 { + static_component_latencies + .insert(prim.name, prim_go_done.get_ports()[0].2); + } + latency_data.insert(prim.name, GoDone::from(prim)); + } + for comp in &ctx.components { + let comp_sig = comp.signature.borrow(); + + let done_ports: HashMap<_, _> = comp_sig + .find_all_with_attr(ir::NumAttr::Done) + .map(|pd| { + let pd_ref = pd.borrow(); + (pd_ref.attributes.get(ir::NumAttr::Done), pd_ref.name) + }) + .collect(); + + let go_ports = comp_sig + .find_all_with_attr(ir::NumAttr::Go) + .filter_map(|pd| { + let pd_ref = pd.borrow(); + pd_ref.attributes.get(ir::NumAttr::Static).and_then(|st| { + done_ports + .get(&pd_ref.attributes.get(ir::NumAttr::Go)) + .map(|done_port| (pd_ref.name, *done_port, st)) + }) + }) + .collect_vec(); + + let go_done_comp = GoDone::new(go_ports); + + if go_done_comp.len() == 1 { + static_component_latencies + .insert(comp.name, go_done_comp.get_ports()[0].2); + } + latency_data.insert(comp.name, go_done_comp); + } + InferenceAnalysis { + latency_data, + static_component_latencies, + updated_components: HashSet::new(), + } + } + + /// Updates the component, given a component name and a new latency and GoDone object. + pub fn add_component( + &mut self, + (comp_name, latency, go_done): (ir::Id, u64, GoDone), + ) { + self.latency_data.insert(comp_name, go_done); + self.static_component_latencies.insert(comp_name, latency); + } + + /// Updates the component, given a component name and a new latency. + /// Note that this expects that the component already is accounted for + /// in self.latency_data and self.static_component_latencies. + pub fn remove_component(&mut self, comp_name: ir::Id) { + self.updated_components.insert(comp_name); + self.latency_data.remove(&comp_name); + self.static_component_latencies.remove(&comp_name); + } + + /// Updates the component, given a component name and a new latency. + /// Note that this expects that the component already is accounted for + /// in self.latency_data and self.static_component_latencies. + pub fn adjust_component( + &mut self, + (comp_name, adjusted_latency): (ir::Id, u64), + ) { + self.updated_components.insert(comp_name); + self.latency_data.entry(comp_name).and_modify(|go_done| { + for (_, _, cur_latency) in &mut go_done.ports { + // Updating components with latency data. + *cur_latency = adjusted_latency; + } + }); + self.static_component_latencies + .insert(comp_name, adjusted_latency); + } + + /// Return true if the edge (`src`, `dst`) meet one these criteria, and false otherwise: + /// - `src` is an "out" port of a constant, and `dst` is a "go" port + /// - `src` is a "done" port, and `dst` is a "go" port + /// - `src` is a "done" port, and `dst` is the "done" port of a group + fn mem_wrt_dep_graph(&self, src: &ir::Port, dst: &ir::Port) -> bool { + match (&src.parent, &dst.parent) { + ( + ir::PortParent::Cell(src_cell_wrf), + ir::PortParent::Cell(dst_cell_wrf), + ) => { + let src_rf = src_cell_wrf.upgrade(); + let src_cell = src_rf.borrow(); + let dst_rf = dst_cell_wrf.upgrade(); + let dst_cell = dst_rf.borrow(); + if let (Some(s_name), Some(d_name)) = + (src_cell.type_name(), dst_cell.type_name()) + { + let data_src = self.latency_data.get(&s_name); + let data_dst = self.latency_data.get(&d_name); + if let (Some(dst_ports), Some(src_ports)) = + (data_dst, data_src) + { + return src_ports.is_done(&src.name) + && dst_ports.is_go(&dst.name); + } + } + + // A constant writes to a cell: to be added to the graph, the cell needs to be a "done" port. + if let (Some(d_name), ir::CellType::Constant { .. }) = + (dst_cell.type_name(), &src_cell.prototype) + { + if let Some(ports) = self.latency_data.get(&d_name) { + return ports.is_go(&dst.name); + } + } + + false + } + + // Something is written to a group: to be added to the graph, this needs to be a "done" port. + (_, ir::PortParent::Group(_)) => dst.name == "done", + + // If we encounter anything else, no need to add it to the graph. + _ => false, + } + } + + /// Return a Vec of edges (`a`, `b`), where `a` is a "go" port and `b` + /// is a "done" port, and `a` and `b` have the same parent cell. + fn find_go_done_edges( + &self, + group: &ir::Group, + ) -> Vec<(RRC, RRC)> { + let rw_set = ReadWriteSet::uses(group.assignments.iter()); + let mut go_done_edges: Vec<(RRC, RRC)> = Vec::new(); + + for cell_ref in rw_set { + let cell = cell_ref.borrow(); + if let Some(ports) = + cell.type_name().and_then(|c| self.latency_data.get(&c)) + { + go_done_edges.extend( + ports + .iter() + .map(|(go, done, _)| (cell.get(go), cell.get(done))), + ) + } + } + go_done_edges + } + + /// Returns true if `port` is a "done" port, and we know the latency data + /// about `port`, or is a constant. + fn is_done_port_or_const(&self, port: &ir::Port) -> bool { + if let ir::PortParent::Cell(cwrf) = &port.parent { + let cr = cwrf.upgrade(); + let cell = cr.borrow(); + if let ir::CellType::Constant { val, .. } = &cell.prototype { + if *val > 0 { + return true; + } + } else if let Some(ports) = + cell.type_name().and_then(|c| self.latency_data.get(&c)) + { + return ports.is_done(&port.name); + } + } + false + } + + /// Returns true if `graph` contains writes to "done" ports + /// that could have dynamic latencies, false otherwise. + fn contains_dyn_writes(&self, graph: &GraphAnalysis) -> bool { + for port in &graph.ports() { + match &port.borrow().parent { + ir::PortParent::Cell(cell_wrf) => { + let cr = cell_wrf.upgrade(); + let cell = cr.borrow(); + if let Some(ports) = + cell.type_name().and_then(|c| self.latency_data.get(&c)) + { + let name = &port.borrow().name; + if ports.is_go(name) { + for write_port in graph.writes_to(&port.borrow()) { + if !self + .is_done_port_or_const(&write_port.borrow()) + { + log::debug!( + "`{}` is not a done port", + write_port.borrow().canonical(), + ); + return true; + } + } + } + } + } + ir::PortParent::Group(_) => { + if port.borrow().name == "done" { + for write_port in graph.writes_to(&port.borrow()) { + if !self.is_done_port_or_const(&write_port.borrow()) + { + log::debug!( + "`{}` is not a done port", + write_port.borrow().canonical(), + ); + return true; + } + } + } + } + + ir::PortParent::StaticGroup(_) => // done ports of static groups should clearly NOT have static latencies + panic!("Have not decided how to handle static groups in infer-static-timing"), + } + } + false + } + + /// Returns true if `graph` contains any nodes with degree > 1. + fn contains_node_deg_gt_one(graph: &GraphAnalysis) -> bool { + for port in graph.ports() { + if graph.writes_to(&port.borrow()).count() > 1 { + return true; + } + } + false + } + + /// Attempts to infer the number of cycles starting when + /// `group[go]` is high, and port is high. If inference is + /// not possible, returns None. + fn infer_latency(&self, group: &ir::Group) -> Option { + // Creates a write dependency graph, which contains an edge (`a`, `b`) if: + // - `a` is a "done" port, and writes to `b`, which is a "go" port + // - `a` is a "done" port, and writes to `b`, which is the "done" port of this group + // - `a` is an "out" port, and is a constant, and writes to `b`, a "go" port + // - `a` is a "go" port, and `b` is a "done" port, and `a` and `b` share a parent cell + // Nodes that are not part of any edges that meet these criteria are excluded. + // + // For example, this group: + // ``` + // group g1 { + // a.in = 32'd1; + // a.write_en = 1'd1; + // g1[done] = a.done; + // } + // ``` + // corresponds to this graph: + // ``` + // constant(1) -> a.write_en + // a.write_en -> a.done + // a.done -> g1[done] + // ``` + log::debug!("Checking group `{}`", group.name()); + let graph_unprocessed = GraphAnalysis::from(group); + if self.contains_dyn_writes(&graph_unprocessed) { + log::debug!("FAIL: contains dynamic writes"); + return None; + } + + let go_done_edges = self.find_go_done_edges(group); + let graph = graph_unprocessed + .edge_induced_subgraph(|src, dst| self.mem_wrt_dep_graph(src, dst)) + .add_edges(&go_done_edges) + .remove_isolated_vertices(); + + // Give up if a port has multiple writes to it. + if Self::contains_node_deg_gt_one(&graph) { + log::debug!("FAIL: Group contains multiple writes"); + return None; + } + + let mut tsort = graph.toposort(); + let start = tsort.next()?; + let finish = tsort.last()?; + + let paths = graph.paths(&start.borrow(), &finish.borrow()); + // If there are no paths, give up. + if paths.is_empty() { + log::debug!("FAIL: No path between @go and @done port"); + return None; + } + let first_path = paths.get(0).unwrap(); + + // Sum the latencies of each primitive along the path. + let mut latency_sum = 0; + for port in first_path { + if let ir::PortParent::Cell(cwrf) = &port.borrow().parent { + let cr = cwrf.upgrade(); + let cell = cr.borrow(); + if let Some(ports) = + cell.type_name().and_then(|c| self.latency_data.get(&c)) + { + if let Some(latency) = + ports.get_latency(&port.borrow().name) + { + latency_sum += latency; + } + } + } + } + + log::debug!("SUCCESS: Latency = {}", latency_sum); + Some(latency_sum) + } + + /// Returns Some(latency) if a control statement has a latency, because + /// it is static or is has the @promotable attribute + pub fn get_possible_latency(c: &ir::Control) -> Option { + match c { + ir::Control::Static(sc) => Some(sc.get_latency()), + _ => c.get_attribute(ir::NumAttr::PromoteStatic), + } + } + + /// Removes the @promotable attribute from the control program. + /// Recursively visits the children of the control. + pub fn remove_promotable_attribute(c: &mut ir::Control) { + c.get_mut_attributes().remove(ir::NumAttr::PromoteStatic); + match c { + ir::Control::Empty(_) + | ir::Control::Invoke(_) + | ir::Control::Enable(_) + | ir::Control::Static(_) => (), + ir::Control::While(ir::While { body, .. }) + | ir::Control::Repeat(ir::Repeat { body, .. }) => { + Self::remove_promotable_attribute(body); + } + ir::Control::If(ir::If { + tbranch, fbranch, .. + }) => { + Self::remove_promotable_attribute(tbranch); + Self::remove_promotable_attribute(fbranch); + } + ir::Control::Seq(ir::Seq { stmts, .. }) + | ir::Control::Par(ir::Par { stmts, .. }) => { + for stmt in stmts { + Self::remove_promotable_attribute(stmt); + } + } + } + } + + /// "Fixes Up" the component. In particular: + /// 1. Removes @promotable annotations for any groups that write to any + /// `updated_components`. + /// 2. Try to re-infer groups' latencies. + /// 3. Removes all @promotable annotation from the control program. + /// 4. Re-infers the @promotable annotations for any groups or control. + /// Note that this only fixes up the component's ``internals''. + /// It does *not* fix the component's signature. + pub fn fixup_timing(&self, comp: &mut ir::Component) { + // Removing @promotable annotations for any groups that write to an updated_component, + // then try to re-infer the latency. + for group in comp.groups.iter() { + // This checks any group that writes to the component: + // We can probably switch this to any group that writes to the component's + // `go` port to be more precise analysis. + if ReadWriteSet::write_set(group.borrow_mut().assignments.iter()) + .any(|cell| match cell.borrow().prototype { + CellType::Component { name } => { + self.updated_components.contains(&name) + } + _ => false, + }) + { + // Remove attribute from group. + group + .borrow_mut() + .attributes + .remove(ir::NumAttr::PromoteStatic); + } + } + + for group in &mut comp.groups.iter() { + // Immediately try to re-infer the latency of the group. + let latency_result = self.infer_latency(&group.borrow()); + if let Some(latency) = latency_result { + group + .borrow_mut() + .attributes + .insert(ir::NumAttr::PromoteStatic, latency); + } + } + + // Removing @promotable annotations for the control flow, then trying + // to re-infer them. + Self::remove_promotable_attribute(&mut comp.control.borrow_mut()); + comp.control + .borrow_mut() + .update_static(&self.static_component_latencies); + } +} diff --git a/calyx-opt/src/analysis/mod.rs b/calyx-opt/src/analysis/mod.rs index 2c0afeb74..3e78bea5e 100644 --- a/calyx-opt/src/analysis/mod.rs +++ b/calyx-opt/src/analysis/mod.rs @@ -11,6 +11,7 @@ mod dataflow_order; mod domination_analysis; mod graph; mod graph_coloring; +mod inference_analysis; mod live_range_analysis; mod port_interface; pub mod reaching_defns; @@ -29,6 +30,8 @@ pub use dataflow_order::DataflowOrder; pub use domination_analysis::DominatorMap; pub use graph::GraphAnalysis; pub use graph_coloring::GraphColoring; +pub use inference_analysis::GoDone; +pub use inference_analysis::InferenceAnalysis; pub use live_range_analysis::LiveRangeAnalysis; pub use port_interface::PortInterface; pub use read_write_set::ReadWriteSet; diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 2528692c3..0f5fe52d7 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -8,9 +8,9 @@ use crate::passes::{ Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, RegisterUnsharing, RemoveIds, ResetInsertion, ScheduleCompaction, - SimplifyStaticGuards, SimplifyWithControl, StaticInliner, StaticPromotion, - SynthesisPapercut, TopDownCompileControl, UnrollBounded, WellFormed, - WireInliner, WrapMain, + SimplifyStaticGuards, SimplifyWithControl, StaticInference, StaticInliner, + StaticPromotion, SynthesisPapercut, TopDownCompileControl, UnrollBounded, + WellFormed, WireInliner, WrapMain, }; use crate::traversal::Named; use crate::{pass_manager::PassManager, register_alias}; @@ -38,6 +38,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -96,6 +97,7 @@ impl PassManager { SimplifyWithControl, // Must run before compile-invoke CompileInvoke, // creates dead comb groups AttributePromotion, + StaticInference, StaticPromotion, ScheduleCompaction, CompileRepeat, diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index cba2e17ea..932e37b5f 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -30,6 +30,7 @@ mod remove_ids; mod reset_insertion; mod schedule_compaction; mod simplify_static_guards; +mod static_inference; mod static_inliner; mod static_promotion; mod sync; @@ -78,6 +79,7 @@ pub use reset_insertion::ResetInsertion; pub use schedule_compaction::ScheduleCompaction; pub use simplify_static_guards::SimplifyStaticGuards; pub use simplify_with_control::SimplifyWithControl; +pub use static_inference::StaticInference; pub use static_inliner::StaticInliner; pub use static_promotion::StaticPromotion; pub use sync::CompileSync; diff --git a/calyx-opt/src/passes/static_inference.rs b/calyx-opt/src/passes/static_inference.rs new file mode 100644 index 000000000..0c1b54d61 --- /dev/null +++ b/calyx-opt/src/passes/static_inference.rs @@ -0,0 +1,106 @@ +use crate::analysis::{GoDone, InferenceAnalysis}; +use crate::traversal::{ + Action, ConstructVisitor, Named, Order, VisResult, Visitor, +}; +use calyx_ir::{self as ir, LibrarySignatures}; +use calyx_utils::CalyxResult; +use itertools::Itertools; + +/// Infer "promote_static" (potentially to be renamed @promotable) annotation +/// for groups and control. +/// Inference occurs whenever possible. +pub struct StaticInference { + /// Takes static information. + inference_analysis: InferenceAnalysis, +} + +// Override constructor to build latency_data information from the primitives +// library. +impl ConstructVisitor for StaticInference { + fn from(ctx: &ir::Context) -> CalyxResult { + Ok(StaticInference { + inference_analysis: InferenceAnalysis::from_ctx(ctx), + }) + } + + // This pass shared information between components + fn clear_data(&mut self) {} +} + +impl Named for StaticInference { + fn name() -> &'static str { + "static-inference" + } + + fn description() -> &'static str { + "infer when dynamic control programs are promotable" + } +} + +impl Visitor for StaticInference { + // Require post order traversal of components to ensure `invoke` nodes + // get timing information for components. + fn iteration_order() -> Order { + Order::Post + } + + fn finish( + &mut self, + comp: &mut ir::Component, + _lib: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + if comp.name != "main" { + // If the entire component's control is promotable. + if let Some(val) = + InferenceAnalysis::get_possible_latency(&comp.control.borrow()) + { + let comp_sig = comp.signature.borrow(); + let mut go_ports: Vec<_> = + comp_sig.find_all_with_attr(ir::NumAttr::Go).collect(); + // Insert @static attribute on the go ports. + for go_port in &mut go_ports { + go_port + .borrow_mut() + .attributes + .insert(ir::NumAttr::Static, val); + } + let mut done_ports: Vec<_> = + comp_sig.find_all_with_attr(ir::NumAttr::Done).collect(); + // Update `latency_data`. + go_ports.sort_by_key(|port| { + port.borrow().attributes.get(ir::NumAttr::Go).unwrap() + }); + done_ports.sort_by_key(|port| { + port.borrow().attributes.get(ir::NumAttr::Done).unwrap() + }); + let zipped: Vec<_> = + go_ports.iter().zip(done_ports.iter()).collect(); + let go_done_ports = zipped + .into_iter() + .map(|(go_port, done_port)| { + (go_port.borrow().name, done_port.borrow().name, val) + }) + .collect_vec(); + self.inference_analysis.add_component(( + comp.name, + val, + GoDone::new(go_done_ports), + )); + } + } + Ok(Action::Continue) + } + + fn start( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + // ``Fix up the timing'', but with the updated_components argument as + // and empty HashMap. This just performs inference. + self.inference_analysis.fixup_timing(comp); + Ok(Action::Continue) + } +} diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 750b5e9ad..0fffcd859 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -1,10 +1,10 @@ -use crate::analysis::{GraphAnalysis, ReadWriteSet}; +use crate::analysis::InferenceAnalysis; use crate::traversal::{ Action, ConstructVisitor, Named, Order, ParseVal, PassOpt, VisResult, Visitor, }; -use calyx_ir::{self as ir, LibrarySignatures, RRC}; -use calyx_utils::{CalyxResult, Error}; +use calyx_ir::{self as ir, LibrarySignatures}; +use calyx_utils::CalyxResult; use ir::GetAttributes; use itertools::Itertools; use std::collections::HashMap; @@ -15,132 +15,24 @@ const APPROX_ENABLE_SIZE: u64 = 1; const APPROX_IF_SIZE: u64 = 3; const APPROX_WHILE_REPEAT_SIZE: u64 = 3; -/// Struct to store information about the go-done interfaces defined by a primitive. -#[derive(Default, Debug)] -struct GoDone { - ports: Vec<(ir::Id, ir::Id, u64)>, -} - -impl GoDone { - pub fn new(ports: Vec<(ir::Id, ir::Id, u64)>) -> Self { - Self { ports } - } - - /// Returns true if this is @go port - pub fn is_go(&self, name: &ir::Id) -> bool { - self.ports.iter().any(|(go, _, _)| name == go) - } - - /// Returns true if this is a @done port - pub fn is_done(&self, name: &ir::Id) -> bool { - self.ports.iter().any(|(_, done, _)| name == done) - } - - /// Returns the latency associated with the provided @go port if present - pub fn get_latency(&self, go_port: &ir::Id) -> Option { - self.ports.iter().find_map(|(go, _, lat)| { - if go == go_port { - Some(*lat) - } else { - None - } - }) - } - - /// Iterate over the defined ports - pub fn iter(&self) -> impl Iterator { - self.ports.iter() - } -} - -impl From<&ir::Primitive> for GoDone { - fn from(prim: &ir::Primitive) -> Self { - let done_ports: HashMap<_, _> = prim - .find_all_with_attr(ir::NumAttr::Done) - .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name())) - .collect(); - - let go_ports = prim - .find_all_with_attr(ir::NumAttr::Go) - .filter_map(|pd| { - pd.attributes.get(ir::NumAttr::Static).and_then(|st| { - done_ports - .get(&pd.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (pd.name(), *done_port, st)) - }) - }) - .collect_vec(); - GoDone::new(go_ports) - } -} - -impl From<&ir::Cell> for GoDone { - fn from(cell: &ir::Cell) -> Self { - let done_ports: HashMap<_, _> = cell - .find_all_with_attr(ir::NumAttr::Done) - .map(|pr| { - let port = pr.borrow(); - (port.attributes.get(ir::NumAttr::Done), port.name) - }) - .collect(); - - let go_ports = cell - .find_all_with_attr(ir::NumAttr::Go) - .filter_map(|pr| { - let port = pr.borrow(); - port.attributes.get(ir::NumAttr::Static).and_then(|st| { - done_ports - .get(&port.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (port.name, *done_port, st)) - }) - }) - .collect_vec(); - GoDone::new(go_ports) - } -} - -/// Infer "promote_static" annotation for groups and promote control to static when -/// (conservatively) possible. +/// Promote control to static when (conservatively) possible, using @promote_static +/// annotations from `infer_static`. +/// +/// Promotion occurs the following policies: +/// 1. ``Threshold'': How large the island must be. We have three const +/// defined as heuristics to measure approximately how big each control program +/// is. It must be larger than that threshold. +/// 2. ``Cycle limit": The maximum number of cycles the island can be when we +/// promote it. +/// 3. ``If Diff Limit": The maximum difference in latency between if statments +/// that we can tolerate to promote it. /// -/// Promotion follows the current policies: -/// 1. if multiple groups enables aligned inside a seq are marked with the "promote_static" -/// attribute, then promote all promotable enables to static enables, meanwhile, -/// wrap them into a static seq -/// for example: -/// ``` -/// seq { -/// a1; -/// @promote_static a2; @promote_static a3; } -/// ``` -/// becomes -/// ``` -/// seq { -/// a1; -/// static seq {a2; a3;}} -/// ``` -/// 2. if all control statements under seq are either static statements or group enables -/// with `promote_static` annotation, then promote all group enables and turn -/// seq into static seq -/// 3. Under a par control op, all group enables marked with `promote_static` will be promoted. -/// all control statements that are either static or group enables with `promote_static` annotation -/// are wrapped inside a static par. -/// ``` -/// par {@promote_static a1; a2; @promote_static a3;} -/// ``` -/// becomes -/// ``` -/// par { -/// static par { a1; a3; } -/// a2; -/// } -/// ``` pub struct StaticPromotion { - /// component name -> vec<(go signal, done signal, latency)> - latency_data: HashMap, + /// An InferenceAnalysis object so that we can re-infer the latencies of + /// certain components. + inference_analysis: InferenceAnalysis, /// dynamic group Id -> promoted static group Id static_group_name: HashMap, - /// Maps static component names to their latencies - static_component_latencies: HashMap, /// Threshold for promotion threshold: u64, /// Threshold for difference in latency for if statements @@ -153,38 +45,10 @@ pub struct StaticPromotion { // library. impl ConstructVisitor for StaticPromotion { fn from(ctx: &ir::Context) -> CalyxResult { - let mut latency_data = HashMap::new(); - //let mut comp_latency = HashMap::new(); - // Construct latency_data for each primitive - for prim in ctx.lib.signatures() { - let done_ports: HashMap<_, _> = prim - .find_all_with_attr(ir::NumAttr::Done) - .map(|pd| (pd.attributes.get(ir::NumAttr::Done), pd.name())) - .collect(); - - let go_ports = prim - .find_all_with_attr(ir::NumAttr::Go) - .filter_map(|pd| { - pd.attributes.get(ir::NumAttr::Static).and_then(|st| { - done_ports - .get(&pd.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (pd.name(), *done_port, st)) - }) - }) - .collect_vec(); - - // If this primitive has exactly one (go, done, static) pair, we - // can infer the latency of its invokes. - if go_ports.len() == 1 { - //comp_latency.insert(prim.name, go_ports[0].2); - } - latency_data.insert(prim.name, GoDone::new(go_ports)); - } let opts = Self::get_opts(ctx); Ok(StaticPromotion { - latency_data, + inference_analysis: InferenceAnalysis::from_ctx(ctx), static_group_name: HashMap::new(), - static_component_latencies: HashMap::new(), threshold: opts["threshold"].pos_num().unwrap(), if_diff_limit: opts["if-diff-limit"].pos_num(), cycle_limit: opts["cycle-limit"].pos_num(), @@ -231,233 +95,6 @@ impl Named for StaticPromotion { } impl StaticPromotion { - /// Return true if the edge (`src`, `dst`) meet one these criteria, and false otherwise: - /// - `src` is an "out" port of a constant, and `dst` is a "go" port - /// - `src` is a "done" port, and `dst` is a "go" port - /// - `src` is a "done" port, and `dst` is the "done" port of a group - fn mem_wrt_dep_graph(&self, src: &ir::Port, dst: &ir::Port) -> bool { - match (&src.parent, &dst.parent) { - ( - ir::PortParent::Cell(src_cell_wrf), - ir::PortParent::Cell(dst_cell_wrf), - ) => { - let src_rf = src_cell_wrf.upgrade(); - let src_cell = src_rf.borrow(); - let dst_rf = dst_cell_wrf.upgrade(); - let dst_cell = dst_rf.borrow(); - if let (Some(s_name), Some(d_name)) = - (src_cell.type_name(), dst_cell.type_name()) - { - let data_src = self.latency_data.get(&s_name); - let data_dst = self.latency_data.get(&d_name); - if let (Some(dst_ports), Some(src_ports)) = - (data_dst, data_src) - { - return src_ports.is_done(&src.name) - && dst_ports.is_go(&dst.name); - } - } - - // A constant writes to a cell: to be added to the graph, the cell needs to be a "done" port. - if let (Some(d_name), ir::CellType::Constant { .. }) = - (dst_cell.type_name(), &src_cell.prototype) - { - if let Some(ports) = self.latency_data.get(&d_name) { - return ports.is_go(&dst.name); - } - } - - false - } - - // Something is written to a group: to be added to the graph, this needs to be a "done" port. - (_, ir::PortParent::Group(_)) => dst.name == "done", - - // If we encounter anything else, no need to add it to the graph. - _ => false, - } - } - - /// Return a Vec of edges (`a`, `b`), where `a` is a "go" port and `b` - /// is a "done" port, and `a` and `b` have the same parent cell. - fn find_go_done_edges( - &self, - group: &ir::Group, - ) -> Vec<(RRC, RRC)> { - let rw_set = ReadWriteSet::uses(group.assignments.iter()); - let mut go_done_edges: Vec<(RRC, RRC)> = Vec::new(); - - for cell_ref in rw_set { - let cell = cell_ref.borrow(); - if let Some(ports) = - cell.type_name().and_then(|c| self.latency_data.get(&c)) - { - go_done_edges.extend( - ports - .iter() - .map(|(go, done, _)| (cell.get(go), cell.get(done))), - ) - } - } - go_done_edges - } - - /// Returns true if `port` is a "done" port, and we know the latency data - /// about `port`, or is a constant. - fn is_done_port_or_const(&self, port: &ir::Port) -> bool { - if let ir::PortParent::Cell(cwrf) = &port.parent { - let cr = cwrf.upgrade(); - let cell = cr.borrow(); - if let ir::CellType::Constant { val, .. } = &cell.prototype { - if *val > 0 { - return true; - } - } else if let Some(ports) = - cell.type_name().and_then(|c| self.latency_data.get(&c)) - { - return ports.is_done(&port.name); - } - } - false - } - - /// Returns true if `graph` contains writes to "done" ports - /// that could have dynamic latencies, false otherwise. - fn contains_dyn_writes(&self, graph: &GraphAnalysis) -> bool { - for port in &graph.ports() { - match &port.borrow().parent { - ir::PortParent::Cell(cell_wrf) => { - let cr = cell_wrf.upgrade(); - let cell = cr.borrow(); - if let Some(ports) = - cell.type_name().and_then(|c| self.latency_data.get(&c)) - { - let name = &port.borrow().name; - if ports.is_go(name) { - for write_port in graph.writes_to(&port.borrow()) { - if !self - .is_done_port_or_const(&write_port.borrow()) - { - log::debug!( - "`{}` is not a done port", - write_port.borrow().canonical(), - ); - return true; - } - } - } - } - } - ir::PortParent::Group(_) => { - if port.borrow().name == "done" { - for write_port in graph.writes_to(&port.borrow()) { - if !self.is_done_port_or_const(&write_port.borrow()) - { - log::debug!( - "`{}` is not a done port", - write_port.borrow().canonical(), - ); - return true; - } - } - } - } - - ir::PortParent::StaticGroup(_) => // done ports of static groups should clearly NOT have static latencies - panic!("Have not decided how to handle static groups in infer-static-timing"), - } - } - false - } - - /// Returns true if `graph` contains any nodes with degree > 1. - fn contains_node_deg_gt_one(graph: &GraphAnalysis) -> bool { - for port in graph.ports() { - if graph.writes_to(&port.borrow()).count() > 1 { - return true; - } - } - false - } - - /// Attempts to infer the number of cycles starting when - /// `group[go]` is high, and port is high. If inference is - /// not possible, returns None. - fn infer_latency(&self, group: &ir::Group) -> Option { - // Creates a write dependency graph, which contains an edge (`a`, `b`) if: - // - `a` is a "done" port, and writes to `b`, which is a "go" port - // - `a` is a "done" port, and writes to `b`, which is the "done" port of this group - // - `a` is an "out" port, and is a constant, and writes to `b`, a "go" port - // - `a` is a "go" port, and `b` is a "done" port, and `a` and `b` share a parent cell - // Nodes that are not part of any edges that meet these criteria are excluded. - // - // For example, this group: - // ``` - // group g1 { - // a.in = 32'd1; - // a.write_en = 1'd1; - // g1[done] = a.done; - // } - // ``` - // corresponds to this graph: - // ``` - // constant(1) -> a.write_en - // a.write_en -> a.done - // a.done -> g1[done] - // ``` - log::debug!("Checking group `{}`", group.name()); - let graph_unprocessed = GraphAnalysis::from(group); - if self.contains_dyn_writes(&graph_unprocessed) { - log::debug!("FAIL: contains dynamic writes"); - return None; - } - - let go_done_edges = self.find_go_done_edges(group); - let graph = graph_unprocessed - .edge_induced_subgraph(|src, dst| self.mem_wrt_dep_graph(src, dst)) - .add_edges(&go_done_edges) - .remove_isolated_vertices(); - - // Give up if a port has multiple writes to it. - if Self::contains_node_deg_gt_one(&graph) { - log::debug!("FAIL: Group contains multiple writes"); - return None; - } - - let mut tsort = graph.toposort(); - let start = tsort.next()?; - let finish = tsort.last()?; - - let paths = graph.paths(&start.borrow(), &finish.borrow()); - // If there are no paths, give up. - if paths.is_empty() { - log::debug!("FAIL: No path between @go and @done port"); - return None; - } - let first_path = paths.get(0).unwrap(); - - // Sum the latencies of each primitive along the path. - let mut latency_sum = 0; - for port in first_path { - if let ir::PortParent::Cell(cwrf) = &port.borrow().parent { - let cr = cwrf.upgrade(); - let cell = cr.borrow(); - if let Some(ports) = - cell.type_name().and_then(|c| self.latency_data.get(&c)) - { - if let Some(latency) = - ports.get_latency(&port.borrow().name) - { - latency_sum += latency; - } - } - } - } - - log::debug!("SUCCESS: Latency = {}", latency_sum); - Some(latency_sum) - } - /// Gets the inferred latency, which should either be from being a static /// control operator or the promote_static attribute. /// Will raise an error if neither of these is true. @@ -512,17 +149,71 @@ impl StaticPromotion { self.static_group_name .insert(group.borrow().name(), sg.borrow().name()); for assignment in group.borrow().assignments.iter() { + // Don't need to include assignment to done hole. if !(assignment.dst.borrow().is_hole() && assignment.dst.borrow().name == "done") { - let static_s = ir::Assignment::from(assignment.clone()); - sg.borrow_mut().assignments.push(static_s); + sg.borrow_mut() + .assignments + .push(ir::Assignment::from(assignment.clone())); } } Rc::clone(&sg) } } + // Converts dynamic enable to static + fn convert_enable_to_static( + &mut self, + s: &mut ir::Enable, + builder: &mut ir::Builder, + ) -> ir::StaticControl { + s.attributes.remove(ir::NumAttr::PromoteStatic); + ir::StaticControl::Enable(ir::StaticEnable { + // upgrading group to static group + group: self.construct_static_group( + builder, + Rc::clone(&s.group), + s.group + .borrow() + .get_attributes() + .unwrap() + .get(ir::NumAttr::PromoteStatic) + .unwrap(), + ), + attributes: std::mem::take(&mut s.attributes), + }) + } + + // Converts dynamic invoke to static + fn convert_invoke_to_static( + &mut self, + s: &mut ir::Invoke, + ) -> ir::StaticControl { + assert!( + s.comb_group.is_none(), + "Shouldn't Promote to Static if there is a Comb Group", + ); + s.attributes.remove(ir::NumAttr::PromoteStatic); + let latency = *self.inference_analysis.static_component_latencies.get( + &s.comp.borrow().type_name().unwrap_or_else(|| { + unreachable!( + "Already checked that comp is component" + ) + }), + ).unwrap_or_else(|| unreachable!("Called convert_to_static for static invoke that does not have a static component")); + let s_inv = ir::StaticInvoke { + comp: Rc::clone(&s.comp), + inputs: std::mem::take(&mut s.inputs), + outputs: std::mem::take(&mut s.outputs), + latency, + attributes: std::mem::take(&mut s.attributes), + ref_cells: std::mem::take(&mut s.ref_cells), + comb_group: std::mem::take(&mut s.comb_group), + }; + ir::StaticControl::Invoke(s_inv) + } + /// Converts control to static control. /// Control must already be static or have the `promote_static` attribute. fn convert_to_static( @@ -542,25 +233,7 @@ impl StaticPromotion { let inferred_latency = Self::get_inferred_latency(c); match c { ir::Control::Empty(_) => ir::StaticControl::empty(), - ir::Control::Enable(ir::Enable { group, attributes }) => { - // Removing the `promote_static` attribute bc we don't need it anymore. - attributes.remove(ir::NumAttr::PromoteStatic); - let enable = ir::StaticControl::Enable(ir::StaticEnable { - // upgrading group to static group - group: self.construct_static_group( - builder, - Rc::clone(group), - group - .borrow() - .get_attributes() - .unwrap() - .get(ir::NumAttr::PromoteStatic) - .unwrap(), - ), - attributes: std::mem::take(attributes), - }); - enable - } + ir::Control::Enable(s) => self.convert_enable_to_static(s, builder), ir::Control::Seq(ir::Seq { stmts, attributes }) => { // Removing the `promote_static` attribute bc we don't need it anymore attributes.remove(ir::NumAttr::PromoteStatic); @@ -655,37 +328,7 @@ impl StaticPromotion { ) } ir::Control::Static(_) => c.take_static_control(), - ir::Control::Invoke(ir::Invoke { - comp, - inputs, - outputs, - attributes, - comb_group, - ref_cells, - }) => { - assert!( - comb_group.is_none(), - "Shouldn't Promote to Static if there is a Comb Group", - ); - attributes.remove(ir::NumAttr::PromoteStatic); - Self::check_latencies_match(self.static_component_latencies.get( - &comp.borrow().type_name().unwrap_or_else(|| { - unreachable!( - "Already checked that comp is component" - ) - }), - ).unwrap_or_else(|| unreachable!("Called convert_to_static for static invoke that does not have a static component")).get(), inferred_latency); - let s_inv = ir::StaticInvoke { - comp: Rc::clone(comp), - inputs: std::mem::take(inputs), - outputs: std::mem::take(outputs), - latency: inferred_latency, - attributes: std::mem::take(attributes), - ref_cells: std::mem::take(ref_cells), - comb_group: std::mem::take(comb_group), - }; - ir::StaticControl::Invoke(s_inv) - } + ir::Control::Invoke(s) => self.convert_invoke_to_static(s), } } @@ -727,7 +370,8 @@ impl StaticPromotion { // static control appears as one big group to the dynamic FSM 1 } - ir::Control::Invoke(_) => 1, + // Invokes are same size as enables. + ir::Control::Invoke(_) => APPROX_ENABLE_SIZE, } } @@ -737,27 +381,35 @@ impl StaticPromotion { v.iter().map(Self::approx_size).sum() } - /// First checks if the vec of control statements satsifies the threshold - /// and cycle count threshold - /// (That is, whether the combined approx_size of the static_vec is greater) - /// than the threshold and cycle count is less than cycle limit). - /// If so, converts vec of control to a static seq, and returns a vec containing - /// the static seq. - /// Otherwise, just returns the vec without changing it. - fn convert_vec_seq_if_sat( + /// Converts the control_vec (i..e, the stmts of the seq) using heuristics. + fn promote_vec_seq_heuristic( &mut self, builder: &mut ir::Builder, - control_vec: Vec, + mut control_vec: Vec, ) -> Vec { - if Self::approx_control_vec_size(&control_vec) <= self.threshold - || !self.within_cycle_limit( - control_vec.iter().map(Self::get_inferred_latency).sum(), - ) + if control_vec.is_empty() { + // Base case + return vec![]; + } else if control_vec.len() == 1 { + return vec![control_vec.pop().unwrap()]; + } else if Self::approx_control_vec_size(&control_vec) <= self.threshold { - // Return unchanged vec + // Too small to be promoted, return as is return control_vec; + } else if !self.within_cycle_limit( + control_vec.iter().map(Self::get_inferred_latency).sum(), + ) { + // Too large, try to break up + let right = control_vec.split_off(control_vec.len() / 2); + dbg!(control_vec.len()); + dbg!(right.len()); + let mut left_res = + self.promote_vec_seq_heuristic(builder, control_vec); + let right_res = self.promote_vec_seq_heuristic(builder, right); + left_res.extend(right_res); + return left_res; } - // Convert vec to static seq + // Correct size, convert the entire vec let s_seq_stmts = self.convert_vec_to_static(builder, control_vec); let latency = s_seq_stmts.iter().map(|sc| sc.get_latency()).sum(); let mut sseq = @@ -772,24 +424,41 @@ impl StaticPromotion { /// If so, converts vec of control to a static par, and returns a vec containing /// the static par. /// Otherwise, just returns the vec without changing it. - fn convert_vec_par_if_sat( + fn promote_vec_par_heuristic( &mut self, builder: &mut ir::Builder, - control_vec: Vec, + mut control_vec: Vec, ) -> Vec { - if Self::approx_control_vec_size(&control_vec) <= self.threshold - || !self.within_cycle_limit( - control_vec - .iter() - .map(Self::get_inferred_latency) - .max() - .unwrap_or_else(|| unreachable!("Non Empty Par Block")), - ) + if control_vec.is_empty() { + // Base case + return vec![]; + } else if control_vec.len() == 1 { + return vec![control_vec.pop().unwrap()]; + } else if Self::approx_control_vec_size(&control_vec) <= self.threshold { - // Return unchanged vec + // Too small to be promoted, return as is return control_vec; + } else if !self.within_cycle_limit( + control_vec + .iter() + .map(Self::get_inferred_latency) + .max() + .unwrap_or_else(|| unreachable!("Empty Par Block")), + ) { + // Too large to be promoted, take out largest thread and try to promote rest. + // Can safely unwrap bc we already checked for an empty vector. + let (index, _) = control_vec + .iter() + .enumerate() + .max_by_key(|&(_, c)| Self::approx_size(c)) + .unwrap(); + // Pop the largest element from the vector + let largest_thread = control_vec.remove(index); + let mut left = self.promote_vec_par_heuristic(builder, control_vec); + left.push(largest_thread); + return left; } - // Convert vec to static seq + // Convert vec to static par let s_par_stmts = self.convert_vec_to_static(builder, control_vec); let latency = s_par_stmts .iter() @@ -815,102 +484,82 @@ impl Visitor for StaticPromotion { _lib: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if comp.name != "main" && comp.control.borrow().is_static() { - if let Some(lat) = comp.control.borrow().get_latency() { - if !comp.is_static() { - comp.attributes.insert(ir::BoolAttr::Promoted, 1); - } - comp.latency = Some(NonZeroU64::new(lat).unwrap()); - let comp_sig = comp.signature.borrow(); - let mut done_ports: Vec<_> = - comp_sig.find_all_with_attr(ir::NumAttr::Done).collect(); - let mut go_ports: Vec<_> = - comp_sig.find_all_with_attr(ir::NumAttr::Go).collect(); - if done_ports.len() == 1 && go_ports.len() == 1 { - let go_done = GoDone::new(vec![( - go_ports.pop().unwrap().borrow().name, - done_ports.pop().unwrap().borrow().name, - lat, - )]); - self.latency_data.insert(comp.name, go_done); + if comp.name != "main" { + let comp_sig = comp.signature.borrow(); + let go_ports = + comp_sig.find_all_with_attr(ir::NumAttr::Go).collect_vec(); + if go_ports.iter().any(|go_port| { + go_port.borrow_mut().attributes.has(ir::NumAttr::Static) + }) { + if comp.control.borrow().is_static() { + // We ended up promoting it + if !comp.is_static() { + // Need this attribute for a weird, in-between state. + // It has a known latency but also produces a done signal. + comp.attributes.insert(ir::BoolAttr::Promoted, 1); + } + // This makes the component appear as a static component. + comp.latency = Some( + NonZeroU64::new( + comp.control.borrow().get_latency().unwrap(), + ) + .unwrap(), + ); + } else { + // We decided not to promote, so we need to update data structures + // and remove @static attribute from the signature. + + // Updating `static_info`. + self.inference_analysis.remove_component(comp.name); + // Removing `@static` from the go ports. + for go_port in go_ports { + go_port + .borrow_mut() + .attributes + .remove(ir::NumAttr::Static); + } } - } - } - if comp.is_static() { - self.static_component_latencies - .insert(comp.name, comp.latency.unwrap()); + }; } + // Remove @promotable (i.e., @promote_static) attribute from control. + // Probably not necessary, since we'll ignore it anyways, but makes for + // cleaner code. + InferenceAnalysis::remove_promotable_attribute( + &mut comp.control.borrow_mut(), + ); Ok(Action::Continue) } fn start( &mut self, comp: &mut ir::Component, - sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let builder = ir::Builder::new(comp, sigs); - let mut latency_result: Option; - for group in builder.component.get_groups() { - if let Some(latency) = self.infer_latency(&group.borrow()) { - let grp = group.borrow(); - if let Some(curr_lat) = grp.attributes.get(ir::NumAttr::Static) - { - // Inferred latency is not the same as the provided latency annotation. - if curr_lat != latency { - let msg1 = format!("Annotated latency: {}", curr_lat); - let msg2 = format!("Inferred latency: {}", latency); - let msg = format!( - "Invalid \"static\" latency annotation for group {}.\n{}\n{}", - grp.name(), - msg1, - msg2 - ); - return Err(Error::malformed_structure(msg) - .with_pos(&grp.attributes)); - } - } - latency_result = Some(latency); - } else { - latency_result = None; - } - - if let Some(latency) = latency_result { - group - .borrow_mut() - .attributes - .insert(ir::NumAttr::PromoteStatic, latency); - } - } - Ok(Action::Continue) - } - - fn empty( - &mut self, - s: &mut ir::Empty, - _comp: &mut ir::Component, _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - s.attributes.insert(ir::NumAttr::PromoteStatic, 0); + // Re-infer static timing based on the components we have updated in + // this pass. + self.inference_analysis.fixup_timing(comp); Ok(Action::Continue) } fn enable( &mut self, s: &mut ir::Enable, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, + comp: &mut ir::Component, + sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if let Some(latency) = s - .group - .borrow() - .get_attributes() - .unwrap() - .get(ir::NumAttr::PromoteStatic) - { - s.attributes.insert(ir::NumAttr::PromoteStatic, latency); + let mut builder = ir::Builder::new(comp, sigs); + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + // Convert to static if enable is + // within cycle limit and size is above threshold. + if self.within_cycle_limit(latency) + && (APPROX_ENABLE_SIZE > self.threshold) + { + return Ok(Action::change(ir::Control::Static( + self.convert_enable_to_static(s, &mut builder), + ))); + } } Ok(Action::Continue) } @@ -922,14 +571,14 @@ impl Visitor for StaticPromotion { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - // Shouldn't promote to static invoke if we have a comb group - if s.comp.borrow().is_component() { - if let Some(latency) = self - .static_component_latencies - .get(&s.comp.borrow().type_name().unwrap()) + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + // Convert to static if within cycle limit and size is above threshold. + if self.within_cycle_limit(latency) + && (APPROX_ENABLE_SIZE > self.threshold) { - s.attributes - .insert(ir::NumAttr::PromoteStatic, latency.get()); + return Ok(Action::change(ir::Control::Static( + self.convert_invoke_to_static(s), + ))); } } Ok(Action::Continue) @@ -943,6 +592,33 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); + // Checking if entire seq is promotable + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + // If seq is too small to promote, then continue without doing anything. + if Self::approx_control_vec_size(&s.stmts) <= self.threshold { + return Ok(Action::Continue); + } else if self.within_cycle_limit(latency) { + // We promote entire seq. + let mut sseq = ir::Control::Static(ir::StaticControl::seq( + self.convert_vec_to_static( + &mut builder, + std::mem::take(&mut s.stmts), + ), + latency, + )); + sseq.get_mut_attributes() + .insert(ir::NumAttr::Compactable, 1); + return Ok(Action::change(sseq)); + } + } + // The seq either a) takes too many cylces to promote entirely or + // b) has dynamic stmts in it. Either way, the solution is to + // break it up into smaller static seqs. + // We know that this seq will *never* be promoted. Therefore, we can + // safely replace it with a standard `seq` that does not have an `@promotable` + // attribute. This temporarily messes up its parents' `@promotable` + // attribute, but this is fine since we know its parent will never try + // to promote it. let old_stmts = std::mem::take(&mut s.stmts); let mut new_stmts: Vec = Vec::new(); let mut cur_vec: Vec = Vec::new(); @@ -950,9 +626,9 @@ impl Visitor for StaticPromotion { if Self::can_be_promoted(&stmt) { cur_vec.push(stmt); } else { - // Accumualte cur_vec into a static seq if it meets threshold + // Use heuristics to decide how to promote this cur_vec of promotable stmts. let possibly_promoted_stmts = - self.convert_vec_seq_if_sat(&mut builder, cur_vec); + self.promote_vec_seq_heuristic(&mut builder, cur_vec); new_stmts.extend(possibly_promoted_stmts); // Add the current (non-promotable) stmt new_stmts.push(stmt); @@ -960,43 +636,7 @@ impl Visitor for StaticPromotion { cur_vec = Vec::new(); } } - if new_stmts.is_empty() { - // The entire seq can be promoted - let approx_size: u64 = cur_vec.iter().map(Self::approx_size).sum(); - if approx_size > self.threshold - && self.within_cycle_limit( - cur_vec.iter().map(Self::get_inferred_latency).sum(), - ) - { - // Promote entire seq to a static seq - let s_seq_stmts = - self.convert_vec_to_static(&mut builder, cur_vec); - let latency = - s_seq_stmts.iter().map(|sc| sc.get_latency()).sum(); - let mut sseq = ir::Control::Static(ir::StaticControl::seq( - s_seq_stmts, - latency, - )); - sseq.get_mut_attributes() - .insert(ir::NumAttr::Compactable, 1); - return Ok(Action::change(sseq)); - } else { - // Doesn't meet threshold. - // Add attribute to seq so parent might promote it. - let inferred_latency = - cur_vec.iter().map(Self::get_inferred_latency).sum(); - s.attributes - .insert(ir::NumAttr::PromoteStatic, inferred_latency); - s.stmts = cur_vec; - return Ok(Action::Continue); - } - } - // Entire seq is not static, so we're only promoting the last - // bit of it if possible. - let possibly_promoted_stmts = - self.convert_vec_seq_if_sat(&mut builder, cur_vec); - new_stmts.extend(possibly_promoted_stmts); - + new_stmts.extend(self.promote_vec_seq_heuristic(&mut builder, cur_vec)); let new_seq = ir::Control::Seq(ir::Seq { stmts: new_stmts, attributes: ir::Attributes::default(), @@ -1012,53 +652,37 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - let mut new_stmts: Vec = Vec::new(); - // Split the par into static and dynamic stmts - let (s_stmts, d_stmts): (Vec, Vec) = - s.stmts.drain(..).partition(|s| { - s.is_static() - || s.get_attributes().has(ir::NumAttr::PromoteStatic) - }); - if d_stmts.is_empty() { - // Entire par block can be promoted to static - if Self::approx_control_vec_size(&s_stmts) > self.threshold - && self.within_cycle_limit( - s_stmts - .iter() - .map(Self::get_inferred_latency) - .max() - .unwrap_or_else(|| unreachable!("Empty Par Block")), - ) - { - // Promote entire par block to static - let static_par_stmts = - self.convert_vec_to_static(&mut builder, s_stmts); - let latency = static_par_stmts - .iter() - .map(|sc| sc.get_latency()) - .max() - .unwrap_or_else(|| unreachable!("empty par block")); - return Ok(Action::change(ir::Control::Static( - ir::StaticControl::par(static_par_stmts, latency), - ))); - } else { - // Doesn't meet threshold, but add promotion attribute since - // parent might want to promote it. - let inferred_latency = s_stmts - .iter() - .map(Self::get_inferred_latency) - .max() - .unwrap_or_else(|| unreachable!("empty par block")); - s.get_mut_attributes() - .insert(ir::NumAttr::PromoteStatic, inferred_latency); - s.stmts = s_stmts; + // Check if entire par is promotable + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + let approx_size: u64 = s.stmts.iter().map(Self::approx_size).sum(); + if approx_size <= self.threshold { + // Par is too small to promote, continue. return Ok(Action::Continue); + } else if self.within_cycle_limit(latency) { + // Promote entire par + let spar = ir::Control::Static(ir::StaticControl::par( + self.convert_vec_to_static( + &mut builder, + std::mem::take(&mut s.stmts), + ), + latency, + )); + return Ok(Action::change(spar)); } } - // Otherwise just promote the par threads that we can into a static par - let s_stmts_possibly_promoted = - self.convert_vec_par_if_sat(&mut builder, s_stmts); - new_stmts.extend(s_stmts_possibly_promoted); + let mut new_stmts: Vec = Vec::new(); + // The par either a) takes too many cylces to promote entirely or + // b) has dynamic stmts in it. Either way, the solution is to + // break it up. + // Split the par into static and dynamic stmts, and use heuristics + // to choose whether to promote the static ones. This replacement will + // not have a `@promotable` attribute. + // This temporarily messes up its parents' `@promotable` + // attribute, but this is fine since we know its parent will never try + // to promote it. + let (s_stmts, d_stmts): (Vec, Vec) = + s.stmts.drain(..).partition(Self::can_be_promoted); + new_stmts.extend(self.promote_vec_par_heuristic(&mut builder, s_stmts)); new_stmts.extend(d_stmts); let new_par = ir::Control::Par(ir::Par { stmts: new_stmts, @@ -1075,17 +699,10 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - if Self::can_be_promoted(&s.tbranch) - && (Self::can_be_promoted(&s.fbranch)) - { - // Both branches can be promoted + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { let approx_size_if = Self::approx_size(&s.tbranch) + Self::approx_size(&s.fbranch) + APPROX_IF_SIZE; - let latency = std::cmp::max( - Self::get_inferred_latency(&s.tbranch), - Self::get_inferred_latency(&s.fbranch), - ); let branch_diff = Self::get_inferred_latency(&s.tbranch) .abs_diff(Self::get_inferred_latency(&s.fbranch)); if approx_size_if > self.threshold @@ -1105,15 +722,14 @@ impl Visitor for StaticPromotion { latency, ), ))); - } else { - // Doesn't meet size threshold, so attach attribute - // so parent might be able to promote it. - let inferred_max_latency = std::cmp::max( - Self::get_inferred_latency(&s.tbranch), - Self::get_inferred_latency(&s.fbranch), - ); - s.get_mut_attributes() - .insert(ir::NumAttr::PromoteStatic, inferred_max_latency) + } + // If this takes too many cycles, then we will + // never promote this if statement, meaning we will never promote any + // of its parents. We can therefore safely remove the `@promotable` attribute. + // This isn't strictly necessary, but it is helpful for parent control + // programs applying heuristics. + if !(self.within_cycle_limit(latency)) { + s.attributes.remove(ir::NumAttr::PromoteStatic); } } Ok(Action::Continue) @@ -1128,35 +744,35 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - // First check that while loop is bounded - if let Some(num_repeats) = s.get_attributes().get(ir::NumAttr::Bound) { - // Then check that body is static/promotable - if Self::can_be_promoted(&s.body) { - let approx_size = - Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; - let latency = Self::get_inferred_latency(&s.body) * num_repeats; - // Then check that it reaches the threshold - if approx_size > self.threshold - && self.within_cycle_limit(latency) - { - // Turn repeat into static repeat - let sc = self.convert_to_static(&mut s.body, &mut builder); - let static_repeat = ir::StaticControl::repeat( - num_repeats, - latency, - Box::new(sc), - ); - return Ok(Action::Change(Box::new(ir::Control::Static( - static_repeat, - )))); - } else { - // Attach static_promote attribute since parent control may - // want to promote - s.attributes.insert( - ir::NumAttr::PromoteStatic, - num_repeats * Self::get_inferred_latency(&s.body), - ) - } + // First check that while loop is promotable + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + let approx_size = + Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; + // Then check that it fits the heuristics + if approx_size > self.threshold && self.within_cycle_limit(latency) + { + // Turn repeat into static repeat + let sc = self.convert_to_static(&mut s.body, &mut builder); + let static_repeat = ir::StaticControl::repeat( + s.attributes.get(ir::NumAttr::Bound).unwrap_or_else(|| { + unreachable!( + "Unbounded loop has has @promotable attribute" + ) + }), + latency, + Box::new(sc), + ); + return Ok(Action::Change(Box::new(ir::Control::Static( + static_repeat, + )))); + } + // If this takes too many cycles, then we will + // never promote this if statement, meaning we will never promote any + // of its parents. We can therefore safely remove the `@promotable` attribute. + // This isn't strictly necessary, but it is helpful for parent control + // programs applying heuristics. + if !(self.within_cycle_limit(latency)) { + s.attributes.remove(ir::NumAttr::PromoteStatic); } } Ok(Action::Continue) @@ -1171,11 +787,9 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - if Self::can_be_promoted(&s.body) { - // Body can be promoted + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { let approx_size = Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; - let latency = Self::get_inferred_latency(&s.body) * s.num_repeats; if approx_size > self.threshold && self.within_cycle_limit(latency) { // Meets size threshold, so turn repeat into static repeat @@ -1188,14 +802,14 @@ impl Visitor for StaticPromotion { return Ok(Action::Change(Box::new(ir::Control::Static( static_repeat, )))); - } else { - // Doesn't meet threshold. - // Attach static_promote attribute since parent control may - // want to promote - s.attributes.insert( - ir::NumAttr::PromoteStatic, - s.num_repeats * Self::get_inferred_latency(&s.body), - ) + } + // If this takes too many cycles, then we will + // never promote this if statement, meaning we will never promote any + // of its parents. We can therefore safely remove the `@promotable` attribute. + // This isn't strictly necessary, but it is helpful for parent control + // programs applying heuristics. + if !(self.within_cycle_limit(latency)) { + s.attributes.remove(ir::NumAttr::PromoteStatic); } } Ok(Action::Continue) diff --git a/tests/correctness/static-control/fixup-necessary.expect b/tests/correctness/static-control/fixup-necessary.expect new file mode 100644 index 000000000..b2a457b3f --- /dev/null +++ b/tests/correctness/static-control/fixup-necessary.expect @@ -0,0 +1,8 @@ +{ + "cycles": 6, + "memories": { + "m": [ + 1 + ] + } +} diff --git a/tests/correctness/static-control/fixup-necessary.futil b/tests/correctness/static-control/fixup-necessary.futil new file mode 100644 index 000000000..6cc087e7c --- /dev/null +++ b/tests/correctness/static-control/fixup-necessary.futil @@ -0,0 +1,63 @@ +import "primitives/core.futil"; + +component foo(in: 1) -> (out: 32) { + cells { + r1 = std_reg(32); + adder = std_add(32); + } + wires { + out = r1.out; + group upd1 { + adder.left = 32'd1; + adder.right = r1.out; + r1.write_en = 1'd1; + r1.in = adder.out; + upd1[done] = r1.done; + } + } + control { + seq { + if in { + seq { + upd1; + upd1; + upd1; + upd1; + upd1; + upd1; + upd1; + } + } + else{ + seq { + upd1; + } + } + } + } +} + + +component main() -> () { + cells { + foo_inst = foo(); + @external m = std_mem_d1(32, 1, 1); + } + + wires { + group M { + m.write_data = foo_inst.out; + m.addr0 = 1'd0; + m.write_en = 1'd1; + M[done] = m.done; + } + } + + control { + seq { + invoke foo_inst(in = 1'd0)(); + M; + } + } +} + diff --git a/tests/correctness/static-control/fixup-necessary.futil.data b/tests/correctness/static-control/fixup-necessary.futil.data new file mode 100644 index 000000000..e2e250183 --- /dev/null +++ b/tests/correctness/static-control/fixup-necessary.futil.data @@ -0,0 +1,12 @@ +{ + "m": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/passes/cell-share/empty-invoke.expect b/tests/passes/cell-share/empty-invoke.expect index 98918ce5a..44dde2c37 100644 --- a/tests/passes/cell-share/empty-invoke.expect +++ b/tests/passes/cell-share/empty-invoke.expect @@ -12,7 +12,7 @@ component write_one<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> out = x.out; } control { - @promote_static invoke0; + invoke0; } } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @@ -50,9 +50,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { seq { invoke0; invoke1; - @promote_static invoke2; + invoke2; invoke3; - @promote_static invoke4; + invoke4; } } } diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect index d9269453e..b991d54e2 100644 --- a/tests/passes/cell-share/inline.expect +++ b/tests/passes/cell-share/inline.expect @@ -12,7 +12,7 @@ component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset r out = r.out; } control { - @promote_static invoke0; + invoke0; } } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { diff --git a/tests/passes/static-promotion/component.expect b/tests/passes/static-inference-promotion/component.expect similarity index 100% rename from tests/passes/static-promotion/component.expect rename to tests/passes/static-inference-promotion/component.expect diff --git a/tests/passes/static-inference-promotion/component.futil b/tests/passes/static-inference-promotion/component.futil new file mode 100644 index 000000000..4ff396973 --- /dev/null +++ b/tests/passes/static-inference-promotion/component.futil @@ -0,0 +1,35 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + } + + control { + seq { A; B; C; } + } +} diff --git a/tests/passes/static-promotion/groups.expect b/tests/passes/static-inference-promotion/groups.expect similarity index 93% rename from tests/passes/static-promotion/groups.expect rename to tests/passes/static-inference-promotion/groups.expect index c46b3770e..9c9fda81f 100644 --- a/tests/passes/static-promotion/groups.expect +++ b/tests/passes/static-inference-promotion/groups.expect @@ -40,9 +40,9 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don mem_wrt_to_done0; } mult_wrts_to_done; - @promote_static one_cycle; + one_cycle; mult_wrts_to_done; - @promote_static(2) two_cycles; + two_cycles; } } } diff --git a/tests/passes/static-inference-promotion/groups.futil b/tests/passes/static-inference-promotion/groups.futil new file mode 100644 index 000000000..8d3b35ae5 --- /dev/null +++ b/tests/passes/static-inference-promotion/groups.futil @@ -0,0 +1,43 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal +import "primitives/core.futil"; + +component main(go: 1, clk: 1) -> (done: 1) { + cells { + r0 = std_reg(1); + r1 = std_reg(1); + m0 = std_mem_d1(32, 1, 1); + } + wires { + group one_cycle { + r0.write_en = 1'd1; + one_cycle[done] = r0.done; + } + group two_cycles { + r0.write_en = 1'd1; + r1.write_en = r0.done; + two_cycles[done] = r1.done; + } + group mem_wrt_to_done { + m0.addr0 = 1'd0; + m0.write_data = 32'd5; + m0.write_en = 1'd1; + mem_wrt_to_done[done] = m0.done; + } + group mult_wrts_to_done { + r0.write_en = 1'd1; + mult_wrts_to_done[done] = r0.done ? 1'd1; + } + } + + control { + seq { + one_cycle; + two_cycles; + mem_wrt_to_done; + mult_wrts_to_done; + one_cycle; + mult_wrts_to_done; + two_cycles; + } + } +} diff --git a/tests/passes/static-promotion/if-diff.expect b/tests/passes/static-inference-promotion/if-diff.expect similarity index 92% rename from tests/passes/static-promotion/if-diff.expect rename to tests/passes/static-inference-promotion/if-diff.expect index c87729aa2..0b3fc0a18 100644 --- a/tests/passes/static-promotion/if-diff.expect +++ b/tests/passes/static-inference-promotion/if-diff.expect @@ -16,7 +16,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @promote_static(5) if cond.out { + if cond.out { @compactable static<5> seq { A0; A0; diff --git a/tests/passes/static-promotion/if-diff.futil b/tests/passes/static-inference-promotion/if-diff.futil similarity index 75% rename from tests/passes/static-promotion/if-diff.futil rename to tests/passes/static-inference-promotion/if-diff.futil index c90174948..1144bfab6 100644 --- a/tests/passes/static-promotion/if-diff.futil +++ b/tests/passes/static-inference-promotion/if-diff.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -x static-promotion:if-diff-limit=3 +// -p well-formed -p static-inference -p static-promotion -x static-promotion:if-diff-limit=3 import "primitives/core.futil"; diff --git a/tests/passes/static-promotion/if-no-else.expect b/tests/passes/static-inference-promotion/if-no-else.expect similarity index 100% rename from tests/passes/static-promotion/if-no-else.expect rename to tests/passes/static-inference-promotion/if-no-else.expect diff --git a/tests/passes/static-inference-promotion/if-no-else.futil b/tests/passes/static-inference-promotion/if-no-else.futil new file mode 100644 index 000000000..618a07947 --- /dev/null +++ b/tests/passes/static-inference-promotion/if-no-else.futil @@ -0,0 +1,24 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + cond = std_reg(1); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + } + + control { + if cond.out { + A; + } + } +} diff --git a/tests/passes/static-promotion/invoke.expect b/tests/passes/static-inference-promotion/invoke.expect similarity index 90% rename from tests/passes/static-promotion/invoke.expect rename to tests/passes/static-inference-promotion/invoke.expect index e437c4e43..e9c2e3ec8 100644 --- a/tests/passes/static-promotion/invoke.expect +++ b/tests/passes/static-inference-promotion/invoke.expect @@ -20,7 +20,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } -static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-inference-promotion/invoke.futil b/tests/passes/static-inference-promotion/invoke.futil new file mode 100644 index 000000000..0d03e4399 --- /dev/null +++ b/tests/passes/static-inference-promotion/invoke.futil @@ -0,0 +1,52 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal +import "primitives/core.futil"; + +/** +* Tests the infer-static-timing pass. `exponent` is intentionally placed +* after main to test post-order iteration of components. +*/ +component main() -> () { + cells { + r = std_reg(32); + exp0 = exponent(); + } + wires { + group upd0 { + r.in = 32'd1; + r.write_en = 1'd1; + upd0[done] = r.done; + } + } + control { + seq { + upd0; + invoke exp0(base = r.out, exp = r.out)(); + } + } +} + +component exponent(base: 32, exp: 32) -> (out: 32) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2 { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1 { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + seq { + upd1; + upd2; + } + } +} + diff --git a/tests/passes/static-promotion/multi-static.expect b/tests/passes/static-inference-promotion/multi-static.expect similarity index 90% rename from tests/passes/static-promotion/multi-static.expect rename to tests/passes/static-inference-promotion/multi-static.expect index af49b1d0c..78d60b674 100644 --- a/tests/passes/static-promotion/multi-static.expect +++ b/tests/passes/static-inference-promotion/multi-static.expect @@ -20,7 +20,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } -static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-promotion/multi-static.futil b/tests/passes/static-inference-promotion/multi-static.futil similarity index 91% rename from tests/passes/static-promotion/multi-static.futil rename to tests/passes/static-inference-promotion/multi-static.futil index 681ed1e23..53eed79bb 100644 --- a/tests/passes/static-promotion/multi-static.futil +++ b/tests/passes/static-inference-promotion/multi-static.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; /** diff --git a/tests/passes/static-inference-promotion/no_promote_loop.expect b/tests/passes/static-inference-promotion/no_promote_loop.expect new file mode 100644 index 000000000..26a22869a --- /dev/null +++ b/tests/passes/static-inference-promotion/no_promote_loop.expect @@ -0,0 +1,39 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + wires { + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + static<1> group C0 { + c.in = 2'd2; + c.write_en = 1'd1; + } + } + control { + seq { + repeat 10 { + @compactable static<4> seq { + A0; + B0; + C0; + C0; + } + } + @compactable static<3> seq { + A0; + B0; + C0; + } + } + } +} diff --git a/tests/passes/static-promotion/no_promote_loop.futil b/tests/passes/static-inference-promotion/no_promote_loop.futil similarity index 82% rename from tests/passes/static-promotion/no_promote_loop.futil rename to tests/passes/static-inference-promotion/no_promote_loop.futil index 727917504..72032baae 100644 --- a/tests/passes/static-promotion/no_promote_loop.futil +++ b/tests/passes/static-inference-promotion/no_promote_loop.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:cycle-limit=25 +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:cycle-limit=25 import "primitives/core.futil"; diff --git a/tests/passes/static-promotion/par.expect b/tests/passes/static-inference-promotion/par.expect similarity index 100% rename from tests/passes/static-promotion/par.expect rename to tests/passes/static-inference-promotion/par.expect diff --git a/tests/passes/static-inference-promotion/par.futil b/tests/passes/static-inference-promotion/par.futil new file mode 100644 index 000000000..828153760 --- /dev/null +++ b/tests/passes/static-inference-promotion/par.futil @@ -0,0 +1,40 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal +import "primitives/core.futil"; + +component main(go: 1, clk: 1) -> (done: 1) { + cells { + r0 = std_reg(1); + r1 = std_reg(1); + m0 = std_mem_d1(32, 1, 1); + } + wires { + group one_cycle { + r0.write_en = 1'd1; + one_cycle[done] = r0.done; + } + group two_cycles { + r0.write_en = 1'd1; + r1.write_en = r0.done; + two_cycles[done] = r1.done; + } + group mem_wrt_to_done { + m0.addr0 = 1'd0; + m0.write_data = 32'd5; + m0.write_en = 1'd1; + mem_wrt_to_done[done] = m0.done; + } + group mult_wrts_to_done { + r0.write_en = 1'd1; + mult_wrts_to_done[done] = r0.done ? 1'd1; + } + } + + control { + par { + one_cycle; + two_cycles; + mult_wrts_to_done; + mem_wrt_to_done; + } + } +} \ No newline at end of file diff --git a/tests/passes/static-promotion/promote-nested.expect b/tests/passes/static-inference-promotion/promote-nested.expect similarity index 100% rename from tests/passes/static-promotion/promote-nested.expect rename to tests/passes/static-inference-promotion/promote-nested.expect diff --git a/tests/passes/static-inference-promotion/promote-nested.futil b/tests/passes/static-inference-promotion/promote-nested.futil new file mode 100644 index 000000000..70179c484 --- /dev/null +++ b/tests/passes/static-inference-promotion/promote-nested.futil @@ -0,0 +1,59 @@ +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:threshold=5 + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + cond_reg = std_reg(1); + r0 = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + + group no_upgrade { + r0.write_en = 1'd1; + no_upgrade[done] = r0.done ? 1'd1; + } + } + + control { + seq { + seq { + par {A; B;} + seq {C; C;} + par {A; B;} + } + no_upgrade; + @bound(2) while cond_reg.out { + seq { + A; + B; + C; + } + } + } + + + + } +} diff --git a/tests/passes/static-promotion/threshold.expect b/tests/passes/static-inference-promotion/threshold.expect similarity index 80% rename from tests/passes/static-promotion/threshold.expect rename to tests/passes/static-inference-promotion/threshold.expect index 976c597a7..66810105d 100644 --- a/tests/passes/static-promotion/threshold.expect +++ b/tests/passes/static-inference-promotion/threshold.expect @@ -23,11 +23,11 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @promote_static(4) seq { - @promote_static A; - @promote_static B; - @promote_static C; - @promote_static C; + seq { + A; + B; + C; + C; } } } diff --git a/tests/passes/static-promotion/threshold.futil b/tests/passes/static-inference-promotion/threshold.futil similarity index 82% rename from tests/passes/static-promotion/threshold.futil rename to tests/passes/static-inference-promotion/threshold.futil index 10375bdec..f254159ce 100644 --- a/tests/passes/static-promotion/threshold.futil +++ b/tests/passes/static-inference-promotion/threshold.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:threshold=4 +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:threshold=4 import "primitives/core.futil"; diff --git a/tests/passes/static-promotion/upgrade-bound.expect b/tests/passes/static-inference-promotion/upgrade-bound.expect similarity index 100% rename from tests/passes/static-promotion/upgrade-bound.expect rename to tests/passes/static-inference-promotion/upgrade-bound.expect diff --git a/tests/passes/static-promotion/upgrade-bound.futil b/tests/passes/static-inference-promotion/upgrade-bound.futil similarity index 86% rename from tests/passes/static-promotion/upgrade-bound.futil rename to tests/passes/static-inference-promotion/upgrade-bound.futil index b20e8fd38..40fc88bea 100644 --- a/tests/passes/static-promotion/upgrade-bound.futil +++ b/tests/passes/static-inference-promotion/upgrade-bound.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; diff --git a/tests/passes/static-promotion/no_promote_loop.expect b/tests/passes/static-inference/component.expect similarity index 60% rename from tests/passes/static-promotion/no_promote_loop.expect rename to tests/passes/static-inference/component.expect index 2aa38ac2b..bf2c58deb 100644 --- a/tests/passes/static-promotion/no_promote_loop.expect +++ b/tests/passes/static-inference/component.expect @@ -21,29 +21,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c.write_en = 1'd1; C[done] = c.done; } - static<1> group A0 { - a.in = 2'd0; - a.write_en = 1'd1; - } - static<1> group B0 { - b.in = 2'd1; - b.write_en = 1'd1; - } - static<1> group C0 { - c.in = 2'd2; - c.write_en = 1'd1; - } } control { - @promote_static(43) seq { - @promote_static(40) repeat 10 { - @compactable static<4> seq { - A0; - B0; - C0; - C0; - } - } + @promote_static(3) seq { @promote_static A; @promote_static B; @promote_static C; diff --git a/tests/passes/static-promotion/component.futil b/tests/passes/static-inference/component.futil similarity index 88% rename from tests/passes/static-promotion/component.futil rename to tests/passes/static-inference/component.futil index b9171d2c5..43d857c8a 100644 --- a/tests/passes/static-promotion/component.futil +++ b/tests/passes/static-inference/component.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference import "primitives/core.futil"; diff --git a/tests/passes/static-inference/groups.expect b/tests/passes/static-inference/groups.expect new file mode 100644 index 000000000..fba56d479 --- /dev/null +++ b/tests/passes/static-inference/groups.expect @@ -0,0 +1,40 @@ +import "primitives/core.futil"; +component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { + cells { + r0 = std_reg(1); + r1 = std_reg(1); + m0 = std_mem_d1(32, 1, 1); + } + wires { + group one_cycle<"promote_static"=1> { + r0.write_en = 1'd1; + one_cycle[done] = r0.done; + } + group two_cycles<"promote_static"=2> { + r0.write_en = 1'd1; + r1.write_en = r0.done; + two_cycles[done] = r1.done; + } + group mem_wrt_to_done<"promote_static"=1> { + m0.addr0 = 1'd0; + m0.write_data = 32'd5; + m0.write_en = 1'd1; + mem_wrt_to_done[done] = m0.done; + } + group mult_wrts_to_done { + r0.write_en = 1'd1; + mult_wrts_to_done[done] = r0.done ? 1'd1; + } + } + control { + seq { + @promote_static one_cycle; + @promote_static(2) two_cycles; + @promote_static mem_wrt_to_done; + mult_wrts_to_done; + @promote_static one_cycle; + mult_wrts_to_done; + @promote_static(2) two_cycles; + } + } +} diff --git a/tests/passes/static-promotion/groups.futil b/tests/passes/static-inference/groups.futil similarity index 93% rename from tests/passes/static-promotion/groups.futil rename to tests/passes/static-inference/groups.futil index ab90109b1..f6571c0e1 100644 --- a/tests/passes/static-promotion/groups.futil +++ b/tests/passes/static-inference/groups.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference import "primitives/core.futil"; component main(go: 1, clk: 1) -> (done: 1) { diff --git a/tests/passes/static-inference/if-no-else.expect b/tests/passes/static-inference/if-no-else.expect new file mode 100644 index 000000000..a0c3588a2 --- /dev/null +++ b/tests/passes/static-inference/if-no-else.expect @@ -0,0 +1,19 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + cond = std_reg(1); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + } + control { + @promote_static if cond.out { + @promote_static A; + } + } +} diff --git a/tests/passes/static-promotion/if-no-else.futil b/tests/passes/static-inference/if-no-else.futil similarity index 81% rename from tests/passes/static-promotion/if-no-else.futil rename to tests/passes/static-inference/if-no-else.futil index 96250f8ea..42ae5f611 100644 --- a/tests/passes/static-promotion/if-no-else.futil +++ b/tests/passes/static-inference/if-no-else.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference import "primitives/core.futil"; diff --git a/tests/passes/static-inference/invoke.expect b/tests/passes/static-inference/invoke.expect new file mode 100644 index 000000000..ae63e3984 --- /dev/null +++ b/tests/passes/static-inference/invoke.expect @@ -0,0 +1,47 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(32); + exp0 = exponent(); + } + wires { + group upd0<"promote_static"=1> { + r.in = 32'd1; + r.write_en = 1'd1; + upd0[done] = r.done; + } + } + control { + @promote_static(3) seq { + @promote_static upd0; + @promote_static(2) invoke exp0( + base = r.out, + exp = r.out + )(); + } + } +} +component exponent(base: 32, exp: 32, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2<"promote_static"=1> { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1<"promote_static"=1> { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + @promote_static(2) seq { + @promote_static upd1; + @promote_static upd2; + } + } +} diff --git a/tests/passes/static-promotion/invoke.futil b/tests/passes/static-inference/invoke.futil similarity index 93% rename from tests/passes/static-promotion/invoke.futil rename to tests/passes/static-inference/invoke.futil index fa786f9e8..a3ea2f77d 100644 --- a/tests/passes/static-promotion/invoke.futil +++ b/tests/passes/static-inference/invoke.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference import "primitives/core.futil"; /** diff --git a/tests/passes/static-inference/par.expect b/tests/passes/static-inference/par.expect new file mode 100644 index 000000000..356396105 --- /dev/null +++ b/tests/passes/static-inference/par.expect @@ -0,0 +1,37 @@ +import "primitives/core.futil"; +component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { + cells { + r0 = std_reg(1); + r1 = std_reg(1); + m0 = std_mem_d1(32, 1, 1); + } + wires { + group one_cycle<"promote_static"=1> { + r0.write_en = 1'd1; + one_cycle[done] = r0.done; + } + group two_cycles<"promote_static"=2> { + r0.write_en = 1'd1; + r1.write_en = r0.done; + two_cycles[done] = r1.done; + } + group mem_wrt_to_done<"promote_static"=1> { + m0.addr0 = 1'd0; + m0.write_data = 32'd5; + m0.write_en = 1'd1; + mem_wrt_to_done[done] = m0.done; + } + group mult_wrts_to_done { + r0.write_en = 1'd1; + mult_wrts_to_done[done] = r0.done ? 1'd1; + } + } + control { + par { + @promote_static one_cycle; + @promote_static(2) two_cycles; + mult_wrts_to_done; + @promote_static mem_wrt_to_done; + } + } +} diff --git a/tests/passes/static-promotion/par.futil b/tests/passes/static-inference/par.futil similarity index 92% rename from tests/passes/static-promotion/par.futil rename to tests/passes/static-inference/par.futil index 0020de7ba..4dede6857 100644 --- a/tests/passes/static-promotion/par.futil +++ b/tests/passes/static-inference/par.futil @@ -1,4 +1,5 @@ -// -p well-formed -p static-promotion -p dead-group-removal +// -p well-formed -p static-inference + import "primitives/core.futil"; component main(go: 1, clk: 1) -> (done: 1) { diff --git a/tests/passes/static-inference/promote-nested.expect b/tests/passes/static-inference/promote-nested.expect new file mode 100644 index 000000000..bbb3e51b4 --- /dev/null +++ b/tests/passes/static-inference/promote-nested.expect @@ -0,0 +1,57 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + cond_reg = std_reg(1); + r0 = std_reg(2); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group C<"promote_static"=1> { + c.in = 2'd2; + c.write_en = 1'd1; + C[done] = c.done; + } + group no_upgrade { + r0.write_en = 1'd1; + no_upgrade[done] = r0.done ? 1'd1; + } + } + control { + seq { + @promote_static(4) seq { + @promote_static par { + @promote_static A; + @promote_static B; + } + @promote_static(2) seq { + @promote_static C; + @promote_static C; + } + @promote_static par { + @promote_static A; + @promote_static B; + } + } + no_upgrade; + @bound(2) @promote_static(6) while cond_reg.out { + @promote_static(3) seq { + @promote_static A; + @promote_static B; + @promote_static C; + } + } + } + } +} diff --git a/tests/passes/static-promotion/promote-nested.futil b/tests/passes/static-inference/promote-nested.futil similarity index 89% rename from tests/passes/static-promotion/promote-nested.futil rename to tests/passes/static-inference/promote-nested.futil index e3a49fbd5..acc8e181e 100644 --- a/tests/passes/static-promotion/promote-nested.futil +++ b/tests/passes/static-inference/promote-nested.futil @@ -1,4 +1,4 @@ -// -p well-formed -p static-promotion -p dead-group-removal -x static-promotion:threshold=5 +// -p well-formed -p static-inference import "primitives/core.futil"; diff --git a/tests/passes/static-inference/promote-repeat.expect b/tests/passes/static-inference/promote-repeat.expect new file mode 100644 index 000000000..c1d43dec1 --- /dev/null +++ b/tests/passes/static-inference/promote-repeat.expect @@ -0,0 +1,48 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group C<"promote_static"=1> { + c.in = 2'd2; + c.write_en = 1'd1; + C[done] = c.done; + } + } + control { + @promote_static(43) seq { + @promote_static(40) repeat 10 { + @promote_static(4) seq { + @promote_static A; + @promote_static B; + @promote_static C; + @promote_static C; + } + } + @promote_static(3) par { + @promote_static(2) seq { + @promote_static A; + @promote_static B; + } + @promote_static(3) seq { + @promote_static C; + @promote_static C; + @promote_static C; + } + } + } + } +} diff --git a/tests/passes/static-inference/promote-repeat.futil b/tests/passes/static-inference/promote-repeat.futil new file mode 100644 index 000000000..043bb0839 --- /dev/null +++ b/tests/passes/static-inference/promote-repeat.futil @@ -0,0 +1,43 @@ +// -p well-formed -p static-inference + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + } + + control { + seq { + repeat 10 { + seq { A; B; C; C;} + } + par { + seq {A; B;} + seq {C; C; C;} + } + } + } +} diff --git a/tests/passes/static-promotion/fixup-necessary.expect b/tests/passes/static-promotion/fixup-necessary.expect new file mode 100644 index 000000000..34bac1aa0 --- /dev/null +++ b/tests/passes/static-promotion/fixup-necessary.expect @@ -0,0 +1,61 @@ +import "primitives/core.futil"; +component foo(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2<"promote_static"=1> { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1<"promote_static"=1> { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + seq { + upd1; + upd2; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + foo_inst = foo(); + } + wires { + group F { + foo_inst.go = 1'd1; + F[done] = foo_inst.done; + } + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + } + control { + seq { + @compactable static<8> seq { + A0; + A0; + A0; + A0; + B0; + B0; + B0; + B0; + } + F; + } + } +} diff --git a/tests/passes/static-promotion/fixup-necessary.futil b/tests/passes/static-promotion/fixup-necessary.futil new file mode 100644 index 000000000..49ddd85e6 --- /dev/null +++ b/tests/passes/static-promotion/fixup-necessary.futil @@ -0,0 +1,64 @@ +// -p well-formed -p static-promotion -x static-promotion:threshold=5 -p dead-group-removal + +import "primitives/core.futil"; + +component foo(base: 32, exp: 4, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2<"promote_static"=1> { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1<"promote_static"=1> { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + @promote_static(2) seq { + @promote_static upd1; + @promote_static upd2; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + foo_inst = foo(); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group F<"promote_static"=2> { + foo_inst.go = 1'd1; + F[done] = foo_inst.done; + } + } + control { + @promote_static(10) seq { + @promote_static A; + @promote_static A; + @promote_static A; + @promote_static A; + @promote_static B; + @promote_static B; + @promote_static B; + @promote_static B; + @promote_static(2) F; + } + } +} \ No newline at end of file From 718dc2163754ee66124db7d4219f4e76d7327fa4 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:01:51 -0500 Subject: [PATCH 159/189] Reorder Compaction (#1884) * progress * first try at separating passes * use helper function * better tests, cleaner code * existing tests passing * inference * updated code * clippy * clippy is annoying * fixup works now * fixup is fixed up * another fixup test * rewrite tests * cleaner code * commented code * first try working in certain cases * test rewrite * refactored code * small bug fix * add better compaction * tests reflect this * rewrite tests * add more fixups * clippy * documentation * small change * small change + another test case * changed failing tests --- calyx-opt/src/analysis/control_order.rs | 35 +- calyx-opt/src/analysis/inference_analysis.rs | 16 +- calyx-opt/src/analysis/mod.rs | 2 + calyx-opt/src/analysis/promotion_analysis.rs | 238 ++++++++++++ calyx-opt/src/analysis/read_write_set.rs | 66 +++- calyx-opt/src/default_passes.rs | 3 +- calyx-opt/src/passes/schedule_compaction.rs | 335 +++++++++++------ calyx-opt/src/passes/static_promotion.rs | 338 ++++-------------- .../continuous-compaction.expect | 26 +- .../continuous-compaction.futil | 28 +- .../continuous-no-compaction.expect | 24 +- .../continuous-no-compaction.futil | 26 +- .../fixup-necessary.expect | 36 ++ .../schedule-compaction/fixup-necessary.futil | 33 ++ .../schedule-compaction/no-compact.expect | 32 ++ .../schedule-compaction/no-compact.futil | 38 ++ .../partial-compaction.expect | 58 +++ .../partial-compaction.futil | 83 +++++ .../schedule-compaction.expect | 27 +- .../schedule-compaction.futil | 30 +- .../component.expect | 2 +- .../static-inference-promotion/groups.expect | 2 +- .../static-inference-promotion/if-diff.expect | 2 +- .../static-inference-promotion/invoke.expect | 4 +- .../multi-static.expect | 4 +- .../no_promote_loop.expect | 4 +- .../promote-nested.expect | 2 +- .../upgrade-bound.expect | 2 +- .../static-passes/both-passes-promote.expect | 46 +++ .../static-passes/both-passes-promote.futil | 38 ++ .../static-promotion/fixup-necessary.expect | 2 +- tests/passes/tdcc/new-fsm-nested.futil | 16 +- tests/passes/tdcc/while.futil | 2 +- 33 files changed, 1107 insertions(+), 493 deletions(-) create mode 100644 calyx-opt/src/analysis/promotion_analysis.rs create mode 100644 tests/passes/schedule-compaction/fixup-necessary.expect create mode 100644 tests/passes/schedule-compaction/fixup-necessary.futil create mode 100644 tests/passes/schedule-compaction/no-compact.expect create mode 100644 tests/passes/schedule-compaction/no-compact.futil create mode 100644 tests/passes/schedule-compaction/partial-compaction.expect create mode 100644 tests/passes/schedule-compaction/partial-compaction.futil create mode 100644 tests/passes/static-passes/both-passes-promote.expect create mode 100644 tests/passes/static-passes/both-passes-promote.futil diff --git a/calyx-opt/src/analysis/control_order.rs b/calyx-opt/src/analysis/control_order.rs index 5edb9a290..5c63623e0 100644 --- a/calyx-opt/src/analysis/control_order.rs +++ b/calyx-opt/src/analysis/control_order.rs @@ -1,4 +1,4 @@ -use crate::analysis::ReadWriteSet; +use crate::analysis::{PromotionAnalysis, ReadWriteSet}; use calyx_ir as ir; use calyx_utils::{CalyxResult, Error}; use ir::RRC; @@ -45,10 +45,10 @@ impl ControlOrder { // Filters out the constants from `cells`, while mapping the remaining `ir:Cell`s // to their cell name. fn filter_out_constants( - cells: Vec>, - ) -> impl Iterator { + cells: &[RRC], + ) -> impl Iterator + '_ { cells - .into_iter() + .iter() .filter_map(|cell| match cell.borrow().prototype { ir::CellType::Constant { .. } => None, ir::CellType::Component { .. } @@ -85,7 +85,7 @@ impl ControlOrder { // Compute read/write sets and add them to the maps for c in stmts { let (port_reads, port_writes) = - ReadWriteSet::control_port_read_write_set(&c); + ReadWriteSet::control_port_read_write_set::(&c); let idx = gr.add_node(Some(c)); add_cells(idx, port_reads, &mut reads); add_cells(idx, port_writes, &mut writes); @@ -122,7 +122,9 @@ impl ControlOrder { let con = gr[*idx].as_ref().unwrap(); let mut msg = ir::Printer::control_to_str(con); let (port_reads, port_writes) = - ReadWriteSet::control_port_read_write_set(con); + ReadWriteSet::control_port_read_write_set::( + con, + ); write!( msg, " which reads: {}\n and writes: {}", @@ -143,6 +145,7 @@ impl ControlOrder { } // Returns a graph of dependency for input programs. + // IMPORTANT: we ignore assignments to done ports. // Input control programs are considered to have data dependency if: // 1. subsequent program writes to cells that previous program reads from // 2. subsequent program writes to cells that previous program writes to @@ -153,15 +156,15 @@ impl ControlOrder { // Then the program "touches" the continuous assignments, and therefore depends // on all previous programs that "touched" continuous assignments as well. // In short, we treat continuous assignments as one big cell. - pub fn get_dependency_graph_static_seq( - stmts: impl Iterator, + pub fn get_dependency_graph_seq( + stmts: impl Iterator, (cont_reads, cont_writes): ( - Vec>, - Vec>, + &Vec>, + &Vec>, ), dependency: &mut HashMap>, latency_map: &mut HashMap, - ) -> DiGraph, ()> { + ) -> DiGraph, ()> { // The names of the cells that are read/written in continuous assignments let cont_read_cell_names = Self::filter_out_constants(cont_reads).collect_vec(); @@ -169,7 +172,7 @@ impl ControlOrder { Self::filter_out_constants(cont_writes).collect_vec(); // Directed graph where edges means that a control program must be run before. - let mut gr: DiGraph, ()> = DiGraph::new(); + let mut gr: DiGraph, ()> = DiGraph::new(); // Mapping name of cell to all the indices that read or write to it. let mut reads: HashMap> = HashMap::default(); @@ -181,10 +184,10 @@ impl ControlOrder { for c in stmts { let (cell_reads, cell_writes) = - ReadWriteSet::control_read_write_set_static(&c); - let r_cell_names = Self::filter_out_constants(cell_reads); - let w_cell_names = Self::filter_out_constants(cell_writes); - let latency = c.get_latency(); + ReadWriteSet::control_read_write_set::(&c); + let r_cell_names = Self::filter_out_constants(&cell_reads); + let w_cell_names = Self::filter_out_constants(&cell_writes); + let latency = PromotionAnalysis::get_inferred_latency(&c); let idx = gr.add_node(Some(c)); dependency.insert(idx, Vec::new()); latency_map.insert(idx, latency); diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs index a7704946c..e13d3998b 100644 --- a/calyx-opt/src/analysis/inference_analysis.rs +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -107,9 +107,8 @@ impl From<&ir::Cell> for GoDone { } } -#[derive(Debug)] -/// Default implemnetation is not provided, since it is almost certainly more helpful -/// to use `from_ctx` instead. +/// Default implemnetation is almost certainly not helpful. +/// You should probably use `from_ctx` instead. pub struct InferenceAnalysis { /// component name -> vec<(go signal, done signal, latency)> pub latency_data: HashMap, @@ -447,6 +446,13 @@ impl InferenceAnalysis { } } + pub fn remove_promotable_from_seq(seq: &mut ir::Seq) { + for stmt in &mut seq.stmts { + Self::remove_promotable_attribute(stmt); + } + seq.get_mut_attributes().remove(ir::NumAttr::PromoteStatic); + } + /// Removes the @promotable attribute from the control program. /// Recursively visits the children of the control. pub fn remove_promotable_attribute(c: &mut ir::Control) { @@ -475,6 +481,10 @@ impl InferenceAnalysis { } } + pub fn fixup_seq(&self, seq: &mut ir::Seq) { + seq.update_static(&self.static_component_latencies); + } + /// "Fixes Up" the component. In particular: /// 1. Removes @promotable annotations for any groups that write to any /// `updated_components`. diff --git a/calyx-opt/src/analysis/mod.rs b/calyx-opt/src/analysis/mod.rs index 3e78bea5e..6be29f0d2 100644 --- a/calyx-opt/src/analysis/mod.rs +++ b/calyx-opt/src/analysis/mod.rs @@ -14,6 +14,7 @@ mod graph_coloring; mod inference_analysis; mod live_range_analysis; mod port_interface; +mod promotion_analysis; pub mod reaching_defns; mod read_write_set; mod schedule_conflicts; @@ -34,6 +35,7 @@ pub use inference_analysis::GoDone; pub use inference_analysis::InferenceAnalysis; pub use live_range_analysis::LiveRangeAnalysis; pub use port_interface::PortInterface; +pub use promotion_analysis::PromotionAnalysis; pub use read_write_set::ReadWriteSet; pub use schedule_conflicts::ScheduleConflicts; pub use share_set::ShareSet; diff --git a/calyx-opt/src/analysis/promotion_analysis.rs b/calyx-opt/src/analysis/promotion_analysis.rs new file mode 100644 index 000000000..271d14a7d --- /dev/null +++ b/calyx-opt/src/analysis/promotion_analysis.rs @@ -0,0 +1,238 @@ +use calyx_ir::{self as ir}; +use std::collections::HashMap; +use std::rc::Rc; + +#[derive(Debug, Default)] +pub struct PromotionAnalysis { + /// dynamic group Id -> promoted static group Id + static_group_name: HashMap, +} + +impl PromotionAnalysis { + fn check_latencies_match(actual: u64, inferred: u64) { + assert_eq!(actual, inferred, "Inferred and Annotated Latencies do not match. Latency: {}. Inferred: {}", actual, inferred); + } + + pub fn get_inferred_latency(c: &ir::Control) -> u64 { + let ir::Control::Static(sc) = c else { + let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) + else { + unreachable!("Called get_latency on control that is neither static nor promotable") + }; + return latency; + }; + sc.get_latency() + } + + /// Returns true if a control statement is already static, or has the static + /// attributes + pub fn can_be_promoted(c: &ir::Control) -> bool { + c.is_static() || c.has_attribute(ir::NumAttr::PromoteStatic) + } + + /// If we've already constructed the static group then use the already existing + /// group. Otherwise construct `static group` and then return that. + fn construct_static_group( + &mut self, + builder: &mut ir::Builder, + group: ir::RRC, + latency: u64, + ) -> ir::RRC { + if let Some(s_name) = self.static_group_name.get(&group.borrow().name()) + { + builder.component.find_static_group(*s_name).unwrap() + } else { + let sg = builder.add_static_group(group.borrow().name(), latency); + self.static_group_name + .insert(group.borrow().name(), sg.borrow().name()); + for assignment in group.borrow().assignments.iter() { + // Don't need to include assignment to done hole. + if !(assignment.dst.borrow().is_hole() + && assignment.dst.borrow().name == "done") + { + sg.borrow_mut() + .assignments + .push(ir::Assignment::from(assignment.clone())); + } + } + Rc::clone(&sg) + } + } + + // Converts dynamic enable to static + pub fn convert_enable_to_static( + &mut self, + s: &mut ir::Enable, + builder: &mut ir::Builder, + ) -> ir::StaticControl { + s.attributes.remove(ir::NumAttr::PromoteStatic); + ir::StaticControl::Enable(ir::StaticEnable { + // upgrading group to static group + group: self.construct_static_group( + builder, + Rc::clone(&s.group), + s.group + .borrow() + .get_attributes() + .unwrap() + .get(ir::NumAttr::PromoteStatic) + .unwrap(), + ), + attributes: std::mem::take(&mut s.attributes), + }) + } + + // Converts dynamic invoke to static + pub fn convert_invoke_to_static( + &mut self, + s: &mut ir::Invoke, + ) -> ir::StaticControl { + assert!( + s.comb_group.is_none(), + "Shouldn't Promote to Static if there is a Comb Group", + ); + let latency = s.attributes.get(ir::NumAttr::PromoteStatic).unwrap(); + s.attributes.remove(ir::NumAttr::PromoteStatic); + let s_inv = ir::StaticInvoke { + comp: Rc::clone(&s.comp), + inputs: std::mem::take(&mut s.inputs), + outputs: std::mem::take(&mut s.outputs), + latency, + attributes: std::mem::take(&mut s.attributes), + ref_cells: std::mem::take(&mut s.ref_cells), + comb_group: std::mem::take(&mut s.comb_group), + }; + ir::StaticControl::Invoke(s_inv) + } + + /// Converts control to static control. + /// Control must already be static or have the `promote_static` attribute. + pub fn convert_to_static( + &mut self, + c: &mut ir::Control, + builder: &mut ir::Builder, + ) -> ir::StaticControl { + assert!( + c.has_attribute(ir::NumAttr::PromoteStatic) || c.is_static(), + "Called convert_to_static control that is neither static nor promotable" + ); + // Need to get bound_attribute here, because we cannot borrow `c` within the + // pattern match. + let bound_attribute = c.get_attribute(ir::NumAttr::Bound); + // Inferred latency of entire control block. Used to double check our + // function is correct. + let inferred_latency = Self::get_inferred_latency(c); + match c { + ir::Control::Empty(_) => ir::StaticControl::empty(), + ir::Control::Enable(s) => self.convert_enable_to_static(s, builder), + ir::Control::Seq(ir::Seq { stmts, attributes }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // The resulting static seq should be compactable. + attributes.insert(ir::NumAttr::Compactable, 1); + let static_stmts = + self.convert_vec_to_static(builder, std::mem::take(stmts)); + let latency = + static_stmts.iter().map(|s| s.get_latency()).sum(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Seq(ir::StaticSeq { + stmts: static_stmts, + attributes: std::mem::take(attributes), + latency, + }) + } + ir::Control::Par(ir::Par { stmts, attributes }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // Convert stmts to static + let static_stmts = + self.convert_vec_to_static(builder, std::mem::take(stmts)); + // Calculate latency + let latency = static_stmts + .iter() + .map(|s| s.get_latency()) + .max() + .unwrap_or_else(|| unreachable!("Empty Par Block")); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Par(ir::StaticPar { + stmts: static_stmts, + attributes: ir::Attributes::default(), + latency, + }) + } + ir::Control::Repeat(ir::Repeat { + body, + num_repeats, + attributes, + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + let sc = self.convert_to_static(body, builder); + let latency = (*num_repeats) * sc.get_latency(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Repeat(ir::StaticRepeat { + attributes: std::mem::take(attributes), + body: Box::new(sc), + num_repeats: *num_repeats, + latency, + }) + } + ir::Control::While(ir::While { + body, attributes, .. + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + // Removing the `bound` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::Bound); + let sc = self.convert_to_static(body, builder); + let num_repeats = bound_attribute.unwrap_or_else(|| unreachable!("Called convert_to_static on a while loop without a bound")); + let latency = num_repeats * sc.get_latency(); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::Repeat(ir::StaticRepeat { + attributes: std::mem::take(attributes), + body: Box::new(sc), + num_repeats, + latency, + }) + } + ir::Control::If(ir::If { + port, + tbranch, + fbranch, + attributes, + .. + }) => { + // Removing the `promote_static` attribute bc we don't need it anymore + attributes.remove(ir::NumAttr::PromoteStatic); + let static_tbranch = self.convert_to_static(tbranch, builder); + let static_fbranch = self.convert_to_static(fbranch, builder); + let latency = std::cmp::max( + static_tbranch.get_latency(), + static_fbranch.get_latency(), + ); + Self::check_latencies_match(latency, inferred_latency); + ir::StaticControl::static_if( + Rc::clone(port), + Box::new(static_tbranch), + Box::new(static_fbranch), + latency, + ) + } + ir::Control::Static(_) => c.take_static_control(), + ir::Control::Invoke(s) => self.convert_invoke_to_static(s), + } + } + + /// Converts vec of control to vec of static control. + /// All control statements in the vec must be promotable or already static. + pub fn convert_vec_to_static( + &mut self, + builder: &mut ir::Builder, + control_vec: Vec, + ) -> Vec { + control_vec + .into_iter() + .map(|mut c| self.convert_to_static(&mut c, builder)) + .collect() + } +} diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index 544a17d88..43d14927b 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -167,12 +167,25 @@ impl ReadWriteSet { inputs, outputs, ref_cells, + comp, .. }) => { let mut inps: Vec> = inputs.iter().map(|(_, p)| p).cloned().collect(); let mut outs: Vec> = outputs.iter().map(|(_, p)| p).cloned().collect(); + // Adding comp.go to input ports + inps.push( + comp.borrow() + .find_all_with_attr(ir::NumAttr::Go) + .next() + .unwrap_or_else(|| { + unreachable!( + "No @go port for component {}", + comp.borrow().name() + ) + }), + ); for (_, cell) in ref_cells.iter() { for port in cell.borrow().ports.iter() { match port.borrow().direction { @@ -215,28 +228,53 @@ impl ReadWriteSet { /// Returns the ports that are read and written, respectively, /// by the given control program. - pub fn control_port_read_write_set( + /// INCLUDE_HOLE_ASSIGNS: in either case, we will ignore done holes. + /// However, if INCLUDE_HOLE_ASSIGNS is false, we ignore all *assignments* + /// that write to holes, even if the src of that assignment is a cell's port. + pub fn control_port_read_write_set( con: &ir::Control, ) -> (Vec>, Vec>) { match con { ir::Control::Empty(_) => (vec![], vec![]), ir::Control::Enable(ir::Enable { group, .. }) => ( - Self::port_read_set(group.borrow().assignments.iter()) - .collect(), - Self::port_write_set(group.borrow().assignments.iter()) - .collect(), + Self::port_read_set(group.borrow().assignments.iter().filter( + |assign| { + INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() + }, + )) + .collect(), + Self::port_write_set(group.borrow().assignments.iter().filter( + |assign| { + INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() + }, + )) + .collect(), ), ir::Control::Invoke(ir::Invoke { inputs, outputs, comb_group, ref_cells, + comp, .. }) => { + // XXX(Caleb): Maybe check that there is one @go port. let inps = inputs.iter().map(|(_, p)| p).cloned(); let outs = outputs.iter().map(|(_, p)| p).cloned(); let mut r: Vec> = inps.collect(); let mut w: Vec> = outs.collect(); + // Adding comp.go to the write set + w.push( + comp.borrow() + .find_all_with_attr(ir::NumAttr::Go) + .next() + .unwrap_or_else(|| { + unreachable!( + "No @go port for component {}", + comp.borrow().name() + ) + }), + ); for (_, cell) in ref_cells { for port in cell.borrow().ports.iter() { @@ -270,7 +308,7 @@ impl ReadWriteSet { let (mut reads, mut writes) = (vec![], vec![]); for stmt in stmts { let (mut read, mut write) = - Self::control_port_read_write_set(stmt); + Self::control_port_read_write_set::(stmt); reads.append(&mut read); writes.append(&mut write); } @@ -284,9 +322,9 @@ impl ReadWriteSet { .. }) => { let (mut treads, mut twrites) = - Self::control_port_read_write_set(tbranch); + Self::control_port_read_write_set::(tbranch); let (mut freads, mut fwrites) = - Self::control_port_read_write_set(fbranch); + Self::control_port_read_write_set::(fbranch); treads.append(&mut freads); treads.push(Rc::clone(port)); twrites.append(&mut fwrites); @@ -305,7 +343,7 @@ impl ReadWriteSet { port, cond, body, .. }) => { let (mut reads, mut writes) = - Self::control_port_read_write_set(body); + Self::control_port_read_write_set::(body); reads.push(Rc::clone(port)); if let Some(cg) = cond { @@ -319,7 +357,7 @@ impl ReadWriteSet { (reads, writes) } ir::Control::Repeat(ir::Repeat { body, .. }) => { - Self::control_port_read_write_set(body) + Self::control_port_read_write_set::(body) } ir::Control::Static(sc) => { Self::control_port_read_write_set_static(sc) @@ -329,10 +367,14 @@ impl ReadWriteSet { /// Returns the cells that are read and written, respectively, /// by the given control program. - pub fn control_read_write_set( + /// INCLUDE_HOLE_ASSIGNS: in either case, we will ignore done holes themselves. + /// However, if INCLUDE_HOLE_ASSIGNS is true, we ignore all assignments + /// that write to holes, even if the src of that assignment is a cell's port. + pub fn control_read_write_set( con: &ir::Control, ) -> (Vec>, Vec>) { - let (port_reads, port_writes) = Self::control_port_read_write_set(con); + let (port_reads, port_writes) = + Self::control_port_read_write_set::(con); ( port_reads .into_iter() diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 0f5fe52d7..824df1bbe 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -98,8 +98,9 @@ impl PassManager { CompileInvoke, // creates dead comb groups AttributePromotion, StaticInference, - StaticPromotion, ScheduleCompaction, + StaticPromotion, + StaticPromotion, CompileRepeat, DeadGroupRemoval, // Since previous passes potentially create dead groups CollapseControl, diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index ec440da8e..ee20290f8 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -1,19 +1,40 @@ -use crate::analysis::ReadWriteSet; -use crate::traversal::Action; +use crate::analysis::{InferenceAnalysis, PromotionAnalysis, ReadWriteSet}; +use crate::traversal::{Action, ConstructVisitor}; use crate::{ analysis, traversal::{Named, Visitor}, }; use calyx_ir as ir; +use calyx_utils::CalyxResult; +use ir::GetAttributes; +use itertools::Itertools; use petgraph::{algo, graph::NodeIndex}; use std::collections::HashMap; -#[derive(Default)] /// For static seqs that are statically promoted by the compiler. /// Aggressively compacts the execution schedule so that the execution /// order of control operators still respects data dependency /// Example: see tests/passes/schedule-compaction/schedule-compaction.futil -pub struct ScheduleCompaction; +pub struct ScheduleCompaction { + inference_analysis: InferenceAnalysis, + promotion_analysis: PromotionAnalysis, +} + +// Override constructor to build latency_data information from the primitives +// library. +impl ConstructVisitor for ScheduleCompaction { + fn from(ctx: &ir::Context) -> CalyxResult { + Ok(ScheduleCompaction { + inference_analysis: InferenceAnalysis::from_ctx(ctx), + promotion_analysis: PromotionAnalysis::default(), + }) + } + + // This pass shared information between components + fn clear_data(&mut self) { + self.promotion_analysis = PromotionAnalysis::default() + } +} impl Named for ScheduleCompaction { fn name() -> &'static str { @@ -25,36 +46,78 @@ impl Named for ScheduleCompaction { } } -impl Visitor for ScheduleCompaction { - fn iteration_order() -> crate::traversal::Order - where - Self: Sized, - { - crate::traversal::Order::Post +impl ScheduleCompaction { + // Compacts `cur_stmts`, and appends the result to `new_stmts`. + fn append_and_compact( + &mut self, + (cont_reads, cont_writes): ( + &Vec>, + &Vec>, + ), + builder: &mut ir::Builder, + cur_stmts: Vec, + new_stmts: &mut Vec, + ) { + if !cur_stmts.is_empty() { + let og_latency = cur_stmts + .iter() + .map(PromotionAnalysis::get_inferred_latency) + .sum(); + // Try to compact cur_stmts. + let possibly_compacted_stmt = self.compact_control_vec( + cur_stmts, + (cont_reads, cont_writes), + builder, + og_latency, + ir::Attributes::default(), + ); + new_stmts.push(possibly_compacted_stmt); + } + } + + // Given a total_order and sorted schedule, builds a seq based on the original + // schedule. + // Note that this function assumes the `total_order`` and `sorted_schedule` + // represent a completely sequential schedule. + fn recover_seq( + mut total_order: petgraph::graph::DiGraph, ()>, + sorted_schedule: Vec<(NodeIndex, u64)>, + attributes: ir::Attributes, + ) -> ir::Control { + let stmts = sorted_schedule + .into_iter() + .map(|(i, _)| total_order[i].take().unwrap()) + .collect_vec(); + ir::Control::Seq(ir::Seq { stmts, attributes }) } - fn finish_static_seq( + // Takes a vec of ctrl stmts and turns it into a compacted schedule (a static par). + // If it can't compact at all, then it just returns a `seq` in the `stmts` + // original order. + fn compact_control_vec( &mut self, - s: &mut calyx_ir::StaticSeq, - comp: &mut calyx_ir::Component, - sigs: &calyx_ir::LibrarySignatures, - _comps: &[calyx_ir::Component], - ) -> crate::traversal::VisResult { - // records the corresponding node indices that each control program - // has data dependency on + stmts: Vec, + (cont_reads, cont_writes): ( + &Vec>, + &Vec>, + ), + builder: &mut ir::Builder, + og_latency: u64, + attributes: ir::Attributes, + ) -> ir::Control { + // Records the corresponding node indices that each control program + // has data dependency on. let mut dependency: HashMap> = HashMap::new(); - // records the latency of corresponding control operator for each node index + // Records the latency of corresponding control operator for each + // node index. let mut latency_map: HashMap = HashMap::new(); - // records the scheduled start time of corresponding control operator for each node index + // Records the scheduled start time of corresponding control operator + // for each node index. let mut schedule: HashMap = HashMap::new(); - let (cont_reads, cont_writes) = ReadWriteSet::cont_read_write_set(comp); - - let mut builder = ir::Builder::new(comp, sigs); - let mut total_order = - analysis::ControlOrder::::get_dependency_graph_static_seq( - s.stmts.drain(..), + analysis::ControlOrder::::get_dependency_graph_seq( + stmts.into_iter(), (cont_reads, cont_writes), &mut dependency, &mut latency_map, @@ -82,27 +145,37 @@ impl Visitor for ScheduleCompaction { schedule.into_iter().collect(); sorted_schedule .sort_by(|(k1, v1), (k2, v2)| (v1, k1).cmp(&(v2, k2))); + + if total_time == og_latency { + // If we can't comapct at all, then just recover the and return + // the original seq. + return Self::recover_seq( + total_order, + sorted_schedule, + attributes, + ); + } + // Threads for the static par, where each entry is (thread, thread_latency) - let mut par_threads: Vec<(Vec, u64)> = - Vec::new(); + let mut par_threads: Vec<(Vec, u64)> = Vec::new(); - // We encode the schedule attempting to minimize the number of + // We encode the schedule while trying to minimize the number of // par threads. 'outer: for (i, start) in sorted_schedule { let control = total_order[i].take().unwrap(); for (thread, thread_latency) in par_threads.iter_mut() { if *thread_latency <= start { if *thread_latency < start { - // Might need a no-op group so the schedule starts correctly + // Need a no-op group so the schedule starts correctly let no_op = builder.add_static_group( "no-op", start - *thread_latency, ); - thread.push(ir::StaticControl::Enable( - ir::StaticEnable { + thread.push(ir::Control::Static( + ir::StaticControl::Enable(ir::StaticEnable { group: no_op, attributes: ir::Attributes::default(), - }, + }), )); *thread_latency = start; } @@ -116,11 +189,12 @@ impl Visitor for ScheduleCompaction { // If start > 0, then we must add a delay to the start of the // group. let no_op = builder.add_static_group("no-op", start); - let no_op_enable = + let no_op_enable = ir::Control::Static( ir::StaticControl::Enable(ir::StaticEnable { group: no_op, attributes: ir::Attributes::default(), - }); + }), + ); par_threads.push(( vec![no_op_enable, control], start + latency_map[&i], @@ -129,76 +203,113 @@ impl Visitor for ScheduleCompaction { par_threads.push((vec![control], latency_map[&i])); } } - // Turn Vec -> StaticSeq let mut par_control_threads: Vec = Vec::new(); for (thread, thread_latency) in par_threads { - par_control_threads.push(ir::StaticControl::Seq( - ir::StaticSeq { - stmts: thread, - attributes: ir::Attributes::default(), - latency: thread_latency, - }, - )); + let mut promoted_stmts = thread + .into_iter() + .map(|mut stmt| { + self.promotion_analysis + .convert_to_static(&mut stmt, builder) + }) + .collect_vec(); + if promoted_stmts.len() == 1 { + // Don't wrap in static seq if we don't need to. + par_control_threads.push(promoted_stmts.pop().unwrap()); + } else { + par_control_threads.push(ir::StaticControl::Seq( + ir::StaticSeq { + stmts: promoted_stmts, + attributes: ir::Attributes::default(), + latency: thread_latency, + }, + )); + } } // Double checking that we have built the static par correctly. - let max = par_control_threads.iter().map(|c| c.get_latency()).max(); + let max: Option = + par_control_threads.iter().map(|c| c.get_latency()).max(); assert!(max.unwrap() == total_time, "The schedule expects latency {}. The static par that was built has latency {}", total_time, max.unwrap()); - if par_control_threads.len() == 1 { - let c = Vec::pop(&mut par_control_threads).unwrap(); - Ok(Action::static_change(c)) - } else { - let s_par = ir::StaticControl::Par(ir::StaticPar { - stmts: par_control_threads, - attributes: ir::Attributes::default(), - latency: total_time, - }); - Ok(Action::static_change(s_par)) - } + let mut s_par = ir::StaticControl::Par(ir::StaticPar { + stmts: par_control_threads, + attributes: ir::Attributes::default(), + latency: total_time, + }); + s_par.get_mut_attributes().insert(ir::BoolAttr::Promoted, 1); + ir::Control::Static(s_par) } else { panic!( "Error when producing topo sort. Dependency graph has a cycle." ); } } +} - fn finish_static_repeat( - &mut self, - s: &mut ir::StaticRepeat, - _comp: &mut ir::Component, - _sigs: &ir::LibrarySignatures, - _comps: &[ir::Component], - ) -> crate::traversal::VisResult { - s.latency = s.body.get_latency() * s.num_repeats; - Ok(Action::Continue) +impl Visitor for ScheduleCompaction { + fn iteration_order() -> crate::traversal::Order + where + Self: Sized, + { + crate::traversal::Order::Post } - fn finish_static_par( + fn finish_seq( &mut self, - s: &mut ir::StaticPar, - _comp: &mut ir::Component, - _sigs: &ir::LibrarySignatures, - _comps: &[ir::Component], + s: &mut calyx_ir::Seq, + comp: &mut calyx_ir::Component, + sigs: &calyx_ir::LibrarySignatures, + _comps: &[calyx_ir::Component], ) -> crate::traversal::VisResult { - let mut latency: u64 = 0; - for stmt in s.stmts.iter() { - latency = std::cmp::max(latency, stmt.get_latency()); + let (cont_reads, cont_writes) = ReadWriteSet::cont_read_write_set(comp); + InferenceAnalysis::remove_promotable_from_seq(s); + self.inference_analysis.fixup_seq(s); + + let mut builder = ir::Builder::new(comp, sigs); + + if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + // If entire seq is promotable, then we can compact entire thing + // and replace it with a static construct. + return Ok(Action::Change(Box::new(self.compact_control_vec( + std::mem::take(&mut s.stmts), + (&cont_reads, &cont_writes), + &mut builder, + latency, + std::mem::take(&mut s.attributes), + )))); } - s.latency = latency; - Ok(Action::Continue) - } - fn finish_static_if( - &mut self, - s: &mut ir::StaticIf, - _comp: &mut ir::Component, - _sigs: &ir::LibrarySignatures, - _comps: &[ir::Component], - ) -> crate::traversal::VisResult { - s.latency = - std::cmp::max(s.tbranch.get_latency(), s.fbranch.get_latency()); - Ok(Action::Continue) + // We have to break up the seq into portions that we can compact. + let old_stmts = std::mem::take(&mut s.stmts); + let mut new_stmts: Vec = Vec::new(); + let mut cur_stmts: Vec = Vec::new(); + + for stmt in old_stmts { + if PromotionAnalysis::can_be_promoted(&stmt) { + cur_stmts.push(stmt); + } else { + self.append_and_compact( + (&cont_reads, &cont_writes), + &mut builder, + cur_stmts, + &mut new_stmts, + ); + // Appending the non-promotable statement. + new_stmts.push(stmt); + // New cur_vec + cur_stmts = Vec::new(); + } + } + self.append_and_compact( + (&cont_reads, &cont_writes), + &mut builder, + cur_stmts, + &mut new_stmts, + ); + Ok(Action::change(ir::Control::Seq(ir::Seq { + stmts: new_stmts, + attributes: ir::Attributes::default(), + }))) } fn finish( @@ -207,29 +318,53 @@ impl Visitor for ScheduleCompaction { _sigs: &ir::LibrarySignatures, _comps: &[ir::Component], ) -> crate::traversal::VisResult { - if comp.is_static() { - comp.latency = Some( - std::num::NonZeroU64::new( - comp.control.borrow().get_latency().unwrap(), + // Re-infer component's latency. + self.inference_analysis.fixup_timing(comp); + if comp.name != "main" { + // Fixup components to show the new latency. + let comp_sig = comp.signature.borrow(); + let go_ports: Vec<_> = + comp_sig.find_all_with_attr(ir::NumAttr::Go).collect_vec(); + if go_ports.iter().any(|go_port| { + go_port.borrow_mut().attributes.has(ir::NumAttr::Static) + }) { + // Getting current latency + let cur_latency = go_ports + .iter() + .filter_map(|go_port| { + go_port.borrow_mut().attributes.get(ir::NumAttr::Static) + }) + .next() + .unwrap(); + // Getting new latency. We know it will exist because compaction + // does not remove latency information, it just alters it. + let new_latency = InferenceAnalysis::get_possible_latency( + &comp.control.borrow(), ) - .unwrap(), - ); + .unwrap(); + if cur_latency != new_latency { + // We adjust the signature of our component + self.inference_analysis + .adjust_component((comp.name, new_latency)); + for go_port in go_ports { + go_port + .borrow_mut() + .attributes + .insert(ir::NumAttr::Static, new_latency); + } + } + }; } Ok(Action::Continue) } - fn static_invoke( + fn start( &mut self, - s: &mut ir::StaticInvoke, - _comp: &mut ir::Component, + comp: &mut ir::Component, _sigs: &ir::LibrarySignatures, - comps: &[ir::Component], + _comps: &[ir::Component], ) -> crate::traversal::VisResult { - for comp in comps { - if comp.name.eq(&s.comp.borrow().type_name().unwrap()) { - s.latency = u64::from(comp.latency.unwrap()); - } - } + self.inference_analysis.fixup_timing(comp); Ok(Action::Continue) } } diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 0fffcd859..6d2e0fc49 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -1,4 +1,4 @@ -use crate::analysis::InferenceAnalysis; +use crate::analysis::{InferenceAnalysis, PromotionAnalysis}; use crate::traversal::{ Action, ConstructVisitor, Named, Order, ParseVal, PassOpt, VisResult, Visitor, @@ -7,7 +7,6 @@ use calyx_ir::{self as ir, LibrarySignatures}; use calyx_utils::CalyxResult; use ir::GetAttributes; use itertools::Itertools; -use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; @@ -31,8 +30,9 @@ pub struct StaticPromotion { /// An InferenceAnalysis object so that we can re-infer the latencies of /// certain components. inference_analysis: InferenceAnalysis, - /// dynamic group Id -> promoted static group Id - static_group_name: HashMap, + /// PromotionAnalysis object so that we can easily infer control, and keep + /// track of which groups were promoted. + promotion_analysis: PromotionAnalysis, /// Threshold for promotion threshold: u64, /// Threshold for difference in latency for if statements @@ -48,7 +48,7 @@ impl ConstructVisitor for StaticPromotion { let opts = Self::get_opts(ctx); Ok(StaticPromotion { inference_analysis: InferenceAnalysis::from_ctx(ctx), - static_group_name: HashMap::new(), + promotion_analysis: PromotionAnalysis::default(), threshold: opts["threshold"].pos_num().unwrap(), if_diff_limit: opts["if-diff-limit"].pos_num(), cycle_limit: opts["cycle-limit"].pos_num(), @@ -57,7 +57,7 @@ impl ConstructVisitor for StaticPromotion { // This pass shared information between components fn clear_data(&mut self) { - self.static_group_name = HashMap::new(); + self.promotion_analysis = PromotionAnalysis::default(); } } @@ -95,30 +95,6 @@ impl Named for StaticPromotion { } impl StaticPromotion { - /// Gets the inferred latency, which should either be from being a static - /// control operator or the promote_static attribute. - /// Will raise an error if neither of these is true. - fn get_inferred_latency(c: &ir::Control) -> u64 { - let ir::Control::Static(sc) = c else { - let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) - else { - unreachable!("Called get_latency on control that is neither static nor promotable") - }; - return latency; - }; - sc.get_latency() - } - - fn check_latencies_match(actual: u64, inferred: u64) { - assert_eq!(actual, inferred, "Inferred and Annotated Latencies do not match. Latency: {}. Inferred: {}", actual, inferred); - } - - /// Returns true if a control statement is already static, or has the static - /// attributes - fn can_be_promoted(c: &ir::Control) -> bool { - c.is_static() || c.has_attribute(ir::NumAttr::PromoteStatic) - } - fn within_cycle_limit(&self, latency: u64) -> bool { if self.cycle_limit.is_none() { return true; @@ -133,224 +109,41 @@ impl StaticPromotion { diff <= self.if_diff_limit.unwrap() } - /// If we've already constructed the static group then use the already existing - /// group. Otherwise construct `static group` and then return that. - fn construct_static_group( - &mut self, - builder: &mut ir::Builder, - group: ir::RRC, - latency: u64, - ) -> ir::RRC { - if let Some(s_name) = self.static_group_name.get(&group.borrow().name()) - { - builder.component.find_static_group(*s_name).unwrap() - } else { - let sg = builder.add_static_group(group.borrow().name(), latency); - self.static_group_name - .insert(group.borrow().name(), sg.borrow().name()); - for assignment in group.borrow().assignments.iter() { - // Don't need to include assignment to done hole. - if !(assignment.dst.borrow().is_hole() - && assignment.dst.borrow().name == "done") - { - sg.borrow_mut() - .assignments - .push(ir::Assignment::from(assignment.clone())); - } - } - Rc::clone(&sg) + fn approx_size_static(sc: &ir::StaticControl, promoted: bool) -> u64 { + if !(sc.get_attributes().has(ir::BoolAttr::Promoted) || promoted) { + return APPROX_ENABLE_SIZE; } - } - - // Converts dynamic enable to static - fn convert_enable_to_static( - &mut self, - s: &mut ir::Enable, - builder: &mut ir::Builder, - ) -> ir::StaticControl { - s.attributes.remove(ir::NumAttr::PromoteStatic); - ir::StaticControl::Enable(ir::StaticEnable { - // upgrading group to static group - group: self.construct_static_group( - builder, - Rc::clone(&s.group), - s.group - .borrow() - .get_attributes() - .unwrap() - .get(ir::NumAttr::PromoteStatic) - .unwrap(), - ), - attributes: std::mem::take(&mut s.attributes), - }) - } - - // Converts dynamic invoke to static - fn convert_invoke_to_static( - &mut self, - s: &mut ir::Invoke, - ) -> ir::StaticControl { - assert!( - s.comb_group.is_none(), - "Shouldn't Promote to Static if there is a Comb Group", - ); - s.attributes.remove(ir::NumAttr::PromoteStatic); - let latency = *self.inference_analysis.static_component_latencies.get( - &s.comp.borrow().type_name().unwrap_or_else(|| { - unreachable!( - "Already checked that comp is component" - ) - }), - ).unwrap_or_else(|| unreachable!("Called convert_to_static for static invoke that does not have a static component")); - let s_inv = ir::StaticInvoke { - comp: Rc::clone(&s.comp), - inputs: std::mem::take(&mut s.inputs), - outputs: std::mem::take(&mut s.outputs), - latency, - attributes: std::mem::take(&mut s.attributes), - ref_cells: std::mem::take(&mut s.ref_cells), - comb_group: std::mem::take(&mut s.comb_group), - }; - ir::StaticControl::Invoke(s_inv) - } - - /// Converts control to static control. - /// Control must already be static or have the `promote_static` attribute. - fn convert_to_static( - &mut self, - c: &mut ir::Control, - builder: &mut ir::Builder, - ) -> ir::StaticControl { - assert!( - c.has_attribute(ir::NumAttr::PromoteStatic) || c.is_static(), - "Called convert_to_static control that is neither static nor promotable" - ); - // Need to get bound_attribute here, because we cannot borrow `c` within the - // pattern match. - let bound_attribute = c.get_attribute(ir::NumAttr::Bound); - // Inferred latency of entire control block. Used to double check our - // function is correct. - let inferred_latency = Self::get_inferred_latency(c); - match c { - ir::Control::Empty(_) => ir::StaticControl::empty(), - ir::Control::Enable(s) => self.convert_enable_to_static(s, builder), - ir::Control::Seq(ir::Seq { stmts, attributes }) => { - // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); - // The resulting static seq should be compactable. - attributes.insert(ir::NumAttr::Compactable, 1); - let static_stmts = - self.convert_vec_to_static(builder, std::mem::take(stmts)); - let latency = - static_stmts.iter().map(|s| s.get_latency()).sum(); - Self::check_latencies_match(latency, inferred_latency); - ir::StaticControl::Seq(ir::StaticSeq { - stmts: static_stmts, - attributes: std::mem::take(attributes), - latency, - }) + match sc { + ir::StaticControl::Empty(_) => 0, + ir::StaticControl::Enable(_) | ir::StaticControl::Invoke(_) => { + APPROX_ENABLE_SIZE } - ir::Control::Par(ir::Par { stmts, attributes }) => { - // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); - // Convert stmts to static - let static_stmts = - self.convert_vec_to_static(builder, std::mem::take(stmts)); - // Calculate latency - let latency = static_stmts - .iter() - .map(|s| s.get_latency()) - .max() - .unwrap_or_else(|| unreachable!("Empty Par Block")); - Self::check_latencies_match(latency, inferred_latency); - ir::StaticControl::Par(ir::StaticPar { - stmts: static_stmts, - attributes: ir::Attributes::default(), - latency, - }) + ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => { + Self::approx_size_static(body, true) + APPROX_WHILE_REPEAT_SIZE } - ir::Control::Repeat(ir::Repeat { - body, - num_repeats, - attributes, - }) => { - // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); - let sc = self.convert_to_static(body, builder); - let latency = (*num_repeats) * sc.get_latency(); - Self::check_latencies_match(latency, inferred_latency); - ir::StaticControl::Repeat(ir::StaticRepeat { - attributes: std::mem::take(attributes), - body: Box::new(sc), - num_repeats: *num_repeats, - latency, - }) - } - ir::Control::While(ir::While { - body, attributes, .. - }) => { - // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); - // Removing the `bound` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::Bound); - let sc = self.convert_to_static(body, builder); - let num_repeats = bound_attribute.unwrap_or_else(|| unreachable!("Called convert_to_static on a while loop without a bound")); - let latency = num_repeats * sc.get_latency(); - Self::check_latencies_match(latency, inferred_latency); - ir::StaticControl::Repeat(ir::StaticRepeat { - attributes: std::mem::take(attributes), - body: Box::new(sc), - num_repeats, - latency, - }) - } - ir::Control::If(ir::If { - port, - tbranch, - fbranch, - attributes, - .. + ir::StaticControl::If(ir::StaticIf { + tbranch, fbranch, .. }) => { - // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); - let static_tbranch = self.convert_to_static(tbranch, builder); - let static_fbranch = self.convert_to_static(fbranch, builder); - let latency = std::cmp::max( - static_tbranch.get_latency(), - static_fbranch.get_latency(), - ); - Self::check_latencies_match(latency, inferred_latency); - ir::StaticControl::static_if( - Rc::clone(port), - Box::new(static_tbranch), - Box::new(static_fbranch), - latency, - ) + Self::approx_size_static(tbranch, true) + + Self::approx_size_static(fbranch, true) + + APPROX_IF_SIZE } - ir::Control::Static(_) => c.take_static_control(), - ir::Control::Invoke(s) => self.convert_invoke_to_static(s), + ir::StaticControl::Par(ir::StaticPar { stmts, .. }) + | ir::StaticControl::Seq(ir::StaticSeq { stmts, .. }) => stmts + .iter() + .map(|stmt| Self::approx_size_static(stmt, true)) + .sum(), } } - /// Converts vec of control to vec of static control. - /// All control statements in the vec must be promotable or already static. - fn convert_vec_to_static( - &mut self, - builder: &mut ir::Builder, - control_vec: Vec, - ) -> Vec { - control_vec - .into_iter() - .map(|mut c| self.convert_to_static(&mut c, builder)) - .collect() - } - /// Calculates the approximate "size" of the control statements. /// Tries to approximate the number of dynamic FSM transitions that will occur fn approx_size(c: &ir::Control) -> u64 { match c { ir::Control::Empty(_) => 0, - ir::Control::Enable(_) => APPROX_ENABLE_SIZE, + ir::Control::Enable(_) | ir::Control::Invoke(_) => { + APPROX_ENABLE_SIZE + } ir::Control::Seq(ir::Seq { stmts, .. }) | ir::Control::Par(ir::Par { stmts, .. }) => { stmts.iter().map(Self::approx_size).sum() @@ -366,12 +159,7 @@ impl StaticPromotion { + Self::approx_size(fbranch) + APPROX_IF_SIZE } - ir::Control::Static(_) => { - // static control appears as one big group to the dynamic FSM - 1 - } - // Invokes are same size as enables. - ir::Control::Invoke(_) => APPROX_ENABLE_SIZE, + ir::Control::Static(sc) => Self::approx_size_static(sc, false), } } @@ -397,7 +185,10 @@ impl StaticPromotion { // Too small to be promoted, return as is return control_vec; } else if !self.within_cycle_limit( - control_vec.iter().map(Self::get_inferred_latency).sum(), + control_vec + .iter() + .map(PromotionAnalysis::get_inferred_latency) + .sum(), ) { // Too large, try to break up let right = control_vec.split_off(control_vec.len() / 2); @@ -410,12 +201,14 @@ impl StaticPromotion { return left_res; } // Correct size, convert the entire vec - let s_seq_stmts = self.convert_vec_to_static(builder, control_vec); + let s_seq_stmts = self + .promotion_analysis + .convert_vec_to_static(builder, control_vec); let latency = s_seq_stmts.iter().map(|sc| sc.get_latency()).sum(); - let mut sseq = + let sseq = ir::Control::Static(ir::StaticControl::seq(s_seq_stmts, latency)); - sseq.get_mut_attributes() - .insert(ir::NumAttr::Compactable, 1); + // sseq.get_mut_attributes() + // .insert(ir::NumAttr::Compactable, 1); vec![sseq] } @@ -441,7 +234,7 @@ impl StaticPromotion { } else if !self.within_cycle_limit( control_vec .iter() - .map(Self::get_inferred_latency) + .map(PromotionAnalysis::get_inferred_latency) .max() .unwrap_or_else(|| unreachable!("Empty Par Block")), ) { @@ -459,7 +252,9 @@ impl StaticPromotion { return left; } // Convert vec to static par - let s_par_stmts = self.convert_vec_to_static(builder, control_vec); + let s_par_stmts = self + .promotion_analysis + .convert_vec_to_static(builder, control_vec); let latency = s_par_stmts .iter() .map(|sc| sc.get_latency()) @@ -557,7 +352,8 @@ impl Visitor for StaticPromotion { && (APPROX_ENABLE_SIZE > self.threshold) { return Ok(Action::change(ir::Control::Static( - self.convert_enable_to_static(s, &mut builder), + self.promotion_analysis + .convert_enable_to_static(s, &mut builder), ))); } } @@ -577,7 +373,7 @@ impl Visitor for StaticPromotion { && (APPROX_ENABLE_SIZE > self.threshold) { return Ok(Action::change(ir::Control::Static( - self.convert_invoke_to_static(s), + self.promotion_analysis.convert_invoke_to_static(s), ))); } } @@ -599,15 +395,15 @@ impl Visitor for StaticPromotion { return Ok(Action::Continue); } else if self.within_cycle_limit(latency) { // We promote entire seq. - let mut sseq = ir::Control::Static(ir::StaticControl::seq( - self.convert_vec_to_static( + let sseq = ir::Control::Static(ir::StaticControl::seq( + self.promotion_analysis.convert_vec_to_static( &mut builder, std::mem::take(&mut s.stmts), ), latency, )); - sseq.get_mut_attributes() - .insert(ir::NumAttr::Compactable, 1); + // sseq.get_mut_attributes() + // .insert(ir::NumAttr::Compactable, 1); return Ok(Action::change(sseq)); } } @@ -623,7 +419,7 @@ impl Visitor for StaticPromotion { let mut new_stmts: Vec = Vec::new(); let mut cur_vec: Vec = Vec::new(); for stmt in old_stmts { - if Self::can_be_promoted(&stmt) { + if PromotionAnalysis::can_be_promoted(&stmt) { cur_vec.push(stmt); } else { // Use heuristics to decide how to promote this cur_vec of promotable stmts. @@ -661,7 +457,7 @@ impl Visitor for StaticPromotion { } else if self.within_cycle_limit(latency) { // Promote entire par let spar = ir::Control::Static(ir::StaticControl::par( - self.convert_vec_to_static( + self.promotion_analysis.convert_vec_to_static( &mut builder, std::mem::take(&mut s.stmts), ), @@ -680,8 +476,10 @@ impl Visitor for StaticPromotion { // This temporarily messes up its parents' `@promotable` // attribute, but this is fine since we know its parent will never try // to promote it. - let (s_stmts, d_stmts): (Vec, Vec) = - s.stmts.drain(..).partition(Self::can_be_promoted); + let (s_stmts, d_stmts): (Vec, Vec) = s + .stmts + .drain(..) + .partition(PromotionAnalysis::can_be_promoted); new_stmts.extend(self.promote_vec_par_heuristic(&mut builder, s_stmts)); new_stmts.extend(d_stmts); let new_par = ir::Control::Par(ir::Par { @@ -703,17 +501,21 @@ impl Visitor for StaticPromotion { let approx_size_if = Self::approx_size(&s.tbranch) + Self::approx_size(&s.fbranch) + APPROX_IF_SIZE; - let branch_diff = Self::get_inferred_latency(&s.tbranch) - .abs_diff(Self::get_inferred_latency(&s.fbranch)); + let branch_diff = PromotionAnalysis::get_inferred_latency( + &s.tbranch, + ) + .abs_diff(PromotionAnalysis::get_inferred_latency(&s.fbranch)); if approx_size_if > self.threshold && self.within_cycle_limit(latency) && self.within_if_diff_limit(branch_diff) { // Meets size threshold so promote to static - let static_tbranch = - self.convert_to_static(&mut s.tbranch, &mut builder); - let static_fbranch = - self.convert_to_static(&mut s.fbranch, &mut builder); + let static_tbranch = self + .promotion_analysis + .convert_to_static(&mut s.tbranch, &mut builder); + let static_fbranch = self + .promotion_analysis + .convert_to_static(&mut s.fbranch, &mut builder); return Ok(Action::change(ir::Control::Static( ir::StaticControl::static_if( Rc::clone(&s.port), @@ -752,7 +554,9 @@ impl Visitor for StaticPromotion { if approx_size > self.threshold && self.within_cycle_limit(latency) { // Turn repeat into static repeat - let sc = self.convert_to_static(&mut s.body, &mut builder); + let sc = self + .promotion_analysis + .convert_to_static(&mut s.body, &mut builder); let static_repeat = ir::StaticControl::repeat( s.attributes.get(ir::NumAttr::Bound).unwrap_or_else(|| { unreachable!( @@ -793,7 +597,9 @@ impl Visitor for StaticPromotion { if approx_size > self.threshold && self.within_cycle_limit(latency) { // Meets size threshold, so turn repeat into static repeat - let sc = self.convert_to_static(&mut s.body, &mut builder); + let sc = self + .promotion_analysis + .convert_to_static(&mut s.body, &mut builder); let static_repeat = ir::StaticControl::repeat( s.num_repeats, latency, diff --git a/tests/passes/schedule-compaction/continuous-compaction.expect b/tests/passes/schedule-compaction/continuous-compaction.expect index 1ccd2ef0f..102e5e38f 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-compaction.expect @@ -8,19 +8,19 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: add = std_add(8); } wires { - static<1> group write_r0 { + static<1> group write_r00 { r0.in = 8'd1; r0.write_en = 1'd1; } - static<1> group write_r1 { + static<1> group write_r10 { r1.in = add.out; r1.write_en = 1'd1; } - static<1> group write_r2 { + static<1> group write_r20 { r2.in = 8'd3; r2.write_en = 1'd1; } - static<1> group write_r3 { + static<1> group write_r30 { r3.in = 8'd3; r3.write_en = 1'd1; } @@ -29,19 +29,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: add.left = r0.out; } control { - seq { - static<2> par { - static<2> seq { - write_r0; - write_r1; - } - static<1> seq { - write_r2; - } - static<1> seq { - write_r3; - } + @promote_static(2) @promoted static<2> par { + static<2> seq { + write_r00; + write_r10; } + write_r20; + write_r30; } } } diff --git a/tests/passes/schedule-compaction/continuous-compaction.futil b/tests/passes/schedule-compaction/continuous-compaction.futil index 017c13cda..c64f8c02d 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-compaction.futil @@ -1,4 +1,4 @@ -// -p validate -p schedule-compaction +// -p validate -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; @@ -11,35 +11,37 @@ component main() -> (out: 8) { add = std_add(8); } wires { - static<1> group write_r0 { + group write_r0<"promote_static"=1> { r0.write_en = 1'd1; r0.in = 8'd1; + write_r0[done] = r0.done; } - static<1> group write_r1 { + group write_r1<"promote_static"=1> { r1.write_en = 1'd1; r1.in = add.out; + write_r1[done] = r1.done; } - static<1> group write_r2 { + group write_r2<"promote_static"=1> { r2.write_en = 1'd1; r2.in = 8'd3; + write_r2[done] = r2.done; } - static<1> group write_r3 { + group write_r3<"promote_static"=1> { r3.write_en = 1'd1; r3.in = 8'd3; + write_r3[done] = r3.done; } add.left = r0.out; add.right = 8'd1; out = r1.out; } control { - seq { - @compactable static seq { - write_r0; - // Continuous assignments to add.left and add.right prevent compation. - write_r1; - write_r2; - write_r3; - } + @promote_static(4) seq { + @promote_static write_r0; + // Continuous assignments to add.left and add.right prevent compation. + @promote_static write_r1; + @promote_static write_r2; + @promote_static write_r3; } } } \ No newline at end of file diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.expect b/tests/passes/schedule-compaction/continuous-no-compaction.expect index b61eaf801..740d15bff 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-no-compaction.expect @@ -6,19 +6,23 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: r2 = std_reg(8); add = std_add(8); add1 = std_add(8); + ud = undef(1); } wires { - static<1> group write_r0 { + group write_r0<"promote_static"=1> { r0.in = 8'd1; r0.write_en = 1'd1; + write_r0[done] = r0.done; } - static<1> group write_r1 { + group write_r1<"promote_static"=1> { r1.in = add.out; r1.write_en = 1'd1; + write_r1[done] = r1.done; } - static<1> group write_add1 { + group write_add1<"promote_static"=1> { add1.right = 8'd4; add1.left = 8'd1; + write_add1[done] = ud.out; } out = r1.out; add.right = 8'd1; @@ -26,14 +30,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: r2.in = add1.out; } control { - seq { - static<2> seq { - write_r0; - write_r1; + @promote_static(4) seq { + @promote_static(2) seq { + @promote_static write_r0; + @promote_static write_r1; } - static<2> seq { - write_r0; - write_add1; + @promote_static(2) seq { + @promote_static write_r0; + @promote_static write_add1; } } } diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.futil b/tests/passes/schedule-compaction/continuous-no-compaction.futil index c69eb1a3f..3f91dd934 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-no-compaction.futil @@ -1,4 +1,4 @@ -// -p validate -p schedule-compaction +// -p validate -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; @@ -9,19 +9,23 @@ component main() -> (out: 8) { r2 = std_reg(8); add = std_add(8); add1 = std_add(8); + ud = undef(1); } wires { - static<1> group write_r0 { + group write_r0<"promote_static"=1> { r0.write_en = 1'd1; r0.in = 8'd1; + write_r0[done] = r0.done; } - static<1> group write_r1 { + group write_r1<"promote_static"=1> { r1.write_en = 1'd1; r1.in = add.out; + write_r1[done] = r1.done; } - static<1> group write_add1 { + group write_add1<"promote_static"=1> { add1.left = 8'd1; add1.right = 8'd4; + write_add1[done] = ud.out; } r2.in = add1.out; add.left = r0.out; @@ -29,17 +33,17 @@ component main() -> (out: 8) { out = r1.out; } control { - seq { - @compactable static seq { - write_r0; + @promote_static(4) seq { + @promote_static(2) seq { + @promote_static write_r0; // Continuous assignments to add.left and add.right prevent compation. - write_r1; + @promote_static write_r1; } - @compactable static seq { - write_r0; + @promote_static(2) seq { + @promote_static write_r0; // Continuous assignment r2.in = add1.out prevents compaction. // This is overly conservative. - write_add1; + @promote_static write_add1; } } } diff --git a/tests/passes/schedule-compaction/fixup-necessary.expect b/tests/passes/schedule-compaction/fixup-necessary.expect new file mode 100644 index 000000000..a6129a88c --- /dev/null +++ b/tests/passes/schedule-compaction/fixup-necessary.expect @@ -0,0 +1,36 @@ +import "primitives/core.futil"; +component example(@go @static go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + } + wires { + out = r1.out; + } + control { + @promote_static @promoted static<1> par { + static<1> invoke r0( + in = 8'd1 + )(); + static<1> invoke r1( + in = 8'd2 + )(); + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + @external mem = std_mem_d1(8, 1, 1); + ex = example(); + } + wires {} + control { + @promote_static(2) seq { + @promote_static invoke ex()(); + @promote_static invoke mem( + addr0 = 1'd0, + write_data = ex.out + )(); + } + } +} diff --git a/tests/passes/schedule-compaction/fixup-necessary.futil b/tests/passes/schedule-compaction/fixup-necessary.futil new file mode 100644 index 000000000..990087667 --- /dev/null +++ b/tests/passes/schedule-compaction/fixup-necessary.futil @@ -0,0 +1,33 @@ +// -p validate -p static-inference -p schedule-compaction -p dead-group-removal + +import "primitives/core.futil"; + +component example() -> (out: 8) { + cells { + r0 = std_reg(8); + r1 = std_reg(8); + } + wires { + out = r1.out; + } + control { + seq { + invoke r0(in = 8'd1)(); + invoke r1(in = 8'd2)(); + } + } +} + +component main() -> () { + cells { + @external mem = std_mem_d1(8, 1, 1); + ex = example(); + } + wires {} + control { + seq { + invoke ex()(); + invoke mem(addr0 = 1'd0, write_data = ex.out)(); + } + } +} \ No newline at end of file diff --git a/tests/passes/schedule-compaction/no-compact.expect b/tests/passes/schedule-compaction/no-compact.expect new file mode 100644 index 000000000..af889a0e9 --- /dev/null +++ b/tests/passes/schedule-compaction/no-compact.expect @@ -0,0 +1,32 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + d_reg = std_reg(32); + } + wires { + group A<"promote_static"=1> { + a_reg.write_en = 1'd1; + a_reg.in = 32'd5; + A[done] = a_reg.done; + } + group B<"promote_static"=1> { + b_reg.write_en = 1'd1; + b_reg.in = a_reg.out; + B[done] = b_reg.done; + } + group D<"promote_static"=1> { + d_reg.write_en = 1'd1; + d_reg.in = b_reg.out; + D[done] = d_reg.done; + } + } + control { + @promote_static(3) seq { + @promote_static A; + @promote_static B; + @promote_static D; + } + } +} diff --git a/tests/passes/schedule-compaction/no-compact.futil b/tests/passes/schedule-compaction/no-compact.futil new file mode 100644 index 000000000..d0b3adcec --- /dev/null +++ b/tests/passes/schedule-compaction/no-compact.futil @@ -0,0 +1,38 @@ +// -p validate -p static-inference -p schedule-compaction -p dead-group-removal + +import "primitives/core.futil"; + +component main() -> () { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + d_reg = std_reg(32); + } + wires { + group A<"promote_static"=1> { + a_reg.in = 32'd5; + a_reg.write_en = 1'd1; + A[done] = a_reg.done; + } + + group B<"promote_static"=1> { + b_reg.in = a_reg.out; + b_reg.write_en = 1'd1; + B[done] = b_reg.done; + } + + group D<"promote_static"=1> { + d_reg.in = b_reg.out; + d_reg.write_en = 1'd1; + D[done] = d_reg.done; + } + + } + control { + seq { + A; + B; + D; + } + } +} \ No newline at end of file diff --git a/tests/passes/schedule-compaction/partial-compaction.expect b/tests/passes/schedule-compaction/partial-compaction.expect new file mode 100644 index 000000000..5acae484d --- /dev/null +++ b/tests/passes/schedule-compaction/partial-compaction.expect @@ -0,0 +1,58 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + e_reg = std_reg(32); + f_reg = std_reg(32); + a = std_add(32); + ud = undef(1); + } + wires { + group A<"promote_static"=1> { + a_reg.write_en = 1'd1; + a_reg.in = 32'd5; + A[done] = a_reg.done; + } + group C { + c_reg.write_en = 1'd1; + c_reg.in = 32'd10; + C[done] = ud.out; + } + group B<"promote_static"=1> { + b_reg.write_en = 1'd1; + a.right = c_reg.out; + a.left = a_reg.out; + b_reg.in = a.out; + B[done] = b_reg.done; + } + static<1> group D0 { + d_reg.write_en = 1'd1; + d_reg.in = a_reg.out; + } + static<1> group E0 { + e_reg.write_en = 1'd1; + e_reg.in = 32'd4; + } + static<1> group F0 { + f_reg.write_en = 1'd1; + f_reg.in = 32'd4; + } + } + control { + seq { + @promote_static(2) seq { + @promote_static A; + @promote_static B; + } + C; + @promote_static @promoted static<1> par { + D0; + E0; + F0; + } + } + } +} diff --git a/tests/passes/schedule-compaction/partial-compaction.futil b/tests/passes/schedule-compaction/partial-compaction.futil new file mode 100644 index 000000000..bb7c49221 --- /dev/null +++ b/tests/passes/schedule-compaction/partial-compaction.futil @@ -0,0 +1,83 @@ +// -p validate -p schedule-compaction -p dead-group-removal +// for control operators under static seq, +// we consider the subsequent control operator B to have data dependency on +// prior operator A in the following three cases: +// 1. B writes to a cell A reads from +// 2. B reads from a cell A writes to +// 3. B writes to a cell A writes to +// As such, we can draw the following dependency graph for the control program: +// A C +// | \ / +// | \ / +// | \ / +// | \ +// | / \ +// | / \ +// | / \ +// B D +// So we can compact the execution schedule to respect this data dependency +import "primitives/core.futil"; + +component main () -> () { + cells { + a_reg = std_reg(32); + b_reg = std_reg(32); + c_reg = std_reg(32); + d_reg = std_reg(32); + e_reg = std_reg(32); + f_reg = std_reg(32); + a = std_add(32); + ud = undef(1); + } + + wires { + group A<"promote_static"=1> { + a_reg.in = 32'd5; + a_reg.write_en = 1'd1; + A[done] = a_reg.done; + } + + group C { + c_reg.in = 32'd10; + c_reg.write_en = 1'd1; + C[done] = ud.out; + } + + group B<"promote_static"=1> { + a.left = a_reg.out; + a.right = c_reg.out; + b_reg.in = a.out; + b_reg.write_en = 1'd1; + B[done] = b_reg.done; + } + + group D<"promote_static"=1> { + d_reg.in = a_reg.out; + d_reg.write_en = 1'd1; + D[done] = ud.out; + } + + group E<"promote_static"=1> { + e_reg.in = 32'd4; + e_reg.write_en = 1'd1; + E[done] = e_reg.done; + } + + group F<"promote_static"=1> { + f_reg.in = 32'd4; + f_reg.write_en = 1'd1; + F[done] = f_reg.done; + } + } + + control { + seq { + @promote_static A; + @promote_static B; + C; + @promote_static D; + @promote_static E; + @promote_static F; + } + } +} \ No newline at end of file diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect index 855907b6b..1fb6f1e05 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.expect +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -6,36 +6,37 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c_reg = std_reg(32); d_reg = std_reg(32); a = std_add(32); + ud = undef(1); } wires { - static<1> group A { + static<1> group A0 { a_reg.write_en = 1'd1; a_reg.in = 32'd5; } - static<10> group C { - c_reg.write_en = %0 ? 1'd1; + static<10> group D0 { + d_reg.write_en = 1'd1; + d_reg.in = a_reg.out; + } + static<10> group C0 { + c_reg.write_en = 1'd1; c_reg.in = 32'd10; } - static<1> group B { + static<1> group B0 { b_reg.write_en = 1'd1; a.right = c_reg.out; a.left = a_reg.out; b_reg.in = a.out; } - static<10> group D { - d_reg.write_en = %0 ? 1'd1; - d_reg.in = a_reg.out; - } } control { - static<11> par { + @promote_static(11) @promoted static<11> par { static<11> seq { - A; - D; + A0; + D0; } static<11> seq { - C; - B; + C0; + B0; } } } diff --git a/tests/passes/schedule-compaction/schedule-compaction.futil b/tests/passes/schedule-compaction/schedule-compaction.futil index 048f335c7..26f0f04bf 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.futil +++ b/tests/passes/schedule-compaction/schedule-compaction.futil @@ -1,6 +1,6 @@ -// -p validate -p schedule-compaction +// -p validate -p schedule-compaction -p dead-group-removal // for control operators under static seq, -// we consider the subsequent control operator B to have data dependency on +// we consider the subsequent control operator B to have data dependency on // prior operator A in the following three cases: // 1. B writes to a cell A reads from // 2. B reads from a cell A writes to @@ -25,35 +25,43 @@ component main () -> () { c_reg = std_reg(32); d_reg = std_reg(32); a = std_add(32); + ud = undef(1); } wires { - static<1> group A { + group A<"promote_static"=1> { a_reg.in = 32'd5; a_reg.write_en = 1'd1; + A[done] = a_reg.done; } - - static<10> group C { + + group C<"promote_static"=10> { c_reg.in = 32'd10; - c_reg.write_en = %0 ? 1'd1; + c_reg.write_en = 1'd1; + C[done] = ud.out; } - static<1> group B { + group B<"promote_static"=1> { a.left = a_reg.out; a.right = c_reg.out; b_reg.in = a.out; b_reg.write_en = 1'd1; + B[done] = b_reg.done; } - static<10> group D { + group D<"promote_static"=10> { d_reg.in = a_reg.out; - d_reg.write_en = %0 ? 1'd1; + d_reg.write_en = 1'd1; + D[done] = ud.out; } } control { - @compactable static seq { - A; C; B; D; + @promote_static(22) seq { + @promote_static A; + @promote_static(10) C; + @promote_static B; + @promote_static(10) D; } } } \ No newline at end of file diff --git a/tests/passes/static-inference-promotion/component.expect b/tests/passes/static-inference-promotion/component.expect index e311382bc..8870d0317 100644 --- a/tests/passes/static-inference-promotion/component.expect +++ b/tests/passes/static-inference-promotion/component.expect @@ -20,7 +20,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @compactable static<3> seq { + static<3> seq { A0; B0; C0; diff --git a/tests/passes/static-inference-promotion/groups.expect b/tests/passes/static-inference-promotion/groups.expect index 9c9fda81f..7fab699b8 100644 --- a/tests/passes/static-inference-promotion/groups.expect +++ b/tests/passes/static-inference-promotion/groups.expect @@ -34,7 +34,7 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don } control { seq { - @compactable static<4> seq { + static<4> seq { one_cycle0; two_cycles0; mem_wrt_to_done0; diff --git a/tests/passes/static-inference-promotion/if-diff.expect b/tests/passes/static-inference-promotion/if-diff.expect index 0b3fc0a18..3a8b024a0 100644 --- a/tests/passes/static-inference-promotion/if-diff.expect +++ b/tests/passes/static-inference-promotion/if-diff.expect @@ -17,7 +17,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { if cond.out { - @compactable static<5> seq { + static<5> seq { A0; A0; A0; diff --git a/tests/passes/static-inference-promotion/invoke.expect b/tests/passes/static-inference-promotion/invoke.expect index e9c2e3ec8..c8070785d 100644 --- a/tests/passes/static-inference-promotion/invoke.expect +++ b/tests/passes/static-inference-promotion/invoke.expect @@ -11,7 +11,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @compactable static<3> seq { + static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go @static(2) go: } } control { - @compactable static<2> seq { + static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-inference-promotion/multi-static.expect b/tests/passes/static-inference-promotion/multi-static.expect index 78d60b674..0b1a4d422 100644 --- a/tests/passes/static-inference-promotion/multi-static.expect +++ b/tests/passes/static-inference-promotion/multi-static.expect @@ -11,7 +11,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @compactable static<3> seq { + static<3> seq { upd00; static<2> invoke exp0( base = r.out, @@ -36,7 +36,7 @@ static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go @static(2) go: } } control { - @compactable static<2> seq { + static<2> seq { upd10; upd20; } diff --git a/tests/passes/static-inference-promotion/no_promote_loop.expect b/tests/passes/static-inference-promotion/no_promote_loop.expect index 26a22869a..82016867e 100644 --- a/tests/passes/static-inference-promotion/no_promote_loop.expect +++ b/tests/passes/static-inference-promotion/no_promote_loop.expect @@ -22,14 +22,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { control { seq { repeat 10 { - @compactable static<4> seq { + static<4> seq { A0; B0; C0; C0; } } - @compactable static<3> seq { + static<3> seq { A0; B0; C0; diff --git a/tests/passes/static-inference-promotion/promote-nested.expect b/tests/passes/static-inference-promotion/promote-nested.expect index cb4141c2a..303bf0379 100644 --- a/tests/passes/static-inference-promotion/promote-nested.expect +++ b/tests/passes/static-inference-promotion/promote-nested.expect @@ -27,7 +27,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { seq { - @compactable static<4> seq { + static<4> seq { static<1> par { A0; B0; diff --git a/tests/passes/static-inference-promotion/upgrade-bound.expect b/tests/passes/static-inference-promotion/upgrade-bound.expect index 18962c3e1..ceecd138e 100644 --- a/tests/passes/static-inference-promotion/upgrade-bound.expect +++ b/tests/passes/static-inference-promotion/upgrade-bound.expect @@ -22,7 +22,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { static repeat 5 { - @compactable static<3> seq { + static<3> seq { A0; B0; C0; diff --git a/tests/passes/static-passes/both-passes-promote.expect b/tests/passes/static-passes/both-passes-promote.expect new file mode 100644 index 000000000..014ad2d58 --- /dev/null +++ b/tests/passes/static-passes/both-passes-promote.expect @@ -0,0 +1,46 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + wires { + group A<"promote_static"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promote_static"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + group C<"promote_static"=1> { + c.in = 2'd2; + c.write_en = 1'd1; + C[done] = c.done; + } + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + static<1> group C0 { + c.in = 2'd2; + c.write_en = 1'd1; + } + } + control { + static repeat 10 { + @promote_static @promoted static<1> par { + A0; + B0; + C0; + } + } + } +} diff --git a/tests/passes/static-passes/both-passes-promote.futil b/tests/passes/static-passes/both-passes-promote.futil new file mode 100644 index 000000000..2eb86d18c --- /dev/null +++ b/tests/passes/static-passes/both-passes-promote.futil @@ -0,0 +1,38 @@ +// -p well-formed -p static-inference -p schedule-compaction -p static-promotion -x static-promotion:threshold=5 +// Compaction should promote the body, promotion should promote the loop. + +import "primitives/core.futil"; + +component main() -> () { + cells { + a = std_reg(2); + b = std_reg(2); + c = std_reg(2); + } + + wires { + group A { + a.in = 2'd0; + a.write_en = 1'b1; + A[done] = a.done; + } + + group B { + b.in = 2'd1; + b.write_en = 1'b1; + B[done] = b.done; + } + + group C { + c.in = 2'd2; + c.write_en = 1'b1; + C[done] = c.done; + } + } + + control { + repeat 10 { + seq { A; B; C;} + } + } +} diff --git a/tests/passes/static-promotion/fixup-necessary.expect b/tests/passes/static-promotion/fixup-necessary.expect index 34bac1aa0..c9b37d6c9 100644 --- a/tests/passes/static-promotion/fixup-necessary.expect +++ b/tests/passes/static-promotion/fixup-necessary.expect @@ -45,7 +45,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { seq { - @compactable static<8> seq { + static<8> seq { A0; A0; A0; diff --git a/tests/passes/tdcc/new-fsm-nested.futil b/tests/passes/tdcc/new-fsm-nested.futil index eb332ce4c..616fa5562 100644 --- a/tests/passes/tdcc/new-fsm-nested.futil +++ b/tests/passes/tdcc/new-fsm-nested.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; @@ -66,28 +66,28 @@ component main() -> () { control { seq { - A; + A; @new_fsm while r.out { seq{ true; @new_fsm if lt.out with cond { seq{ - B; + B; @new_fsm seq { - A; + A; B; } - D; + D; } } else{ - E; + E; } false; } } - C; + C; } - + } } diff --git a/tests/passes/tdcc/while.futil b/tests/passes/tdcc/while.futil index 1b9266d7f..938da9a96 100644 --- a/tests/passes/tdcc/while.futil +++ b/tests/passes/tdcc/while.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; From 18f1301d15ed5477f97063095069c424498ea016 Mon Sep 17 00:00:00 2001 From: Anshuman Mohan <10830208+anshumanmohan@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:55:11 -0500 Subject: [PATCH 160/189] Docs: static keyword (#1872) * Tweaks * Guarantees * nix tricks and tips * Correct syntax * Title case * Various comments from Adrian * Drag guarantees out into their own section * Push guarantees in throughout * More headings for better linking --- docs/lang/static.md | 132 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/docs/lang/static.md b/docs/lang/static.md index 827d7e52a..4e3dc3051 100644 --- a/docs/lang/static.md +++ b/docs/lang/static.md @@ -1,42 +1,120 @@ # Static Timing -By default, Calyx programs use a *latency-insensitive* model of computation. -This means that the compiler does not track the number of cycles it takes to perform a computation or run a control operator -In general, latency-insensitivity makes it easier to compose programs together and gives the compiler freedom to schedule operators however it wants. -However, the generated hardware to schedule the execution may not be efficient–especially if the program can take advantage of the *latency* information. +By default, Calyx programs use a *latency-insensitive*, or *dynamic*, model of computation. +This means that the compiler does not know, track, or guarantee the number of cycles it takes to perform a computation or run a control operator. +This is in contrast to a *latency-sensitive*, or *static*, model of computation, where the number of cycles a component needs is known to, and honored by, the compiler. -More crucially, however, it is impossible for *latency-insensitive* programs to interact with *latency-sensitive* hardware implemented in RTL. +In general, latency-insensitivity makes it easier to compose programs. +It grants the compiler freedom to schedule operators however it wants, as long as the schedule meets the program's dataflow constraints. +It also prevents code from implicitly depending on the state of other code running in parallel. -Calyx uses the `@static` attribute to provide latency information to various constructs and provides strong guarantees about the generated programs. +However, there are two drawbacks to this approach. +First, the generated hardware may not be efficient: if the compiler does not know how long computations take, it must schedule them conservatively. +Second, it is impossible for *latency-insensitive* programs to interact with *latency-sensitive* hardware implemented in RTL; +this means that the use of black-box hardware designs requires costly handshaking logic at the interface. -## Guarantees +To address these issues, Calyx provides a `static` qualifier that modifies components and groups, along with static variants of other control operators. -## Tricks & Tips +Broadly, the `static` qualifier is a promise to the compiler that the component or group will take exactly the specified number of cycles to execute. +The compiler is free to take advantage of this promise to generate more efficient hardware. +In return, the compiler must access out-ports of static components only after the specified number of cycles have passed, or risk receiving incorrect results. -### Delay by `n` cycles +## Static Constructs in the Calyx IL -Sometimes it can be useful to delay the execution of a group by `n` cycles: +We will now discuss the static constructs available in the Calyx IL, along with the guarantees they come with. + +### Static Components + +Briefly consider a divider component, `std_div`, which divides the value `left` by the value `right` and puts the result in `out`. +This component is dynamic; its latency is unknown. ``` -seq { - @static(1) a; // Run in first cycle - ??? - @static(2) b; // Run in the 10th cycle -} +primitive std_div[W](go: 1, left: W, right: W) -> (out: W, done: 1); ``` +A client of the divider must pass two inputs, raise the `go` signal, and wait for the component itself to raise its `done` signal. +The client can then read the result from the `out` port. +That is, it obeys the [go-done interface][go-done-interface]. -A simple trick to achieve this is adding an empty group with `@static(n)` attribute on it: +Compare this to a multiplier component, `std_mult`, which has a similar signature but whose latency is known to be three cycles. +We declare it as follows: ``` -cell { - r = @std_reg(0); -} -@static(9) group delay_9 { - delay_9[done] = r.out; // Don't use r.done here -} -seq { - @static(1) a; // Run in first cycle - @static(9) delay_9; - @static(2) b; // Run in the 10th cycle +static<3> primitive std_mult[W](go: 1, left: W, right: W) -> (out: W); +``` + +The key differences are: +- The `static` qualifier is used to declare the component as static and to specify its latency. +- The `done` port is not present in the static component. + +A client of the multiplier must pass two inputs and raise the `go` signal as before. +However, the client need not then wait for the component to indicate completion. +It can simply and safely assume that the result will be available after 3 cycles. +This is a guarantee that the author of the component has made to the client, and the compiler is free to take advantage of it. + + +### Static Groups and Relative Timing Guards + +Much like components, groups can be declared as static. +Since groups are just unordered sets of assignments, it pays to have a little more control over the scheduling of the assignments within a group. +To this end, static groups have a unique feature that ordinary dynamic groups do not: *relative timing guards*. + +Consider this group, which multiplies `6` and `7` and stores the result in `ans`. + +``` +static<4> group mult_and_store { + mult.left = %[0:3] ? 6; + mult.right = %[0:3] ? 7; + mult.go = %[0:3] ? 1; + ans.in = %3 ? mult.out; + ans.write_en = %3 ? 1; } ``` +The `static<4>` qualifier specifies that the group should take 4 cycles to execute. + +The first three assignments are guarded (using the [standard `?` separator][guard-sep]) by the relative timing guard `%[0:3]`. +In general, a relative timing guard `%[i:j]` is *true* in the half-open interval from cycle `i` to +cycle `j` of the group’s execution and *false* otherwise. + +In our case, the first three assignments execute only in the first three cycles of the group's execution. +The guard `%3`, which we see immediately afterwards, is syntactic sugar for `%[3:4]`. +We have used it in this case to ensure that the last two assignments execute only in the last cycle of the group's execution. + + +### Static Control Operators + +Calyx provides static variants of each of its [control operators][]. +While dynamic commands may contain both static and dynamic children, static commands must only have static children. +In the examples below, assume that `A5`, `B6`, `C7`, and `D8` are static groups with latencies 5, 6, 7, and 8, respectively. + +#### `static seq`, a static version of [`seq`][seq] +If we have `static seq { A5; B6; C7; D8; }`, we can guarantee that the latency of the entire operation is the sum of the latencies of its children: 5 + 6 + 7 + 8 = 26 cycles in this case. +We can also guarantee that, each child will begin executing exactly one cycle after the previous child has finished. +In our case, for example, `B6` will begin executing exactly one cycle after `A5` has finished. + +#### `static par`, a static version of [`par`][par] +If we have `static par { A5; B6; C7; D8; }`, we can guarantee that the latency of the entire operation is the maximum of the latencies of its children: 8 cycles in this case. +Further, all the children of a `static par` are guaranteed to begin executing at the same time. +The children can rely on this "lockstep" behavior and can communicate with each other. +Such communication is undefined behavior in a standard, dynamic, `par`. + +#### `static if`, a static version of [`if`][if] +If we have `static if { A5; B6; }`, we can guarantee that the latency of the entire operation is the maximum of the latencies of its children: 6 cycles in this case. + + +#### `static repeat`, a static version of [`repeat`][repeat] + +> Calyx's `while` loop is unbouded and so it does not have a static variant. + +If we have `static repeat 7 { B6; }`, we can guarantee that the latency of the entire operation is the product of the number of iterations and the latency of its child: 7 × 6 = 42 cycles in this case. +The body of a `static repeat` is guaranteed to begin executing exactly one cycle after the previous iteration has finished. + +#### `static invoke`, a static version of [`invoke`][invoke] + +Its latency is the latency of the invoked cell. -The static compilation pass `tdst` will never attempt to use the `delay_9`'s `done` condition and since there are no assignments in the group, it'll not generate any additional hardware. +[guard-sep]: ./ref.md#guarded-assignments +[go-done-interface]: ./ref.md#the-go-done-interface +[control operators]: ./ref.md#the-control-operators +[seq]: ./ref.md#seq +[par]: ./ref.md#par +[if]: ./ref.md#if +[repeat]: ./ref.md#repeat +[invoke]: ./ref.md#invoke From f2ae18f59318c59d7f46661db5d1587abdaaebf1 Mon Sep 17 00:00:00 2001 From: Elise Song <111922608+eys29@users.noreply.github.com> Date: Sun, 4 Feb 2024 07:47:32 -0500 Subject: [PATCH 161/189] Docs: multicomponent tutorial fud command fix (#1891) --- docs/lang/multi-component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/lang/multi-component.md b/docs/lang/multi-component.md index aae618713..eb9c96e78 100644 --- a/docs/lang/multi-component.md +++ b/docs/lang/multi-component.md @@ -41,5 +41,5 @@ The component executes the two groups in-order. To see the output from running this component, run the command: ``` -fud e examples/futil/multi-component.futil --to vcd_json +fud e examples/futil/multi-component.futil --to vcd ``` From 5f70f237ef0b933e49bcfb026b6b956a046e1369 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 4 Feb 2024 18:39:57 +0530 Subject: [PATCH 162/189] Reorganize `fud2` directory (#1883) * Reorganize `fud2` directory * add tool metadata * fix location for README * reorg driver files * extra some setup into functions * create `fud-core` crate * update desc * add lisc * bump version --- Cargo.lock | 36 +++---- Cargo.toml | 2 +- fud2/Cargo.toml | 19 +++- fud2/README.md | 27 +++++ fud2/fake/src/lib.rs | 6 -- fud2/{fake => fud-core}/Cargo.toml | 10 +- fud2/{fake => fud-core}/src/cli.rs | 2 +- fud2/{fake => fud-core}/src/config.rs | 0 fud2/fud-core/src/exec/data.rs | 58 ++++++++++ .../{fake/src => fud-core/src/exec}/driver.rs | 100 +----------------- fud2/fud-core/src/exec/mod.rs | 8 ++ fud2/fud-core/src/exec/request.rs | 24 +++++ fud2/fud-core/src/lib.rs | 7 ++ fud2/{fake => fud-core}/src/run.rs | 3 +- fud2/fud-core/src/utils.rs | 14 +++ fud2/src/main.rs | 40 +++++-- 16 files changed, 221 insertions(+), 135 deletions(-) create mode 100644 fud2/README.md delete mode 100644 fud2/fake/src/lib.rs rename fud2/{fake => fud-core}/Cargo.toml (61%) rename fud2/{fake => fud-core}/src/cli.rs (99%) rename fud2/{fake => fud-core}/src/config.rs (100%) create mode 100644 fud2/fud-core/src/exec/data.rs rename fud2/{fake/src => fud-core/src/exec}/driver.rs (74%) create mode 100644 fud2/fud-core/src/exec/mod.rs create mode 100644 fud2/fud-core/src/exec/request.rs create mode 100644 fud2/fud-core/src/lib.rs rename fud2/{fake => fud-core}/src/run.rs (99%) create mode 100644 fud2/fud-core/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index e19067059..d23b808d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -734,21 +734,6 @@ dependencies = [ "str-buf", ] -[[package]] -name = "fake" -version = "0.6.1" -dependencies = [ - "anyhow", - "argh", - "camino", - "cranelift-entity", - "env_logger", - "figment", - "log", - "pathdiff", - "serde", -] - [[package]] name = "fastrand" version = "2.0.0" @@ -804,11 +789,26 @@ dependencies = [ ] [[package]] -name = "fud2" -version = "0.6.1" +name = "fud" +version = "0.0.2" dependencies = [ "anyhow", - "fake", + "fud-core", +] + +[[package]] +name = "fud-core" +version = "0.0.2" +dependencies = [ + "anyhow", + "argh", + "camino", + "cranelift-entity", + "env_logger", + "figment", + "log", + "pathdiff", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 189d19015..cfc23a90c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ "tools/data_gen", "cider-dap", "fud2", - "fud2/fake", + "fud2/fud-core", ] exclude = ["site"] diff --git a/fud2/Cargo.toml b/fud2/Cargo.toml index 31e4c39a3..c188ff981 100644 --- a/fud2/Cargo.toml +++ b/fud2/Cargo.toml @@ -1,8 +1,21 @@ [package] -name = "fud2" -version.workspace = true +name = "fud" +version = "0.0.2" edition.workspace = true +authors.workspace = true +license-file.workspace = true +repository.workspace = true +homepage.workspace = true + +keywords = ["build-tool"] +readme = "README.md" +categories = ["build-tool"] +description = "Compiler driver for the Calyx infrastructure" [dependencies] -fake = { path = "fake" } +fud-core = { path = "fud-core", version = "0.0.2" } anyhow.workspace = true + +[[bin]] +name = "fud2" +path = "src/main.rs" diff --git a/fud2/README.md b/fud2/README.md new file mode 100644 index 000000000..a0f028030 --- /dev/null +++ b/fud2/README.md @@ -0,0 +1,27 @@ +# `fud`: The Calyx Build Tool + +Reimplementation of the [fud][] compiler driver for Calyx. + +### Installation + +To install from source, run the following from `calyx/fud2`: +``` +cargo install --path . +``` + +This will install the binary `fud2` to the default `cargo` binary location. + +### Configuration + +The minimal required configuration requires setting the `calyx.base` key so that `fud` knows where the Calyx compiler is. Open the configuration file by running: +``` +fud edit-config +``` + +Add the path to the location of the Calyx compiler: +```toml +[calyx] +base = "" +``` + +[fud]: https://docs.calyxir.org/fud/index.html \ No newline at end of file diff --git a/fud2/fake/src/lib.rs b/fud2/fake/src/lib.rs deleted file mode 100644 index 2e2faa0a1..000000000 --- a/fud2/fake/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod cli; -pub mod config; -pub mod driver; -pub mod run; - -pub use driver::{Driver, DriverBuilder}; diff --git a/fud2/fake/Cargo.toml b/fud2/fud-core/Cargo.toml similarity index 61% rename from fud2/fake/Cargo.toml rename to fud2/fud-core/Cargo.toml index 021d7cd28..271ea0ffc 100644 --- a/fud2/fake/Cargo.toml +++ b/fud2/fud-core/Cargo.toml @@ -1,7 +1,13 @@ [package] -name = "fake" -version.workspace = true +name = "fud-core" +version = "0.0.2" edition.workspace = true +license-file.workspace = true + +keywords = ["build-tool"] +readme = "../README.md" +categories = ["build-tool"] +description = "Library for building declarative build tools" [dependencies] argh.workspace = true diff --git a/fud2/fake/src/cli.rs b/fud2/fud-core/src/cli.rs similarity index 99% rename from fud2/fake/src/cli.rs rename to fud2/fud-core/src/cli.rs index 1af8660f1..55797205c 100644 --- a/fud2/fake/src/cli.rs +++ b/fud2/fud-core/src/cli.rs @@ -1,5 +1,5 @@ use crate::config; -use crate::driver::{Driver, Request, StateRef}; +use crate::exec::{Driver, Request, StateRef}; use crate::run::Run; use anyhow::{anyhow, bail}; use argh::FromArgs; diff --git a/fud2/fake/src/config.rs b/fud2/fud-core/src/config.rs similarity index 100% rename from fud2/fake/src/config.rs rename to fud2/fud-core/src/config.rs diff --git a/fud2/fud-core/src/exec/data.rs b/fud2/fud-core/src/exec/data.rs new file mode 100644 index 000000000..6bb64ca6f --- /dev/null +++ b/fud2/fud-core/src/exec/data.rs @@ -0,0 +1,58 @@ +use crate::run; +use cranelift_entity::entity_impl; + +/// A State is a type of file that Operations produce or consume. +pub struct State { + /// The name of the state, for the UI. + pub name: String, + + /// The file extensions that this state can be represented by. + /// + /// The first extension in the list is used when generating a new filename for the state. If + /// the list is empty, this is a "pseudo-state" that doesn't correspond to an actual file. + /// Pseudo-states can only be final outputs; they are appropraite for representing actions that + /// interact directly with the user, for example. + pub extensions: Vec, +} + +impl State { + /// Check whether a filename extension indicates this state. + pub fn ext_matches(&self, ext: &str) -> bool { + self.extensions.iter().any(|e| e == ext) + } + + /// Is this a "pseudo-state": doesn't correspond to an actual file, and must be an output state? + pub fn is_pseudo(&self) -> bool { + self.extensions.is_empty() + } +} + +/// A reference to a State. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct StateRef(u32); +entity_impl!(StateRef, "state"); + +/// An Operation transforms files from one State to another. +pub struct Operation { + pub name: String, + pub input: StateRef, + pub output: StateRef, + pub setups: Vec, + pub emit: Box, +} + +/// A reference to an Operation. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct OpRef(u32); +entity_impl!(OpRef, "op"); + +/// A Setup runs at configuration time and produces Ninja machinery for Operations. +pub struct Setup { + pub name: String, + pub emit: Box, +} + +/// A reference to a Setup. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct SetupRef(u32); +entity_impl!(SetupRef, "setup"); diff --git a/fud2/fake/src/driver.rs b/fud2/fud-core/src/exec/driver.rs similarity index 74% rename from fud2/fake/src/driver.rs rename to fud2/fud-core/src/exec/driver.rs index ee4945909..29b00d70c 100644 --- a/fud2/fake/src/driver.rs +++ b/fud2/fud-core/src/exec/driver.rs @@ -1,75 +1,7 @@ -use crate::run; +use super::{OpRef, Operation, Request, Setup, SetupRef, State, StateRef}; +use crate::{run, utils}; use camino::{Utf8Path, Utf8PathBuf}; -use cranelift_entity::{entity_impl, PrimaryMap, SecondaryMap}; -use pathdiff::diff_utf8_paths; - -/// A State is a type of file that Operations produce or consume. -pub struct State { - /// The name of the state, for the UI. - pub name: String, - - /// The file extensions that this state can be represented by. - /// - /// The first extension in the list is used when generating a new filename for the state. If - /// the list is empty, this is a "pseudo-state" that doesn't correspond to an actual file. - /// Pseudo-states can only be final outputs; they are appropraite for representing actions that - /// interact directly with the user, for example. - pub extensions: Vec, -} - -/// A reference to a State. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct StateRef(u32); -entity_impl!(StateRef, "state"); - -/// An Operation transforms files from one State to another. -pub struct Operation { - pub name: String, - pub input: StateRef, - pub output: StateRef, - pub setups: Vec, - pub emit: Box, -} - -/// A reference to an Operation. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct OpRef(u32); -entity_impl!(OpRef, "op"); - -/// A Setup runs at configuration time and produces Ninja machinery for Operations. -pub struct Setup { - pub name: String, - pub emit: Box, -} - -/// A reference to a Setup. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct SetupRef(u32); -entity_impl!(SetupRef, "setup"); - -impl State { - /// Check whether a filename extension indicates this state. - fn ext_matches(&self, ext: &str) -> bool { - self.extensions.iter().any(|e| e == ext) - } - - /// Is this a "pseudo-state": doesn't correspond to an actual file, and must be an output state? - fn is_pseudo(&self) -> bool { - self.extensions.is_empty() - } -} - -/// Get a version of `path` that works when the working directory is `base`. This is -/// opportunistically a relative path, but we can always fall back to an absolute path to make sure -/// the path still works. -pub fn relative_path(path: &Utf8Path, base: &Utf8Path) -> Utf8PathBuf { - match diff_utf8_paths(path, base) { - Some(p) => p, - None => path - .canonicalize_utf8() - .expect("could not get absolute path"), - } -} +use cranelift_entity::{PrimaryMap, SecondaryMap}; #[derive(PartialEq)] enum Destination { @@ -196,7 +128,7 @@ impl Driver { // Get the initial input filename and the stem to use to generate all intermediate filenames. let (stdin, start_file) = match req.start_file { - Some(path) => (false, relative_path(&path, &req.workdir)), + Some(path) => (false, utils::relative_path(&path, &req.workdir)), None => (true, "stdin".into()), }; let stem = start_file.file_stem().unwrap(); @@ -211,7 +143,7 @@ impl Driver { let stdout = if let Some(end_file) = req.end_file { // TODO Can we just avoid generating the unused filename in the first place? let last_step = steps.last_mut().expect("no steps"); - last_step.1 = relative_path(&end_file, &req.workdir); + last_step.1 = utils::relative_path(&end_file, &req.workdir); false } else { // Print to stdout if the last state is a real (non-pseudo) state. @@ -350,28 +282,6 @@ impl DriverBuilder { } } -/// A request to the Driver directing it what to build. -#[derive(Debug)] -pub struct Request { - /// The input format. - pub start_state: StateRef, - - /// The output format to produce. - pub end_state: StateRef, - - /// The filename to read the input from, or None to read from stdin. - pub start_file: Option, - - /// The filename to write the output to, or None to print to stdout. - pub end_file: Option, - - /// A sequence of operators to route the conversion through. - pub through: Vec, - - /// The working directory for the build. - pub workdir: Utf8PathBuf, -} - #[derive(Debug)] pub struct Plan { /// The input to the first step. diff --git a/fud2/fud-core/src/exec/mod.rs b/fud2/fud-core/src/exec/mod.rs new file mode 100644 index 000000000..48895a4b1 --- /dev/null +++ b/fud2/fud-core/src/exec/mod.rs @@ -0,0 +1,8 @@ +mod data; +mod driver; +mod request; + +pub use data::{OpRef, SetupRef, StateRef}; +pub(super) use data::{Operation, Setup, State}; +pub use driver::{Driver, DriverBuilder, Plan}; +pub use request::Request; diff --git a/fud2/fud-core/src/exec/request.rs b/fud2/fud-core/src/exec/request.rs new file mode 100644 index 000000000..ebde6047e --- /dev/null +++ b/fud2/fud-core/src/exec/request.rs @@ -0,0 +1,24 @@ +use super::{OpRef, StateRef}; +use camino::Utf8PathBuf; + +/// A request to the Driver directing it what to build. +#[derive(Debug)] +pub struct Request { + /// The input format. + pub start_state: StateRef, + + /// The output format to produce. + pub end_state: StateRef, + + /// The filename to read the input from, or None to read from stdin. + pub start_file: Option, + + /// The filename to write the output to, or None to print to stdout. + pub end_file: Option, + + /// A sequence of operators to route the conversion through. + pub through: Vec, + + /// The working directory for the build. + pub workdir: Utf8PathBuf, +} diff --git a/fud2/fud-core/src/lib.rs b/fud2/fud-core/src/lib.rs new file mode 100644 index 000000000..489530a39 --- /dev/null +++ b/fud2/fud-core/src/lib.rs @@ -0,0 +1,7 @@ +pub mod cli; +pub mod config; +pub mod exec; +pub mod run; +pub mod utils; + +pub use exec::{Driver, DriverBuilder}; diff --git a/fud2/fake/src/run.rs b/fud2/fud-core/src/run.rs similarity index 99% rename from fud2/fake/src/run.rs rename to fud2/fud-core/src/run.rs index 780c62f53..c63c65c57 100644 --- a/fud2/fake/src/run.rs +++ b/fud2/fud-core/src/run.rs @@ -1,5 +1,6 @@ use crate::config; -use crate::driver::{relative_path, Driver, OpRef, Plan, SetupRef, StateRef}; +use crate::exec::{Driver, OpRef, Plan, SetupRef, StateRef}; +use crate::utils::relative_path; use camino::{Utf8Path, Utf8PathBuf}; use std::collections::{HashMap, HashSet}; use std::io::Write; diff --git a/fud2/fud-core/src/utils.rs b/fud2/fud-core/src/utils.rs new file mode 100644 index 000000000..0bfcbd67e --- /dev/null +++ b/fud2/fud-core/src/utils.rs @@ -0,0 +1,14 @@ +use camino::{Utf8Path, Utf8PathBuf}; +use pathdiff::diff_utf8_paths; + +/// Get a version of `path` that works when the working directory is `base`. This is +/// opportunistically a relative path, but we can always fall back to an absolute path to make sure +/// the path still works. +pub fn relative_path(path: &Utf8Path, base: &Utf8Path) -> Utf8PathBuf { + match diff_utf8_paths(path, base) { + Some(p) => p, + None => path + .canonicalize_utf8() + .expect("could not get absolute path"), + } +} diff --git a/fud2/src/main.rs b/fud2/src/main.rs index 69da9c974..14c9dba71 100644 --- a/fud2/src/main.rs +++ b/fud2/src/main.rs @@ -1,15 +1,15 @@ -use fake::{ +use fud_core::{ cli, + exec::{SetupRef, StateRef}, run::{EmitResult, Emitter}, Driver, DriverBuilder, }; -fn build_driver() -> Driver { - let mut bld = DriverBuilder::new("fud2"); - - // Calyx. +fn setup_calyx( + bld: &mut DriverBuilder, + verilog: StateRef, +) -> (StateRef, SetupRef) { let calyx = bld.state("calyx", &["futil"]); - let verilog = bld.state("verilog", &["sv", "v"]); let calyx_setup = bld.setup("Calyx compiler", |e| { e.config_var("calyx-base", "calyx.base")?; e.config_var_or( @@ -34,8 +34,13 @@ fn build_driver() -> Driver { Ok(()) }, ); + (calyx, calyx_setup) +} - // Dahlia. +fn setup_dahlia( + bld: &mut DriverBuilder, + calyx: StateRef, +) -> (StateRef, SetupRef) { let dahlia = bld.state("dahlia", &["fuse"]); let dahlia_setup = bld.setup("Dahlia compiler", |e| { e.config_var("dahlia-exe", "dahlia")?; @@ -46,8 +51,13 @@ fn build_driver() -> Driver { Ok(()) }); bld.rule(&[dahlia_setup], dahlia, calyx, "dahlia-to-calyx"); + (dahlia, dahlia_setup) +} - // MrXL. +fn setup_mrxl( + bld: &mut DriverBuilder, + calyx: StateRef, +) -> (StateRef, SetupRef) { let mrxl = bld.state("mrxl", &["mrxl"]); let mrxl_setup = bld.setup("MrXL compiler", |e| { e.var("mrxl-exe", "mrxl")?; @@ -55,6 +65,20 @@ fn build_driver() -> Driver { Ok(()) }); bld.rule(&[mrxl_setup], mrxl, calyx, "mrxl-to-calyx"); + (mrxl, mrxl_setup) +} + +fn build_driver() -> Driver { + let mut bld = DriverBuilder::new("fud2"); + + // The verilog state + let verilog = bld.state("verilog", &["sv", "v"]); + // Calyx. + let (calyx, calyx_setup) = setup_calyx(&mut bld, verilog); + // Dahlia. + setup_dahlia(&mut bld, calyx); + // MrXL. + setup_mrxl(&mut bld, calyx); // Shared machinery for RTL simulators. let dat = bld.state("dat", &["json"]); From e4df5352b9da9405e0cd102f35c7e945045da951 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 4 Feb 2024 18:43:02 +0530 Subject: [PATCH 163/189] Deploy docs on `main` (#1892) --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8562d1041..0eaac9b68 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,7 +6,7 @@ name: Docs website on: push: branches: - - master + - main jobs: playground: From 51de164df32cca286831a85bd046001d6b83564c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 4 Feb 2024 19:23:47 +0530 Subject: [PATCH 164/189] fud2 docs (#1893) --- docs/running-calyx/fud2.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/running-calyx/fud2.md b/docs/running-calyx/fud2.md index d847962a2..4ba2a8d75 100644 --- a/docs/running-calyx/fud2.md +++ b/docs/running-calyx/fud2.md @@ -17,13 +17,19 @@ You might then want to do something like ``ln -s `pwd`/target/debug/fud2 ~/.loca fud2 depends on [Ninja][]. Install it using your OS package manager or by downloading a binary. -Create a configuration file at `~/.config/fud2.toml`, using the path to your checkout of the Calyx git repository: +### Configuration +Run the following command to edit `fud2`'s configuration file (usually `~/.config/fud2.toml`): +``` +fud edit-config +``` + +Add the following fields: ```toml -rsrc = ".../calyx/fud2/rsrc" +rsrc = "/fud2/rsrc" [calyx] -base = ".../calyx" +base = "" ``` Now you're ready to use fud2. From 6fab07043537ef5e481349611797978d84d75d73 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Mon, 5 Feb 2024 03:26:58 -0500 Subject: [PATCH 165/189] Fix tiny typo for fud2 doc (#1895) --- docs/running-calyx/fud2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/running-calyx/fud2.md b/docs/running-calyx/fud2.md index 4ba2a8d75..3a9e74f2a 100644 --- a/docs/running-calyx/fud2.md +++ b/docs/running-calyx/fud2.md @@ -21,7 +21,7 @@ Install it using your OS package manager or by downloading a binary. Run the following command to edit `fud2`'s configuration file (usually `~/.config/fud2.toml`): ``` -fud edit-config +fud2 edit-config ``` Add the following fields: From 99736569458188090cb37f6dcd7122d334e8268f Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:41:52 -0500 Subject: [PATCH 166/189] Move `numeric_types.py` from `fud/verilator` to `calyx-py` (another attempt at #1715 ) (#1719) * refactor numeric types * moved test * changed error location * fix test location --------- Co-authored-by: Rachit Nigam --- .github/workflows/rust.yml | 2 +- calyx-py/calyx/gen_exp.py | 30 +++++++------------ calyx-py/calyx/gen_ln.py | 2 +- calyx-py/calyx/gen_msb.py | 15 ---------- .../calyx}/numeric_types.py | 11 ++++++- .../tests => calyx-py/test}/numeric_types.py | 3 +- frontends/relay/relay_visitor.py | 2 +- frontends/systolic-lang/convert-mems.py | 2 +- .../systolic-lang/gen_array_component.py | 2 +- frontends/systolic-lang/gen_post_op.py | 4 +-- fud/fud/errors.py | 10 ------- fud/fud/stages/interpreter.py | 20 ++++++------- fud/fud/stages/verilator/json_to_dat.py | 4 +-- fud/fud/stages/verilator/tables.py | 2 +- fud/fud/xclrun.py | 25 +++++++++------- 15 files changed, 54 insertions(+), 80 deletions(-) rename {fud/fud/stages/verilator => calyx-py/calyx}/numeric_types.py (98%) rename {fud/fud/stages/verilator/tests => calyx-py/test}/numeric_types.py (97%) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 33c04ab62..747637f01 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -185,7 +185,7 @@ jobs: - name: Run Python Tests working-directory: /home/calyx - run: pytest fud/fud/stages/verilator/tests/numeric_types.py + run: pytest calyx-py/test/numeric_types.py evaluation: name: Polybench Integration diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index 32509d9db..b7d5c7064 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -8,9 +8,8 @@ ) from calyx.utils import float_to_fixed_point from math import factorial, log2 -from fud.stages.verilator import numeric_types +from calyx.numeric_types import FixedPoint from calyx.gen_ln import generate_ln - from calyx.builder import ( Builder, ComponentBuilder, @@ -19,7 +18,6 @@ if_with, invoke, CellBuilder, - ExprBuilder, const, HI, par, @@ -52,7 +50,7 @@ def generate_fp_pow_component( # groups with comp.group("init") as init: - pow.in_ = numeric_types.FixedPoint( + pow.in_ = FixedPoint( "1.0", width, int_width, is_signed=is_signed ).unsigned_integer() pow.write_en = 1 @@ -105,14 +103,12 @@ def generate_cells( comp.const( "one", width, - numeric_types.FixedPoint( - "1.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) comp.const( "e", width, - numeric_types.FixedPoint( + FixedPoint( str(float_to_fixed_point(2.7182818284, frac_width)), width, int_width, @@ -124,7 +120,7 @@ def generate_cells( comp.const( "negative_one", width, - numeric_types.FixedPoint( + FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) @@ -168,7 +164,7 @@ def generate_cells( # reciprocal factorials for i in range(2, degree + 1): fixed_point_value = float_to_fixed_point(1.0 / factorial(i), frac_width) - value = numeric_types.FixedPoint( + value = FixedPoint( str(fixed_point_value), width, int_width, is_signed=is_signed ).unsigned_integer() comp.const(f"reciprocal_factorial{i}", width, value) @@ -540,9 +536,7 @@ def gen_constant_cell( return comp.const( name, width, - numeric_types.FixedPoint( - value, width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint(value, width, int_width, is_signed=is_signed).unsigned_integer(), ) @@ -571,16 +565,12 @@ def generate_fp_pow_full( const_one = comp.const( "one", width, - numeric_types.FixedPoint( - "1.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("1.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) const_zero = comp.const( "zero", width, - numeric_types.FixedPoint( - "0.0", width, int_width, is_signed=is_signed - ).unsigned_integer(), + FixedPoint("0.0", width, int_width, is_signed=is_signed).unsigned_integer(), ) mult = comp.cell( "mult", @@ -597,7 +587,7 @@ def generate_fp_pow_full( const_neg_one = comp.const( "neg_one", width, - numeric_types.FixedPoint( + FixedPoint( "-1.0", width, int_width, is_signed=is_signed ).unsigned_integer(), ) diff --git a/calyx-py/calyx/gen_ln.py b/calyx-py/calyx/gen_ln.py index 209813e42..e6c60b474 100644 --- a/calyx-py/calyx/gen_ln.py +++ b/calyx-py/calyx/gen_ln.py @@ -6,7 +6,7 @@ Import, ) from calyx.utils import float_to_fixed_point -from fud.stages.verilator import numeric_types +from calyx import numeric_types from calyx.gen_msb import gen_msb_calc from calyx.builder import Builder, ComponentBuilder, CellBuilder, HI, par, invoke diff --git a/calyx-py/calyx/gen_msb.py b/calyx-py/calyx/gen_msb.py index d86481ad5..8f7ae5e15 100644 --- a/calyx-py/calyx/gen_msb.py +++ b/calyx-py/calyx/gen_msb.py @@ -1,26 +1,11 @@ from typing import List from calyx.py_ast import ( - Connect, - CompVar, - Cell, - Group, - ConstantPort, - CompPort, Stdlib, Component, - ThisPort, - HolePort, - PortDef, - SeqComp, - Enable, - While, - Control, - CombGroup, ) from calyx.builder import ( Builder, CellAndGroup, - ComponentBuilder, const, HI, while_with, diff --git a/fud/fud/stages/verilator/numeric_types.py b/calyx-py/calyx/numeric_types.py similarity index 98% rename from fud/fud/stages/verilator/numeric_types.py rename to calyx-py/calyx/numeric_types.py index 5d6fca493..da5c901ed 100644 --- a/fud/fud/stages/verilator/numeric_types.py +++ b/calyx-py/calyx/numeric_types.py @@ -5,11 +5,20 @@ from fractions import Fraction from dataclasses import dataclass from decimal import Decimal, getcontext -from fud.errors import InvalidNumericType import math import logging as log +class InvalidNumericType(Exception): + """ + An error raised when an invalid numeric type is provided. + """ + + def __init__(self, msg): + msg = f"""Invalid Numeric Type: {msg}""" + super().__init__(msg) + + @dataclass class NumericType: """Interface for a numeric type. diff --git a/fud/fud/stages/verilator/tests/numeric_types.py b/calyx-py/test/numeric_types.py similarity index 97% rename from fud/fud/stages/verilator/tests/numeric_types.py rename to calyx-py/test/numeric_types.py index b4d4d445d..b48e6d2d8 100644 --- a/fud/fud/stages/verilator/tests/numeric_types.py +++ b/calyx-py/test/numeric_types.py @@ -1,6 +1,5 @@ from random import randint -from fud.stages.verilator.numeric_types import FixedPoint, Bitnum -from fud.errors import InvalidNumericType +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from hypothesis import given, strategies as st # type: ignore import numpy as np import pytest # type: ignore diff --git a/frontends/relay/relay_visitor.py b/frontends/relay/relay_visitor.py index 6ccc36282..be4b0ac34 100755 --- a/frontends/relay/relay_visitor.py +++ b/frontends/relay/relay_visitor.py @@ -24,7 +24,7 @@ Component, ) from calyx.utils import float_to_fixed_point -from fud.stages.verilator import numeric_types +from calyx import numeric_types from dahlia_impl import emit_components calyx_keywords_list = ["input"] diff --git a/frontends/systolic-lang/convert-mems.py b/frontends/systolic-lang/convert-mems.py index 22af8aaf4..2d6c09905 100644 --- a/frontends/systolic-lang/convert-mems.py +++ b/frontends/systolic-lang/convert-mems.py @@ -1,6 +1,6 @@ import argparse import json -from fud.stages.verilator import numeric_types +from calyx import numeric_types if __name__ == "__main__": diff --git a/frontends/systolic-lang/gen_array_component.py b/frontends/systolic-lang/gen_array_component.py index 76f09ae39..3910b6f77 100644 --- a/frontends/systolic-lang/gen_array_component.py +++ b/frontends/systolic-lang/gen_array_component.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from gen_pe import pe, PE_NAME, BITWIDTH -import calyx.builder as cb +from calyx import builder as cb from calyx import py_ast from calyx.utils import bits_needed from systolic_arg_parser import SystolicConfiguration diff --git a/frontends/systolic-lang/gen_post_op.py b/frontends/systolic-lang/gen_post_op.py index 206c39332..702f5efb9 100644 --- a/frontends/systolic-lang/gen_post_op.py +++ b/frontends/systolic-lang/gen_post_op.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import calyx.builder as cb +from calyx import builder as cb from calyx import py_ast from gen_array_component import NAME_SCHEME from gen_pe import BITWIDTH, INTWIDTH, FRACWIDTH -from fud.stages.verilator import numeric_types +from calyx import numeric_types from calyx.utils import float_to_fixed_point from systolic_arg_parser import SystolicConfiguration from calyx.utils import bits_needed diff --git a/fud/fud/errors.py b/fud/fud/errors.py index 96e7f0b35..e29911408 100644 --- a/fud/fud/errors.py +++ b/fud/fud/errors.py @@ -255,16 +255,6 @@ def __init__(self, path): super().__init__(msg) -class InvalidNumericType(FudError): - """ - An error raised when an invalid numeric type is provided. - """ - - def __init__(self, msg): - msg = f"""Invalid Numeric Type: {msg}""" - super().__init__(msg) - - class Malformed(FudError): """ An error raised when the input to a stage is malformed in some manner. diff --git a/fud/fud/stages/interpreter.py b/fud/fud/stages/interpreter.py index 7a9b65130..9eca39b99 100644 --- a/fud/fud/stages/interpreter.py +++ b/fud/fud/stages/interpreter.py @@ -3,8 +3,7 @@ from pathlib import Path import simplejson as sjson import numpy as np -from fud.stages.verilator.numeric_types import FixedPoint, Bitnum -from fud.errors import InvalidNumericType +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed from fud.utils import shell, TmpDir, unwrap_or, transparent_shell from fud import config as cfg @@ -88,8 +87,9 @@ def _is_data_converter(self): def _define_steps(self, input_data, builder, config): script = config["stages", self.name, "exec"] - data_path_exists: bool = (config["stages", "verilog", "data"] or - config.get(["stages", "mrxl", "data"])) + data_path_exists: bool = config["stages", "verilog", "data"] or config.get( + ["stages", "mrxl", "data"] + ) cmd = [ script, @@ -118,7 +118,9 @@ def mktmp() -> SourceType.Directory: """ return TmpDir() - @builder.step(description="Dynamically retrieve the value of stages.verilog.data") + @builder.step( + description="Dynamically retrieve the value of stages.verilog.data" + ) def get_verilog_data() -> SourceType.Path: data_path = config.get(["stages", "verilog", "data"]) path = Path(data_path) if data_path else None @@ -197,9 +199,7 @@ def parse_output( data_path = get_verilog_data() if data_path_exists: - convert_json_to_interp_json( - tmpdir, data_path - ) + convert_json_to_interp_json(tmpdir, data_path) if self._is_data_converter(): if data_path_exists: @@ -213,9 +213,7 @@ def parse_output( result = interpret(input_data, tmpdir) if "--raw" in cmd: - return parse_output( - result, data_path, tmpdir - ) + return parse_output(result, data_path, tmpdir) else: return result diff --git a/fud/fud/stages/verilator/json_to_dat.py b/fud/fud/stages/verilator/json_to_dat.py index f74f86190..a988f62ff 100644 --- a/fud/fud/stages/verilator/json_to_dat.py +++ b/fud/fud/stages/verilator/json_to_dat.py @@ -1,8 +1,8 @@ import simplejson as sjson import numpy as np -from .numeric_types import FixedPoint, Bitnum +from calyx.numeric_types import FixedPoint, Bitnum, InvalidNumericType from pathlib import Path -from fud.errors import InvalidNumericType, Malformed +from fud.errors import Malformed import logging as log diff --git a/fud/fud/stages/verilator/tables.py b/fud/fud/stages/verilator/tables.py index eae5c6241..e802a90ed 100644 --- a/fud/fud/stages/verilator/tables.py +++ b/fud/fud/stages/verilator/tables.py @@ -1,6 +1,6 @@ from itertools import product from decimal import Decimal -from fud.stages.verilator.numeric_types import FixedPoint +from calyx.numeric_types import FixedPoint def compute_exp_frac_table(frac_width: int): diff --git a/fud/fud/xclrun.py b/fud/fud/xclrun.py index 7141a0c4d..67fbda642 100644 --- a/fud/fud/xclrun.py +++ b/fud/fud/xclrun.py @@ -36,7 +36,7 @@ from typing import Mapping, Any, Dict from pathlib import Path from fud.stages.verilator.json_to_dat import parse_fp_widths, float_to_fixed -from fud.errors import InvalidNumericType +from calyx.numeric_types import InvalidNumericType def mem_to_buf(mem): @@ -96,8 +96,9 @@ def run(xclbin: Path, data: Mapping[str, Any]) -> Dict[str, Any]: # Collect the output data. for buf in buffers: buf.sync_from_device() - mems = {name: buf_to_mem(data[name]["format"], buf) - for name, buf in zip(data, buffers)} + mems = { + name: buf_to_mem(data[name]["format"], buf) for name, buf in zip(data, buffers) + } # PYNQ recommends explicitly freeing its resources. del buffers @@ -118,14 +119,16 @@ def _dtype(fmt) -> np.dtype: def xclrun(): # Parse command-line arguments. parser = argparse.ArgumentParser( - description='run a compiled XRT program', + description="run a compiled XRT program", + ) + parser.add_argument("bin", metavar="XCLBIN", help="the .xclbin binary file to run") + parser.add_argument("data", metavar="DATA", help="the JSON input data file") + parser.add_argument( + "--out", + "-o", + metavar="FILE", + help="write JSON results to a file instead of stdout", ) - parser.add_argument('bin', metavar='XCLBIN', - help='the .xclbin binary file to run') - parser.add_argument('data', metavar='DATA', - help='the JSON input data file') - parser.add_argument('--out', '-o', metavar='FILE', - help='write JSON results to a file instead of stdout') args = parser.parse_args() # Load the input JSON data file. @@ -136,7 +139,7 @@ def xclrun(): out_data = run(Path(args.bin), in_data) # Dump the output JSON data. - outfile = open(args.out, 'w') if args.out else sys.stdout + outfile = open(args.out, "w") if args.out else sys.stdout sjson.dump(out_data, outfile, indent=2, use_decimal=True) From 5f262c373a98adf42d66dcd7e3e15cceecf37b87 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 6 Feb 2024 12:17:56 +0530 Subject: [PATCH 167/189] Remove versions/ folder (#1900) --- versions/tvm | 1 - versions/verilator | 1 - 2 files changed, 2 deletions(-) delete mode 100644 versions/tvm delete mode 100644 versions/verilator diff --git a/versions/tvm b/versions/tvm deleted file mode 100644 index 366579d26..000000000 --- a/versions/tvm +++ /dev/null @@ -1 +0,0 @@ -v0.10.dev0 \ No newline at end of file diff --git a/versions/verilator b/versions/verilator deleted file mode 100644 index 246f76ff1..000000000 --- a/versions/verilator +++ /dev/null @@ -1 +0,0 @@ -v4.026-92-g890cecc1 \ No newline at end of file From a7a109d714244fd082b2bc24891b5499a684f5cb Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 6 Feb 2024 20:09:59 +0530 Subject: [PATCH 168/189] Reorganize memories in primitives (#1901) * move std_mem and seq_mem to separate folder * rename `std_mem_*` to `comb_mem_*` * use pinned commit in Dahlia repo within Dockerfile * run command in repo dir * reorder deps * Disable Dahlia update * upd tests --- .github/workflows/rust.yml | 18 - Dockerfile | 10 +- benches/component-sharing/gemm2.futil | 23 +- benches/component-sharing/gemm3.futil | 37 +- benches/component-sharing/gemm4.futil | 55 +- benches/component-sharing/gemm6.futil | 103 ++-- benches/component-sharing/gemm8.futil | 167 +++---- calyx-backend/src/mlir.rs | 8 +- calyx-backend/src/resources.rs | 8 +- calyx-backend/src/verilog.rs | 4 +- calyx-backend/src/xilinx/toplevel.rs | 4 +- calyx-ir/src/utils.rs | 8 +- calyx-opt/src/passes/externalize.rs | 2 +- calyx-opt/src/passes/synthesis_papercut.rs | 9 +- calyx-py/calyx/builder.py | 19 +- calyx-py/calyx/gen_exp.py | 50 +- calyx-py/calyx/gen_ln.py | 4 +- calyx-py/calyx/py_ast.py | 64 +-- calyx-py/test/correctness/arbiter_6.py | 14 +- calyx-py/test/correctness/reduction_tree.py | 5 +- calyx-stdlib/src/primitives.rs | 8 +- docs/lang/attributes.md | 6 +- docs/lang/data-format.md | 6 +- docs/lang/memories-by-reference.md | 24 +- docs/lang/ref.md | 10 +- docs/libraries/core.md | 8 +- docs/running-calyx/fud/resource-estimation.md | 2 +- docs/tutorial/frontend-tut.md | 6 +- docs/tutorial/language-tut.md | 4 +- docs/tutorial/sos.calyx | 6 +- examples/futil/dot-product.expect | 7 +- examples/futil/dot-product.futil | 7 +- .../memory-by-reference.futil | 3 +- examples/futil/multi-component.expect | 1 + examples/futil/multi-component.futil | 1 + examples/futil/pass-in-register.expect | 1 + examples/futil/pass-in-register.futil | 1 + examples/futil/simple.expect | 1 + examples/futil/simple.futil | 1 + examples/futil/vectorized-add.expect | 7 +- examples/futil/vectorized-add.futil | 7 +- examples/sync/sync-doc-example.futil | 5 +- examples/sync/sync-if.futil | 7 +- examples/sync/sync-t-w-t-r.futil | 11 +- examples/sync/sync-two-writers.futil | 11 +- examples/sync/sync.futil | 5 +- .../unsync-example/unsync-doc-example.futil | 3 +- .../tutorial/language-tutorial-compute.futil | 3 +- .../tutorial/language-tutorial-control.futil | 3 +- .../tutorial/language-tutorial-iterate.futil | 3 +- examples/tutorial/language-tutorial-mem.futil | 3 +- frontends/mrxl/mrxl/gen_calyx.py | 8 +- .../mrxl/test/expect/futil_out/add.expect | 12 +- .../mrxl/test/expect/futil_out/dot.expect | 8 +- .../mrxl/test/expect/futil_out/prod.expect | 4 +- .../mrxl/test/expect/futil_out/sos.expect | 6 +- .../mrxl/test/expect/futil_out/squares.expect | 8 +- .../mrxl/test/expect/futil_out/sum.expect | 4 +- frontends/ntt-pipeline/gen-ntt-pipeline.py | 9 +- frontends/relay/onnx_to_calyx.py | 8 +- frontends/relay/relay_utils.py | 4 +- frontends/relay/relay_visitor.py | 2 +- frontends/systolic-lang/gen-systolic.py | 2 +- frontends/systolic-lang/pe/mac.futil | 1 + fud2/rsrc/primitives-for-firrtl.sv | 4 +- interp/src/flatten/flat_ir/cell_prototype.rs | 16 +- interp/src/structures/environment.rs | 8 +- interp/src/tests/primitives.rs | 8 +- interp/tests/complex/unsigned-div.futil | 13 +- .../tests/complex/unsigned-dot-product.futil | 7 +- interp/tests/control/if.futil | 7 +- interp/tests/control/if_reg.futil | 5 +- interp/tests/control/invoke/invoke.futil | 3 +- interp/tests/control/invoke/k3.futil | 5 +- .../tests/control/iteration/iter_mult.futil | 1 + interp/tests/control/iteration/while.futil | 3 +- interp/tests/control/par_mem.futil | 7 +- interp/tests/control/par_reg.futil | 1 + interp/tests/control/reg_seq.futil | 1 + .../tests/control/static/while_static.futil | 1 + .../tests/errors/multiple_drivers_comb.futil | 1 + .../tests/errors/multiple_drivers_reg.futil | 1 + interp/tests/primitives/add-overflow.futil | 15 +- interp/tests/primitives/binary.futil | 1 + interp/tests/primitives/flickering_go.futil | 19 +- interp/tests/primitives/mem.futil | 3 +- interp/tests/primitives/mem2.futil | 17 +- interp/tests/primitives/reg.futil | 9 +- interp/tests/primitives/slice.futil | 1 + .../unit/assign-order-does-not-matter.futil | 1 + interp/tests/unit/combinational-chain.futil | 1 + ...register-writes-visible-inside-group.futil | 1 + .../uninitialized-port-returns-zero.futil | 1 + primitives/core.futil | 67 --- primitives/core.sv | 238 --------- primitives/memories/comb.futil | 73 +++ primitives/memories/comb.sv | 237 +++++++++ .../{memories.futil => memories/seq.futil} | 3 +- primitives/{memories.sv => memories/seq.sv} | 2 +- tests/backend/firrtl/basic-cell.futil | 1 + tests/backend/firrtl/primitive-cells.futil | 1 + tests/backend/mlir/attributes.futil | 1 + tests/backend/mlir/no-guards.futil | 5 +- tests/backend/mlir/simple.futil | 1 + tests/backend/mlir/with-guards.futil | 13 +- .../memory-with-external-attribute.expect | 470 +++++++++--------- .../memory-with-external-attribute.futil | 5 +- tests/backend/yxi/dot-product.futil | 7 +- tests/backend/yxi/seq-mem-d4-add.futil | 67 +-- .../infer-comp-latency.futil | 31 +- .../group-static-promotion/seq.futil | 4 +- .../if-static-different-latencies.futil | 3 +- tests/correctness/if.futil | 3 +- tests/correctness/inlining.futil | 11 +- tests/correctness/invoke-memory.futil | 5 +- tests/correctness/invoke-with.futil | 3 +- tests/correctness/invoke.futil | 3 +- tests/correctness/new_fsm.futil | 3 +- .../bitnum/binary-operators.futil | 29 +- .../numeric-types/bitnum/sqrt.futil | 9 +- .../numeric-types/bitnum/std-sdiv.futil | 9 +- .../fixed-point/binary-operators.futil | 29 +- .../numeric-types/fixed-point/constants.futil | 3 +- .../numeric-types/fixed-point/sqrt.futil | 9 +- .../fixed-point/std-fp-sdiv.futil | 9 +- .../numeric-types/parsing/signed-bitnum.futil | 3 +- .../numeric-types/parsing/signed-fp.futil | 3 +- .../parsing/unsigned-bitnum.futil | 3 +- .../numeric-types/parsing/unsigned-fp.futil | 3 +- tests/correctness/par.futil | 7 +- tests/correctness/pipelined-mac.futil | 13 +- tests/correctness/pow.futil | 7 +- .../ref-cells/dot-product-ref.futil | 15 +- .../correctness/ref-cells/higher-order.futil | 3 +- tests/correctness/ref-cells/invoke.futil | 5 +- tests/correctness/ref-cells/ref.futil | 5 +- tests/correctness/seq-mem-d4-add.futil | 69 +-- tests/correctness/seq-mem-dot-product.futil | 3 +- tests/correctness/seq.futil | 5 +- .../static-control/bounded-while.futil | 3 +- .../static-control/fixup-necessary.futil | 3 +- .../correctness/static-control/if-start.futil | 9 +- .../nested-one-cycle-body.futil | 3 +- .../static-control/nested-static-while.futil | 9 +- .../static-control/nested-while.futil | 3 +- .../static-control/seq-component-chain.futil | 7 +- .../static-control/static-island.futil | 29 +- .../static-mult-dot-product.futil | 7 +- .../static-control/three-cycles.futil | 3 +- tests/correctness/static-control/while.futil | 5 +- .../static-interface-promoted-one-cycle.futil | 3 +- .../static-interface-promoted.futil | 3 +- .../static-interface-repeat.futil | 3 +- .../static-interface/static-interface.futil | 3 +- .../static-islands/par-static-islands.futil | 17 +- .../static-islands/seq-mem-dot-product.futil | 3 +- .../sync/sync-dot-product-opt.futil | 7 +- tests/correctness/sync/sync-dot-product.futil | 7 +- tests/correctness/sync/sync-if-asym.futil | 15 +- tests/correctness/sync/sync-if.futil | 7 +- tests/correctness/sync/sync-simple.futil | 3 +- .../correctness/sync/sync-three-threads.futil | 3 +- .../correctness/sync/sync-two-barriers.futil | 7 +- tests/correctness/sync/sync-while.futil | 3 +- tests/correctness/tcam/lpm.futil | 3 +- tests/correctness/tcam/no-matches.futil | 3 +- tests/correctness/while.futil | 3 +- tests/errors/comb-component-groups.expect | 2 +- tests/errors/comb-component-groups.futil | 1 + tests/errors/comb-component.expect | 4 +- tests/errors/comb-component.futil | 3 +- tests/errors/comb-group-in-control.expect | 2 +- tests/errors/comb-group-in-control.futil | 1 + tests/errors/comb-port-in-condition.expect | 4 +- tests/errors/comb-port-in-condition.futil | 1 + tests/errors/comb-static-comp.expect | 4 +- tests/errors/comb-static-comp.futil | 1 + tests/errors/duplicate-cells.expect | 4 +- tests/errors/duplicate-cells.futil | 1 + tests/errors/group-comb-conflict.expect | 6 +- tests/errors/group-comb-conflict.futil | 1 + .../errors/group-cont-assign-conflict.expect | 6 +- tests/errors/group-cont-assign-conflict.futil | 1 + tests/errors/if-cond-conflict.expect | 6 +- tests/errors/if-cond-conflict.futil | 1 + tests/errors/insufficient-params.expect | 2 +- tests/errors/insufficient-params.futil | 1 + tests/errors/invoke-undefined-port.expect | 2 +- tests/errors/invoke-undefined-port.futil | 1 + tests/errors/mem-only-reads.futil | 3 +- tests/errors/mismatch-widths.expect | 2 +- tests/errors/mismatch-widths.futil | 1 + tests/errors/multiple-attr-vals.expect | 4 +- tests/errors/multiple-attr-vals.futil | 1 + tests/errors/multiple-done.expect | 2 +- tests/errors/multiple-done.futil | 1 + tests/errors/no-drive.expect | 2 +- tests/errors/no-drive.futil | 1 + tests/errors/non-entrypoint-external.expect | 2 +- tests/errors/non-entrypoint-external.futil | 1 + tests/errors/obvious-conflict.expect | 4 +- tests/errors/obvious-conflict.futil | 1 + tests/errors/orphan-done.futil | 1 + .../papercut/cell-and-group-conflict.expect | 6 +- .../papercut/cell-and-group-conflict.futil | 1 + tests/errors/papercut/cell-as-group.expect | 4 +- tests/errors/papercut/cell-as-group.futil | 1 + tests/errors/papercut/multi-done.futil | 2 +- .../errors/papercut/no-control-no-done.futil | 3 +- tests/errors/papercut/no-done.expect | 2 +- tests/errors/papercut/no-done.futil | 1 + .../papercut/read-missing-write-comb.expect | 4 +- .../papercut/read-missing-write-comb.futil | 3 +- .../errors/papercut/read-missing-write.expect | 4 +- .../errors/papercut/read-missing-write.futil | 3 +- tests/errors/redefine-external.futil | 1 + tests/errors/reserved-name.expect | 2 +- tests/errors/reserved-name.futil | 1 + tests/errors/runtime/multiple-drivers.futil | 15 +- tests/errors/while-unstable.expect | 3 +- tests/errors/while-unstable.futil | 11 +- tests/frontend/dahlia/binop_tree.expect | 2 +- tests/frontend/dahlia/combine.expect | 2 +- tests/frontend/dahlia/dot-func.expect | 2 +- tests/frontend/dahlia/fixed-point-add.expect | 2 +- tests/frontend/dahlia/for.expect | 2 +- tests/frontend/dahlia/if.expect | 2 +- tests/frontend/dahlia/invoke-memory.expect | 2 +- tests/frontend/dahlia/invoke.expect | 2 +- .../frontend/dahlia/matadd-fixed-point.expect | 2 +- tests/frontend/dahlia/memory.expect | 2 +- tests/frontend/dahlia/par.expect | 2 +- tests/frontend/dahlia/seq.expect | 2 +- .../frontend/dahlia/signed_dotproduct.expect | 2 +- tests/frontend/dahlia/unroll.expect | 2 +- tests/frontend/exp/degree-2-unsigned.expect | 5 +- tests/frontend/exp/degree-4-signed.expect | 5 +- tests/frontend/exp/degree-4-unsigned.expect | 5 +- .../ntt-pipeline/ntt-4-reduced-2.expect | 5 +- tests/frontend/ntt-pipeline/ntt-4.expect | 5 +- .../batch_flatten-same-dimensions.expect | 2 +- tests/frontend/relay/batch_flatten.expect | 2 +- tests/frontend/relay/batch_matmul.expect | 2 +- tests/frontend/relay/bias_add.expect | 2 +- tests/frontend/relay/broadcast.expect | 2 +- tests/frontend/relay/constant-multiply.expect | 2 +- tests/frontend/relay/conv2d.expect | 2 +- tests/frontend/relay/dense.expect | 2 +- .../relay/duplicate-relay-call.expect | 2 +- tests/frontend/relay/max_pool2d.expect | 2 +- tests/frontend/relay/negative.expect | 2 +- tests/frontend/relay/relu.expect | 2 +- tests/frontend/relay/reshape.expect | 2 +- tests/frontend/relay/softmax.expect | 2 +- tests/frontend/relay/sqrt.expect | 2 +- tests/frontend/relay/tensor_add.expect | 2 +- tests/frontend/systolic/array-1.expect | 7 +- tests/import/a.expect | 10 +- tests/import/a.futil | 1 + tests/import/b.futil | 1 + tests/import/c.futil | 1 + tests/parsing/guards.expect | 5 +- tests/passes/attr-promotion.expect | 1 + tests/passes/attr-promotion.futil | 13 +- tests/passes/canonical/comb-path.expect | 1 + tests/passes/canonical/comb-path.futil | 1 + .../canonical/combinational-cycle.futil | 1 + tests/passes/canonical/dataflow-order.expect | 1 + tests/passes/canonical/dataflow-order.futil | 1 + tests/passes/canonical/group-done.expect | 1 + tests/passes/canonical/group-done.futil | 13 +- tests/passes/canonical/guard-dataflow.expect | 1 + tests/passes/canonical/guard-dataflow.futil | 1 + tests/passes/canonical/guard.expect | 3 +- tests/passes/canonical/guard.futil | 3 +- tests/passes/cell-share/bounded.expect | 1 + tests/passes/cell-share/bounded.futil | 1 + tests/passes/cell-share/calyx_2020.expect | 1 + tests/passes/cell-share/calyx_2020.futil | 1 + .../cell-share/comb-groups-invoke.expect | 1 + .../cell-share/comb-groups-invoke.futil | 17 +- .../passes/cell-share/comb-groups-regs.expect | 1 + .../passes/cell-share/comb-groups-regs.futil | 61 +-- tests/passes/cell-share/cond-port.expect | 1 + tests/passes/cell-share/cond-port.futil | 1 + .../cell-share/condition-register.expect | 1 + .../cell-share/condition-register.futil | 1 + .../continuous-assign-no-groups.expect | 1 + .../continuous-assign-no-groups.futil | 1 + .../cell-share/continuous-assignment.expect | 1 + .../cell-share/continuous-assignment.futil | 1 + tests/passes/cell-share/empty-invoke.expect | 3 +- tests/passes/cell-share/empty-invoke.futil | 3 +- .../passes/cell-share/escape-boundary.expect | 1 + tests/passes/cell-share/escape-boundary.futil | 1 + tests/passes/cell-share/ignore_done.expect | 1 + tests/passes/cell-share/ignore_done.futil | 1 + tests/passes/cell-share/inline.expect | 3 +- tests/passes/cell-share/inline.futil | 3 +- tests/passes/cell-share/invoke.expect | 1 + tests/passes/cell-share/invoke.futil | 1 + .../cell-share/live-register-analysis.expect | 7 +- .../cell-share/live-register-analysis.futil | 7 +- .../passes/cell-share/multiple-adders.expect | 1 + tests/passes/cell-share/multiple-adders.futil | 1 + tests/passes/cell-share/nested-par.expect | 1 + tests/passes/cell-share/nested-par.futil | 1 + tests/passes/cell-share/par-if-while.expect | 1 + tests/passes/cell-share/par-if-while.futil | 51 +- tests/passes/cell-share/par-if.expect | 1 + tests/passes/cell-share/par-if.futil | 31 +- .../cell-share/par-invoke-adders.expect | 1 + .../passes/cell-share/par-invoke-adders.futil | 5 +- tests/passes/cell-share/par-invoke.expect | 1 + tests/passes/cell-share/par-invoke.futil | 3 +- tests/passes/cell-share/par-seq.expect | 1 + tests/passes/cell-share/par-seq.futil | 37 +- tests/passes/cell-share/par-seq2.expect | 1 + tests/passes/cell-share/par-seq2.futil | 35 +- .../cell-share/par-while-liveness.expect | 13 +- .../cell-share/par-while-liveness.futil | 13 +- tests/passes/cell-share/par-write.expect | 1 + tests/passes/cell-share/par-write.futil | 1 + tests/passes/cell-share/repeat.expect | 1 + tests/passes/cell-share/repeat.futil | 35 +- tests/passes/cell-share/seq-invoke.expect | 1 + tests/passes/cell-share/seq-invoke.futil | 3 +- tests/passes/cell-share/share-adders.expect | 1 + tests/passes/cell-share/share-adders.futil | 1 + tests/passes/cell-share/share-comp.expect | 1 + tests/passes/cell-share/share-comp.futil | 17 +- tests/passes/cell-share/share-mult.expect | 5 +- tests/passes/cell-share/share-mult.futil | 9 +- .../passes/cell-share/simple-liveness.expect | 1 + tests/passes/cell-share/simple-liveness.futil | 1 + tests/passes/cell-share/static-par.expect | 1 + tests/passes/cell-share/static-par.futil | 1 + tests/passes/cell-share/thread-local.expect | 1 + tests/passes/cell-share/thread-local.futil | 1 + tests/passes/cell-share/while-no-share.expect | 1 + tests/passes/cell-share/while-no-share.futil | 21 +- .../cell-share/while-write-guard.expect | 1 + .../passes/cell-share/while-write-guard.futil | 23 +- tests/passes/clk-insertion.expect | 1 + tests/passes/clk-insertion.futil | 1 + tests/passes/comb-prop/comb-prop.expect | 1 + tests/passes/comb-prop/comb-prop.futil | 7 +- tests/passes/comb-prop/inline-write.expect | 1 + tests/passes/comb-prop/inline-write.futil | 1 + .../multiple-reads-from-write.expect | 1 + .../comb-prop/multiple-reads-from-write.futil | 1 + tests/passes/comb-prop/visible-write.expect | 1 + tests/passes/comb-prop/visible-write.futil | 1 + tests/passes/compile-empty.expect | 1 + tests/passes/compile-empty.futil | 1 + .../compile-invoke/compile-invoke.expect | 1 + .../compile-invoke/compile-invoke.futil | 1 + .../compile-static-invoke.expect | 1 + .../compile-static-invoke.futil | 1 + tests/passes/compile-invoke/static-ref.expect | 3 +- tests/passes/compile-invoke/static-ref.futil | 5 +- tests/passes/compile-repeat/nested.expect | 1 + tests/passes/compile-repeat/nested.futil | 9 +- tests/passes/compile-repeat/simple.expect | 1 + tests/passes/compile-repeat/simple.futil | 19 +- .../compile-static-interface-one-cycle.expect | 1 + .../compile-static-interface-one-cycle.futil | 1 + .../compile-static-interface-repeat.expect | 1 + .../compile-static-interface-repeat.futil | 1 + tests/passes/compile-static-interface.expect | 1 + tests/passes/compile-static-interface.futil | 1 + .../compile-static/rewrite-group-go.expect | 1 + .../compile-static/rewrite-group-go.futil | 27 +- .../rewrite-static-while-nested.expect | 3 +- .../rewrite-static-while-nested.futil | 11 +- .../rewrite-static-while.expect | 1 + .../compile-static/rewrite-static-while.futil | 7 +- .../compile-static/separate-fsms.expect | 1 + .../passes/compile-static/separate-fsms.futil | 13 +- .../sync-simple.expect | 3 +- .../sync-simple.futil | 3 +- .../compile-sync/compile-sync-if-asym.expect | 7 +- .../compile-sync/compile-sync-if-asym.futil | 7 +- .../compile-sync/compile-sync-if.expect | 7 +- .../passes/compile-sync/compile-sync-if.futil | 7 +- .../compile-sync/compile-sync-nested.expect | 3 +- .../compile-sync/compile-sync-nested.futil | 5 +- .../compile-sync/compile-sync-no-sync.expect | 1 + .../compile-sync/compile-sync-no-sync.futil | 1 + .../compile-sync/compile-sync-simple.expect | 3 +- .../compile-sync/compile-sync-simple.futil | 5 +- .../compile-sync-two-barriers.expect | 3 +- .../compile-sync-two-barriers.futil | 5 +- tests/passes/compile-sync/compile-sync.expect | 3 +- tests/passes/compile-sync/compile-sync.futil | 5 +- .../passes/dead-assign-removal/simple.expect | 1 + tests/passes/dead-assign-removal/simple.futil | 1 + .../dead-assign-removal/unused-cont.expect | 1 + .../dead-assign-removal/unused-cont.futil | 1 + .../dead-assign-removal/used-cont.expect | 1 + .../dead-assign-removal/used-cont.futil | 1 + tests/passes/dead-cell-removal.expect | 1 + tests/passes/dead-cell-removal.futil | 1 + tests/passes/dead-group-removal.expect | 1 + tests/passes/dead-group-removal.futil | 1 + tests/passes/discover-external.expect | 9 +- tests/passes/discover-external.futil | 1 + tests/passes/dom-map-static/par-if.expect | 1 + tests/passes/dom-map-static/par-if.futil | 1 + tests/passes/dom-map-static/repeat.expect | 1 + tests/passes/dom-map-static/repeat.futil | 1 + tests/passes/domination-map/blank.expect | 1 + tests/passes/domination-map/blank.futil | 1 + .../passes/domination-map/complex-test.expect | 1 + .../passes/domination-map/complex-test.futil | 1 + tests/passes/domination-map/dyn-repeat.expect | 1 + tests/passes/domination-map/dyn-repeat.futil | 1 + .../domination-map/empty-fbranch.expect | 1 + .../passes/domination-map/empty-fbranch.futil | 1 + .../passes/domination-map/if-dominated.expect | 1 + .../passes/domination-map/if-dominated.futil | 1 + tests/passes/domination-map/nested-seq.expect | 1 + tests/passes/domination-map/nested-seq.futil | 1 + .../domination-map/par-if-nested.expect | 1 + .../passes/domination-map/par-if-nested.futil | 1 + tests/passes/domination-map/static-par.expect | 1 + tests/passes/domination-map/static-par.futil | 1 + .../passes/domination-map/while-nested.expect | 1 + .../passes/domination-map/while-nested.futil | 1 + tests/passes/externalize.expect | 3 +- tests/passes/externalize.futil | 5 +- tests/passes/go-insertion.expect | 1 + tests/passes/go-insertion.futil | 1 + .../multi-go-done-component.expect | 1 + .../multi-go-done-component.futil | 1 + .../passes/group2invoke/multi-go-done.expect | 1 + tests/passes/group2invoke/multi-go-done.futil | 1 + tests/passes/group2invoke/no_transform.expect | 1 + tests/passes/group2invoke/no_transform.futil | 11 +- .../group2invoke/no_transform_simple.expect | 1 + .../group2invoke/no_transform_simple.futil | 1 + tests/passes/group2invoke/transform.expect | 1 + tests/passes/group2invoke/transform.futil | 3 +- tests/passes/group_to_seq/dahlia_mult.expect | 5 +- tests/passes/group_to_seq/dahlia_mult.futil | 5 +- tests/passes/group_to_seq/no_transform.expect | 1 + tests/passes/group_to_seq/no_transform.futil | 13 +- .../group_to_seq/should_transform.expect | 1 + .../group_to_seq/should_transform.futil | 27 +- tests/passes/infer-share-pass/invoke.expect | 1 + tests/passes/infer-share-pass/invoke.futil | 45 +- .../infer-share-pass/maybe-write.expect | 1 + .../passes/infer-share-pass/maybe-write.futil | 21 +- tests/passes/infer-share-pass/par-if.expect | 1 + tests/passes/infer-share-pass/par-if.futil | 85 ++-- .../infer-share-pass/seq-dominate.expect | 1 + .../infer-share-pass/seq-dominate.futil | 57 +-- .../infer-share-pass/simple-dominate.expect | 1 + .../infer-share-pass/simple-dominate.futil | 13 +- .../passes/infer-share-pass/static-par.expect | 1 + .../passes/infer-share-pass/static-par.futil | 19 +- .../user_defined_non_share.expect | 3 +- .../user_defined_non_share.futil | 13 +- tests/passes/infer-share-pass/uses_ref.expect | 3 +- tests/passes/infer-share-pass/uses_ref.futil | 17 +- tests/passes/inliner.expect | 1 + tests/passes/inliner.futil | 1 + tests/passes/inliner/always.expect | 1 + tests/passes/inliner/always.futil | 1 + tests/passes/inliner/invoke_reg.expect | 1 + tests/passes/inliner/invoke_reg.futil | 7 +- tests/passes/inliner/simple.expect | 1 + tests/passes/inliner/simple.futil | 1 + tests/passes/lower-guards.expect | 1 + tests/passes/lower-guards.futil | 1 + tests/passes/merge-assign.expect | 1 + tests/passes/merge-assign.futil | 1 + tests/passes/papercut-multi-done.expect | 2 +- tests/passes/papercut-multi-done.futil | 2 +- tests/passes/par-timing-map/nested-par.expect | 1 + tests/passes/par-timing-map/nested-par.futil | 1 + .../passes/par-timing-map/nested-while.expect | 1 + .../passes/par-timing-map/nested-while.futil | 1 + tests/passes/par-timing-map/simple.expect | 1 + tests/passes/par-timing-map/simple.futil | 1 + .../passes/par-to-seq/ignore-this-comp.expect | 1 + .../passes/par-to-seq/ignore-this-comp.futil | 1 + tests/passes/par-to-seq/no-order.futil | 1 + tests/passes/par-to-seq/reorder.expect | 1 + tests/passes/par-to-seq/reorder.futil | 1 + .../regressions/group-multi-drive.expect | 1 + .../regressions/group-multi-drive.futil | 1 + .../continuous-compaction.expect | 1 + .../continuous-compaction.futil | 1 + .../continuous-no-compaction.expect | 1 + .../continuous-no-compaction.futil | 1 + .../fixup-necessary.expect | 3 +- .../schedule-compaction/fixup-necessary.futil | 3 +- .../schedule-compaction/no-compact.expect | 1 + .../schedule-compaction/no-compact.futil | 1 + .../partial-compaction.expect | 1 + .../partial-compaction.futil | 1 + .../schedule-compaction.expect | 1 + .../schedule-compaction.futil | 1 + .../simplify-static-guards/basic.expect | 1 + .../passes/simplify-static-guards/basic.futil | 1 + .../simplify-static-guards/simplify-or.expect | 1 + .../simplify-static-guards/simplify-or.futil | 1 + .../comb-with-static.expect | 2 +- .../comb-with-static.futil | 1 + .../simplify-with-control/invoke-with.expect | 1 + .../simplify-with-control/invoke-with.futil | 1 + .../simplify-with-control/multi-use.expect | 1 + .../simplify-with-control/multi-use.futil | 1 + .../component.expect | 1 + .../component.futil | 1 + .../static-inference-promotion/groups.expect | 3 +- .../static-inference-promotion/groups.futil | 3 +- .../static-inference-promotion/if-diff.expect | 1 + .../static-inference-promotion/if-diff.futil | 1 + .../if-no-else.expect | 1 + .../if-no-else.futil | 1 + .../static-inference-promotion/invoke.expect | 1 + .../static-inference-promotion/invoke.futil | 1 + .../multi-static.expect | 1 + .../multi-static.futil | 1 + .../no_promote_loop.expect | 1 + .../no_promote_loop.futil | 1 + .../static-inference-promotion/par.expect | 3 +- .../static-inference-promotion/par.futil | 3 +- .../promote-nested.expect | 1 + .../promote-nested.futil | 1 + .../threshold.expect | 1 + .../threshold.futil | 1 + .../upgrade-bound.expect | 1 + .../upgrade-bound.futil | 1 + .../passes/static-inference/component.expect | 1 + tests/passes/static-inference/component.futil | 1 + tests/passes/static-inference/groups.expect | 3 +- tests/passes/static-inference/groups.futil | 3 +- .../passes/static-inference/if-no-else.expect | 1 + .../passes/static-inference/if-no-else.futil | 1 + tests/passes/static-inference/invoke.expect | 1 + tests/passes/static-inference/invoke.futil | 1 + tests/passes/static-inference/par.expect | 3 +- tests/passes/static-inference/par.futil | 3 +- .../static-inference/promote-nested.expect | 1 + .../static-inference/promote-nested.futil | 1 + .../static-inference/promote-repeat.expect | 1 + .../static-inference/promote-repeat.futil | 1 + .../static-inliner/nested-repeat.expect | 1 + .../passes/static-inliner/nested-repeat.futil | 3 +- tests/passes/static-inliner/par-if.expect | 1 + tests/passes/static-inliner/par-if.futil | 9 +- tests/passes/static-inliner/repeat-seq.expect | 1 + tests/passes/static-inliner/repeat-seq.futil | 17 +- .../static-passes/both-passes-promote.expect | 1 + .../static-passes/both-passes-promote.futil | 1 + .../static-promotion/fixup-necessary.expect | 1 + .../static-promotion/fixup-necessary.futil | 1 + tests/passes/tdcc/branch-at-start.futil | 1 + tests/passes/tdcc/empty-exit.futil | 1 + tests/passes/tdcc/if.futil | 1 + tests/passes/tdcc/nested-while.futil | 1 + tests/passes/tdcc/new-fsm-nested.futil | 1 + tests/passes/tdcc/new-fsm-seq.futil | 3 +- tests/passes/tdcc/par.futil | 1 + tests/passes/tdcc/seq-with-same-done.futil | 1 + tests/passes/tdcc/seq.futil | 1 + tests/passes/tdcc/while-if.futil | 1 + tests/passes/tdcc/while.futil | 1 + tests/passes/unroll-bound.expect | 1 + tests/passes/unroll-bound.futil | 1 + tests/passes/unsharing/continuous.expect | 1 + tests/passes/unsharing/continuous.futil | 1 + tests/passes/unsharing/invoke.expect | 1 + tests/passes/unsharing/invoke.futil | 1 + tests/passes/unsharing/unshare-par.expect | 1 + tests/passes/unsharing/unshare-par.futil | 1 + tests/passes/unsharing/unsharing.expect | 1 + tests/passes/unsharing/unsharing.futil | 1 + tests/passes/unsharing/while.expect | 1 + tests/passes/unsharing/while.futil | 1 + .../well-formed/constant-ref-cell.expect | 2 +- .../well-formed/constant-ref-cell.futil | 3 +- .../well-formed/guard-out-of-bounds.expect | 2 +- .../well-formed/guard-out-of-bounds.futil | 3 +- tests/passes/well-formed/main-ref-cell.expect | 2 +- tests/passes/well-formed/main-ref-cell.futil | 1 + .../well-formed/ref-incorrect-name.futil | 1 + .../well-formed/ref-invoke-unmentioned.expect | 2 +- .../well-formed/ref-invoke-unmentioned.futil | 3 +- .../well-formed/ref-type-mismatch.expect | 2 +- .../well-formed/ref-type-mismatch.futil | 1 + tests/passes/wire-inliner.expect | 1 + tests/passes/wire-inliner.futil | 1 + tools/btor2/core/std_mem_d1.btor | 2 +- tools/btor2/core/std_mem_d2.btor | 2 +- tools/btor2/core/std_mem_d3.btor | 2 +- tools/btor2/core/std_mem_d4.btor | 2 +- tools/data_gen/src/main.rs | 10 +- tools/data_gen/tests/all.futil | 13 +- tools/firrtl/templates/std_mem_d1.fir | 2 +- yxi/axi-calyx/axi-combined-calyx.futil | 81 +-- yxi/axi-calyx/axi-reads-calyx.futil | 27 +- yxi/axi-calyx/axi-writes-calyx.futil | 35 +- 606 files changed, 2462 insertions(+), 1960 deletions(-) create mode 100644 primitives/memories/comb.futil create mode 100644 primitives/memories/comb.sv rename primitives/{memories.futil => memories/seq.futil} (94%) rename primitives/{memories.sv => memories/seq.sv} (99%) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 747637f01..5eac5bb9d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -79,12 +79,6 @@ jobs: mkdir -p $HOME/.config cp -r /root/.config/* $HOME/.config - - name: Update Dahlia - working-directory: /home/dahlia - run: | - git pull - sbt "; assembly" - - name: Checkout commit that triggered run working-directory: /home/calyx run: | @@ -136,12 +130,6 @@ jobs: mkdir -p $HOME/.config cp -r /root/.config/* $HOME/.config - - name: Update Dahlia - working-directory: /home/dahlia - run: | - git pull - sbt "; assembly" - - name: Checkout commit that triggered run working-directory: /home/calyx run: | @@ -201,12 +189,6 @@ jobs: mkdir -p $HOME/.config cp -r /root/.config/* $HOME/.config - - name: Update Dahlia - working-directory: /home/dahlia - run: | - git pull - sbt "; assembly" - - name: Checkout commit that triggered run working-directory: /home/calyx run: | diff --git a/Dockerfile b/Dockerfile index d17eb728b..530a656a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,6 +49,8 @@ RUN python3 setup.py bdist_wheel && python3 -m pip install --user dist/tvm-*.whl WORKDIR /home RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia +## Checkout specific version +RUN git checkout a352e60 RUN sbt "; getHeaders; assembly" # Add the Calyx source code from the build context @@ -67,6 +69,10 @@ RUN mkdir -p /root/.config ENV PATH=$PATH:/root/.local/bin ENV PYTHONPATH=/root/.local/lib/python3.9/site-packages:$PYTHONPATH +# Install calyx-py +WORKDIR /home/calyx/calyx-py +RUN FLIT_ROOT_INSTALL=1 flit install --symlink + # Setup fud RUN fud config --create global.root /home/calyx && \ fud config stages.dahlia.exec '/home/dahlia/fuse' && \ @@ -76,10 +82,6 @@ RUN fud config --create global.root /home/calyx && \ fud register mrxl -p '/home/calyx/frontends/mrxl/fud/mrxl.py' && \ fud register icarus-verilog -p '/home/calyx/fud/icarus/icarus.py' -# Install calyx-py -WORKDIR /home/calyx/calyx-py -RUN FLIT_ROOT_INSTALL=1 flit install --symlink - # Install MrXL WORKDIR /home/calyx/frontends/mrxl RUN FLIT_ROOT_INSTALL=1 flit install --symlink diff --git a/benches/component-sharing/gemm2.futil b/benches/component-sharing/gemm2.futil index 375bea747..82ea272a8 100644 --- a/benches/component-sharing/gemm2.futil +++ b/benches/component-sharing/gemm2.futil @@ -1,29 +1,30 @@ // git.status = clean, build.date = Mon Mar 22 14:26:22 EDT 2021, git.hash = 8dd37e4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - A0_0 = std_mem_d2(32,1,2,1,2); - A1_0 = std_mem_d2(32,1,2,1,2); - @external(1) A_int0_0 = std_mem_d2(32,2,2,2,2); + A0_0 = comb_mem_d2(32,1,2,1,2); + A1_0 = comb_mem_d2(32,1,2,1,2); + @external(1) A_int0_0 = comb_mem_d2(32,2,2,2,2); A_int_read0_0 = std_reg(32); A_read0_0_00 = std_reg(32); A_read0_0_10 = std_reg(32); A_read0_1_00 = std_reg(32); A_read0_1_10 = std_reg(32); - B0_0 = std_mem_d2(32,2,1,2,1); - B0_1 = std_mem_d2(32,2,1,2,1); - @external(1) B_int0_0 = std_mem_d2(32,2,2,2,2); + B0_0 = comb_mem_d2(32,2,1,2,1); + B0_1 = comb_mem_d2(32,2,1,2,1); + @external(1) B_int0_0 = comb_mem_d2(32,2,2,2,2); B_int_read0_0 = std_reg(32); B_read0_0_00 = std_reg(32); B_read0_0_10 = std_reg(32); B_read0_1_00 = std_reg(32); B_read0_1_10 = std_reg(32); - C0_0 = std_mem_d2(32,1,1,1,1); - C0_1 = std_mem_d2(32,1,1,1,1); - C1_0 = std_mem_d2(32,1,1,1,1); - C1_1 = std_mem_d2(32,1,1,1,1); - @external(1) C_int0_0 = std_mem_d2(32,2,2,2,2); + C0_0 = comb_mem_d2(32,1,1,1,1); + C0_1 = comb_mem_d2(32,1,1,1,1); + C1_0 = comb_mem_d2(32,1,1,1,1); + C1_1 = comb_mem_d2(32,1,1,1,1); + @external(1) C_int0_0 = comb_mem_d2(32,2,2,2,2); C_int_read0_0 = std_reg(32); C_sh_read0_0 = std_reg(32); add0 = std_add(4); diff --git a/benches/component-sharing/gemm3.futil b/benches/component-sharing/gemm3.futil index 4d2c6593f..0572297e2 100644 --- a/benches/component-sharing/gemm3.futil +++ b/benches/component-sharing/gemm3.futil @@ -1,12 +1,13 @@ // git.status = clean, build.date = Mon Mar 22 14:26:22 EDT 2021, git.hash = 8dd37e4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - A0_0 = std_mem_d2(32,1,3,1,2); - A1_0 = std_mem_d2(32,1,3,1,2); - A2_0 = std_mem_d2(32,1,3,1,2); - @external(1) A_int0_0 = std_mem_d2(32,3,3,2,2); + A0_0 = comb_mem_d2(32,1,3,1,2); + A1_0 = comb_mem_d2(32,1,3,1,2); + A2_0 = comb_mem_d2(32,1,3,1,2); + @external(1) A_int0_0 = comb_mem_d2(32,3,3,2,2); A_int_read0_0 = std_reg(32); A_read0_0_00 = std_reg(32); A_read0_0_10 = std_reg(32); @@ -17,10 +18,10 @@ component main() -> () { A_read0_2_00 = std_reg(32); A_read0_2_10 = std_reg(32); A_read0_2_20 = std_reg(32); - B0_0 = std_mem_d2(32,3,1,2,1); - B0_1 = std_mem_d2(32,3,1,2,1); - B0_2 = std_mem_d2(32,3,1,2,1); - @external(1) B_int0_0 = std_mem_d2(32,3,3,2,2); + B0_0 = comb_mem_d2(32,3,1,2,1); + B0_1 = comb_mem_d2(32,3,1,2,1); + B0_2 = comb_mem_d2(32,3,1,2,1); + @external(1) B_int0_0 = comb_mem_d2(32,3,3,2,2); B_int_read0_0 = std_reg(32); B_read0_0_00 = std_reg(32); B_read0_0_10 = std_reg(32); @@ -31,16 +32,16 @@ component main() -> () { B_read0_2_00 = std_reg(32); B_read0_2_10 = std_reg(32); B_read0_2_20 = std_reg(32); - C0_0 = std_mem_d2(32,1,1,1,1); - C0_1 = std_mem_d2(32,1,1,1,1); - C0_2 = std_mem_d2(32,1,1,1,1); - C1_0 = std_mem_d2(32,1,1,1,1); - C1_1 = std_mem_d2(32,1,1,1,1); - C1_2 = std_mem_d2(32,1,1,1,1); - C2_0 = std_mem_d2(32,1,1,1,1); - C2_1 = std_mem_d2(32,1,1,1,1); - C2_2 = std_mem_d2(32,1,1,1,1); - @external(1) C_int0_0 = std_mem_d2(32,3,3,2,2); + C0_0 = comb_mem_d2(32,1,1,1,1); + C0_1 = comb_mem_d2(32,1,1,1,1); + C0_2 = comb_mem_d2(32,1,1,1,1); + C1_0 = comb_mem_d2(32,1,1,1,1); + C1_1 = comb_mem_d2(32,1,1,1,1); + C1_2 = comb_mem_d2(32,1,1,1,1); + C2_0 = comb_mem_d2(32,1,1,1,1); + C2_1 = comb_mem_d2(32,1,1,1,1); + C2_2 = comb_mem_d2(32,1,1,1,1); + @external(1) C_int0_0 = comb_mem_d2(32,3,3,2,2); C_int_read0_0 = std_reg(32); C_sh_read0_0 = std_reg(32); add0 = std_add(4); diff --git a/benches/component-sharing/gemm4.futil b/benches/component-sharing/gemm4.futil index c142e7086..d24f5e87d 100644 --- a/benches/component-sharing/gemm4.futil +++ b/benches/component-sharing/gemm4.futil @@ -1,13 +1,14 @@ // git.status = clean, build.date = Mon Mar 22 14:26:22 EDT 2021, git.hash = 8dd37e4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - A0_0 = std_mem_d2(32,1,4,1,3); - A1_0 = std_mem_d2(32,1,4,1,3); - A2_0 = std_mem_d2(32,1,4,1,3); - A3_0 = std_mem_d2(32,1,4,1,3); - @external(1) A_int0_0 = std_mem_d2(32,4,4,3,3); + A0_0 = comb_mem_d2(32,1,4,1,3); + A1_0 = comb_mem_d2(32,1,4,1,3); + A2_0 = comb_mem_d2(32,1,4,1,3); + A3_0 = comb_mem_d2(32,1,4,1,3); + @external(1) A_int0_0 = comb_mem_d2(32,4,4,3,3); A_int_read0_0 = std_reg(32); A_read0_0_00 = std_reg(32); A_read0_0_10 = std_reg(32); @@ -25,11 +26,11 @@ component main() -> () { A_read0_3_10 = std_reg(32); A_read0_3_20 = std_reg(32); A_read0_3_30 = std_reg(32); - B0_0 = std_mem_d2(32,4,1,3,1); - B0_1 = std_mem_d2(32,4,1,3,1); - B0_2 = std_mem_d2(32,4,1,3,1); - B0_3 = std_mem_d2(32,4,1,3,1); - @external(1) B_int0_0 = std_mem_d2(32,4,4,3,3); + B0_0 = comb_mem_d2(32,4,1,3,1); + B0_1 = comb_mem_d2(32,4,1,3,1); + B0_2 = comb_mem_d2(32,4,1,3,1); + B0_3 = comb_mem_d2(32,4,1,3,1); + @external(1) B_int0_0 = comb_mem_d2(32,4,4,3,3); B_int_read0_0 = std_reg(32); B_read0_0_00 = std_reg(32); B_read0_0_10 = std_reg(32); @@ -47,23 +48,23 @@ component main() -> () { B_read0_3_10 = std_reg(32); B_read0_3_20 = std_reg(32); B_read0_3_30 = std_reg(32); - C0_0 = std_mem_d2(32,1,1,1,1); - C0_1 = std_mem_d2(32,1,1,1,1); - C0_2 = std_mem_d2(32,1,1,1,1); - C0_3 = std_mem_d2(32,1,1,1,1); - C1_0 = std_mem_d2(32,1,1,1,1); - C1_1 = std_mem_d2(32,1,1,1,1); - C1_2 = std_mem_d2(32,1,1,1,1); - C1_3 = std_mem_d2(32,1,1,1,1); - C2_0 = std_mem_d2(32,1,1,1,1); - C2_1 = std_mem_d2(32,1,1,1,1); - C2_2 = std_mem_d2(32,1,1,1,1); - C2_3 = std_mem_d2(32,1,1,1,1); - C3_0 = std_mem_d2(32,1,1,1,1); - C3_1 = std_mem_d2(32,1,1,1,1); - C3_2 = std_mem_d2(32,1,1,1,1); - C3_3 = std_mem_d2(32,1,1,1,1); - @external(1) C_int0_0 = std_mem_d2(32,4,4,3,3); + C0_0 = comb_mem_d2(32,1,1,1,1); + C0_1 = comb_mem_d2(32,1,1,1,1); + C0_2 = comb_mem_d2(32,1,1,1,1); + C0_3 = comb_mem_d2(32,1,1,1,1); + C1_0 = comb_mem_d2(32,1,1,1,1); + C1_1 = comb_mem_d2(32,1,1,1,1); + C1_2 = comb_mem_d2(32,1,1,1,1); + C1_3 = comb_mem_d2(32,1,1,1,1); + C2_0 = comb_mem_d2(32,1,1,1,1); + C2_1 = comb_mem_d2(32,1,1,1,1); + C2_2 = comb_mem_d2(32,1,1,1,1); + C2_3 = comb_mem_d2(32,1,1,1,1); + C3_0 = comb_mem_d2(32,1,1,1,1); + C3_1 = comb_mem_d2(32,1,1,1,1); + C3_2 = comb_mem_d2(32,1,1,1,1); + C3_3 = comb_mem_d2(32,1,1,1,1); + @external(1) C_int0_0 = comb_mem_d2(32,4,4,3,3); C_int_read0_0 = std_reg(32); C_sh_read0_0 = std_reg(32); add0 = std_add(4); diff --git a/benches/component-sharing/gemm6.futil b/benches/component-sharing/gemm6.futil index 384a326ef..1baa139a1 100644 --- a/benches/component-sharing/gemm6.futil +++ b/benches/component-sharing/gemm6.futil @@ -1,15 +1,16 @@ // git.status = clean, build.date = Mon Mar 22 14:26:22 EDT 2021, git.hash = 8dd37e4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - A0_0 = std_mem_d2(32,1,6,1,3); - A1_0 = std_mem_d2(32,1,6,1,3); - A2_0 = std_mem_d2(32,1,6,1,3); - A3_0 = std_mem_d2(32,1,6,1,3); - A4_0 = std_mem_d2(32,1,6,1,3); - A5_0 = std_mem_d2(32,1,6,1,3); - @external(1) A_int0_0 = std_mem_d2(32,6,6,3,3); + A0_0 = comb_mem_d2(32,1,6,1,3); + A1_0 = comb_mem_d2(32,1,6,1,3); + A2_0 = comb_mem_d2(32,1,6,1,3); + A3_0 = comb_mem_d2(32,1,6,1,3); + A4_0 = comb_mem_d2(32,1,6,1,3); + A5_0 = comb_mem_d2(32,1,6,1,3); + @external(1) A_int0_0 = comb_mem_d2(32,6,6,3,3); A_int_read0_0 = std_reg(32); A_read0_0_00 = std_reg(32); A_read0_0_10 = std_reg(32); @@ -47,13 +48,13 @@ component main() -> () { A_read0_5_30 = std_reg(32); A_read0_5_40 = std_reg(32); A_read0_5_50 = std_reg(32); - B0_0 = std_mem_d2(32,6,1,3,1); - B0_1 = std_mem_d2(32,6,1,3,1); - B0_2 = std_mem_d2(32,6,1,3,1); - B0_3 = std_mem_d2(32,6,1,3,1); - B0_4 = std_mem_d2(32,6,1,3,1); - B0_5 = std_mem_d2(32,6,1,3,1); - @external(1) B_int0_0 = std_mem_d2(32,6,6,3,3); + B0_0 = comb_mem_d2(32,6,1,3,1); + B0_1 = comb_mem_d2(32,6,1,3,1); + B0_2 = comb_mem_d2(32,6,1,3,1); + B0_3 = comb_mem_d2(32,6,1,3,1); + B0_4 = comb_mem_d2(32,6,1,3,1); + B0_5 = comb_mem_d2(32,6,1,3,1); + @external(1) B_int0_0 = comb_mem_d2(32,6,6,3,3); B_int_read0_0 = std_reg(32); B_read0_0_00 = std_reg(32); B_read0_0_10 = std_reg(32); @@ -91,43 +92,43 @@ component main() -> () { B_read0_5_30 = std_reg(32); B_read0_5_40 = std_reg(32); B_read0_5_50 = std_reg(32); - C0_0 = std_mem_d2(32,1,1,1,1); - C0_1 = std_mem_d2(32,1,1,1,1); - C0_2 = std_mem_d2(32,1,1,1,1); - C0_3 = std_mem_d2(32,1,1,1,1); - C0_4 = std_mem_d2(32,1,1,1,1); - C0_5 = std_mem_d2(32,1,1,1,1); - C1_0 = std_mem_d2(32,1,1,1,1); - C1_1 = std_mem_d2(32,1,1,1,1); - C1_2 = std_mem_d2(32,1,1,1,1); - C1_3 = std_mem_d2(32,1,1,1,1); - C1_4 = std_mem_d2(32,1,1,1,1); - C1_5 = std_mem_d2(32,1,1,1,1); - C2_0 = std_mem_d2(32,1,1,1,1); - C2_1 = std_mem_d2(32,1,1,1,1); - C2_2 = std_mem_d2(32,1,1,1,1); - C2_3 = std_mem_d2(32,1,1,1,1); - C2_4 = std_mem_d2(32,1,1,1,1); - C2_5 = std_mem_d2(32,1,1,1,1); - C3_0 = std_mem_d2(32,1,1,1,1); - C3_1 = std_mem_d2(32,1,1,1,1); - C3_2 = std_mem_d2(32,1,1,1,1); - C3_3 = std_mem_d2(32,1,1,1,1); - C3_4 = std_mem_d2(32,1,1,1,1); - C3_5 = std_mem_d2(32,1,1,1,1); - C4_0 = std_mem_d2(32,1,1,1,1); - C4_1 = std_mem_d2(32,1,1,1,1); - C4_2 = std_mem_d2(32,1,1,1,1); - C4_3 = std_mem_d2(32,1,1,1,1); - C4_4 = std_mem_d2(32,1,1,1,1); - C4_5 = std_mem_d2(32,1,1,1,1); - C5_0 = std_mem_d2(32,1,1,1,1); - C5_1 = std_mem_d2(32,1,1,1,1); - C5_2 = std_mem_d2(32,1,1,1,1); - C5_3 = std_mem_d2(32,1,1,1,1); - C5_4 = std_mem_d2(32,1,1,1,1); - C5_5 = std_mem_d2(32,1,1,1,1); - @external(1) C_int0_0 = std_mem_d2(32,6,6,3,3); + C0_0 = comb_mem_d2(32,1,1,1,1); + C0_1 = comb_mem_d2(32,1,1,1,1); + C0_2 = comb_mem_d2(32,1,1,1,1); + C0_3 = comb_mem_d2(32,1,1,1,1); + C0_4 = comb_mem_d2(32,1,1,1,1); + C0_5 = comb_mem_d2(32,1,1,1,1); + C1_0 = comb_mem_d2(32,1,1,1,1); + C1_1 = comb_mem_d2(32,1,1,1,1); + C1_2 = comb_mem_d2(32,1,1,1,1); + C1_3 = comb_mem_d2(32,1,1,1,1); + C1_4 = comb_mem_d2(32,1,1,1,1); + C1_5 = comb_mem_d2(32,1,1,1,1); + C2_0 = comb_mem_d2(32,1,1,1,1); + C2_1 = comb_mem_d2(32,1,1,1,1); + C2_2 = comb_mem_d2(32,1,1,1,1); + C2_3 = comb_mem_d2(32,1,1,1,1); + C2_4 = comb_mem_d2(32,1,1,1,1); + C2_5 = comb_mem_d2(32,1,1,1,1); + C3_0 = comb_mem_d2(32,1,1,1,1); + C3_1 = comb_mem_d2(32,1,1,1,1); + C3_2 = comb_mem_d2(32,1,1,1,1); + C3_3 = comb_mem_d2(32,1,1,1,1); + C3_4 = comb_mem_d2(32,1,1,1,1); + C3_5 = comb_mem_d2(32,1,1,1,1); + C4_0 = comb_mem_d2(32,1,1,1,1); + C4_1 = comb_mem_d2(32,1,1,1,1); + C4_2 = comb_mem_d2(32,1,1,1,1); + C4_3 = comb_mem_d2(32,1,1,1,1); + C4_4 = comb_mem_d2(32,1,1,1,1); + C4_5 = comb_mem_d2(32,1,1,1,1); + C5_0 = comb_mem_d2(32,1,1,1,1); + C5_1 = comb_mem_d2(32,1,1,1,1); + C5_2 = comb_mem_d2(32,1,1,1,1); + C5_3 = comb_mem_d2(32,1,1,1,1); + C5_4 = comb_mem_d2(32,1,1,1,1); + C5_5 = comb_mem_d2(32,1,1,1,1); + @external(1) C_int0_0 = comb_mem_d2(32,6,6,3,3); C_int_read0_0 = std_reg(32); C_sh_read0_0 = std_reg(32); add0 = std_add(4); diff --git a/benches/component-sharing/gemm8.futil b/benches/component-sharing/gemm8.futil index 02e5ba069..cf8a0a2e7 100644 --- a/benches/component-sharing/gemm8.futil +++ b/benches/component-sharing/gemm8.futil @@ -1,18 +1,19 @@ // git.status = clean, build.date = Mon Mar 22 14:26:22 EDT 2021, git.hash = 8dd37e4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - A0_0 = std_mem_d2(32,1,8,1,4); - A1_0 = std_mem_d2(32,1,8,1,4); - A2_0 = std_mem_d2(32,1,8,1,4); - A3_0 = std_mem_d2(32,1,8,1,4); - A4_0 = std_mem_d2(32,1,8,1,4); - A5_0 = std_mem_d2(32,1,8,1,4); - A6_0 = std_mem_d2(32,1,8,1,4); - A7_0 = std_mem_d2(32,1,8,1,4); - @external(1) A_int0_0 = std_mem_d2(32,8,8,4,4); + A0_0 = comb_mem_d2(32,1,8,1,4); + A1_0 = comb_mem_d2(32,1,8,1,4); + A2_0 = comb_mem_d2(32,1,8,1,4); + A3_0 = comb_mem_d2(32,1,8,1,4); + A4_0 = comb_mem_d2(32,1,8,1,4); + A5_0 = comb_mem_d2(32,1,8,1,4); + A6_0 = comb_mem_d2(32,1,8,1,4); + A7_0 = comb_mem_d2(32,1,8,1,4); + @external(1) A_int0_0 = comb_mem_d2(32,8,8,4,4); A_int_read0_0 = std_reg(32); A_read0_0_00 = std_reg(32); A_read0_0_10 = std_reg(32); @@ -78,15 +79,15 @@ component main() -> () { A_read0_7_50 = std_reg(32); A_read0_7_60 = std_reg(32); A_read0_7_70 = std_reg(32); - B0_0 = std_mem_d2(32,8,1,4,1); - B0_1 = std_mem_d2(32,8,1,4,1); - B0_2 = std_mem_d2(32,8,1,4,1); - B0_3 = std_mem_d2(32,8,1,4,1); - B0_4 = std_mem_d2(32,8,1,4,1); - B0_5 = std_mem_d2(32,8,1,4,1); - B0_6 = std_mem_d2(32,8,1,4,1); - B0_7 = std_mem_d2(32,8,1,4,1); - @external(1) B_int0_0 = std_mem_d2(32,8,8,4,4); + B0_0 = comb_mem_d2(32,8,1,4,1); + B0_1 = comb_mem_d2(32,8,1,4,1); + B0_2 = comb_mem_d2(32,8,1,4,1); + B0_3 = comb_mem_d2(32,8,1,4,1); + B0_4 = comb_mem_d2(32,8,1,4,1); + B0_5 = comb_mem_d2(32,8,1,4,1); + B0_6 = comb_mem_d2(32,8,1,4,1); + B0_7 = comb_mem_d2(32,8,1,4,1); + @external(1) B_int0_0 = comb_mem_d2(32,8,8,4,4); B_int_read0_0 = std_reg(32); B_read0_0_00 = std_reg(32); B_read0_0_10 = std_reg(32); @@ -152,71 +153,71 @@ component main() -> () { B_read0_7_50 = std_reg(32); B_read0_7_60 = std_reg(32); B_read0_7_70 = std_reg(32); - C0_0 = std_mem_d2(32,1,1,1,1); - C0_1 = std_mem_d2(32,1,1,1,1); - C0_2 = std_mem_d2(32,1,1,1,1); - C0_3 = std_mem_d2(32,1,1,1,1); - C0_4 = std_mem_d2(32,1,1,1,1); - C0_5 = std_mem_d2(32,1,1,1,1); - C0_6 = std_mem_d2(32,1,1,1,1); - C0_7 = std_mem_d2(32,1,1,1,1); - C1_0 = std_mem_d2(32,1,1,1,1); - C1_1 = std_mem_d2(32,1,1,1,1); - C1_2 = std_mem_d2(32,1,1,1,1); - C1_3 = std_mem_d2(32,1,1,1,1); - C1_4 = std_mem_d2(32,1,1,1,1); - C1_5 = std_mem_d2(32,1,1,1,1); - C1_6 = std_mem_d2(32,1,1,1,1); - C1_7 = std_mem_d2(32,1,1,1,1); - C2_0 = std_mem_d2(32,1,1,1,1); - C2_1 = std_mem_d2(32,1,1,1,1); - C2_2 = std_mem_d2(32,1,1,1,1); - C2_3 = std_mem_d2(32,1,1,1,1); - C2_4 = std_mem_d2(32,1,1,1,1); - C2_5 = std_mem_d2(32,1,1,1,1); - C2_6 = std_mem_d2(32,1,1,1,1); - C2_7 = std_mem_d2(32,1,1,1,1); - C3_0 = std_mem_d2(32,1,1,1,1); - C3_1 = std_mem_d2(32,1,1,1,1); - C3_2 = std_mem_d2(32,1,1,1,1); - C3_3 = std_mem_d2(32,1,1,1,1); - C3_4 = std_mem_d2(32,1,1,1,1); - C3_5 = std_mem_d2(32,1,1,1,1); - C3_6 = std_mem_d2(32,1,1,1,1); - C3_7 = std_mem_d2(32,1,1,1,1); - C4_0 = std_mem_d2(32,1,1,1,1); - C4_1 = std_mem_d2(32,1,1,1,1); - C4_2 = std_mem_d2(32,1,1,1,1); - C4_3 = std_mem_d2(32,1,1,1,1); - C4_4 = std_mem_d2(32,1,1,1,1); - C4_5 = std_mem_d2(32,1,1,1,1); - C4_6 = std_mem_d2(32,1,1,1,1); - C4_7 = std_mem_d2(32,1,1,1,1); - C5_0 = std_mem_d2(32,1,1,1,1); - C5_1 = std_mem_d2(32,1,1,1,1); - C5_2 = std_mem_d2(32,1,1,1,1); - C5_3 = std_mem_d2(32,1,1,1,1); - C5_4 = std_mem_d2(32,1,1,1,1); - C5_5 = std_mem_d2(32,1,1,1,1); - C5_6 = std_mem_d2(32,1,1,1,1); - C5_7 = std_mem_d2(32,1,1,1,1); - C6_0 = std_mem_d2(32,1,1,1,1); - C6_1 = std_mem_d2(32,1,1,1,1); - C6_2 = std_mem_d2(32,1,1,1,1); - C6_3 = std_mem_d2(32,1,1,1,1); - C6_4 = std_mem_d2(32,1,1,1,1); - C6_5 = std_mem_d2(32,1,1,1,1); - C6_6 = std_mem_d2(32,1,1,1,1); - C6_7 = std_mem_d2(32,1,1,1,1); - C7_0 = std_mem_d2(32,1,1,1,1); - C7_1 = std_mem_d2(32,1,1,1,1); - C7_2 = std_mem_d2(32,1,1,1,1); - C7_3 = std_mem_d2(32,1,1,1,1); - C7_4 = std_mem_d2(32,1,1,1,1); - C7_5 = std_mem_d2(32,1,1,1,1); - C7_6 = std_mem_d2(32,1,1,1,1); - C7_7 = std_mem_d2(32,1,1,1,1); - @external(1) C_int0_0 = std_mem_d2(32,8,8,4,4); + C0_0 = comb_mem_d2(32,1,1,1,1); + C0_1 = comb_mem_d2(32,1,1,1,1); + C0_2 = comb_mem_d2(32,1,1,1,1); + C0_3 = comb_mem_d2(32,1,1,1,1); + C0_4 = comb_mem_d2(32,1,1,1,1); + C0_5 = comb_mem_d2(32,1,1,1,1); + C0_6 = comb_mem_d2(32,1,1,1,1); + C0_7 = comb_mem_d2(32,1,1,1,1); + C1_0 = comb_mem_d2(32,1,1,1,1); + C1_1 = comb_mem_d2(32,1,1,1,1); + C1_2 = comb_mem_d2(32,1,1,1,1); + C1_3 = comb_mem_d2(32,1,1,1,1); + C1_4 = comb_mem_d2(32,1,1,1,1); + C1_5 = comb_mem_d2(32,1,1,1,1); + C1_6 = comb_mem_d2(32,1,1,1,1); + C1_7 = comb_mem_d2(32,1,1,1,1); + C2_0 = comb_mem_d2(32,1,1,1,1); + C2_1 = comb_mem_d2(32,1,1,1,1); + C2_2 = comb_mem_d2(32,1,1,1,1); + C2_3 = comb_mem_d2(32,1,1,1,1); + C2_4 = comb_mem_d2(32,1,1,1,1); + C2_5 = comb_mem_d2(32,1,1,1,1); + C2_6 = comb_mem_d2(32,1,1,1,1); + C2_7 = comb_mem_d2(32,1,1,1,1); + C3_0 = comb_mem_d2(32,1,1,1,1); + C3_1 = comb_mem_d2(32,1,1,1,1); + C3_2 = comb_mem_d2(32,1,1,1,1); + C3_3 = comb_mem_d2(32,1,1,1,1); + C3_4 = comb_mem_d2(32,1,1,1,1); + C3_5 = comb_mem_d2(32,1,1,1,1); + C3_6 = comb_mem_d2(32,1,1,1,1); + C3_7 = comb_mem_d2(32,1,1,1,1); + C4_0 = comb_mem_d2(32,1,1,1,1); + C4_1 = comb_mem_d2(32,1,1,1,1); + C4_2 = comb_mem_d2(32,1,1,1,1); + C4_3 = comb_mem_d2(32,1,1,1,1); + C4_4 = comb_mem_d2(32,1,1,1,1); + C4_5 = comb_mem_d2(32,1,1,1,1); + C4_6 = comb_mem_d2(32,1,1,1,1); + C4_7 = comb_mem_d2(32,1,1,1,1); + C5_0 = comb_mem_d2(32,1,1,1,1); + C5_1 = comb_mem_d2(32,1,1,1,1); + C5_2 = comb_mem_d2(32,1,1,1,1); + C5_3 = comb_mem_d2(32,1,1,1,1); + C5_4 = comb_mem_d2(32,1,1,1,1); + C5_5 = comb_mem_d2(32,1,1,1,1); + C5_6 = comb_mem_d2(32,1,1,1,1); + C5_7 = comb_mem_d2(32,1,1,1,1); + C6_0 = comb_mem_d2(32,1,1,1,1); + C6_1 = comb_mem_d2(32,1,1,1,1); + C6_2 = comb_mem_d2(32,1,1,1,1); + C6_3 = comb_mem_d2(32,1,1,1,1); + C6_4 = comb_mem_d2(32,1,1,1,1); + C6_5 = comb_mem_d2(32,1,1,1,1); + C6_6 = comb_mem_d2(32,1,1,1,1); + C6_7 = comb_mem_d2(32,1,1,1,1); + C7_0 = comb_mem_d2(32,1,1,1,1); + C7_1 = comb_mem_d2(32,1,1,1,1); + C7_2 = comb_mem_d2(32,1,1,1,1); + C7_3 = comb_mem_d2(32,1,1,1,1); + C7_4 = comb_mem_d2(32,1,1,1,1); + C7_5 = comb_mem_d2(32,1,1,1,1); + C7_6 = comb_mem_d2(32,1,1,1,1); + C7_7 = comb_mem_d2(32,1,1,1,1); + @external(1) C_int0_0 = comb_mem_d2(32,8,8,4,4); C_int_read0_0 = std_reg(32); C_sh_read0_0 = std_reg(32); add0 = std_add(4); diff --git a/calyx-backend/src/mlir.rs b/calyx-backend/src/mlir.rs index baca083af..97532ffa8 100644 --- a/calyx-backend/src/mlir.rs +++ b/calyx-backend/src/mlir.rs @@ -160,14 +160,14 @@ impl MlirBackend { "std_reg" => { write!(f, "calyx.register @{cell_name}")? } - "std_mem_d1" => write!( + "comb_mem_d1" => write!( f, "calyx.memory @{cell_name} <[{}] x {}> [{}]", bind["SIZE"], bind["WIDTH"], bind["IDX_SIZE"] )?, - "std_mem_d2" => write!( + "comb_mem_d2" => write!( f, "calyx.memory @{cell_name} <[{}, {}] x {}> [{}, {}]", bind["D0_SIZE"], @@ -176,7 +176,7 @@ impl MlirBackend { bind["D0_IDX_SIZE"], bind["D1_IDX_SIZE"] )?, - "std_mem_d3" => write!( + "comb_mem_d3" => write!( f, "calyx.memory @{cell_name} <[{}, {}, {}] x {}> [{}, {}, {}]", bind["D0_SIZE"], @@ -187,7 +187,7 @@ impl MlirBackend { bind["D1_IDX_SIZE"], bind["D2_IDX_SIZE"] )?, - "std_mem_d4" => write!( + "comb_mem_d4" => write!( f, "calyx.memory @{cell_name} <[{}, {}, {}, {}] x {}> [{}, {}, {}, {}]", bind["D0_SIZE"], diff --git a/calyx-backend/src/resources.rs b/calyx-backend/src/resources.rs index c774120c1..161cc2bf0 100644 --- a/calyx-backend/src/resources.rs +++ b/calyx-backend/src/resources.rs @@ -152,7 +152,7 @@ fn estimated_size(count_map: HashMap<(ir::Id, ir::Binding, bool), u32>) { params[0].1 ) } - "std_mem_d1" => { + "comb_mem_d1" => { add_size( is_external, count as u64, @@ -164,7 +164,7 @@ fn estimated_size(count_map: HashMap<(ir::Id, ir::Binding, bool), u32>) { count, externalize_name(name, is_external), params[1].1, params[0].1); } - "std_mem_d2" => { + "comb_mem_d2" => { add_size( is_external, count as u64, @@ -176,7 +176,7 @@ fn estimated_size(count_map: HashMap<(ir::Id, ir::Binding, bool), u32>) { count, externalize_name(name, is_external), (params[1].1 * params[2].1), params[0].1); } - "std_mem_d3" => { + "comb_mem_d3" => { add_size( is_external, count as u64, @@ -188,7 +188,7 @@ fn estimated_size(count_map: HashMap<(ir::Id, ir::Binding, bool), u32>) { count, externalize_name(name, is_external), (params[1].1 * params[2].1 * params[3].1), params[0].1); } - "std_mem_d4" => { + "comb_mem_d4" => { add_size( is_external, count as u64, diff --git a/calyx-backend/src/verilog.rs b/calyx-backend/src/verilog.rs index 2b330c738..9da5f2ebf 100644 --- a/calyx-backend/src/verilog.rs +++ b/calyx-backend/src/verilog.rs @@ -19,14 +19,14 @@ use vast::v17::ast as v; pub struct VerilogBackend; // input string should be the cell type name of a memory cell. In other words one -// of "seq/std_mem_d_1/2/3/4". Becase we define seq_mem_d2/3/4 in terms of seq_mem_d1 +// of "seq/comb_mem_d_1/2/3/4". Becase we define seq_mem_d2/3/4 in terms of seq_mem_d1 // we need another layer of memory access to get the actual memory array in verilog // for these mem types. // In other words, for memories not defined in terms of another memory, we can just use // "mem" to access them. But for memories defined in terms of another memory, // which are seq_mem_d2/3/4, we need "mem.mem" to access them. fn get_mem_str(mem_type: &str) -> &str { - if mem_type.contains("d1") || mem_type.contains("std_mem") { + if mem_type.contains("d1") || mem_type.contains("comb_mem") { "mem" } else { "mem.mem" diff --git a/calyx-backend/src/xilinx/toplevel.rs b/calyx-backend/src/xilinx/toplevel.rs index 5f98fa3c5..e451a0247 100644 --- a/calyx-backend/src/xilinx/toplevel.rs +++ b/calyx-backend/src/xilinx/toplevel.rs @@ -99,8 +99,8 @@ impl Backend for XilinxInterfaceBackend { fn external_1d_memories_cells(comp: &ir::Component) -> Vec> { let memories = ir::utils::external_memories_cells(comp); for memory in memories.iter() { - if !memory.borrow().is_primitive(Some("std_mem_d1")) { - panic!("cell `{}' marked with `@external' but is not a std_mem_d1. The AXI generator currently only supports `std_mem_d1'", memory.borrow().name()) + if !memory.borrow().is_primitive(Some("comb_mem_d1")) { + panic!("cell `{}' marked with `@external' but is not a comb_mem_d1. The AXI generator currently only supports `comb_mem_d1'", memory.borrow().name()) } } memories diff --git a/calyx-ir/src/utils.rs b/calyx-ir/src/utils.rs index f93f99bb2..c64eadcc7 100644 --- a/calyx-ir/src/utils.rs +++ b/calyx-ir/src/utils.rs @@ -44,22 +44,22 @@ impl GetMemInfo for Vec> { let mut idx_sizes: Vec = Vec::new(); let idx_count: u64; match mem.prototype.get_name().unwrap().as_ref() { - "std_mem_d1" | "seq_mem_d1" => { + "comb_mem_d1" | "seq_mem_d1" => { mem_size = mem.get_parameter("SIZE").unwrap(); idx_count = 1; } - "std_mem_d2" | "seq_mem_d2" => { + "comb_mem_d2" | "seq_mem_d2" => { mem_size = mem.get_parameter("D0_SIZE").unwrap() * mem.get_parameter("D1_SIZE").unwrap(); idx_count = 2; } - "std_mem_d3" | "seq_mem_d3" => { + "comb_mem_d3" | "seq_mem_d3" => { mem_size = mem.get_parameter("D0_SIZE").unwrap() * mem.get_parameter("D1_SIZE").unwrap() * mem.get_parameter("D2_SIZE").unwrap(); idx_count = 3; } - "std_mem_d4" | "seq_mem_d4" => { + "comb_mem_d4" | "seq_mem_d4" => { mem_size = mem.get_parameter("D0_SIZE").unwrap() * mem.get_parameter("D1_SIZE").unwrap() * mem.get_parameter("D2_SIZE").unwrap() diff --git a/calyx-opt/src/passes/externalize.rs b/calyx-opt/src/passes/externalize.rs index 1c743345d..28e19c407 100644 --- a/calyx-opt/src/passes/externalize.rs +++ b/calyx-opt/src/passes/externalize.rs @@ -13,7 +13,7 @@ use calyx_utils::CalyxResult; /// cells { /// // Inputs: addr0, write_data, write_en /// // Outputs: read_data, done -/// @external(1) m1 = prim std_mem_d1(32, 10, 4); +/// @external(1) m1 = prim comb_mem_d1(32, 10, 4); /// } /// wires { /// m1.addr0 = 1'd1; diff --git a/calyx-opt/src/passes/synthesis_papercut.rs b/calyx-opt/src/passes/synthesis_papercut.rs index a23afa172..d56e1a5e5 100644 --- a/calyx-opt/src/passes/synthesis_papercut.rs +++ b/calyx-opt/src/passes/synthesis_papercut.rs @@ -17,10 +17,11 @@ pub struct SynthesisPapercut { impl Default for SynthesisPapercut { fn default() -> Self { - let memories = ["std_mem_d1", "std_mem_d2", "std_mem_d3", "std_mem_d4"] - .iter() - .map(|&mem| mem.into()) - .collect(); + let memories = + ["comb_mem_d1", "comb_mem_d2", "comb_mem_d3", "comb_mem_d4"] + .iter() + .map(|&mem| mem.into()) + .collect(); SynthesisPapercut { memories } } } diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index 2b444a499..bbfea8ac7 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -280,7 +280,7 @@ def const(self, name: str, width: int, value: int) -> CellBuilder: """Generate a StdConstant cell.""" return self.cell(name, ast.Stdlib.constant(width, value)) - def mem_d1( + def comb_mem_d1( self, name: str, bitwidth: int, @@ -290,8 +290,9 @@ def mem_d1( is_ref: bool = False, ) -> CellBuilder: """Generate a StdMemD1 cell.""" + self.prog.import_("primitives/memories/comb.futil") return self.cell( - name, ast.Stdlib.mem_d1(bitwidth, len, idx_size), is_external, is_ref + name, ast.Stdlib.comb_mem_d1(bitwidth, len, idx_size), is_external, is_ref ) def seq_mem_d1( @@ -304,7 +305,7 @@ def seq_mem_d1( is_ref: bool = False, ) -> CellBuilder: """Generate a SeqMemD1 cell.""" - self.prog.import_("primitives/memories.futil") + self.prog.import_("primitives/memories/seq.futil") return self.cell( name, ast.Stdlib.seq_mem_d1(bitwidth, len, idx_size), is_external, is_ref ) @@ -568,7 +569,7 @@ def mem_load_std_d1(self, mem, i, reg, groupname=None): """Inserts wiring into `self` to perform `reg := mem[i]`, where `mem` is a std_d1 memory. """ - assert mem.is_std_mem_d1() + assert mem.is_comb_mem_d1() groupname = groupname or f"{mem.name()}_load_to_reg" with self.group(groupname) as load_grp: mem.addr0 = i @@ -580,7 +581,7 @@ def mem_load_std_d1(self, mem, i, reg, groupname=None): def mem_store_std_d1(self, mem, i, val, groupname=None): """Inserts wiring into `self` to perform `mem[i] := val`, where `mem` is a std_d1 memory.""" - assert mem.is_std_mem_d1() + assert mem.is_comb_mem_d1() groupname = groupname or f"store_into_{mem.name()}" with self.group(groupname) as store_grp: mem.addr0 = i @@ -631,7 +632,7 @@ def mem_load_to_mem(self, mem, i, ans, j, groupname=None): """Inserts wiring into `self` to perform `ans[j] := mem[i]`, where `mem` and `ans` are both std_d1 memories. """ - assert mem.is_std_mem_d1() and ans.is_std_mem_d1() + assert mem.is_comb_mem_d1() and ans.is_comb_mem_d1() groupname = groupname or f"{mem.name()}_load_to_mem" with self.group(groupname) as load_grp: mem.addr0 = i @@ -1045,9 +1046,9 @@ def is_primitive(self, prim_name) -> bool: and self._cell.comp.id == prim_name ) - def is_std_mem_d1(self) -> bool: + def is_comb_mem_d1(self) -> bool: """Check if the cell is a StdMemD1 cell.""" - return self.is_primitive("std_mem_d1") + return self.is_primitive("comb_mem_d1") def is_seq_mem_d1(self) -> bool: """Check if the cell is a SeqMemD1 cell.""" @@ -1085,7 +1086,7 @@ def infer_width(self, port_name) -> int: ): if port_name in ("left", "right"): return inst.args[0] - if prim in ("std_mem_d1", "seq_mem_d1"): + if prim in ("comb_mem_d1", "seq_mem_d1"): if port_name == "write_en": return 1 if port_name == "addr0": diff --git a/calyx-py/calyx/gen_exp.py b/calyx-py/calyx/gen_exp.py index b7d5c7064..96407963c 100644 --- a/calyx-py/calyx/gen_exp.py +++ b/calyx-py/calyx/gen_exp.py @@ -419,15 +419,17 @@ def generate_control(comp: ComponentBuilder, degree: int, is_signed: bool): x for x in ( init, - if_with( - CellAndGroup( - lt, - comp.get_group("is_negative"), - ), - comp.get_group("negate"), - ) - if is_signed - else [], + ( + if_with( + CellAndGroup( + lt, + comp.get_group("is_negative"), + ), + comp.get_group("negate"), + ) + if is_signed + else [] + ), split_bits, pow_invokes, consume_pow, @@ -435,15 +437,17 @@ def generate_control(comp: ComponentBuilder, degree: int, is_signed: bool): *divide_and_conquer, comp.get_group("add_degree_zero"), comp.get_group("final_multiply"), - if_with( - CellAndGroup( - lt, - comp.get_group("is_negative"), - ), - comp.get_group("reciprocal"), - ) - if is_signed - else [], + ( + if_with( + CellAndGroup( + lt, + comp.get_group("is_negative"), + ), + comp.get_group("reciprocal"), + ) + if is_signed + else [] + ), ) if x != [] ] @@ -691,9 +695,9 @@ def build_base_not_e(degree, width, int_width, is_signed) -> Program: main = builder.component("main") base_reg = main.reg("base_reg", width) exp_reg = main.reg("exp_reg", width) - x = main.mem_d1("x", width, 1, 1, is_external=True) - b = main.mem_d1("b", width, 1, 1, is_external=True) - ret = main.mem_d1("ret", width, 1, 1, is_external=True) + x = main.comb_mem_d1("x", width, 1, 1, is_external=True) + b = main.comb_mem_d1("b", width, 1, 1, is_external=True) + ret = main.comb_mem_d1("ret", width, 1, 1, is_external=True) f = main.comp_instance("f", "fp_pow_full") read_base = main.mem_load_std_d1(b, 0, base_reg, "read_base") @@ -727,8 +731,8 @@ def build_base_is_e(degree, width, int_width, is_signed) -> Program: main = builder.component("main") t = main.reg("t", width) - x = main.mem_d1("x", width, 1, 1, is_external=True) - ret = main.mem_d1("ret", width, 1, 1, is_external=True) + x = main.comb_mem_d1("x", width, 1, 1, is_external=True) + ret = main.comb_mem_d1("ret", width, 1, 1, is_external=True) e = main.comp_instance("e", "exp") with main.group("init") as init: diff --git a/calyx-py/calyx/gen_ln.py b/calyx-py/calyx/gen_ln.py index e6c60b474..6535b569b 100644 --- a/calyx-py/calyx/gen_ln.py +++ b/calyx-py/calyx/gen_ln.py @@ -394,8 +394,8 @@ def generate_ln(width: int, int_width: int, is_signed: bool) -> List[Component]: # main component for testing purposes main = builder.component("main") x = main.reg("x", width) - in_ = main.mem_d1("in", width, 1, 1, is_external=True) - out = main.mem_d1("out", width, 1, 1, is_external=True) + in_ = main.comb_mem_d1("in", width, 1, 1, is_external=True) + out = main.comb_mem_d1("out", width, 1, 1, is_external=True) ln = main.comp_instance("l", "ln") with main.group("read_in_mem") as read_in_mem: diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index 5b91d42c5..e22fdf894 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -522,40 +522,17 @@ def pad(in_: int, out: int): return CompInst("std_pad", [in_, out]) @staticmethod - def mem_d1(bitwidth: int, size: int, idx_size: int): - return CompInst("std_mem_d1", [bitwidth, size, idx_size]) + def comb_mem_d1(bitwidth: int, size: int, idx_size: int): + return CompInst("comb_mem_d1", [bitwidth, size, idx_size]) @staticmethod - def seq_mem_d1(bitwidth: int, size: int, idx_size: int): - return CompInst("seq_mem_d1", [bitwidth, size, idx_size]) - - @staticmethod - def mem_d2(bitwidth: int, size0: int, size1: int, idx_size0: int, idx_size1: int): - return CompInst("std_mem_d2", [bitwidth, size0, size1, idx_size0, idx_size1]) - - @staticmethod - def seq_mem_d2( + def comb_mem_d2( bitwidth: int, size0: int, size1: int, idx_size0: int, idx_size1: int ): - return CompInst("seq_mem_d2", [bitwidth, size0, size1, idx_size0, idx_size1]) - - @staticmethod - def mem_d3( - bitwidth: int, - size0: int, - size1: int, - size2: int, - idx_size0: int, - idx_size1: int, - idx_size2: int, - ): - return CompInst( - "std_mem_d3", - [bitwidth, size0, size1, size2, idx_size0, idx_size1, idx_size2], - ) + return CompInst("comb_mem_d2", [bitwidth, size0, size1, idx_size0, idx_size1]) @staticmethod - def seq_mem_d3( + def comb_mem_d3( bitwidth: int, size0: int, size1: int, @@ -565,12 +542,12 @@ def seq_mem_d3( idx_size2: int, ): return CompInst( - "seq_mem_d3", + "comb_mem_d3", [bitwidth, size0, size1, size2, idx_size0, idx_size1, idx_size2], ) @staticmethod - def mem_d4( + def comb_mem_d4( bitwidth: int, size0: int, size1: int, @@ -582,7 +559,7 @@ def mem_d4( idx_size3: int, ): return CompInst( - "std_mem_d4", + "comb_mem_d4", [ bitwidth, size0, @@ -596,6 +573,31 @@ def mem_d4( ], ) + @staticmethod + def seq_mem_d1(bitwidth: int, size: int, idx_size: int): + return CompInst("seq_mem_d1", [bitwidth, size, idx_size]) + + @staticmethod + def seq_mem_d2( + bitwidth: int, size0: int, size1: int, idx_size0: int, idx_size1: int + ): + return CompInst("seq_mem_d2", [bitwidth, size0, size1, idx_size0, idx_size1]) + + @staticmethod + def seq_mem_d3( + bitwidth: int, + size0: int, + size1: int, + size2: int, + idx_size0: int, + idx_size1: int, + idx_size2: int, + ): + return CompInst( + "seq_mem_d3", + [bitwidth, size0, size1, size2, idx_size0, idx_size1, idx_size2], + ) + @staticmethod def seq_mem_d4( bitwidth: int, diff --git a/calyx-py/test/correctness/arbiter_6.py b/calyx-py/test/correctness/arbiter_6.py index 6c087f741..e6b6be48d 100644 --- a/calyx-py/test/correctness/arbiter_6.py +++ b/calyx-py/test/correctness/arbiter_6.py @@ -22,8 +22,8 @@ def add_wrap2(prog): j = wrap.input("j", 32) # Six memory cells, plus an answer cell. - mems = [wrap.mem_d1(f"mem{i}", 32, 4, 32, is_ref=True) for i in range(6)] - ans = wrap.mem_d1("ans", 32, 1, 32, is_ref=True) + mems = [wrap.comb_mem_d1(f"mem{i}", 32, 4, 32, is_ref=True) for i in range(6)] + ans = wrap.comb_mem_d1("ans", 32, 1, 32, is_ref=True) # We will need j % 4, so we'll store it in a cell. j_mod_4 = wrap.reg("j_mod_4", 32) @@ -105,8 +105,8 @@ def add_wrap3(prog): j = wrap.input("j", 32) # Six memory cells, plus an answer cell. - mems = [wrap.mem_d1(f"mem{i}", 32, 4, 32, is_ref=True) for i in range(6)] - ans = wrap.mem_d1("ans", 32, 1, 32, is_ref=True) + mems = [wrap.comb_mem_d1(f"mem{i}", 32, 4, 32, is_ref=True) for i in range(6)] + ans = wrap.comb_mem_d1("ans", 32, 1, 32, is_ref=True) # We will need j % 4, so we'll store it in a cell. j_mod_4 = wrap.reg("j_mod_4", 32) @@ -161,11 +161,11 @@ def add_main(prog, wrap2, wrap3): # Six memory cells, plus an two answer cells. [mem_a, mem_b, mem_c, mem_d, mem_e, mem_f] = [ - main.mem_d1(name, 32, 4, 32, is_external=True) + main.comb_mem_d1(name, 32, 4, 32, is_external=True) for name in ["A", "B", "C", "D", "E", "F"] ] - out2 = main.mem_d1("out2", 32, 1, 32, is_external=True) - out3 = main.mem_d1("out3", 32, 1, 32, is_external=True) + out2 = main.comb_mem_d1("out2", 32, 1, 32, is_external=True) + out3 = main.comb_mem_d1("out3", 32, 1, 32, is_external=True) together2 = main.cell("together2", wrap2) together3 = main.cell("together3", wrap3) diff --git a/calyx-py/test/correctness/reduction_tree.py b/calyx-py/test/correctness/reduction_tree.py index 475a293d3..a9bdd8a6f 100644 --- a/calyx-py/test/correctness/reduction_tree.py +++ b/calyx-py/test/correctness/reduction_tree.py @@ -97,9 +97,10 @@ def add_main(prog, tree): main = prog.component("main") # Four memories, each of length 4. [mem_a, mem_b, mem_c, mem_d] = [ - main.mem_d1(name, 32, 4, 32, is_external=True) for name in ["A", "B", "C", "D"] + main.comb_mem_d1(name, 32, 4, 32, is_external=True) + for name in ["A", "B", "C", "D"] ] - mem_ans = main.mem_d1("ans", 32, 1, 1, is_external=True) + mem_ans = main.comb_mem_d1("ans", 32, 1, 1, is_external=True) # Four answer registers. [sum_col0, sum_col1, sum_col2, sum_col3] = [ main.reg(f"sum_col{i}", 32) for i in range(4) diff --git a/calyx-stdlib/src/primitives.rs b/calyx-stdlib/src/primitives.rs index 9616973ca..1a213c0b2 100644 --- a/calyx-stdlib/src/primitives.rs +++ b/calyx-stdlib/src/primitives.rs @@ -22,7 +22,8 @@ macro_rules! load_prims { load_prims! { CORE, "core.futil", "core.sv" } load_prims! { BINARY_OPERATORS, "binary_operators.futil", "binary_operators.sv" } load_prims! { MATH, "math.futil", "math.sv" } -load_prims! { MEMORIES, "memories.futil", "memories.sv" } +load_prims! { COMB_MEMORIES, "memories/comb.futil", "memories/comb.sv" } +load_prims! { SEQ_MEMORIES, "memories/seq.futil", "memories/seq.sv" } load_prims! { PIPELINED, "pipelined.futil", "pipelined.sv" } load_prims! { SYNC, "sync.futil", "sync.sv" } @@ -30,11 +31,12 @@ load_prims! { SYNC, "sync.futil", "sync.sv" } pub const COMPILE_LIB: (&str, &str) = ("compile.futil", include_str!("../primitives/compile.futil")); -pub const KNOWN_LIBS: [(&str, [(&str, &str); 2]); 6] = [ +pub const KNOWN_LIBS: [(&str, [(&str, &str); 2]); 7] = [ ("core", CORE), ("binary_operators", BINARY_OPERATORS), ("math", MATH), - ("memories", MEMORIES), + ("comb_memories", COMB_MEMORIES), + ("seq_memories", SEQ_MEMORIES), ("pipelined", PIPELINED), ("sync", SYNC), ]; diff --git a/docs/lang/attributes.md b/docs/lang/attributes.md index 80e6ca671..6c39f7ee4 100644 --- a/docs/lang/attributes.md +++ b/docs/lang/attributes.md @@ -21,7 +21,7 @@ component main<"static"=10>(@go go: 1) -> (@done done: 1) { #### **Cell Attributes** ``` cells { - @external mem = std_mem_d1(32, 8, 4); + @external mem = comb_mem_d1(32, 8, 4); reg = std_reg(32); ... } @@ -147,7 +147,7 @@ Marks the special clock signal inserted by the `clk-insertion` pass, which helps Used by the `papercut` pass. Defines a group `n` of signals that all must be driven together: ``` -primitive std_mem_d2<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( +primitive comb_mem_d2<"static"=1>[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( @write_together(2) addr0: D0_IDX_SIZE, @write_together(2) addr1: D1_IDX_SIZE, @write_together(1) write_data: WIDTH, @@ -169,7 +169,7 @@ Used by `papercut` and `canonicalize`. Defines a combinational path `n` between a set of an input ports and an output port. ``` -primitive std_mem_d1<"static"=1>[WIDTH, SIZE, IDX_SIZE]( +primitive comb_mem_d1<"static"=1>[WIDTH, SIZE, IDX_SIZE]( @read_together(1) addr0: IDX_SIZE, ... ) -> ( @read_together(1) read_data: WIDTH, ... diff --git a/docs/lang/data-format.md b/docs/lang/data-format.md index da6c26ea6..891af417d 100644 --- a/docs/lang/data-format.md +++ b/docs/lang/data-format.md @@ -9,8 +9,8 @@ First, a Calyx program must mark memories using the [`@external` attribute][ext- ``` component main() { cells { - @external ext = std_mem_d1(...); - internal = std_mem_d1(...); + @external ext = comb_mem_d1(...); + internal = comb_mem_d1(...); } } ``` @@ -30,7 +30,7 @@ The JSON-based data format allows us to provide inputs for a memory and specify {{#include ../../examples/tutorial/data.json}} ``` -The `data` field represents the initial data for the memory and can use mutlidimensional arrays to describe it. For example, the following is the initial data for a two-dimensional (`std_mem_d2`) memory: +The `data` field represents the initial data for the memory and can use mutlidimensional arrays to describe it. For example, the following is the initial data for a two-dimensional (`comb_mem_d2`) memory: ```json { diff --git a/docs/lang/memories-by-reference.md b/docs/lang/memories-by-reference.md index aea5329e9..15063c237 100644 --- a/docs/lang/memories-by-reference.md +++ b/docs/lang/memories-by-reference.md @@ -32,7 +32,7 @@ Calyx uses the `ref` keyword to describe cells that are passed by reference: ``` component add_one() -> () { cells { - ref mem = std_mem_d1(32, 4, 3); // A memory passed by reference. + ref mem = comb_mem_d1(32, 4, 3); // A memory passed by reference. ... } ... @@ -47,7 +47,7 @@ Next, to pass the memory to the component, we use the `invoke` syntax: component add_one() -> () { ... } component main() -> () { cells { - A = std_mem_d1(32, 4, 3); // A memory passed by reference. + A = comb_mem_d1(32, 4, 3); // A memory passed by reference. one = add_one(); ... } @@ -77,11 +77,11 @@ We will do up two components that are designed to receive memories by reference: component wrap2(i: 32, j: 32) -> () { cells { // Six memories that will be passed by reference. - ref mem1 = std_mem_d1(32, 4, 32); + ref mem1 = comb_mem_d1(32, 4, 32); // ... - ref mem6 = std_mem_d1(32, 4, 32); + ref mem6 = comb_mem_d1(32, 4, 32); // An answer cell, also passed by reference. - ref ans = std_mem_d1(32, 1, 32); + ref ans = comb_mem_d1(32, 1, 32); } wires { ... } control { ... } @@ -92,11 +92,11 @@ and component wrap3(i: 32, j: 32) -> () { cells { // Six memories that will be passed by reference. - ref mem1 = std_mem_d1(32, 4, 32); + ref mem1 = comb_mem_d1(32, 4, 32); // ... - ref mem6 = std_mem_d1(32, 4, 32); + ref mem6 = comb_mem_d1(32, 4, 32); // An answer cell, also passed by reference. - ref ans = std_mem_d1(32, 1, 32); + ref ans = comb_mem_d1(32, 1, 32); } wires { ... } control { ... } @@ -113,13 +113,13 @@ By passing these memories to the components above, the invoker is able to wrap t component main() -> () { cells { // Six memories that will pass by reference. - @external A = std_mem_d1(32, 4, 32); + @external A = comb_mem_d1(32, 4, 32); //... - @external F = std_mem_d1(32, 4, 32); + @external F = comb_mem_d1(32, 4, 32); // Two answer cells that we will also pass. - @external out2 = std_mem_d1(32, 1, 32); - @external out3 = std_mem_d1(32, 1, 32); + @external out2 = comb_mem_d1(32, 1, 32); + @external out3 = comb_mem_d1(32, 1, 32); // Preparing to invoke the components above. together2 = wrap2(); diff --git a/docs/lang/ref.md b/docs/lang/ref.md index a0de7729a..f32ba0c91 100644 --- a/docs/lang/ref.md +++ b/docs/lang/ref.md @@ -227,7 +227,7 @@ Guards can use the following constructs: - `guard || guard`: Disjunction between two guards - `guard && guard`: Conjunction of two guards -In the context of guards, a port can also be a literal (i.e., `counter.out == 3'd2` is a valid guard). +In the context of guards, a port can also be a literal (i.e., `counter.out == 3'd2` is a valid guard). > **Well-formedness**: For each input port on the LHS, only one guard should be active in any given cycle during the execution of a Calyx program. @@ -415,7 +415,7 @@ repeat { } ``` -Repeatedly executes the control program `body_c` `num_repeat` times in a row. +Repeatedly executes the control program `body_c` `num_repeat` times in a row. ## The `go`-`done` Interface @@ -456,7 +456,7 @@ Calyx components can specify that a cell needs to be passed "by reference": // Component that performs mem[0] += 1; component update_memory() -> () { cells { - ref mem = std_mem_d1(...) + ref mem = comb_mem_d1(...) } wires { ... } control { ... } @@ -468,8 +468,8 @@ When invoking such a component, the calling component must provide a binding for component main() -> () { cells { upd = update_memory(); - m1 = std_mem_d1(...); - m2 = std_mem_d2(...); + m1 = comb_mem_d1(...); + m2 = comb_mem_d2(...); } wires { ... } control { diff --git a/docs/libraries/core.md b/docs/libraries/core.md index 0c017fd71..235492f23 100644 --- a/docs/libraries/core.md +++ b/docs/libraries/core.md @@ -290,7 +290,7 @@ Less than or equal. This component is combinational. ## Memories -### `std_mem_d1` +### `comb_mem_d1` A one-dimensional memory. @@ -313,7 +313,7 @@ A one-dimensional memory. --- -### `std_mem_d2` +### `comb_mem_d2` A two-dimensional memory. @@ -339,7 +339,7 @@ A two-dimensional memory. --- -### `std_mem_d3` +### `comb_mem_d3` A three-dimensional memory. @@ -368,7 +368,7 @@ A three-dimensional memory. --- -### `std_mem_d4` +### `comb_mem_d4` A four-dimensional memory. diff --git a/docs/running-calyx/fud/resource-estimation.md b/docs/running-calyx/fud/resource-estimation.md index 4d597e496..d0fade6c9 100644 --- a/docs/running-calyx/fud/resource-estimation.md +++ b/docs/running-calyx/fud/resource-estimation.md @@ -1,6 +1,6 @@ # Resource Estimation Backend -The resources estimation backend aims to provide a size estimation for the hardware that Calyx generates. Currently, it only supports estimation for `std_reg`, `std_mem_*`, and `seq_mem_*` primitives, but more primitives will be added. +The resources estimation backend aims to provide a size estimation for the hardware that Calyx generates. Currently, it only supports estimation for `std_reg`, `comb_mem_*`, and `seq_mem_*` primitives, but more primitives will be added. ## Running the resource estimation backend diff --git a/docs/tutorial/frontend-tut.md b/docs/tutorial/frontend-tut.md index fdfbad215..f1eb62eb4 100644 --- a/docs/tutorial/frontend-tut.md +++ b/docs/tutorial/frontend-tut.md @@ -170,14 +170,14 @@ main = prog.component("main") # Create a component named "main" `Decl` nodes instantiate new memories and registers. We need these to be instantiated in the `cells` section of our Calyx output. -We use Calyx's [`std_reg`][reg-calyx] and [`std_mem_d1`][mem-calyx] primitives to represent [registers][reg-verilog] and [memories][mem-verilog]: +We use Calyx's [`std_reg`][reg-calyx] and [`comb_mem_d1`][mem-calyx] primitives to represent [registers][reg-verilog] and [memories][mem-verilog]: ```C import "primitives/core.futil"; // Import standard library component main() -> () { cells { // A memory with 4 32-bit elements. Indexed using a 6-bit value. - avec = std_mem_d1(32, 4, 6); + avec = comb_mem_d1(32, 4, 6); // A register that contains a 32-bit value sos = std_reg(32); } @@ -306,7 +306,7 @@ The noteworthy change is the parallelism factor of the `map` operation. The parallelism factor `2` specifies that two copies of the loop bodies should be executed in parallel. Translating this into a hardware implementation has a couple of associated challenges: -1. Our memories (`std_mem_d1`) are *extremely* primitive and do not support parallel accesses; a program may only read or write to one memory location every cycle. In order to support parallel accesses, we need to create *multiple physical banks* that represent one logical memory and contain distinct elements. +1. Our memories (`comb_mem_d1`) are *extremely* primitive and do not support parallel accesses; a program may only read or write to one memory location every cycle. In order to support parallel accesses, we need to create *multiple physical banks* that represent one logical memory and contain distinct elements. 2. We need to generate *multiple copies* of the hardware we generated above because, again, adders and multipliers are physical resources and can only support one computation at a time. To produce the full Calyx program for the above example, run the following from the root of the Calyx repository: diff --git a/docs/tutorial/language-tut.md b/docs/tutorial/language-tut.md index 20bf4a660..b26e8bbba 100644 --- a/docs/tutorial/language-tut.md +++ b/docs/tutorial/language-tut.md @@ -46,8 +46,8 @@ We'll start by adding a memory component to the cells: {{#include ../../examples/tutorial/language-tutorial-mem.futil:cells}} ``` -This new line declares a new cell called `mem` and the primitive component `std_mem_d1` represents a 1D memory. -You can see the definition of `std_mem_d1`, and all the other standard components, in the `primitives/core.futil` library we imported. +This new line declares a new cell called `mem` and the primitive component `comb_mem_d1` represents a 1D memory. +You can see the definition of `comb_mem_d1`, and all the other standard components, in the `primitives/core.futil` library we imported. This one has three parameters: the data width (here, 32 bits), diff --git a/docs/tutorial/sos.calyx b/docs/tutorial/sos.calyx index 412cb1d4f..5429f8504 100644 --- a/docs/tutorial/sos.calyx +++ b/docs/tutorial/sos.calyx @@ -2,10 +2,10 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 4, 32); - @external sos = std_mem_d1(32, 1, 32); + @external avec_b0 = comb_mem_d1(32, 4, 32); + @external sos = comb_mem_d1(32, 1, 32); sos_reg = std_reg(32); - squares_b0 = std_mem_d1(32, 4, 32); + squares_b0 = comb_mem_d1(32, 4, 32); idx_b0_0 = std_reg(32); incr_b0_0 = std_add(32); lt_b0_0 = std_lt(32); diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index 4021912c6..892882468 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external @data A0 = std_mem_d1(32, 8, 4); + @external @data A0 = comb_mem_d1(32, 8, 4); @data A_read0_0 = std_reg(32); - @external @data B0 = std_mem_d1(32, 8, 4); + @external @data B0 = comb_mem_d1(32, 8, 4); @data B_read0_0 = std_reg(32); @data add0 = std_add(32); @data add1 = std_add(4); @@ -15,7 +16,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @data i0 = std_reg(4); @control le0 = std_le(4); @data mult_pipe0 = std_mult_pipe(32); - @external @data v0 = std_mem_d1(32, 1, 1); + @external @data v0 = comb_mem_d1(32, 1, 1); @generated comb_reg = std_reg(1); @generated fsm = std_reg(4); @generated ud = undef(1); diff --git a/examples/futil/dot-product.futil b/examples/futil/dot-product.futil index 96025ad19..a4f5bfbe0 100644 --- a/examples/futil/dot-product.futil +++ b/examples/futil/dot-product.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,8,4); + @external(1) A0 = comb_mem_d1(32,8,4); A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,8,4); + @external(1) B0 = comb_mem_d1(32,8,4); B_read0_0 = std_reg(32); add0 = std_add(32); add1 = std_add(4); @@ -17,7 +18,7 @@ component main() -> () { i0 = std_reg(4); le0 = std_le(4); mult_pipe0 = std_mult_pipe(32); - @external(1) v0 = std_mem_d1(32,1,1); + @external(1) v0 = comb_mem_d1(32,1,1); } wires { comb group cond0 { diff --git a/examples/futil/memory-by-reference/memory-by-reference.futil b/examples/futil/memory-by-reference/memory-by-reference.futil index 72a5749a3..306757d13 100644 --- a/examples/futil/memory-by-reference/memory-by-reference.futil +++ b/examples/futil/memory-by-reference/memory-by-reference.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; //// ANCHOR: component //// ANCHOR: component_ports @@ -40,7 +41,7 @@ component add_one(x_done: 1, x_read_data: 32) -> component main() -> () { cells { add_one0 = add_one(); - @external(1) x = std_mem_d1(32, 1, 1); + @external(1) x = comb_mem_d1(32, 1, 1); } wires { } diff --git a/examples/futil/multi-component.expect b/examples/futil/multi-component.expect index 21ec08df6..18fae6749 100644 --- a/examples/futil/multi-component.expect +++ b/examples/futil/multi-component.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component identity<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { @data r = std_reg(32); diff --git a/examples/futil/multi-component.futil b/examples/futil/multi-component.futil index f2db44632..47b078f0c 100644 --- a/examples/futil/multi-component.futil +++ b/examples/futil/multi-component.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; //// ANCHOR: component component identity(in: 32) -> (out: 32) { diff --git a/examples/futil/pass-in-register.expect b/examples/futil/pass-in-register.expect index 4fe2b20f1..2b66663f0 100644 --- a/examples/futil/pass-in-register.expect +++ b/examples/futil/pass-in-register.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/unsynthesizable.futil"; component times_10_and_add_1<"state_share"=1>(reg_done: 1, reg_out: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (reg_in: 32, reg_write_en: 1, @done done: 1) { cells { diff --git a/examples/futil/pass-in-register.futil b/examples/futil/pass-in-register.futil index 8c18e4f98..43d83facb 100644 --- a/examples/futil/pass-in-register.futil +++ b/examples/futil/pass-in-register.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/unsynthesizable.futil"; //// ANCHOR: component diff --git a/examples/futil/simple.expect b/examples/futil/simple.expect index 27bcdd76d..ad0210d99 100644 --- a/examples/futil/simple.expect +++ b/examples/futil/simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/examples/futil/simple.futil b/examples/futil/simple.futil index 30139d947..172d7a800 100644 --- a/examples/futil/simple.futil +++ b/examples/futil/simple.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; // *NOTE*: This was hand-written, and does not demonstrate the capabilities of Calyx. diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index 005c8bc0f..45a34acfd 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external @data A0 = std_mem_d1(32, 8, 4); + @external @data A0 = comb_mem_d1(32, 8, 4); @data A_read0_0 = std_reg(32); - @external @data B0 = std_mem_d1(32, 8, 4); + @external @data B0 = comb_mem_d1(32, 8, 4); @data B_read0_0 = std_reg(32); - @external @data Sum0 = std_mem_d1(32, 8, 4); + @external @data Sum0 = comb_mem_d1(32, 8, 4); @data add0 = std_add(32); @data add1 = std_add(4); @data const0 = std_const(4, 0); diff --git a/examples/futil/vectorized-add.futil b/examples/futil/vectorized-add.futil index 94097f231..926c718b2 100644 --- a/examples/futil/vectorized-add.futil +++ b/examples/futil/vectorized-add.futil @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,8,4); + @external(1) A0 = comb_mem_d1(32,8,4); A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,8,4); + @external(1) B0 = comb_mem_d1(32,8,4); B_read0_0 = std_reg(32); - @external(1) Sum0 = std_mem_d1(32,8,4); + @external(1) Sum0 = comb_mem_d1(32,8,4); add0 = std_add(32); add1 = std_add(4); const0 = std_const(4,0); diff --git a/examples/sync/sync-doc-example.futil b/examples/sync/sync-doc-example.futil index e4839ab24..a9f7624af 100644 --- a/examples/sync/sync-doc-example.futil +++ b/examples/sync/sync-doc-example.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - @external accm = std_mem_d1(32, 1, 1); + @external accm = comb_mem_d1(32, 1, 1); add1 = std_add(32); add2 = std_add(32); r = std_reg(32); @@ -45,7 +46,7 @@ component main () -> () { } control { - /// ANCHOR: control + /// ANCHOR: control par { // thread A while lt.out with comp { diff --git a/examples/sync/sync-if.futil b/examples/sync/sync-if.futil index a0e147a92..3a5b47c50 100644 --- a/examples/sync/sync-if.futil +++ b/examples/sync/sync-if.futil @@ -4,13 +4,14 @@ // thread 2: // no-op; sync; r(1); sync; r(4); sync; r(5); sync; r(8); sync; r(9); sync; r(12); import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - @external in_0 = std_mem_d1(32, 6, 3); - @external in_1 = std_mem_d1(32, 6, 3); - @external out = std_mem_d1(32, 6, 3); + @external in_0 = comb_mem_d1(32, 6, 3); + @external in_1 = comb_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/examples/sync/sync-t-w-t-r.futil b/examples/sync/sync-t-w-t-r.futil index 93cb7c936..012045251 100644 --- a/examples/sync/sync-t-w-t-r.futil +++ b/examples/sync/sync-t-w-t-r.futil @@ -1,16 +1,17 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; // Sum up values of same indices from two arrays of equal length. // Expected resolution order for arbitration: -// below we denote 1 is written to the synchronized register by writer_0 as 1W0, and +// below we denote 1 is written to the synchronized register by writer_0 as 1W0, and // 6 is read from the synchronized register by reader_1 as 6R1. // 1W0 1R0 6W1 6R1 5W1 5R1 2W0 2R0 3W0 3R0 4W1 4R1 3W1 3R1 4W0 4R0 5W0 5R0 2W1 2R1 1W0 1R0 6W1 6R1 component main() -> () { cells { - @external in_0 = std_mem_d1(32, 6, 3); - @external in_1 = std_mem_d1(32, 6, 3); - @external out = std_mem_d1(32, 6, 3); + @external in_0 = comb_mem_d1(32, 6, 3); + @external in_1 = comb_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 6, 3); lt = std_lt(3); sum = std_add(32); add = std_add(3); @@ -32,7 +33,7 @@ component main() -> () { in_0.addr0 = idx.out; write_imm_0[done] = imm.write_done_0; } - + group write_imm_1 { imm.write_en_1 = 1'd1; imm.in_1 = in_1.read_data; diff --git a/examples/sync/sync-two-writers.futil b/examples/sync/sync-two-writers.futil index 462613fe6..059bfba9a 100644 --- a/examples/sync/sync-two-writers.futil +++ b/examples/sync/sync-two-writers.futil @@ -1,16 +1,17 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; // Sum up all values from two arrays. // Expected resolution order for arbitration: -// below we denote 1 is written to the synchronized register as 1W, and +// below we denote 1 is written to the synchronized register as 1W, and // 6 is read from the synchronized register as 6R. // 1W 1R 6W 6R 5W 5R 2W 2R 3W 3R 4W 4R 3W 3R 4W 4R 5W 5R 2W 2R 1W 1R 6W 6R component main() -> () { cells { - @external in_0 = std_mem_d1(32, 6, 3); - @external in_1 = std_mem_d1(32, 6, 3); - @external out = std_mem_d1(32, 1, 3); + @external in_0 = comb_mem_d1(32, 6, 3); + @external in_1 = comb_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 1, 3); lt = std_lt(3); sum = std_add(32); add = std_add(3); @@ -36,7 +37,7 @@ component main() -> () { in_0.addr0 = idx.out; write_imm_0[done] = imm.write_done_0; } - + group write_imm_1 { imm.write_en_1 = 1'd1; imm.in_1 = in_1.read_data; diff --git a/examples/sync/sync.futil b/examples/sync/sync.futil index be17daaa3..a17193791 100644 --- a/examples/sync/sync.futil +++ b/examples/sync/sync.futil @@ -1,12 +1,13 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; // Move data from one array to another with the index as a synchronized // register. component main() -> () { cells { - @external in = std_mem_d1(32, 5, 3); - @external out = std_mem_d1(32, 5, 3); + @external in = comb_mem_d1(32, 5, 3); + @external out = comb_mem_d1(32, 5, 3); lt = std_lt(3); add = std_add(3); diff --git a/examples/sync/unsync-example/unsync-doc-example.futil b/examples/sync/unsync-example/unsync-doc-example.futil index 5d56934eb..bd9e6c840 100644 --- a/examples/sync/unsync-example/unsync-doc-example.futil +++ b/examples/sync/unsync-example/unsync-doc-example.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - @external accm = std_mem_d1(32, 1, 1); + @external accm = comb_mem_d1(32, 1, 1); add1 = std_add(32); add2 = std_add(32); r = std_reg(32); diff --git a/examples/tutorial/language-tutorial-compute.futil b/examples/tutorial/language-tutorial-compute.futil index 869fbc664..b6e12b474 100644 --- a/examples/tutorial/language-tutorial-compute.futil +++ b/examples/tutorial/language-tutorial-compute.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1) -> (@done done: 1) { // ANCHOR: cells cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); val = std_reg(32); add = std_add(32); } diff --git a/examples/tutorial/language-tutorial-control.futil b/examples/tutorial/language-tutorial-control.futil index 0739b7845..106ebd4c4 100644 --- a/examples/tutorial/language-tutorial-control.futil +++ b/examples/tutorial/language-tutorial-control.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1) -> (@done done: 1) { // ANCHOR: cells cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); } // ANCHOR_END: cells // ANCHOR: wires diff --git a/examples/tutorial/language-tutorial-iterate.futil b/examples/tutorial/language-tutorial-iterate.futil index 95118dde1..878bd1473 100644 --- a/examples/tutorial/language-tutorial-iterate.futil +++ b/examples/tutorial/language-tutorial-iterate.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); val = std_reg(32); add = std_add(32); diff --git a/examples/tutorial/language-tutorial-mem.futil b/examples/tutorial/language-tutorial-mem.futil index 5be0f0f24..615ab15d2 100644 --- a/examples/tutorial/language-tutorial-mem.futil +++ b/examples/tutorial/language-tutorial-mem.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1) -> (@done done: 1) { // ANCHOR: cells cells { - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); } // ANCHOR_END: cells // ANCHOR: wires diff --git a/frontends/mrxl/mrxl/gen_calyx.py b/frontends/mrxl/mrxl/gen_calyx.py index 19152834e..862b8bbbe 100644 --- a/frontends/mrxl/mrxl/gen_calyx.py +++ b/frontends/mrxl/mrxl/gen_calyx.py @@ -359,11 +359,13 @@ def emit(prog: ast.Prog, use_my_map_impl: bool = False): par = par_factor[name] # ANCHOR: collect-decls for i in range(par): - main.mem_d1(f"{name}_b{i}", 32, arr_size // par, 32, is_external=True) + main.comb_mem_d1( + f"{name}_b{i}", 32, arr_size // par, 32, is_external=True + ) # ANCHOR_END: collect-decls else: # A register name = decl.name - mem = main.mem_d1(name, 32, 1, 32, is_external=True) + mem = main.comb_mem_d1(name, 32, 1, 32, is_external=True) reg = main.reg(f"{name}_reg", 32) if not decl.input: reg_to_mem.append(Enable(reg_to_mem_group(main, name, reg, mem))) @@ -380,7 +382,7 @@ def emit(prog: ast.Prog, use_my_map_impl: bool = False): name = stmt.dst par = par_factor[name] for i in range(par): - main.mem_d1(f"{name}_b{i}", 32, arr_size // par, 32) + main.comb_mem_d1(f"{name}_b{i}", 32, arr_size // par, 32) else: raise NotImplementedError("Generating register declarations") # cells.append(emit_reg_decl(stmt.dest, 32)) diff --git a/frontends/mrxl/test/expect/futil_out/add.expect b/frontends/mrxl/test/expect/futil_out/add.expect index 838fed5e1..c4bdafc97 100644 --- a/frontends/mrxl/test/expect/futil_out/add.expect +++ b/frontends/mrxl/test/expect/futil_out/add.expect @@ -2,12 +2,12 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external in_a_b0 = std_mem_d1(32, 2, 32); - @external in_a_b1 = std_mem_d1(32, 2, 32); - @external in_b_b0 = std_mem_d1(32, 2, 32); - @external in_b_b1 = std_mem_d1(32, 2, 32); - @external out_b0 = std_mem_d1(32, 2, 32); - @external out_b1 = std_mem_d1(32, 2, 32); + @external in_a_b0 = comb_mem_d1(32, 2, 32); + @external in_a_b1 = comb_mem_d1(32, 2, 32); + @external in_b_b0 = comb_mem_d1(32, 2, 32); + @external in_b_b1 = comb_mem_d1(32, 2, 32); + @external out_b0 = comb_mem_d1(32, 2, 32); + @external out_b1 = comb_mem_d1(32, 2, 32); idx_b0_0 = std_reg(32); incr_b0_0 = std_add(32); lt_b0_0 = std_lt(32); diff --git a/frontends/mrxl/test/expect/futil_out/dot.expect b/frontends/mrxl/test/expect/futil_out/dot.expect index 9a373d398..c7fee19bf 100644 --- a/frontends/mrxl/test/expect/futil_out/dot.expect +++ b/frontends/mrxl/test/expect/futil_out/dot.expect @@ -2,11 +2,11 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 4, 32); - @external bvec_b0 = std_mem_d1(32, 4, 32); - @external dot = std_mem_d1(32, 1, 32); + @external avec_b0 = comb_mem_d1(32, 4, 32); + @external bvec_b0 = comb_mem_d1(32, 4, 32); + @external dot = comb_mem_d1(32, 1, 32); dot_reg = std_reg(32); - prodvec_b0 = std_mem_d1(32, 4, 32); + prodvec_b0 = comb_mem_d1(32, 4, 32); idx_b0_0 = std_reg(32); incr_b0_0 = std_add(32); lt_b0_0 = std_lt(32); diff --git a/frontends/mrxl/test/expect/futil_out/prod.expect b/frontends/mrxl/test/expect/futil_out/prod.expect index f5f62ee4d..cdefeefe7 100644 --- a/frontends/mrxl/test/expect/futil_out/prod.expect +++ b/frontends/mrxl/test/expect/futil_out/prod.expect @@ -2,8 +2,8 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 8, 32); - @external out = std_mem_d1(32, 1, 32); + @external avec_b0 = comb_mem_d1(32, 8, 32); + @external out = comb_mem_d1(32, 1, 32); out_reg = std_reg(32); idx0 = std_reg(32); incr_0 = std_add(32); diff --git a/frontends/mrxl/test/expect/futil_out/sos.expect b/frontends/mrxl/test/expect/futil_out/sos.expect index 412cb1d4f..5429f8504 100644 --- a/frontends/mrxl/test/expect/futil_out/sos.expect +++ b/frontends/mrxl/test/expect/futil_out/sos.expect @@ -2,10 +2,10 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 4, 32); - @external sos = std_mem_d1(32, 1, 32); + @external avec_b0 = comb_mem_d1(32, 4, 32); + @external sos = comb_mem_d1(32, 1, 32); sos_reg = std_reg(32); - squares_b0 = std_mem_d1(32, 4, 32); + squares_b0 = comb_mem_d1(32, 4, 32); idx_b0_0 = std_reg(32); incr_b0_0 = std_add(32); lt_b0_0 = std_lt(32); diff --git a/frontends/mrxl/test/expect/futil_out/squares.expect b/frontends/mrxl/test/expect/futil_out/squares.expect index 2c2ada81c..d5251e65d 100644 --- a/frontends/mrxl/test/expect/futil_out/squares.expect +++ b/frontends/mrxl/test/expect/futil_out/squares.expect @@ -2,10 +2,10 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 2, 32); - @external avec_b1 = std_mem_d1(32, 2, 32); - @external squares_b0 = std_mem_d1(32, 2, 32); - @external squares_b1 = std_mem_d1(32, 2, 32); + @external avec_b0 = comb_mem_d1(32, 2, 32); + @external avec_b1 = comb_mem_d1(32, 2, 32); + @external squares_b0 = comb_mem_d1(32, 2, 32); + @external squares_b1 = comb_mem_d1(32, 2, 32); idx_b0_0 = std_reg(32); incr_b0_0 = std_add(32); lt_b0_0 = std_lt(32); diff --git a/frontends/mrxl/test/expect/futil_out/sum.expect b/frontends/mrxl/test/expect/futil_out/sum.expect index 69b800acc..0734b9559 100644 --- a/frontends/mrxl/test/expect/futil_out/sum.expect +++ b/frontends/mrxl/test/expect/futil_out/sum.expect @@ -2,8 +2,8 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external avec_b0 = std_mem_d1(32, 16, 32); - @external out = std_mem_d1(32, 1, 32); + @external avec_b0 = comb_mem_d1(32, 16, 32); + @external out = comb_mem_d1(32, 1, 32); out_reg = std_reg(32); idx0 = std_reg(32); incr_0 = std_add(32); diff --git a/frontends/ntt-pipeline/gen-ntt-pipeline.py b/frontends/ntt-pipeline/gen-ntt-pipeline.py index ef951be34..8c66a9ba0 100755 --- a/frontends/ntt-pipeline/gen-ntt-pipeline.py +++ b/frontends/ntt-pipeline/gen-ntt-pipeline.py @@ -233,8 +233,12 @@ def cells(): input = CompVar("a") phis = CompVar("phis") memories = [ - Cell(input, Stdlib.mem_d1(input_bitwidth, n, bitwidth), is_external=True), - Cell(phis, Stdlib.mem_d1(input_bitwidth, n, bitwidth), is_external=True), + Cell( + input, Stdlib.comb_mem_d1(input_bitwidth, n, bitwidth), is_external=True + ), + Cell( + phis, Stdlib.comb_mem_d1(input_bitwidth, n, bitwidth), is_external=True + ), ] r_regs = [ Cell(CompVar(f"r{r}"), Stdlib.register(input_bitwidth)) for r in range(n) @@ -322,6 +326,7 @@ def control(): pp_table(operations, multiplies, n, num_stages) prog = cb.Builder() prog.import_("primitives/binary_operators.futil") + prog.import_("primitives/memories/comb.futil") main = prog.component("main", cells()) wires(main) main.component.controls = control() diff --git a/frontends/relay/onnx_to_calyx.py b/frontends/relay/onnx_to_calyx.py index ab4e762ad..72c762201 100644 --- a/frontends/relay/onnx_to_calyx.py +++ b/frontends/relay/onnx_to_calyx.py @@ -61,7 +61,7 @@ def write_calyx(relay_ir, filename: str, save_mem=True): Import("primitives/core.futil"), Import("primitives/binary_operators.futil"), Import("primitives/math.futil"), - Import("primitives/memories.futil"), + Import("primitives/memories/seq.futil"), ] for imp in imports: file.writelines(imp.doc()) @@ -178,7 +178,11 @@ def run_net(net_name: str, input, onnx_model_path: str, output: str, save_mem=Tr # Determines whether you want to save memory or not since save_mem is # an optional argument, we want default setting of save_mem to be true - save_mem = args["save_mem"] is None or args["save_mem"] == "True" or args["save_mem"] == "true" + save_mem = ( + args["save_mem"] is None + or args["save_mem"] == "True" + or args["save_mem"] == "true" + ) # Runs the net and prints the classification output. run_net(net_name, data, onnx_model_path, output, save_mem) diff --git a/frontends/relay/relay_utils.py b/frontends/relay/relay_utils.py index c76a4ff44..864fa3634 100644 --- a/frontends/relay/relay_utils.py +++ b/frontends/relay/relay_utils.py @@ -49,7 +49,7 @@ def get_dimension_sizes(c: CompInst) -> List[int]: """Given a cell `c`, returns the corresponding memory sizes. Example: - std_mem_d1(32, 8, 3) returns [8].""" + comb_mem_d1(32, 8, 3) returns [8].""" dims = get_dims(c) return [c.args[i] for i in range(1, dims + 1)] @@ -110,7 +110,7 @@ def add_arg2(arg_cell, param_cell): args ), "we are reusing a dahlia function but the args are different lengths" assert old_dest is not None, "if using old_args must provide an old_dest too" - for (cell1, cell2) in zip(args, old_args): + for cell1, cell2 in zip(args, old_args): add_arg2(cell1, cell2) add_arg2(dest, old_dest) diff --git a/frontends/relay/relay_visitor.py b/frontends/relay/relay_visitor.py index be4b0ac34..731dbb2ca 100755 --- a/frontends/relay/relay_visitor.py +++ b/frontends/relay/relay_visitor.py @@ -530,7 +530,7 @@ def get_program_dat_memories(relay_ir): imports = [ Import("primitives/core.futil"), - Import("primitives/memories.futil"), + Import("primitives/memories/seq.futil"), Import("primitives/binary_operators.futil"), Import("primitives/math.futil"), ] diff --git a/frontends/systolic-lang/gen-systolic.py b/frontends/systolic-lang/gen-systolic.py index dfe992b6e..03f426556 100755 --- a/frontends/systolic-lang/gen-systolic.py +++ b/frontends/systolic-lang/gen-systolic.py @@ -46,7 +46,7 @@ def create_mem_connections( If `read_mem` == False, then connects memory ports such that `component_builder` can write to memory. """ - mem = main.mem_d1( + mem = main.comb_mem_d1( mem_name, BITWIDTH, mem_size, diff --git a/frontends/systolic-lang/pe/mac.futil b/frontends/systolic-lang/pe/mac.futil index 2cbe9b950..6b86c2830 100644 --- a/frontends/systolic-lang/pe/mac.futil +++ b/frontends/systolic-lang/pe/mac.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; // A MAC pipelined MAC that performs an add in the first cycle and multiply diff --git a/fud2/rsrc/primitives-for-firrtl.sv b/fud2/rsrc/primitives-for-firrtl.sv index 6335c649a..c92fdfaee 100644 --- a/fud2/rsrc/primitives-for-firrtl.sv +++ b/fud2/rsrc/primitives-for-firrtl.sv @@ -1,4 +1,4 @@ -module std_mem_d1 #( +module comb_mem_d1 #( parameter WIDTH = 32, parameter SIZE = 16, parameter IDX_SIZE = 4 @@ -43,7 +43,7 @@ module std_mem_d1 #( always_comb begin if (addr0 >= SIZE) $error( - "std_mem_d1: Out of bounds access\n", + "comb_mem_d1: Out of bounds access\n", "addr0: %0d\n", addr0, "SIZE: %0d", SIZE ); diff --git a/interp/src/flatten/flat_ir/cell_prototype.rs b/interp/src/flatten/flat_ir/cell_prototype.rs index 4bfa11ed5..b51a63c42 100644 --- a/interp/src/flatten/flat_ir/cell_prototype.rs +++ b/interp/src/flatten/flat_ir/cell_prototype.rs @@ -457,14 +457,14 @@ impl CellPrototype { out: out_width.try_into().unwrap(), } } - n @ ("std_mem_d1" | "seq_mem_d1") => { + n @ ("comb_mem_d1" | "seq_mem_d1") => { get_params![params; width: "WIDTH", size: "SIZE", idx_size: "IDX_SIZE" ]; Self::MemD1 { - mem_type: if n == "std_mem_d1" { + mem_type: if n == "comb_mem_d1" { MemType::Std } else { MemType::Seq @@ -474,7 +474,7 @@ impl CellPrototype { idx_size: idx_size.try_into().unwrap(), } } - n @ ("std_mem_d2" | "seq_mem_d2") => { + n @ ("comb_mem_d2" | "seq_mem_d2") => { get_params![params; width: "WIDTH", d0_size: "D0_SIZE", @@ -483,7 +483,7 @@ impl CellPrototype { d1_idx_size: "D1_IDX_SIZE" ]; Self::MemD2 { - mem_type: if n == "std_mem_d2" { + mem_type: if n == "comb_mem_d2" { MemType::Std } else { MemType::Seq @@ -495,7 +495,7 @@ impl CellPrototype { d1_idx_size: d1_idx_size.try_into().unwrap(), } } - n @ ("std_mem_d3" | "seq_mem_d3") => { + n @ ("comb_mem_d3" | "seq_mem_d3") => { get_params![params; width: "WIDTH", d0_size: "D0_SIZE", @@ -506,7 +506,7 @@ impl CellPrototype { d2_idx_size: "D2_IDX_SIZE" ]; Self::MemD3 { - mem_type: if n == "std_mem_d3" { + mem_type: if n == "comb_mem_d3" { MemType::Std } else { MemType::Seq @@ -520,7 +520,7 @@ impl CellPrototype { d2_idx_size: d2_idx_size.try_into().unwrap(), } } - n @ ("std_mem_d4" | "seq_mem_d4") => { + n @ ("comb_mem_d4" | "seq_mem_d4") => { get_params![params; width: "WIDTH", d0_size: "D0_SIZE", @@ -534,7 +534,7 @@ impl CellPrototype { ]; Self::MemD4 { - mem_type: if n == "std_mem_d4" { + mem_type: if n == "comb_mem_d4" { MemType::Std } else { MemType::Seq diff --git a/interp/src/structures/environment.rs b/interp/src/structures/environment.rs index fda7aa741..c3526566b 100644 --- a/interp/src/structures/environment.rs +++ b/interp/src/structures/environment.rs @@ -257,7 +257,7 @@ impl InterpreterState { "std_pad" => Box::new(combinational::StdPad::new(params, cell_qin)), // State components "std_reg" => Box::new(stateful::mem::StdReg::new(params, cell_qin)), - "std_mem_d1" => { + "comb_mem_d1" => { let init = mems.as_mut().and_then(|x| x.remove(&cell_name)); match init { @@ -276,7 +276,7 @@ impl InterpreterState { )), } } - "std_mem_d2" => { + "comb_mem_d2" => { let init = mems.as_mut().and_then(|x| x.remove(&cell_name)); match init { @@ -295,7 +295,7 @@ impl InterpreterState { )), } } - "std_mem_d3" => { + "comb_mem_d3" => { let init = mems.as_mut().and_then(|x| x.remove(&cell_name)); match init { @@ -314,7 +314,7 @@ impl InterpreterState { )), } } - "std_mem_d4" => { + "comb_mem_d4" => { let init = mems.as_mut().and_then(|x| x.remove(&cell_name)); match init { diff --git a/interp/src/tests/primitives.rs b/interp/src/tests/primitives.rs index 9290558ad..7a8d80dda 100644 --- a/interp/src/tests/primitives.rs +++ b/interp/src/tests/primitives.rs @@ -221,7 +221,7 @@ fn test_std_reg_imval() { } #[test] -fn test_std_mem_d1() { +fn test_comb_mem_d1() { let mut mem = stfl::mem::StdMemD1::from_constants(6, 10, 4, "".into()); //see that unitialized mem, executed w/ write_en low, //returns 0, and no DONE @@ -288,7 +288,7 @@ fn test_std_mem_d1() { } #[test] -fn test_std_mem_d2() { +fn test_comb_mem_d2() { let mut mem = stfl::mem::StdMemD2::from_constants(6, 4, 4, 2, 2, "".into()); //see that unitialized mem, executed w/ write_en low, //returns 0, and no DONE @@ -353,7 +353,7 @@ fn test_std_mem_d2() { } #[test] -fn test_std_mem_d3() { +fn test_comb_mem_d3() { let mut mem = stfl::mem::StdMemD3::from_constants(6, 4, 4, 4, 2, 2, 2, "".into()); //see that unitialized mem, executed w/ write_en low, @@ -424,7 +424,7 @@ fn test_std_mem_d3() { } #[test] -fn test_std_mem_d4() { +fn test_comb_mem_d4() { let mut mem = stfl::mem::StdMemD4::from_constants( 6, 4, diff --git a/interp/tests/complex/unsigned-div.futil b/interp/tests/complex/unsigned-div.futil index 78ade1b29..3f7f37403 100644 --- a/interp/tests/complex/unsigned-div.futil +++ b/interp/tests/complex/unsigned-div.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; //a simple test for division @@ -12,13 +13,13 @@ component main() -> () { wires { group div_group { - div.go = 1'd1; - div.left = 32'd56; - div.right = 32'd5; - reg_q.write_en = div.done ? 1'd1; - reg_r.write_en = div.done ? 1'd1; + div.go = 1'd1; + div.left = 32'd56; + div.right = 32'd5; + reg_q.write_en = div.done ? 1'd1; + reg_r.write_en = div.done ? 1'd1; reg_q.in = div.out_quotient; - reg_r.in = div.out_remainder; + reg_r.in = div.out_remainder; div_group[done] = reg_q.done; //b/c this group ends a cycle after div ends, the next output of div will be 0 //aka, div will not assert 11 and 1 in its outputs } diff --git a/interp/tests/complex/unsigned-dot-product.futil b/interp/tests/complex/unsigned-dot-product.futil index be581681a..7f7117b7c 100644 --- a/interp/tests/complex/unsigned-dot-product.futil +++ b/interp/tests/complex/unsigned-dot-product.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; // @@ -10,8 +11,8 @@ component main() -> () { @external r_2 = std_reg(32); @external t = std_reg(32); lt0 = std_lt(3); - @external mem0 = std_mem_d2(32, 4, 4, 3, 3); - @external mem1 = std_mem_d2(32, 4, 4, 3, 3); + @external mem0 = comb_mem_d2(32, 4, 4, 3, 3); + @external mem1 = comb_mem_d2(32, 4, 4, 3, 3); add1 = std_add(32); @external mult = std_mult_pipe(32); } @@ -92,7 +93,7 @@ component main() -> () { mult.right = mem1.read_data; mult.go = !mult.done ? 1'd1; t.write_en = mult.done; - //isn't a dot product the sum of the individual entries? make it so + //isn't a dot product the sum of the individual entries? make it so add1.left = t.out; add1.right = mult.out; t.in = add1.out; diff --git a/interp/tests/control/if.futil b/interp/tests/control/if.futil index 69ff5ed80..1803ceacc 100644 --- a/interp/tests/control/if.futil +++ b/interp/tests/control/if.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); lt = std_lt(32); } @@ -22,7 +23,7 @@ component main() -> () { } group false<"static"=1> { - //since this isn't a single group + //since this isn't a single group //execution, mem also has a done of 0 mem.write_en = 1'd1; mem.addr0 = 1'd0; @@ -33,7 +34,7 @@ component main() -> () { control { //you can't really check - //contents of [mem] at end, + //contents of [mem] at end, //cuz our serializiation doesn't //support that currently if lt.out with cond { //reg0 should have a done of 0 at the end of main execution diff --git a/interp/tests/control/if_reg.futil b/interp/tests/control/if_reg.futil index 69fde2ae2..3ee480e34 100644 --- a/interp/tests/control/if_reg.futil +++ b/interp/tests/control/if_reg.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -33,8 +34,8 @@ component main() -> () { control { //similar to [if.futil], - //b/c this isn't just 1 group prog, - //reg1 should have [done] low + //b/c this isn't just 1 group prog, + //reg1 should have [done] low //at the end of execution (tho prog. ends when reg1.done is high) seq { cond; diff --git a/interp/tests/control/invoke/invoke.futil b/interp/tests/control/invoke/invoke.futil index 01022bae0..ef3175b2e 100644 --- a/interp/tests/control/invoke/invoke.futil +++ b/interp/tests/control/invoke/invoke.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component exponent(base: 32, exp: 4) -> (out: 32) { @@ -52,7 +53,7 @@ component exponent(base: 32, exp: 4) -> (out: 32) { component main() -> () { cells { - @external(1) a0 = std_mem_d1(32,10,4); + @external(1) a0 = comb_mem_d1(32,10,4); a_read0_0 = std_reg(32); add0 = std_add(4); const0 = std_const(4,0); diff --git a/interp/tests/control/invoke/k3.futil b/interp/tests/control/invoke/k3.futil index 049afb671..2fa348289 100644 --- a/interp/tests/control/invoke/k3.futil +++ b/interp/tests/control/invoke/k3.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) depth_output = std_mem_d1(3, 1, 1); + @external(1) depth_output = comb_mem_d1(3, 1, 1); @eternal(1) depth = std_reg(3); - @external(1) path_ids1 = std_mem_d1(3, 1, 1); + @external(1) path_ids1 = comb_mem_d1(3, 1, 1); pe1 = node_depth_pe(); } wires { diff --git a/interp/tests/control/iteration/iter_mult.futil b/interp/tests/control/iteration/iter_mult.futil index a83ec7d26..3c86294a8 100644 --- a/interp/tests/control/iteration/iter_mult.futil +++ b/interp/tests/control/iteration/iter_mult.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; //model iterative multiplication of two binary numbers diff --git a/interp/tests/control/iteration/while.futil b/interp/tests/control/iteration/while.futil index 30466105a..92c072e64 100644 --- a/interp/tests/control/iteration/while.futil +++ b/interp/tests/control/iteration/while.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external i = std_mem_d1(32, 1, 1); + @external i = comb_mem_d1(32, 1, 1); lt = std_lt(32); lt_reg = std_reg(1); add = std_add(32); diff --git a/interp/tests/control/par_mem.futil b/interp/tests/control/par_mem.futil index 8bd93c046..d0d1dabe2 100644 --- a/interp/tests/control/par_mem.futil +++ b/interp/tests/control/par_mem.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external a = std_mem_d1(32, 1, 1); - @external b = std_mem_d1(32, 1, 1); - @external c = std_mem_d1(32, 1, 1); + @external a = comb_mem_d1(32, 1, 1); + @external b = comb_mem_d1(32, 1, 1); + @external c = comb_mem_d1(32, 1, 1); } wires { diff --git a/interp/tests/control/par_reg.futil b/interp/tests/control/par_reg.futil index cac8dc66b..d4e1b0d35 100644 --- a/interp/tests/control/par_reg.futil +++ b/interp/tests/control/par_reg.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/control/reg_seq.futil b/interp/tests/control/reg_seq.futil index ef905b6f6..33e99a4c2 100644 --- a/interp/tests/control/reg_seq.futil +++ b/interp/tests/control/reg_seq.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/control/static/while_static.futil b/interp/tests/control/static/while_static.futil index f0765cdae..a5fe6935a 100644 --- a/interp/tests/control/static/while_static.futil +++ b/interp/tests/control/static/while_static.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/errors/multiple_drivers_comb.futil b/interp/tests/errors/multiple_drivers_comb.futil index 4f818c835..8f9c1f62a 100644 --- a/interp/tests/errors/multiple_drivers_comb.futil +++ b/interp/tests/errors/multiple_drivers_comb.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/errors/multiple_drivers_reg.futil b/interp/tests/errors/multiple_drivers_reg.futil index c1a93035d..fdfb3f5e3 100644 --- a/interp/tests/errors/multiple_drivers_reg.futil +++ b/interp/tests/errors/multiple_drivers_reg.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/primitives/add-overflow.futil b/interp/tests/primitives/add-overflow.futil index 5021d363d..a9af8f539 100644 --- a/interp/tests/primitives/add-overflow.futil +++ b/interp/tests/primitives/add-overflow.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -10,17 +11,17 @@ component main() -> () { wires { group add { - adder.left = 4'd8; - adder.right = 4'd15; + adder.left = 4'd8; + adder.right = 4'd15; - reg0.write_en = 1'b1; + reg0.write_en = 1'b1; reg0.in = adder.out; - pad4_5.in = adder.out; - reg1.write_en = 1'b1; - reg1.in = pad4_5.out; + pad4_5.in = adder.out; + reg1.write_en = 1'b1; + reg1.in = pad4_5.out; - add[done] = reg0.done & reg1.done ? 1'b1; + add[done] = reg0.done & reg1.done ? 1'b1; } } diff --git a/interp/tests/primitives/binary.futil b/interp/tests/primitives/binary.futil index caee5817a..88f47a86a 100644 --- a/interp/tests/primitives/binary.futil +++ b/interp/tests/primitives/binary.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { diff --git a/interp/tests/primitives/flickering_go.futil b/interp/tests/primitives/flickering_go.futil index d0754ea2f..39a86324a 100644 --- a/interp/tests/primitives/flickering_go.futil +++ b/interp/tests/primitives/flickering_go.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; @@ -12,8 +13,8 @@ component main() -> () { cells { @external reg0 = std_reg(32); @external reg1 = std_reg(32); - add0 = std_add(1); - @external mult0 = std_mult_pipe(32); + add0 = std_add(1); + @external mult0 = std_mult_pipe(32); @external mult1 = std_mult_pipe(32); @external mult_reg0 = std_reg(32); @external mult_reg1 = std_reg(32); @@ -26,20 +27,20 @@ component main() -> () { reg0.in = 32'd12; add0.left = 1'd1; - add0.right = 1'd0; + add0.right = 1'd0; reg1.in = 32'd12; - exec_reg[done] = reg0.done | reg1.done ? 1'd1; + exec_reg[done] = reg0.done | reg1.done ? 1'd1; } group exec_mult { mult0.go = add0.out == 1'd0 ? 1'd1; //mult_reg0 should have a 0 written to it mult1.go = add0.out; - mult0.left = 32'd1; + mult0.left = 32'd1; mult0.right = 32'd32; - mult1.left = 32'd1; + mult1.left = 32'd1; mult1.right = 32'd32; mult_reg0.write_en = mult1.done; //not a typo @@ -49,11 +50,11 @@ component main() -> () { mult_reg1.in = mult1.out; add0.left = 1'd1; - add0.right = 1'd0; + add0.right = 1'd0; - - exec_mult[done] = mult_reg0.done | mult_reg1.done ? 1'd1; + + exec_mult[done] = mult_reg0.done | mult_reg1.done ? 1'd1; } } diff --git a/interp/tests/primitives/mem.futil b/interp/tests/primitives/mem.futil index 65dd15d5c..951a48503 100644 --- a/interp/tests/primitives/mem.futil +++ b/interp/tests/primitives/mem.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); @external reg0 = std_reg(32); } diff --git a/interp/tests/primitives/mem2.futil b/interp/tests/primitives/mem2.futil index 2a1bac1d7..1d18e37be 100644 --- a/interp/tests/primitives/mem2.futil +++ b/interp/tests/primitives/mem2.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external mem0 = std_mem_d1(32, 8, 3); - @external mem1 = std_mem_d1(32, 8, 3); + @external mem0 = comb_mem_d1(32, 8, 3); + @external mem1 = comb_mem_d1(32, 8, 3); @external reg0 = std_reg(32); } @@ -11,24 +12,24 @@ component main() -> () { group write{ mem0.write_en = 1'd1; mem0.addr0 = 3'd4; - mem0.write_data = 32'd1; + mem0.write_data = 32'd1; write[done] = mem0.done; } group write2{ - mem0.write_en = 1'd1; - mem0.addr0 = 3'd3; + mem0.write_en = 1'd1; + mem0.addr0 = 3'd3; mem0.write_data = 32'd2; - write2[done] = mem0.done; + write2[done] = mem0.done; } group dont_write{ mem0.write_en = 1'd0; mem0.addr0 = 3'd3; mem0.write_data = 32'd4; //make sure there's a 1 at mem0[3], not a 4 - mem1.write_en = 1'd1; + mem1.write_en = 1'd1; mem1.addr0 = 3'd4; - mem1.write_data = 32'd1; + mem1.write_data = 32'd1; dont_write[done] = mem1.done; //does this guarantee mem0 was ticked? no idts } diff --git a/interp/tests/primitives/reg.futil b/interp/tests/primitives/reg.futil index 53c37d5b0..76ffb9197 100644 --- a/interp/tests/primitives/reg.futil +++ b/interp/tests/primitives/reg.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -9,20 +10,20 @@ component main() -> () { wires { group write{ reg0.write_en = 1'd1; - reg0.in = 32'd157; + reg0.in = 32'd157; write[done] = reg0.done; } group dont_write{ reg0.write_en = 1'd0; reg0.in = 32'd0; - reg1.write_en = 1'd1; + reg1.write_en = 1'd1; reg1.in = 32'd23; - dont_write[done] = reg1.done; + dont_write[done] = reg1.done; } group dont_write2{ - reg1.write_en = 1'd1; + reg1.write_en = 1'd1; reg1.in = reg0.out; dont_write2[done] = reg1.done; } diff --git a/interp/tests/primitives/slice.futil b/interp/tests/primitives/slice.futil index e1a7855f0..0e50e1558 100644 --- a/interp/tests/primitives/slice.futil +++ b/interp/tests/primitives/slice.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; //confirm slice of length 1 from any # is LSB component main() -> () { diff --git a/interp/tests/unit/assign-order-does-not-matter.futil b/interp/tests/unit/assign-order-does-not-matter.futil index a3bb2d123..5e3b2e8d2 100644 --- a/interp/tests/unit/assign-order-does-not-matter.futil +++ b/interp/tests/unit/assign-order-does-not-matter.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/unit/combinational-chain.futil b/interp/tests/unit/combinational-chain.futil index b9cb6ad63..4b1d2b5a7 100644 --- a/interp/tests/unit/combinational-chain.futil +++ b/interp/tests/unit/combinational-chain.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/unit/register-writes-visible-inside-group.futil b/interp/tests/unit/register-writes-visible-inside-group.futil index 3e49fc888..3162529a0 100644 --- a/interp/tests/unit/register-writes-visible-inside-group.futil +++ b/interp/tests/unit/register-writes-visible-inside-group.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/interp/tests/unit/uninitialized-port-returns-zero.futil b/interp/tests/unit/uninitialized-port-returns-zero.futil index 99adc9fe4..26626239f 100644 --- a/interp/tests/unit/uninitialized-port-returns-zero.futil +++ b/interp/tests/unit/uninitialized-port-returns-zero.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { diff --git a/primitives/core.futil b/primitives/core.futil index 24d87d20e..1e13daa5d 100644 --- a/primitives/core.futil +++ b/primitives/core.futil @@ -24,71 +24,4 @@ extern "core.sv" { comb primitive std_rsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_mux<"share"=1>[WIDTH](@data cond: 1, @data tru: WIDTH, @data fal: WIDTH) -> (out: WIDTH); - /// Memories - primitive std_mem_d1[WIDTH, SIZE, IDX_SIZE]( - @read_together(1) addr0: IDX_SIZE, - @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, - @clk clk: 1, - @reset reset: 1 - ) -> ( - @read_together(1) read_data: WIDTH, - @done done: 1 - ); - - primitive std_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( - @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, - @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, - @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, - @clk clk: 1, - @reset reset: 1 - ) -> ( - @read_together(1) read_data: WIDTH, - @done done: 1 - ); - - primitive std_mem_d3[ - WIDTH, - D0_SIZE, - D1_SIZE, - D2_SIZE, - D0_IDX_SIZE, - D1_IDX_SIZE, - D2_IDX_SIZE - ] ( - @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, - @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, - @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, - @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, - @clk clk: 1, - @reset reset: 1 - ) -> ( - @read_together(1) read_data: WIDTH, - @done done: 1 - ); - - primitive std_mem_d4[ - WIDTH, - D0_SIZE, - D1_SIZE, - D2_SIZE, - D3_SIZE, - D0_IDX_SIZE, - D1_IDX_SIZE, - D2_IDX_SIZE, - D3_IDX_SIZE - ] ( - @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, - @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, - @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, - @read_together(1) @write_together(2) addr3: D3_IDX_SIZE, - @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, - @clk clk: 1 - ) -> ( - @read_together(1) read_data: WIDTH, - @done done: 1 - ); } diff --git a/primitives/core.sv b/primitives/core.sv index 3c20cd47e..208057491 100644 --- a/primitives/core.sv +++ b/primitives/core.sv @@ -217,242 +217,4 @@ module std_mux #( assign out = cond ? tru : fal; endmodule -module std_mem_d1 #( - parameter WIDTH = 32, - parameter SIZE = 16, - parameter IDX_SIZE = 4 -) ( - input wire logic [IDX_SIZE-1:0] addr0, - input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - input wire logic clk, - input wire logic reset, - output logic [ WIDTH-1:0] read_data, - output logic done -); - - logic [WIDTH-1:0] mem[SIZE-1:0]; - - /* verilator lint_off WIDTH */ - assign read_data = mem[addr0]; - - always_ff @(posedge clk) begin - if (reset) - done <= '0; - else if (write_en) - done <= '1; - else - done <= '0; - end - - always_ff @(posedge clk) begin - if (!reset && write_en) - mem[addr0] <= write_data; - end - - // Check for out of bounds access - `ifdef VERILATOR - always_comb begin - if (addr0 >= SIZE) - $error( - "std_mem_d1: Out of bounds access\n", - "addr0: %0d\n", addr0, - "SIZE: %0d", SIZE - ); - end - `endif -endmodule - -module std_mem_d2 #( - parameter WIDTH = 32, - parameter D0_SIZE = 16, - parameter D1_SIZE = 16, - parameter D0_IDX_SIZE = 4, - parameter D1_IDX_SIZE = 4 -) ( - input wire logic [D0_IDX_SIZE-1:0] addr0, - input wire logic [D1_IDX_SIZE-1:0] addr1, - input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - input wire logic clk, - input wire logic reset, - output logic [ WIDTH-1:0] read_data, - output logic done -); - - /* verilator lint_off WIDTH */ - logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0]; - - assign read_data = mem[addr0][addr1]; - - always_ff @(posedge clk) begin - if (reset) - done <= '0; - else if (write_en) - done <= '1; - else - done <= '0; - end - - always_ff @(posedge clk) begin - if (!reset && write_en) - mem[addr0][addr1] <= write_data; - end - - // Check for out of bounds access - `ifdef VERILATOR - always_comb begin - if (addr0 >= D0_SIZE) - $error( - "std_mem_d2: Out of bounds access\n", - "addr0: %0d\n", addr0, - "D0_SIZE: %0d", D0_SIZE - ); - if (addr1 >= D1_SIZE) - $error( - "std_mem_d2: Out of bounds access\n", - "addr1: %0d\n", addr1, - "D1_SIZE: %0d", D1_SIZE - ); - end - `endif -endmodule - -module std_mem_d3 #( - parameter WIDTH = 32, - parameter D0_SIZE = 16, - parameter D1_SIZE = 16, - parameter D2_SIZE = 16, - parameter D0_IDX_SIZE = 4, - parameter D1_IDX_SIZE = 4, - parameter D2_IDX_SIZE = 4 -) ( - input wire logic [D0_IDX_SIZE-1:0] addr0, - input wire logic [D1_IDX_SIZE-1:0] addr1, - input wire logic [D2_IDX_SIZE-1:0] addr2, - input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - input wire logic clk, - input wire logic reset, - output logic [ WIDTH-1:0] read_data, - output logic done -); - - /* verilator lint_off WIDTH */ - logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0]; - - assign read_data = mem[addr0][addr1][addr2]; - - always_ff @(posedge clk) begin - if (reset) - done <= '0; - else if (write_en) - done <= '1; - else - done <= '0; - end - - always_ff @(posedge clk) begin - if (!reset && write_en) - mem[addr0][addr1][addr2] <= write_data; - end - - // Check for out of bounds access - `ifdef VERILATOR - always_comb begin - if (addr0 >= D0_SIZE) - $error( - "std_mem_d3: Out of bounds access\n", - "addr0: %0d\n", addr0, - "D0_SIZE: %0d", D0_SIZE - ); - if (addr1 >= D1_SIZE) - $error( - "std_mem_d3: Out of bounds access\n", - "addr1: %0d\n", addr1, - "D1_SIZE: %0d", D1_SIZE - ); - if (addr2 >= D2_SIZE) - $error( - "std_mem_d3: Out of bounds access\n", - "addr2: %0d\n", addr2, - "D2_SIZE: %0d", D2_SIZE - ); - end - `endif -endmodule - -module std_mem_d4 #( - parameter WIDTH = 32, - parameter D0_SIZE = 16, - parameter D1_SIZE = 16, - parameter D2_SIZE = 16, - parameter D3_SIZE = 16, - parameter D0_IDX_SIZE = 4, - parameter D1_IDX_SIZE = 4, - parameter D2_IDX_SIZE = 4, - parameter D3_IDX_SIZE = 4 -) ( - input wire logic [D0_IDX_SIZE-1:0] addr0, - input wire logic [D1_IDX_SIZE-1:0] addr1, - input wire logic [D2_IDX_SIZE-1:0] addr2, - input wire logic [D3_IDX_SIZE-1:0] addr3, - input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - input wire logic clk, - input wire logic reset, - output logic [ WIDTH-1:0] read_data, - output logic done -); - - /* verilator lint_off WIDTH */ - logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0][D3_SIZE-1:0]; - - assign read_data = mem[addr0][addr1][addr2][addr3]; - - always_ff @(posedge clk) begin - if (reset) - done <= '0; - else if (write_en) - done <= '1; - else - done <= '0; - end - - always_ff @(posedge clk) begin - if (!reset && write_en) - mem[addr0][addr1][addr2][addr3] <= write_data; - end - - // Check for out of bounds access - `ifdef VERILATOR - always_comb begin - if (addr0 >= D0_SIZE) - $error( - "std_mem_d4: Out of bounds access\n", - "addr0: %0d\n", addr0, - "D0_SIZE: %0d", D0_SIZE - ); - if (addr1 >= D1_SIZE) - $error( - "std_mem_d4: Out of bounds access\n", - "addr1: %0d\n", addr1, - "D1_SIZE: %0d", D1_SIZE - ); - if (addr2 >= D2_SIZE) - $error( - "std_mem_d4: Out of bounds access\n", - "addr2: %0d\n", addr2, - "D2_SIZE: %0d", D2_SIZE - ); - if (addr3 >= D3_SIZE) - $error( - "std_mem_d4: Out of bounds access\n", - "addr3: %0d\n", addr3, - "D3_SIZE: %0d", D3_SIZE - ); - end - `endif -endmodule - `default_nettype wire diff --git a/primitives/memories/comb.futil b/primitives/memories/comb.futil new file mode 100644 index 000000000..434775241 --- /dev/null +++ b/primitives/memories/comb.futil @@ -0,0 +1,73 @@ +// Memories with combinational reads and single-cycle writes. +// These cannot be mapped to URAMs (see: https://github.com/orgs/calyxir/discussions/1221). +// These are only defined for compatability and will be removed in the future. +// Prefer using `seq_mem` variants instead. +extern "comb.sv" { + /// Memories + primitive comb_mem_d1[WIDTH, SIZE, IDX_SIZE]( + @read_together(1) addr0: IDX_SIZE, + @write_together(1) @data write_data: WIDTH, + @write_together(1) @static(1) @go write_en: 1, + @clk clk: 1, + @reset reset: 1 + ) -> ( + @read_together(1) read_data: WIDTH, + @done done: 1 + ); + + primitive comb_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( + @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, + @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, + @write_together(1) @data write_data: WIDTH, + @write_together(1) @static(1) @go write_en: 1, + @clk clk: 1, + @reset reset: 1 + ) -> ( + @read_together(1) read_data: WIDTH, + @done done: 1 + ); + + primitive comb_mem_d3[ + WIDTH, + D0_SIZE, + D1_SIZE, + D2_SIZE, + D0_IDX_SIZE, + D1_IDX_SIZE, + D2_IDX_SIZE + ] ( + @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, + @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, + @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, + @write_together(1) @data write_data: WIDTH, + @write_together(1) @static(1) @go write_en: 1, + @clk clk: 1, + @reset reset: 1 + ) -> ( + @read_together(1) read_data: WIDTH, + @done done: 1 + ); + + primitive comb_mem_d4[ + WIDTH, + D0_SIZE, + D1_SIZE, + D2_SIZE, + D3_SIZE, + D0_IDX_SIZE, + D1_IDX_SIZE, + D2_IDX_SIZE, + D3_IDX_SIZE + ] ( + @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, + @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, + @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, + @read_together(1) @write_together(2) addr3: D3_IDX_SIZE, + @write_together(1) @data write_data: WIDTH, + @write_together(1) @static(1) @go write_en: 1, + @clk clk: 1 + ) -> ( + @read_together(1) read_data: WIDTH, + @done done: 1 + ); +} \ No newline at end of file diff --git a/primitives/memories/comb.sv b/primitives/memories/comb.sv new file mode 100644 index 000000000..c2c35a44d --- /dev/null +++ b/primitives/memories/comb.sv @@ -0,0 +1,237 @@ +module comb_mem_d1 #( + parameter WIDTH = 32, + parameter SIZE = 16, + parameter IDX_SIZE = 4 +) ( + input wire logic [IDX_SIZE-1:0] addr0, + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en, + input wire logic clk, + input wire logic reset, + output logic [ WIDTH-1:0] read_data, + output logic done +); + + logic [WIDTH-1:0] mem[SIZE-1:0]; + + /* verilator lint_off WIDTH */ + assign read_data = mem[addr0]; + + always_ff @(posedge clk) begin + if (reset) + done <= '0; + else if (write_en) + done <= '1; + else + done <= '0; + end + + always_ff @(posedge clk) begin + if (!reset && write_en) + mem[addr0] <= write_data; + end + + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (addr0 >= SIZE) + $error( + "comb_mem_d1: Out of bounds access\n", + "addr0: %0d\n", addr0, + "SIZE: %0d", SIZE + ); + end + `endif +endmodule + +module comb_mem_d2 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4 +) ( + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en, + input wire logic clk, + input wire logic reset, + output logic [ WIDTH-1:0] read_data, + output logic done +); + + /* verilator lint_off WIDTH */ + logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0]; + + assign read_data = mem[addr0][addr1]; + + always_ff @(posedge clk) begin + if (reset) + done <= '0; + else if (write_en) + done <= '1; + else + done <= '0; + end + + always_ff @(posedge clk) begin + if (!reset && write_en) + mem[addr0][addr1] <= write_data; + end + + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (addr0 >= D0_SIZE) + $error( + "comb_mem_d2: Out of bounds access\n", + "addr0: %0d\n", addr0, + "D0_SIZE: %0d", D0_SIZE + ); + if (addr1 >= D1_SIZE) + $error( + "comb_mem_d2: Out of bounds access\n", + "addr1: %0d\n", addr1, + "D1_SIZE: %0d", D1_SIZE + ); + end + `endif +endmodule + +module comb_mem_d3 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D2_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4, + parameter D2_IDX_SIZE = 4 +) ( + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en, + input wire logic clk, + input wire logic reset, + output logic [ WIDTH-1:0] read_data, + output logic done +); + + /* verilator lint_off WIDTH */ + logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0]; + + assign read_data = mem[addr0][addr1][addr2]; + + always_ff @(posedge clk) begin + if (reset) + done <= '0; + else if (write_en) + done <= '1; + else + done <= '0; + end + + always_ff @(posedge clk) begin + if (!reset && write_en) + mem[addr0][addr1][addr2] <= write_data; + end + + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (addr0 >= D0_SIZE) + $error( + "comb_mem_d3: Out of bounds access\n", + "addr0: %0d\n", addr0, + "D0_SIZE: %0d", D0_SIZE + ); + if (addr1 >= D1_SIZE) + $error( + "comb_mem_d3: Out of bounds access\n", + "addr1: %0d\n", addr1, + "D1_SIZE: %0d", D1_SIZE + ); + if (addr2 >= D2_SIZE) + $error( + "comb_mem_d3: Out of bounds access\n", + "addr2: %0d\n", addr2, + "D2_SIZE: %0d", D2_SIZE + ); + end + `endif +endmodule + +module comb_mem_d4 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D2_SIZE = 16, + parameter D3_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4, + parameter D2_IDX_SIZE = 4, + parameter D3_IDX_SIZE = 4 +) ( + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic [D3_IDX_SIZE-1:0] addr3, + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en, + input wire logic clk, + input wire logic reset, + output logic [ WIDTH-1:0] read_data, + output logic done +); + + /* verilator lint_off WIDTH */ + logic [WIDTH-1:0] mem[D0_SIZE-1:0][D1_SIZE-1:0][D2_SIZE-1:0][D3_SIZE-1:0]; + + assign read_data = mem[addr0][addr1][addr2][addr3]; + + always_ff @(posedge clk) begin + if (reset) + done <= '0; + else if (write_en) + done <= '1; + else + done <= '0; + end + + always_ff @(posedge clk) begin + if (!reset && write_en) + mem[addr0][addr1][addr2][addr3] <= write_data; + end + + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (addr0 >= D0_SIZE) + $error( + "comb_mem_d4: Out of bounds access\n", + "addr0: %0d\n", addr0, + "D0_SIZE: %0d", D0_SIZE + ); + if (addr1 >= D1_SIZE) + $error( + "comb_mem_d4: Out of bounds access\n", + "addr1: %0d\n", addr1, + "D1_SIZE: %0d", D1_SIZE + ); + if (addr2 >= D2_SIZE) + $error( + "comb_mem_d4: Out of bounds access\n", + "addr2: %0d\n", addr2, + "D2_SIZE: %0d", D2_SIZE + ); + if (addr3 >= D3_SIZE) + $error( + "comb_mem_d4: Out of bounds access\n", + "addr3: %0d\n", addr3, + "D3_SIZE: %0d", D3_SIZE + ); + end + `endif +endmodule diff --git a/primitives/memories.futil b/primitives/memories/seq.futil similarity index 94% rename from primitives/memories.futil rename to primitives/memories/seq.futil index c824530cb..4f0c26ad0 100644 --- a/primitives/memories.futil +++ b/primitives/memories/seq.futil @@ -1,4 +1,5 @@ -extern "memories.sv" { +// Singe-ported memories with one-cycle read and one-cycle write latencies. +extern "seq.sv" { primitive seq_mem_d1[WIDTH, SIZE, IDX_SIZE]( @clk clk: 1, @reset reset: 1, diff --git a/primitives/memories.sv b/primitives/memories/seq.sv similarity index 99% rename from primitives/memories.sv rename to primitives/memories/seq.sv index 43acc6869..68712f239 100644 --- a/primitives/memories.sv +++ b/primitives/memories/seq.sv @@ -69,7 +69,7 @@ module seq_mem_d1 #( if (content_en && !write_en) if (addr0 >= SIZE) $error( - "std_mem_d1: Out of bounds access\n", + "comb_mem_d1: Out of bounds access\n", "addr0: %0d\n", addr0, "SIZE: %0d", SIZE ); diff --git a/tests/backend/firrtl/basic-cell.futil b/tests/backend/firrtl/basic-cell.futil index 09effbe5c..312b340ea 100644 --- a/tests/backend/firrtl/basic-cell.futil +++ b/tests/backend/firrtl/basic-cell.futil @@ -1,5 +1,6 @@ // -b firrtl --emit-primitive-extmodules import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component identity(in : 32) -> (out : 32) { cells {} wires { diff --git a/tests/backend/firrtl/primitive-cells.futil b/tests/backend/firrtl/primitive-cells.futil index b8ce90186..399e0009b 100644 --- a/tests/backend/firrtl/primitive-cells.futil +++ b/tests/backend/firrtl/primitive-cells.futil @@ -1,5 +1,6 @@ // -b firrtl --emit-primitive-extmodules import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component plus_one(in : 32) -> (out : 32) { cells { add = std_add(32); diff --git a/tests/backend/mlir/attributes.futil b/tests/backend/mlir/attributes.futil index 4f936393d..fa05d9fa8 100644 --- a/tests/backend/mlir/attributes.futil +++ b/tests/backend/mlir/attributes.futil @@ -1,5 +1,6 @@ // -p well-formed -b mlir import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main<"state_share"=1>(@foo(32) in: 32, @static(10) @go go: 1, @clk clk: 1, @reset reset: 1) -> (@static(0) out: 32, @done done: 1) { cells { diff --git a/tests/backend/mlir/no-guards.futil b/tests/backend/mlir/no-guards.futil index 940dfcadb..a1e43bac7 100644 --- a/tests/backend/mlir/no-guards.futil +++ b/tests/backend/mlir/no-guards.futil @@ -1,5 +1,6 @@ // -p well-formed -b mlir import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component A(in: 8, go: 1, clk: 1, reset: 1) -> (out: 8, done: 1) { cells { } @@ -21,8 +22,8 @@ component main(go: 1, clk: 1, reset: 1) -> (done: 1) { c0 = A(); c1 = B(); r = std_reg(8); - m0 = std_mem_d1(32, 1, 1); - m1 = std_mem_d2(8, 64, 64, 6, 6); + m0 = comb_mem_d1(32, 1, 1); + m1 = comb_mem_d2(8, 64, 64, 6, 6); add = std_add(8); lt = std_lt(8); } diff --git a/tests/backend/mlir/simple.futil b/tests/backend/mlir/simple.futil index dec898651..5b5a78875 100644 --- a/tests/backend/mlir/simple.futil +++ b/tests/backend/mlir/simple.futil @@ -1,5 +1,6 @@ // -p well-formed -b mlir import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) { cells { r1 = std_reg(1); diff --git a/tests/backend/mlir/with-guards.futil b/tests/backend/mlir/with-guards.futil index 2ce89783e..c0fe7c1f3 100644 --- a/tests/backend/mlir/with-guards.futil +++ b/tests/backend/mlir/with-guards.futil @@ -1,5 +1,6 @@ // -p well-formed -p lower-guards -b mlir import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component A(in: 8, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, flag: 1, @done done: 1) { cells { } @@ -24,18 +25,18 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: r1 = std_reg(8); r2 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); - m1 = std_mem_d2(8, 64, 64, 6, 6); - m2 = std_mem_d3(1, 8, 8, 8, 3, 3, 3); + m0 = comb_mem_d1(32, 1, 1); + m1 = comb_mem_d2(8, 64, 64, 6, 6); + m2 = comb_mem_d3(1, 8, 8, 8, 3, 3, 3); a0 = std_add(32); s0 = std_slice(32, 8); add = std_add(8); } wires { group write_c1_res { - c1_res.write_en = 1'd1; - c1_res.in = c1.out; - write_c1_res[done] = c1_res.done; + c1_res.write_en = 1'd1; + c1_res.in = c1.out; + write_c1_res[done] = c1_res.done; } group Group1 { s0.in = a0.out; diff --git a/tests/backend/verilog/memory-with-external-attribute.expect b/tests/backend/verilog/memory-with-external-attribute.expect index 42ed382ee..b428e9e23 100644 --- a/tests/backend/verilog/memory-with-external-attribute.expect +++ b/tests/backend/verilog/memory-with-external-attribute.expect @@ -1,223 +1,4 @@ -/** - * Core primitives for Calyx. - * Implements core primitives used by the compiler. - * - * Conventions: - * - All parameter names must be SNAKE_CASE and all caps. - * - Port names must be snake_case, no caps. - */ -`default_nettype none - -module std_slice #( - parameter IN_WIDTH = 32, - parameter OUT_WIDTH = 32 -) ( - input wire logic [ IN_WIDTH-1:0] in, - output logic [OUT_WIDTH-1:0] out -); - assign out = in[OUT_WIDTH-1:0]; - - `ifdef VERILATOR - always_comb begin - if (IN_WIDTH < OUT_WIDTH) - $error( - "std_slice: Input width less than output width\n", - "IN_WIDTH: %0d", IN_WIDTH, - "OUT_WIDTH: %0d", OUT_WIDTH - ); - end - `endif -endmodule - -module std_pad #( - parameter IN_WIDTH = 32, - parameter OUT_WIDTH = 32 -) ( - input wire logic [IN_WIDTH-1:0] in, - output logic [OUT_WIDTH-1:0] out -); - localparam EXTEND = OUT_WIDTH - IN_WIDTH; - assign out = { {EXTEND {1'b0}}, in}; - - `ifdef VERILATOR - always_comb begin - if (IN_WIDTH > OUT_WIDTH) - $error( - "std_pad: Output width less than input width\n", - "IN_WIDTH: %0d", IN_WIDTH, - "OUT_WIDTH: %0d", OUT_WIDTH - ); - end - `endif -endmodule - -module std_cat #( - parameter LEFT_WIDTH = 32, - parameter RIGHT_WIDTH = 32, - parameter OUT_WIDTH = 64 -) ( - input wire logic [LEFT_WIDTH-1:0] left, - input wire logic [RIGHT_WIDTH-1:0] right, - output logic [OUT_WIDTH-1:0] out -); - assign out = {left, right}; - - `ifdef VERILATOR - always_comb begin - if (LEFT_WIDTH + RIGHT_WIDTH != OUT_WIDTH) - $error( - "std_cat: Output width must equal sum of input widths\n", - "LEFT_WIDTH: %0d", LEFT_WIDTH, - "RIGHT_WIDTH: %0d", RIGHT_WIDTH, - "OUT_WIDTH: %0d", OUT_WIDTH - ); - end - `endif -endmodule - -module std_not #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] in, - output logic [WIDTH-1:0] out -); - assign out = ~in; -endmodule - -module std_and #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left & right; -endmodule - -module std_or #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left | right; -endmodule - -module std_xor #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left ^ right; -endmodule - -module std_sub #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left - right; -endmodule - -module std_gt #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left > right; -endmodule - -module std_lt #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left < right; -endmodule - -module std_eq #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left == right; -endmodule - -module std_neq #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left != right; -endmodule - -module std_ge #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left >= right; -endmodule - -module std_le #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic out -); - assign out = left <= right; -endmodule - -module std_lsh #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left << right; -endmodule - -module std_rsh #( - parameter WIDTH = 32 -) ( - input wire logic [WIDTH-1:0] left, - input wire logic [WIDTH-1:0] right, - output logic [WIDTH-1:0] out -); - assign out = left >> right; -endmodule - -/// this primitive is intended to be used -/// for lowering purposes (not in source programs) -module std_mux #( - parameter WIDTH = 32 -) ( - input wire logic cond, - input wire logic [WIDTH-1:0] tru, - input wire logic [WIDTH-1:0] fal, - output logic [WIDTH-1:0] out -); - assign out = cond ? tru : fal; -endmodule - -module std_mem_d1 #( +module comb_mem_d1 #( parameter WIDTH = 32, parameter SIZE = 16, parameter IDX_SIZE = 4 @@ -255,7 +36,7 @@ module std_mem_d1 #( always_comb begin if (addr0 >= SIZE) $error( - "std_mem_d1: Out of bounds access\n", + "comb_mem_d1: Out of bounds access\n", "addr0: %0d\n", addr0, "SIZE: %0d", SIZE ); @@ -263,7 +44,7 @@ module std_mem_d1 #( `endif endmodule -module std_mem_d2 #( +module comb_mem_d2 #( parameter WIDTH = 32, parameter D0_SIZE = 16, parameter D1_SIZE = 16, @@ -304,13 +85,13 @@ module std_mem_d2 #( always_comb begin if (addr0 >= D0_SIZE) $error( - "std_mem_d2: Out of bounds access\n", + "comb_mem_d2: Out of bounds access\n", "addr0: %0d\n", addr0, "D0_SIZE: %0d", D0_SIZE ); if (addr1 >= D1_SIZE) $error( - "std_mem_d2: Out of bounds access\n", + "comb_mem_d2: Out of bounds access\n", "addr1: %0d\n", addr1, "D1_SIZE: %0d", D1_SIZE ); @@ -318,7 +99,7 @@ module std_mem_d2 #( `endif endmodule -module std_mem_d3 #( +module comb_mem_d3 #( parameter WIDTH = 32, parameter D0_SIZE = 16, parameter D1_SIZE = 16, @@ -362,19 +143,19 @@ module std_mem_d3 #( always_comb begin if (addr0 >= D0_SIZE) $error( - "std_mem_d3: Out of bounds access\n", + "comb_mem_d3: Out of bounds access\n", "addr0: %0d\n", addr0, "D0_SIZE: %0d", D0_SIZE ); if (addr1 >= D1_SIZE) $error( - "std_mem_d3: Out of bounds access\n", + "comb_mem_d3: Out of bounds access\n", "addr1: %0d\n", addr1, "D1_SIZE: %0d", D1_SIZE ); if (addr2 >= D2_SIZE) $error( - "std_mem_d3: Out of bounds access\n", + "comb_mem_d3: Out of bounds access\n", "addr2: %0d\n", addr2, "D2_SIZE: %0d", D2_SIZE ); @@ -382,7 +163,7 @@ module std_mem_d3 #( `endif endmodule -module std_mem_d4 #( +module comb_mem_d4 #( parameter WIDTH = 32, parameter D0_SIZE = 16, parameter D1_SIZE = 16, @@ -429,25 +210,25 @@ module std_mem_d4 #( always_comb begin if (addr0 >= D0_SIZE) $error( - "std_mem_d4: Out of bounds access\n", + "comb_mem_d4: Out of bounds access\n", "addr0: %0d\n", addr0, "D0_SIZE: %0d", D0_SIZE ); if (addr1 >= D1_SIZE) $error( - "std_mem_d4: Out of bounds access\n", + "comb_mem_d4: Out of bounds access\n", "addr1: %0d\n", addr1, "D1_SIZE: %0d", D1_SIZE ); if (addr2 >= D2_SIZE) $error( - "std_mem_d4: Out of bounds access\n", + "comb_mem_d4: Out of bounds access\n", "addr2: %0d\n", addr2, "D2_SIZE: %0d", D2_SIZE ); if (addr3 >= D3_SIZE) $error( - "std_mem_d4: Out of bounds access\n", + "comb_mem_d4: Out of bounds access\n", "addr3: %0d\n", addr3, "D3_SIZE: %0d", D3_SIZE ); @@ -455,6 +236,225 @@ module std_mem_d4 #( `endif endmodule +/** + * Core primitives for Calyx. + * Implements core primitives used by the compiler. + * + * Conventions: + * - All parameter names must be SNAKE_CASE and all caps. + * - Port names must be snake_case, no caps. + */ +`default_nettype none + +module std_slice #( + parameter IN_WIDTH = 32, + parameter OUT_WIDTH = 32 +) ( + input wire logic [ IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + assign out = in[OUT_WIDTH-1:0]; + + `ifdef VERILATOR + always_comb begin + if (IN_WIDTH < OUT_WIDTH) + $error( + "std_slice: Input width less than output width\n", + "IN_WIDTH: %0d", IN_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_pad #( + parameter IN_WIDTH = 32, + parameter OUT_WIDTH = 32 +) ( + input wire logic [IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + localparam EXTEND = OUT_WIDTH - IN_WIDTH; + assign out = { {EXTEND {1'b0}}, in}; + + `ifdef VERILATOR + always_comb begin + if (IN_WIDTH > OUT_WIDTH) + $error( + "std_pad: Output width less than input width\n", + "IN_WIDTH: %0d", IN_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_cat #( + parameter LEFT_WIDTH = 32, + parameter RIGHT_WIDTH = 32, + parameter OUT_WIDTH = 64 +) ( + input wire logic [LEFT_WIDTH-1:0] left, + input wire logic [RIGHT_WIDTH-1:0] right, + output logic [OUT_WIDTH-1:0] out +); + assign out = {left, right}; + + `ifdef VERILATOR + always_comb begin + if (LEFT_WIDTH + RIGHT_WIDTH != OUT_WIDTH) + $error( + "std_cat: Output width must equal sum of input widths\n", + "LEFT_WIDTH: %0d", LEFT_WIDTH, + "RIGHT_WIDTH: %0d", RIGHT_WIDTH, + "OUT_WIDTH: %0d", OUT_WIDTH + ); + end + `endif +endmodule + +module std_not #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] in, + output logic [WIDTH-1:0] out +); + assign out = ~in; +endmodule + +module std_and #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left & right; +endmodule + +module std_or #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left | right; +endmodule + +module std_xor #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left ^ right; +endmodule + +module std_sub #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left - right; +endmodule + +module std_gt #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left > right; +endmodule + +module std_lt #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left < right; +endmodule + +module std_eq #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left == right; +endmodule + +module std_neq #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left != right; +endmodule + +module std_ge #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left >= right; +endmodule + +module std_le #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic out +); + assign out = left <= right; +endmodule + +module std_lsh #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left << right; +endmodule + +module std_rsh #( + parameter WIDTH = 32 +) ( + input wire logic [WIDTH-1:0] left, + input wire logic [WIDTH-1:0] right, + output logic [WIDTH-1:0] out +); + assign out = left >> right; +endmodule + +/// this primitive is intended to be used +/// for lowering purposes (not in source programs) +module std_mux #( + parameter WIDTH = 32 +) ( + input wire logic cond, + input wire logic [WIDTH-1:0] tru, + input wire logic [WIDTH-1:0] fal, + output logic [WIDTH-1:0] out +); + assign out = cond ? tru : fal; +endmodule + `default_nettype wire module undef #( @@ -545,7 +545,7 @@ logic m1_clk; logic m1_reset; logic [31:0] m1_read_data; logic m1_done; -std_mem_d1 # ( +comb_mem_d1 # ( .IDX_SIZE(4), .SIZE(4), .WIDTH(32) @@ -558,7 +558,7 @@ std_mem_d1 # ( .write_data(m0_write_data), .write_en(m0_write_en) ); -std_mem_d1 # ( +comb_mem_d1 # ( .IDX_SIZE(4), .SIZE(4), .WIDTH(32) diff --git a/tests/backend/verilog/memory-with-external-attribute.futil b/tests/backend/verilog/memory-with-external-attribute.futil index 786b454f7..d6861a85e 100644 --- a/tests/backend/verilog/memory-with-external-attribute.futil +++ b/tests/backend/verilog/memory-with-external-attribute.futil @@ -1,9 +1,10 @@ // -d dead-cell-removal -b verilog import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - m0 = std_mem_d1(32, 4, 4); - @external(1) m1 = std_mem_d1(32, 4, 4); + m0 = comb_mem_d1(32, 4, 4); + @external(1) m1 = comb_mem_d1(32, 4, 4); } wires { done = m1.done; diff --git a/tests/backend/yxi/dot-product.futil b/tests/backend/yxi/dot-product.futil index abf815854..bc922fa88 100644 --- a/tests/backend/yxi/dot-product.futil +++ b/tests/backend/yxi/dot-product.futil @@ -1,11 +1,12 @@ // -b yxi import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,8,4); + @external(1) A0 = comb_mem_d1(32,8,4); A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,8,4); + @external(1) B0 = comb_mem_d1(32,8,4); B_read0_0 = std_reg(32); add0 = std_add(32); add1 = std_add(4); @@ -18,7 +19,7 @@ component main() -> () { i0 = std_reg(4); le0 = std_le(4); mult_pipe0 = std_mult_pipe(32); - @external(1) v0 = std_mem_d1(32,1,1); + @external(1) v0 = comb_mem_d1(32,1,1); } wires { comb group cond0 { diff --git a/tests/backend/yxi/seq-mem-d4-add.futil b/tests/backend/yxi/seq-mem-d4-add.futil index 7f7ff4c7f..5e09f5f06 100644 --- a/tests/backend/yxi/seq-mem-d4-add.futil +++ b/tests/backend/yxi/seq-mem-d4-add.futil @@ -1,7 +1,8 @@ // -b yxi import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component main() -> () { cells { @@ -71,63 +72,63 @@ component main() -> () { lt4.right = 3'd4; } group read_in1{ - in1.addr0 = i.out; - in1.addr1 = j.out; - in1.addr2 = k.out; - in1.addr3 = l.out; - in1.read_en = 1'd1; - in1_reg.write_en = in1.read_done; + in1.addr0 = i.out; + in1.addr1 = j.out; + in1.addr2 = k.out; + in1.addr3 = l.out; + in1.read_en = 1'd1; + in1_reg.write_en = in1.read_done; in1_reg.in = in1.read_data; - read_in1[done] = in1_reg.done; + read_in1[done] = in1_reg.done; } group read_in2{ - in2.addr0 = i.out; - in2.addr1 = j.out; - in2.addr2 = k.out; - in2.addr3 = l.out; + in2.addr0 = i.out; + in2.addr1 = j.out; + in2.addr2 = k.out; + in2.addr3 = l.out; in2.read_en = 1'd1; - in2_reg.write_en = in2.read_done; + in2_reg.write_en = in2.read_done; in2_reg.in = in2.read_data; - read_in2[done] = in2_reg.done; + read_in2[done] = in2_reg.done; } group update_val { - add.left = in1_reg.out; - add.right = in2_reg.out; - out.addr0 = i.out; + add.left = in1_reg.out; + add.right = in2_reg.out; + out.addr0 = i.out; out.addr1 = j.out; out.addr2 = k.out; out.addr3 = l.out; - out.write_en = 1'd1; + out.write_en = 1'd1; out.write_data = add.out; update_val[done] = out.write_done; } group incr_i { - add_i.left = i.out; + add_i.left = i.out; add_i.right = 2'd1; - i.write_en = 1'd1; + i.write_en = 1'd1; i.in = add_i.out; - incr_i[done] = i.done; + incr_i[done] = i.done; } group incr_j { - add_j.left = j.out; + add_j.left = j.out; add_j.right = 2'd1; - j.write_en = 1'd1; + j.write_en = 1'd1; j.in = add_j.out; - incr_j[done] = j.done; + incr_j[done] = j.done; } group incr_k { - add_k.left = k.out; + add_k.left = k.out; add_k.right = 1'd1; - k.write_en = 1'd1; + k.write_en = 1'd1; k.in = add_k.out; - incr_k[done] = k.done; + incr_k[done] = k.done; } group incr_l { - add_l.left = l.out; + add_l.left = l.out; add_l.right = 3'd1; - l.write_en = 1'd1; + l.write_en = 1'd1; l.in = add_l.out; - incr_l[done] = l.done; + incr_l[done] = l.done; } } control { @@ -138,17 +139,17 @@ component main() -> () { init_j; while lt2.out with j_lt{ seq{ - init_k; + init_k; while lt3.out with k_lt{ seq{ init_l; while lt4.out with l_lt{ seq{ par{ - read_in1; + read_in1; read_in2; } - update_val; + update_val; incr_l; } } diff --git a/tests/correctness/group-static-promotion/infer-comp-latency.futil b/tests/correctness/group-static-promotion/infer-comp-latency.futil index 11e2cc4bc..23d59765b 100644 --- a/tests/correctness/group-static-promotion/infer-comp-latency.futil +++ b/tests/correctness/group-static-promotion/infer-comp-latency.futil @@ -1,9 +1,10 @@ //-p infer-share import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -// share is just some user defined component that should be shareable +// share is just some user defined component that should be shareable component add_5_mult_3(in: 32) -> (out: 32) { cells { r = std_reg(32); @@ -12,26 +13,26 @@ component add_5_mult_3(in: 32) -> (out: 32) { } wires { group A { - add_32.left = in; - add_32.right = 32'd5; + add_32.left = in; + add_32.right = 32'd5; r.in = add_32.out; r.write_en = 1'd1; A[done] = r.done; } group B { - mult_pipe.left = r.out; - mult_pipe.right = 32'd3; - mult_pipe.go = !mult_pipe.done ? 1'd1; + mult_pipe.left = r.out; + mult_pipe.right = 32'd3; + mult_pipe.go = !mult_pipe.done ? 1'd1; r.write_en = mult_pipe.done; - r.in = mult_pipe.out; + r.in = mult_pipe.out; B[done] = r.done; } out = r.out; } control { seq { - A; - B; + A; + B; } } } @@ -41,20 +42,20 @@ component add_5_mult_3(in: 32) -> (out: 32) { component main() -> () { cells { my_comp = add_5_mult_3(); - @external mem = std_mem_d1(32,1,1); + @external mem = comb_mem_d1(32,1,1); } wires { group write_mem { - mem.addr0 = 1'd0; + mem.addr0 = 1'd0; mem.write_en = 1'd1; - mem.write_data = my_comp.out; - write_mem[done] = mem.done; + mem.write_data = my_comp.out; + write_mem[done] = mem.done; } } control { seq { - invoke my_comp(in = 32'd1)(); - write_mem; + invoke my_comp(in = 32'd1)(); + write_mem; } } } diff --git a/tests/correctness/group-static-promotion/seq.futil b/tests/correctness/group-static-promotion/seq.futil index 2ea18583f..e7e74bca6 100644 --- a/tests/correctness/group-static-promotion/seq.futil +++ b/tests/correctness/group-static-promotion/seq.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { @@ -6,7 +7,7 @@ component main() -> () { a = std_reg(2); b = std_reg(2); c = std_reg(2); - @external mem = std_mem_d1(2, 1, 1); + @external mem = comb_mem_d1(2, 1, 1); } wires { @@ -41,4 +42,3 @@ component main() -> () { } } - \ No newline at end of file diff --git a/tests/correctness/if-static-different-latencies.futil b/tests/correctness/if-static-different-latencies.futil index 7903fd7e7..b6b767612 100644 --- a/tests/correctness/if-static-different-latencies.futil +++ b/tests/correctness/if-static-different-latencies.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -12,7 +13,7 @@ component main() -> () { t4 = std_reg(32); // false branch - @external(1) i = std_mem_d1(32, 1, 1); + @external(1) i = comb_mem_d1(32, 1, 1); add = std_add(32); } wires { diff --git a/tests/correctness/if.futil b/tests/correctness/if.futil index 7bf5565bf..8f09964cd 100644 --- a/tests/correctness/if.futil +++ b/tests/correctness/if.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); lt = std_lt(32); } diff --git a/tests/correctness/inlining.futil b/tests/correctness/inlining.futil index b556d8bd8..7993fe57a 100644 --- a/tests/correctness/inlining.futil +++ b/tests/correctness/inlining.futil @@ -1,20 +1,21 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/unsynthesizable.futil"; component main() -> () { cells { t0_idx = std_reg(2); t0_add = std_add(2); - @external(1) t0 = std_mem_d1(32, 3, 2); + @external(1) t0 = comb_mem_d1(32, 3, 2); t1_idx = std_reg(2); t1_add = std_add(2); - @external(1) t1 = std_mem_d1(32, 3, 2); + @external(1) t1 = comb_mem_d1(32, 3, 2); l0_idx = std_reg(2); l0_add = std_add(2); - @external(1) l0 = std_mem_d1(32, 3, 2); + @external(1) l0 = comb_mem_d1(32, 3, 2); l1_idx = std_reg(2); l1_add = std_add(2); - @external(1) l1 = std_mem_d1(32, 3, 2); - @external(1) out_mem = std_mem_d1(32, 4, 3); + @external(1) l1 = comb_mem_d1(32, 3, 2); + @external(1) out_mem = comb_mem_d1(32, 4, 3); top_0_0 = std_reg(32); left_0_0 = std_reg(32); top_0_1 = std_reg(32); diff --git a/tests/correctness/invoke-memory.futil b/tests/correctness/invoke-memory.futil index 4b672f2ed..3d7fd3804 100644 --- a/tests/correctness/invoke-memory.futil +++ b/tests/correctness/invoke-memory.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component copy(dest_done: 1, src_read_data: 32, length: 3) -> (dest_write_data: 32, dest_write_en: 1, dest_addr0: 3, src_addr0: 3) { cells { @@ -38,8 +39,8 @@ component copy(dest_done: 1, src_read_data: 32, length: 3) -> component main() -> () { cells { - @external(1) d = std_mem_d1(32,5,3); - @external(1) s = std_mem_d1(32,5,3); + @external(1) d = comb_mem_d1(32,5,3); + @external(1) s = comb_mem_d1(32,5,3); length = std_const(3, 5); copy0 = copy(); } diff --git a/tests/correctness/invoke-with.futil b/tests/correctness/invoke-with.futil index 55b96901b..37cf13a25 100644 --- a/tests/correctness/invoke-with.futil +++ b/tests/correctness/invoke-with.futil @@ -1,5 +1,6 @@ // -p simplify-with-control import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { @@ -7,7 +8,7 @@ component main() -> () { m = std_mult_pipe(32); a0 = std_add(32); a1 = std_add(32); - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); } wires { comb group do_adds { diff --git a/tests/correctness/invoke.futil b/tests/correctness/invoke.futil index 01022bae0..ef3175b2e 100644 --- a/tests/correctness/invoke.futil +++ b/tests/correctness/invoke.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component exponent(base: 32, exp: 4) -> (out: 32) { @@ -52,7 +53,7 @@ component exponent(base: 32, exp: 4) -> (out: 32) { component main() -> () { cells { - @external(1) a0 = std_mem_d1(32,10,4); + @external(1) a0 = comb_mem_d1(32,10,4); a_read0_0 = std_reg(32); add0 = std_add(4); const0 = std_const(4,0); diff --git a/tests/correctness/new_fsm.futil b/tests/correctness/new_fsm.futil index 168b5c425..0bda80869 100644 --- a/tests/correctness/new_fsm.futil +++ b/tests/correctness/new_fsm.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -8,7 +9,7 @@ component main() -> () { lt0 = std_lt(32); lt1 = std_lt(32); add = std_add(32); - @external(1) out = std_mem_d1(32, 1, 1); + @external(1) out = comb_mem_d1(32, 1, 1); } wires { group A{ diff --git a/tests/correctness/numeric-types/bitnum/binary-operators.futil b/tests/correctness/numeric-types/bitnum/binary-operators.futil index 6b029f087..0efd95e06 100644 --- a/tests/correctness/numeric-types/bitnum/binary-operators.futil +++ b/tests/correctness/numeric-types/bitnum/binary-operators.futil @@ -1,22 +1,23 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) slhs = std_mem_d1(4, 1, 1); - @external(1) srhs = std_mem_d1(4, 1, 1); - @external(1) signed_add = std_mem_d1(4, 1, 1); - @external(1) signed_sub = std_mem_d1(4, 1, 1); - @external(1) signed_mul = std_mem_d1(4, 1, 1); - @external(1) signed_div = std_mem_d1(4, 1, 1); - @external(1) signed_mod = std_mem_d1(4, 1, 1); + @external(1) slhs = comb_mem_d1(4, 1, 1); + @external(1) srhs = comb_mem_d1(4, 1, 1); + @external(1) signed_add = comb_mem_d1(4, 1, 1); + @external(1) signed_sub = comb_mem_d1(4, 1, 1); + @external(1) signed_mul = comb_mem_d1(4, 1, 1); + @external(1) signed_div = comb_mem_d1(4, 1, 1); + @external(1) signed_mod = comb_mem_d1(4, 1, 1); - @external(1) lhs = std_mem_d1(32, 1, 1); - @external(1) rhs = std_mem_d1(32, 1, 1); - @external(1) unsigned_add = std_mem_d1(32, 1, 1); - @external(1) unsigned_sub = std_mem_d1(32, 1, 1); - @external(1) unsigned_mul = std_mem_d1(32, 1, 1); - @external(1) unsigned_div = std_mem_d1(32, 1, 1); - @external(1) unsigned_mod = std_mem_d1(32, 1, 1); + @external(1) lhs = comb_mem_d1(32, 1, 1); + @external(1) rhs = comb_mem_d1(32, 1, 1); + @external(1) unsigned_add = comb_mem_d1(32, 1, 1); + @external(1) unsigned_sub = comb_mem_d1(32, 1, 1); + @external(1) unsigned_mul = comb_mem_d1(32, 1, 1); + @external(1) unsigned_div = comb_mem_d1(32, 1, 1); + @external(1) unsigned_mod = comb_mem_d1(32, 1, 1); sadd = std_sadd(4); ssub = std_ssub(4); diff --git a/tests/correctness/numeric-types/bitnum/sqrt.futil b/tests/correctness/numeric-types/bitnum/sqrt.futil index 8607c9cbf..3c4481c97 100644 --- a/tests/correctness/numeric-types/bitnum/sqrt.futil +++ b/tests/correctness/numeric-types/bitnum/sqrt.futil @@ -1,13 +1,14 @@ import "primitives/math.futil"; import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) radicand_31 = std_mem_d1(31, 1, 1); - @external(1) root_31 = std_mem_d1(31, 1, 1); + @external(1) radicand_31 = comb_mem_d1(31, 1, 1); + @external(1) root_31 = comb_mem_d1(31, 1, 1); - @external(1) radicand_32 = std_mem_d1(32, 1, 1); - @external(1) root_32 = std_mem_d1(32, 1, 1); + @external(1) radicand_32 = comb_mem_d1(32, 1, 1); + @external(1) root_32 = comb_mem_d1(32, 1, 1); t_31 = std_reg(31); t_32 = std_reg(32); diff --git a/tests/correctness/numeric-types/bitnum/std-sdiv.futil b/tests/correctness/numeric-types/bitnum/std-sdiv.futil index 091d83a7e..0578b1252 100644 --- a/tests/correctness/numeric-types/bitnum/std-sdiv.futil +++ b/tests/correctness/numeric-types/bitnum/std-sdiv.futil @@ -1,12 +1,13 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external left = std_mem_d1(32, 4, 3); - @external right = std_mem_d1(32, 4, 3); - @external out_rem = std_mem_d1(32, 4, 3); - @external out_quot = std_mem_d1(32, 4, 3); + @external left = comb_mem_d1(32, 4, 3); + @external right = comb_mem_d1(32, 4, 3); + @external out_rem = comb_mem_d1(32, 4, 3); + @external out_quot = comb_mem_d1(32, 4, 3); div = std_sdiv_pipe(32); add = std_add(3); diff --git a/tests/correctness/numeric-types/fixed-point/binary-operators.futil b/tests/correctness/numeric-types/fixed-point/binary-operators.futil index d2983263f..7694f37c4 100644 --- a/tests/correctness/numeric-types/fixed-point/binary-operators.futil +++ b/tests/correctness/numeric-types/fixed-point/binary-operators.futil @@ -1,22 +1,23 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) slhs = std_mem_d1(4, 1, 1); - @external(1) srhs = std_mem_d1(4, 1, 1); - @external(1) signed_add = std_mem_d1(4, 1, 1); - @external(1) signed_sub = std_mem_d1(4, 1, 1); - @external(1) signed_mul = std_mem_d1(4, 1, 1); - @external(1) signed_div = std_mem_d1(4, 1, 1); - @external(1) signed_mod = std_mem_d1(4, 1, 1); + @external(1) slhs = comb_mem_d1(4, 1, 1); + @external(1) srhs = comb_mem_d1(4, 1, 1); + @external(1) signed_add = comb_mem_d1(4, 1, 1); + @external(1) signed_sub = comb_mem_d1(4, 1, 1); + @external(1) signed_mul = comb_mem_d1(4, 1, 1); + @external(1) signed_div = comb_mem_d1(4, 1, 1); + @external(1) signed_mod = comb_mem_d1(4, 1, 1); - @external(1) lhs = std_mem_d1(32, 1, 1); - @external(1) rhs = std_mem_d1(32, 1, 1); - @external(1) unsigned_add = std_mem_d1(32, 1, 1); - @external(1) unsigned_sub = std_mem_d1(32, 1, 1); - @external(1) unsigned_mul = std_mem_d1(32, 1, 1); - @external(1) unsigned_div = std_mem_d1(32, 1, 1); - @external(1) unsigned_mod = std_mem_d1(32, 1, 1); + @external(1) lhs = comb_mem_d1(32, 1, 1); + @external(1) rhs = comb_mem_d1(32, 1, 1); + @external(1) unsigned_add = comb_mem_d1(32, 1, 1); + @external(1) unsigned_sub = comb_mem_d1(32, 1, 1); + @external(1) unsigned_mul = comb_mem_d1(32, 1, 1); + @external(1) unsigned_div = comb_mem_d1(32, 1, 1); + @external(1) unsigned_mod = comb_mem_d1(32, 1, 1); sadd = std_fp_sadd(4,2,2); ssub = std_fp_ssub(4,2,2); diff --git a/tests/correctness/numeric-types/fixed-point/constants.futil b/tests/correctness/numeric-types/fixed-point/constants.futil index 04f9bf4cf..fe44040fa 100644 --- a/tests/correctness/numeric-types/fixed-point/constants.futil +++ b/tests/correctness/numeric-types/fixed-point/constants.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem0 = std_mem_d1(4, 1, 1); + @external(1) mem0 = comb_mem_d1(4, 1, 1); const0 = std_const(4, 6); /* 1.5 in unsigned fixed point Q4.2 */ } wires { diff --git a/tests/correctness/numeric-types/fixed-point/sqrt.futil b/tests/correctness/numeric-types/fixed-point/sqrt.futil index c08f7da2e..7e7099eb4 100644 --- a/tests/correctness/numeric-types/fixed-point/sqrt.futil +++ b/tests/correctness/numeric-types/fixed-point/sqrt.futil @@ -1,13 +1,14 @@ import "primitives/math.futil"; import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) radicand_31 = std_mem_d1(31, 1, 1); - @external(1) root_31 = std_mem_d1(31, 1, 1); + @external(1) radicand_31 = comb_mem_d1(31, 1, 1); + @external(1) root_31 = comb_mem_d1(31, 1, 1); - @external(1) radicand_32 = std_mem_d1(32, 1, 1); - @external(1) root_32 = std_mem_d1(32, 1, 1); + @external(1) radicand_32 = comb_mem_d1(32, 1, 1); + @external(1) root_32 = comb_mem_d1(32, 1, 1); t_31 = std_reg(31); t_32 = std_reg(32); diff --git a/tests/correctness/numeric-types/fixed-point/std-fp-sdiv.futil b/tests/correctness/numeric-types/fixed-point/std-fp-sdiv.futil index f142c7a7e..0b646a0df 100644 --- a/tests/correctness/numeric-types/fixed-point/std-fp-sdiv.futil +++ b/tests/correctness/numeric-types/fixed-point/std-fp-sdiv.futil @@ -1,12 +1,13 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external left = std_mem_d1(32, 4, 3); - @external right = std_mem_d1(32, 4, 3); - @external out_rem = std_mem_d1(32, 4, 3); - @external out_quot = std_mem_d1(32, 4, 3); + @external left = comb_mem_d1(32, 4, 3); + @external right = comb_mem_d1(32, 4, 3); + @external out_rem = comb_mem_d1(32, 4, 3); + @external out_quot = comb_mem_d1(32, 4, 3); div = std_fp_sdiv_pipe(32, 24, 8); add = std_add(3); diff --git a/tests/correctness/numeric-types/parsing/signed-bitnum.futil b/tests/correctness/numeric-types/parsing/signed-bitnum.futil index 356611b5d..5d11444ef 100644 --- a/tests/correctness/numeric-types/parsing/signed-bitnum.futil +++ b/tests/correctness/numeric-types/parsing/signed-bitnum.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem0 = std_mem_d1(32, 1, 1); + @external(1) mem0 = comb_mem_d1(32, 1, 1); } wires { group identity { diff --git a/tests/correctness/numeric-types/parsing/signed-fp.futil b/tests/correctness/numeric-types/parsing/signed-fp.futil index 972340748..c1f4a5c72 100644 --- a/tests/correctness/numeric-types/parsing/signed-fp.futil +++ b/tests/correctness/numeric-types/parsing/signed-fp.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem0 = std_mem_d1(4, 1, 1); + @external(1) mem0 = comb_mem_d1(4, 1, 1); } wires { group identity { diff --git a/tests/correctness/numeric-types/parsing/unsigned-bitnum.futil b/tests/correctness/numeric-types/parsing/unsigned-bitnum.futil index 356611b5d..5d11444ef 100644 --- a/tests/correctness/numeric-types/parsing/unsigned-bitnum.futil +++ b/tests/correctness/numeric-types/parsing/unsigned-bitnum.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem0 = std_mem_d1(32, 1, 1); + @external(1) mem0 = comb_mem_d1(32, 1, 1); } wires { group identity { diff --git a/tests/correctness/numeric-types/parsing/unsigned-fp.futil b/tests/correctness/numeric-types/parsing/unsigned-fp.futil index 972340748..c1f4a5c72 100644 --- a/tests/correctness/numeric-types/parsing/unsigned-fp.futil +++ b/tests/correctness/numeric-types/parsing/unsigned-fp.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) mem0 = std_mem_d1(4, 1, 1); + @external(1) mem0 = comb_mem_d1(4, 1, 1); } wires { group identity { diff --git a/tests/correctness/par.futil b/tests/correctness/par.futil index 4f5a32650..a3dd68b00 100644 --- a/tests/correctness/par.futil +++ b/tests/correctness/par.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) a = std_mem_d1(32, 1, 1); - @external(1) b = std_mem_d1(32, 1, 1); - @external(1) c = std_mem_d1(32, 1, 1); + @external(1) a = comb_mem_d1(32, 1, 1); + @external(1) b = comb_mem_d1(32, 1, 1); + @external(1) c = comb_mem_d1(32, 1, 1); } wires { diff --git a/tests/correctness/pipelined-mac.futil b/tests/correctness/pipelined-mac.futil index bb38af07e..fc7d1ab14 100644 --- a/tests/correctness/pipelined-mac.futil +++ b/tests/correctness/pipelined-mac.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component pipelined_mac( @@ -21,7 +22,7 @@ component pipelined_mac( stage2_valid = std_reg(1); // Stage 2 should run this execution out_valid = std_reg(1); // Output is valid - data_valid_reg = std_reg(1); // Stores value of data_valid + data_valid_reg = std_reg(1); // Stores value of data_valid } wires { group stage1<"static"=4> { @@ -61,8 +62,8 @@ component pipelined_mac( unset_out_valid[done] = out_valid.done; } group write_data_valid { - data_valid_reg.write_en = 1'd1; - data_valid_reg.in = data_valid; + data_valid_reg.write_en = 1'd1; + data_valid_reg.in = data_valid; write_data_valid[done] = data_valid_reg.done; } @@ -97,11 +98,11 @@ component pipelined_mac( component main() -> () { cells { // Input memories - @external a = std_mem_d1(32, 10, 4); - @external b = std_mem_d1(32, 10, 4); + @external a = comb_mem_d1(32, 10, 4); + @external b = comb_mem_d1(32, 10, 4); // Output memory: Expected output 31178 - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); // Registers to save value at current memory index read_a = std_reg(32); diff --git a/tests/correctness/pow.futil b/tests/correctness/pow.futil index 90dab545c..8e163ecb5 100644 --- a/tests/correctness/pow.futil +++ b/tests/correctness/pow.futil @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/math.futil"; component main() -> () { cells { - @external(1) out = std_mem_d1(32, 1, 1); - @external(1) base = std_mem_d1(32, 1, 1); - @external(1) exp = std_mem_d1(32, 1, 1); + @external(1) out = comb_mem_d1(32, 1, 1); + @external(1) base = comb_mem_d1(32, 1, 1); + @external(1) exp = comb_mem_d1(32, 1, 1); base_reg = std_reg(32); exp_reg = std_reg(32); p = pow(); diff --git a/tests/correctness/ref-cells/dot-product-ref.futil b/tests/correctness/ref-cells/dot-product-ref.futil index fefba869c..3f2923d56 100644 --- a/tests/correctness/ref-cells/dot-product-ref.futil +++ b/tests/correctness/ref-cells/dot-product-ref.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,8,4); + @external(1) A0 = comb_mem_d1(32,8,4); A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,8,4); + @external(1) B0 = comb_mem_d1(32,8,4); B_read0_0 = std_reg(32); add0 = std_add(32); add1 = std_add(4); @@ -15,7 +16,7 @@ component main() -> () { i0 = std_reg(4); le0 = std_le(4); mult_pipe0 = std_mult_pipe(32); - @external(1) v0 = std_mem_d1(32,1,1); + @external(1) v0 = comb_mem_d1(32,1,1); inpar = in_par(); afterpar = after_par(); } @@ -29,7 +30,7 @@ component main() -> () { i0.write_en = 1'd1; let0[done] = i0.done; } - + } control { seq { @@ -49,8 +50,8 @@ component in_par() -> () { cells { ref A_read = std_reg(32); ref B_read = std_reg(32); - ref A = std_mem_d1(32,8,4); - ref B = std_mem_d1(32,8,4); + ref A = comb_mem_d1(32,8,4); + ref B = comb_mem_d1(32,8,4); ref i0 = std_reg(4); ref bin_read = std_reg(32); ref mult_pipe = std_mult_pipe(32); @@ -93,7 +94,7 @@ component in_par() -> () { component after_par() -> () { cells { ref dot = std_reg(32); - ref v = std_mem_d1(32,1,1); + ref v = comb_mem_d1(32,1,1); ref adder0 = std_add(32); ref i = std_reg(4); ref adder1 = std_add(4); diff --git a/tests/correctness/ref-cells/higher-order.futil b/tests/correctness/ref-cells/higher-order.futil index 4d9caf43a..a3038600b 100644 --- a/tests/correctness/ref-cells/higher-order.futil +++ b/tests/correctness/ref-cells/higher-order.futil @@ -1,5 +1,6 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/comb.futil"; +import "primitives/memories/seq.futil"; /// The function we can map over the array. /// This function increments in input by 10 and tracks the number of elements diff --git a/tests/correctness/ref-cells/invoke.futil b/tests/correctness/ref-cells/invoke.futil index b4c00e794..ad6215766 100644 --- a/tests/correctness/ref-cells/invoke.futil +++ b/tests/correctness/ref-cells/invoke.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); pe1 = add_one(); } wires {} @@ -15,7 +16,7 @@ component main() -> () { } component add_one() -> () { cells { - ref mem = std_mem_d1(32, 1, 1); + ref mem = comb_mem_d1(32, 1, 1); adder = std_add(32); r = std_reg(32); } diff --git a/tests/correctness/ref-cells/ref.futil b/tests/correctness/ref-cells/ref.futil index 99a817989..25c6afc24 100644 --- a/tests/correctness/ref-cells/ref.futil +++ b/tests/correctness/ref-cells/ref.futil @@ -1,12 +1,13 @@ // -p well-formed -p compile-external import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component add_one() -> () { cells { add = std_add(32); r = std_reg(32); - ref out = std_mem_d1(32, 1, 1); + ref out = comb_mem_d1(32, 1, 1); } wires { @@ -36,7 +37,7 @@ component add_one() -> () { component main() -> () { cells { adder = add_one(); - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); add = std_add(32); r = std_reg(32); } diff --git a/tests/correctness/seq-mem-d4-add.futil b/tests/correctness/seq-mem-d4-add.futil index af173460d..bff939899 100644 --- a/tests/correctness/seq-mem-d4-add.futil +++ b/tests/correctness/seq-mem-d4-add.futil @@ -1,6 +1,7 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component main() -> () { cells { @@ -70,66 +71,66 @@ component main() -> () { lt4.right = 3'd4; } group read_in1{ - in1.addr0 = i.out; - in1.addr1 = j.out; - in1.addr2 = k.out; - in1.addr3 = l.out; - in1.content_en = 1'd1; - in1.write_en = 1'd0; - in1_reg.write_en = in1.done; + in1.addr0 = i.out; + in1.addr1 = j.out; + in1.addr2 = k.out; + in1.addr3 = l.out; + in1.content_en = 1'd1; + in1.write_en = 1'd0; + in1_reg.write_en = in1.done; in1_reg.in = in1.read_data; - read_in1[done] = in1_reg.done; + read_in1[done] = in1_reg.done; } group read_in2{ - in2.addr0 = i.out; - in2.addr1 = j.out; - in2.addr2 = k.out; - in2.addr3 = l.out; + in2.addr0 = i.out; + in2.addr1 = j.out; + in2.addr2 = k.out; + in2.addr3 = l.out; in2.content_en = 1'd1; in2.write_en = 1'd0; - in2_reg.write_en = in2.done; + in2_reg.write_en = in2.done; in2_reg.in = in2.read_data; - read_in2[done] = in2_reg.done; + read_in2[done] = in2_reg.done; } group update_val { - add.left = in1_reg.out; - add.right = in2_reg.out; - out.addr0 = i.out; + add.left = in1_reg.out; + add.right = in2_reg.out; + out.addr0 = i.out; out.addr1 = j.out; out.addr2 = k.out; out.addr3 = l.out; out.content_en = 1'd1; - out.write_en = 1'd1; + out.write_en = 1'd1; out.write_data = add.out; update_val[done] = out.write_done; } group incr_i { - add_i.left = i.out; + add_i.left = i.out; add_i.right = 2'd1; - i.write_en = 1'd1; + i.write_en = 1'd1; i.in = add_i.out; - incr_i[done] = i.done; + incr_i[done] = i.done; } group incr_j { - add_j.left = j.out; + add_j.left = j.out; add_j.right = 2'd1; - j.write_en = 1'd1; + j.write_en = 1'd1; j.in = add_j.out; - incr_j[done] = j.done; + incr_j[done] = j.done; } group incr_k { - add_k.left = k.out; + add_k.left = k.out; add_k.right = 1'd1; - k.write_en = 1'd1; + k.write_en = 1'd1; k.in = add_k.out; - incr_k[done] = k.done; + incr_k[done] = k.done; } group incr_l { - add_l.left = l.out; + add_l.left = l.out; add_l.right = 3'd1; - l.write_en = 1'd1; + l.write_en = 1'd1; l.in = add_l.out; - incr_l[done] = l.done; + incr_l[done] = l.done; } } control { @@ -140,17 +141,17 @@ component main() -> () { init_j; while lt2.out with j_lt{ seq{ - init_k; + init_k; while lt3.out with k_lt{ seq{ init_l; while lt4.out with l_lt{ seq{ par{ - read_in1; + read_in1; read_in2; } - update_val; + update_val; incr_l; } } diff --git a/tests/correctness/seq-mem-dot-product.futil b/tests/correctness/seq-mem-dot-product.futil index 0dc2175d3..91d96df71 100644 --- a/tests/correctness/seq-mem-dot-product.futil +++ b/tests/correctness/seq-mem-dot-product.futil @@ -1,6 +1,7 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component main() -> () { cells { diff --git a/tests/correctness/seq.futil b/tests/correctness/seq.futil index 2d9b72e32..e210a4cea 100644 --- a/tests/correctness/seq.futil +++ b/tests/correctness/seq.futil @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) in = std_mem_d1(32, 1, 1); + @external(1) in = comb_mem_d1(32, 1, 1); b = std_reg(32); c = std_reg(32); - @external(1) out = std_mem_d1(32, 1, 1); + @external(1) out = comb_mem_d1(32, 1, 1); } wires { diff --git a/tests/correctness/static-control/bounded-while.futil b/tests/correctness/static-control/bounded-while.futil index 3af245af2..4d9f288db 100644 --- a/tests/correctness/static-control/bounded-while.futil +++ b/tests/correctness/static-control/bounded-while.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); } wires { diff --git a/tests/correctness/static-control/fixup-necessary.futil b/tests/correctness/static-control/fixup-necessary.futil index 6cc087e7c..db7536e15 100644 --- a/tests/correctness/static-control/fixup-necessary.futil +++ b/tests/correctness/static-control/fixup-necessary.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo(in: 1) -> (out: 32) { cells { @@ -41,7 +42,7 @@ component foo(in: 1) -> (out: 32) { component main() -> () { cells { foo_inst = foo(); - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); } wires { diff --git a/tests/correctness/static-control/if-start.futil b/tests/correctness/static-control/if-start.futil index 6a6f6d001..50e03521f 100644 --- a/tests/correctness/static-control/if-start.futil +++ b/tests/correctness/static-control/if-start.futil @@ -1,17 +1,18 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external cond = std_mem_d1(1, 1, 1); - @external m = std_mem_d1(32, 1, 1); + @external cond = comb_mem_d1(1, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); read_cond_reg = std_reg(1); } wires { static<1> group read_cond { cond.addr0 = 1'd0; - read_cond_reg.write_en = 1'd1; + read_cond_reg.write_en = 1'd1; read_cond_reg.in = cond.read_data; } static<1> group one { @@ -26,7 +27,7 @@ component main() -> () { } control { static seq { - read_cond; + read_cond; static if read_cond_reg.out { four; } else { diff --git a/tests/correctness/static-control/nested-one-cycle-body.futil b/tests/correctness/static-control/nested-one-cycle-body.futil index 850f1efce..ba7e5da2a 100644 --- a/tests/correctness/static-control/nested-one-cycle-body.futil +++ b/tests/correctness/static-control/nested-one-cycle-body.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); } wires { diff --git a/tests/correctness/static-control/nested-static-while.futil b/tests/correctness/static-control/nested-static-while.futil index da64ac556..2fd22740b 100644 --- a/tests/correctness/static-control/nested-static-while.futil +++ b/tests/correctness/static-control/nested-static-while.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main () -> () { cells { - @external p = std_mem_d1(3,1,1); + @external p = comb_mem_d1(3,1,1); incr = std_add(3); l = std_lt(3); r = std_reg(3); @@ -28,7 +29,7 @@ component main () -> () { r_cond.write_en = 1'd1; } - + group B { p.write_data = 3'd0; p.write_en = 1'd1; @@ -43,7 +44,7 @@ component main () -> () { r.write_en = 1'd1; C[done] = r.done; } - + comb group comp { l2.left = r.out; l2.right = 3'd3; @@ -60,7 +61,7 @@ component main () -> () { static seq { A; A2; } } C; - } + } } } } \ No newline at end of file diff --git a/tests/correctness/static-control/nested-while.futil b/tests/correctness/static-control/nested-while.futil index 32ed44d37..1924e348b 100644 --- a/tests/correctness/static-control/nested-while.futil +++ b/tests/correctness/static-control/nested-while.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); r0 = std_reg(1); r1 = std_reg(1); diff --git a/tests/correctness/static-control/seq-component-chain.futil b/tests/correctness/static-control/seq-component-chain.futil index f5c64d2d2..0785ca25f 100644 --- a/tests/correctness/static-control/seq-component-chain.futil +++ b/tests/correctness/static-control/seq-component-chain.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; import "primitives/pipelined.futil"; @@ -10,9 +11,9 @@ import "primitives/pipelined.futil"; component main() -> () { cells { - @external(1) x = std_mem_d1(32, 1, 1); - @external(1) y = std_mem_d1(32, 1, 1); - @external(1) z = std_mem_d1(32, 1, 1); + @external(1) x = comb_mem_d1(32, 1, 1); + @external(1) y = comb_mem_d1(32, 1, 1); + @external(1) z = comb_mem_d1(32, 1, 1); mult_pipe0 = std_mult_pipe(32); } wires { diff --git a/tests/correctness/static-control/static-island.futil b/tests/correctness/static-control/static-island.futil index 203cf9257..933761745 100644 --- a/tests/correctness/static-control/static-island.futil +++ b/tests/correctness/static-control/static-island.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); lt = std_lt(32); lt_cond = std_reg(1); @@ -11,38 +12,38 @@ component main() -> () { } wires { group check_mem_cond { - m.addr0 = 1'd0; - lt.left = m.read_data; - lt.right = 32'd4; - lt_cond.in = lt.out; - lt_cond.write_en = 1'd1; - check_mem_cond[done] = lt_cond.done; + m.addr0 = 1'd0; + lt.left = m.read_data; + lt.right = 32'd4; + lt_cond.in = lt.out; + lt_cond.write_en = 1'd1; + check_mem_cond[done] = lt_cond.done; } static<1> group add_five_reg { add.left = r.out; add.right = 32'd5; r.in = add.out; - r.write_en = 1'd1; + r.write_en = 1'd1; } static<1> group write_mem { m.addr0 = 1'd0; add.left = m.read_data; add.right = r.out; - m.write_data = add.out; - m.write_en = 1'd1; + m.write_data = add.out; + m.write_en = 1'd1; } } control { seq { - check_mem_cond; + check_mem_cond; if lt_cond.out { - add_five_reg; + add_five_reg; } static seq { static repeat 15 { - add_five_reg; + add_five_reg; } - write_mem; + write_mem; } } } diff --git a/tests/correctness/static-control/static-mult-dot-product.futil b/tests/correctness/static-control/static-mult-dot-product.futil index bdbdd54b2..fe136867c 100644 --- a/tests/correctness/static-control/static-mult-dot-product.futil +++ b/tests/correctness/static-control/static-mult-dot-product.futil @@ -1,12 +1,13 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { mul = pipelined_mult(32); - @external left = std_mem_d1(32, 10, 4); - @external right = std_mem_d1(32, 10, 4); - @external out = std_mem_d1(32, 10, 4); + @external left = comb_mem_d1(32, 10, 4); + @external right = comb_mem_d1(32, 10, 4); + @external out = comb_mem_d1(32, 10, 4); idx = std_reg(4); add = std_add(4); sub = std_sub(4); diff --git a/tests/correctness/static-control/three-cycles.futil b/tests/correctness/static-control/three-cycles.futil index 1db12d7d9..647e8e85b 100644 --- a/tests/correctness/static-control/three-cycles.futil +++ b/tests/correctness/static-control/three-cycles.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); add = std_add(32); } wires { diff --git a/tests/correctness/static-control/while.futil b/tests/correctness/static-control/while.futil index a48aa318a..6d352d6a2 100644 --- a/tests/correctness/static-control/while.futil +++ b/tests/correctness/static-control/while.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main () -> () { cells { - @external p = std_mem_d1(3,1,1); + @external p = comb_mem_d1(3,1,1); incr = std_add(3); l = std_lt(3); r = std_reg(1); @@ -17,7 +18,7 @@ component main () -> () { s.in = incr.out; s.write_en = %0 ? 1'd1; p.addr0 = 1'd0; - } + } static<1> group C { p.write_data = s.out; diff --git a/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil index be82a5a5e..311725a94 100644 --- a/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil +++ b/tests/correctness/static-interface/static-interface-promoted-one-cycle.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component do_add(left: 32, right: 32) -> (out: 32) { cells { @@ -24,7 +25,7 @@ component do_add(left: 32, right: 32) -> (out: 32) { component main () -> () { cells { a = do_add(); - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); } wires { group inv_a { diff --git a/tests/correctness/static-interface/static-interface-promoted.futil b/tests/correctness/static-interface/static-interface-promoted.futil index f978950df..b07bdc9b4 100644 --- a/tests/correctness/static-interface/static-interface-promoted.futil +++ b/tests/correctness/static-interface/static-interface-promoted.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component do_add(left: 32, right: 32) -> (out: 32) { cells { @@ -30,7 +31,7 @@ component do_add(left: 32, right: 32) -> (out: 32) { component main () -> () { cells { a = do_add(); - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); } wires { group inv_a { diff --git a/tests/correctness/static-interface/static-interface-repeat.futil b/tests/correctness/static-interface/static-interface-repeat.futil index c4c6d9b43..9a86f9629 100644 --- a/tests/correctness/static-interface/static-interface-repeat.futil +++ b/tests/correctness/static-interface/static-interface-repeat.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<6> component do_add(left: 32, right: 32) -> (out: 32) { cells { @@ -36,7 +37,7 @@ static<6> component do_add(left: 32, right: 32) -> (out: 32) { component main () -> () { cells { a = do_add(); - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); } wires { group a_to_out { diff --git a/tests/correctness/static-interface/static-interface.futil b/tests/correctness/static-interface/static-interface.futil index 73d0c71ac..da6bed86a 100644 --- a/tests/correctness/static-interface/static-interface.futil +++ b/tests/correctness/static-interface/static-interface.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<2> component do_add(left: 32, right: 32) -> (out: 32) { cells { @@ -30,7 +31,7 @@ static<2> component do_add(left: 32, right: 32) -> (out: 32) { component main () -> () { cells { a = do_add(); - @external out = std_mem_d1(32, 1, 1); + @external out = comb_mem_d1(32, 1, 1); } wires { group a_to_out { diff --git a/tests/correctness/static-islands/par-static-islands.futil b/tests/correctness/static-islands/par-static-islands.futil index 90d5bdba4..d4bc511aa 100644 --- a/tests/correctness/static-islands/par-static-islands.futil +++ b/tests/correctness/static-islands/par-static-islands.futil @@ -1,12 +1,13 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external m = std_mem_d1(32, 1, 1); + @external m = comb_mem_d1(32, 1, 1); r1 = std_reg(32); r2 = std_reg(32); add1 = std_add(32); - add2 = std_add(32); + add2 = std_add(32); add = std_add(32); } wires { @@ -14,21 +15,21 @@ component main() -> () { add1.left = r1.out; add1.right = 32'd5; r1.in = add1.out; - r1.write_en = 1'd1; + r1.write_en = 1'd1; } static<1> group add_five_r2 { add2.left = r2.out; add2.right = 32'd5; r2.in = add2.out; - r2.write_en = 1'd1; + r2.write_en = 1'd1; } group write_mem { m.addr0 = 1'd0; add.left = r1.out; add.right = r2.out; - m.write_data = add.out; - m.write_en = 1'd1; - write_mem[done] = m.done; + m.write_data = add.out; + m.write_en = 1'd1; + write_mem[done] = m.done; } } control { @@ -41,7 +42,7 @@ component main() -> () { add_five_r2; } } - write_mem; + write_mem; } } } \ No newline at end of file diff --git a/tests/correctness/static-islands/seq-mem-dot-product.futil b/tests/correctness/static-islands/seq-mem-dot-product.futil index 5fe73ce97..0d0dac3aa 100644 --- a/tests/correctness/static-islands/seq-mem-dot-product.futil +++ b/tests/correctness/static-islands/seq-mem-dot-product.futil @@ -1,6 +1,7 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component main() -> () { cells { diff --git a/tests/correctness/sync/sync-dot-product-opt.futil b/tests/correctness/sync/sync-dot-product-opt.futil index cd6848e4d..4dbf37270 100644 --- a/tests/correctness/sync/sync-dot-product-opt.futil +++ b/tests/correctness/sync/sync-dot-product-opt.futil @@ -4,14 +4,15 @@ // the other vector // thread B is in charge of doing the multiplication and addition import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; import "primitives/binary_operators.futil"; component main () -> () { cells { - @external in_0 = std_mem_d1(32, 18, 32); - @external in_1 = std_mem_d1(32, 18, 32); - @external out = std_mem_d1(32, 1, 32); + @external in_0 = comb_mem_d1(32, 18, 32); + @external in_1 = comb_mem_d1(32, 18, 32); + @external out = comb_mem_d1(32, 1, 32); idx_0 = std_reg(32); idx_1 = std_reg(32); point_0 = std_reg(32); diff --git a/tests/correctness/sync/sync-dot-product.futil b/tests/correctness/sync/sync-dot-product.futil index cbf3e2ac5..ad83b6f5c 100644 --- a/tests/correctness/sync/sync-dot-product.futil +++ b/tests/correctness/sync/sync-dot-product.futil @@ -9,14 +9,15 @@ // means that we have a sparse vector of length 17, and has non-zero values // 4 at index 4, 5 at index 6, 9 at index 10 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; import "primitives/binary_operators.futil"; component main () -> () { cells { - @external in_0 = std_mem_d1(32, 18, 32); - @external in_1 = std_mem_d1(32, 18, 32); - @external out = std_mem_d1(32, 1, 32); + @external in_0 = comb_mem_d1(32, 18, 32); + @external in_1 = comb_mem_d1(32, 18, 32); + @external out = comb_mem_d1(32, 1, 32); idx_0 = std_reg(32); idx_1 = std_reg(32); point_0 = std_reg(32); diff --git a/tests/correctness/sync/sync-if-asym.futil b/tests/correctness/sync/sync-if-asym.futil index f4e9df493..b279a6b63 100644 --- a/tests/correctness/sync/sync-if-asym.futil +++ b/tests/correctness/sync/sync-if-asym.futil @@ -3,18 +3,19 @@ // expected resolution order: // thread 1: // w(1); sync; no-op; sync; r(4); w(8); sync; no-op; sync; r(9); w(12); -// sync; +// sync; // thread 2: -// no-op; sync; r(1); w(4); sync; no-op; sync; r(8); w(9); sync; no-op; -// sync; r(12); +// no-op; sync; r(1); w(4); sync; no-op; sync; r(8); w(9); sync; no-op; +// sync; r(12); import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - @external in_0 = std_mem_d1(32, 6, 3); - @external in_1 = std_mem_d1(32, 6, 3); - @external out = std_mem_d1(32, 6, 3); + @external in_0 = comb_mem_d1(32, 6, 3); + @external in_1 = comb_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); @@ -98,7 +99,7 @@ component main () -> () { } } } - + // thread 2 while lt.out with comp { if eq.out with st_0 { diff --git a/tests/correctness/sync/sync-if.futil b/tests/correctness/sync/sync-if.futil index 8aa986e00..719d0b7fd 100644 --- a/tests/correctness/sync/sync-if.futil +++ b/tests/correctness/sync/sync-if.futil @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - @external in_0 = std_mem_d1(32, 6, 3); - @external in_1 = std_mem_d1(32, 6, 3); - @external out = std_mem_d1(32, 6, 3); + @external in_0 = comb_mem_d1(32, 6, 3); + @external in_1 = comb_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/tests/correctness/sync/sync-simple.futil b/tests/correctness/sync/sync-simple.futil index 39e84690d..058ce601e 100644 --- a/tests/correctness/sync/sync-simple.futil +++ b/tests/correctness/sync/sync-simple.futil @@ -1,11 +1,12 @@ // -p compile-sync -p validate import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - @external out = std_mem_d1(32, 1, 3); + @external out = comb_mem_d1(32, 1, 3); val = std_reg(32); add_0 = std_add(32); } diff --git a/tests/correctness/sync/sync-three-threads.futil b/tests/correctness/sync/sync-three-threads.futil index e1396fa38..de44aebd4 100644 --- a/tests/correctness/sync/sync-three-threads.futil +++ b/tests/correctness/sync/sync-three-threads.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external out = std_mem_d1(32, 1, 3); + @external out = comb_mem_d1(32, 1, 3); val_1 = std_reg(32); incr_1 = std_add(32); val_2 = std_reg(32); diff --git a/tests/correctness/sync/sync-two-barriers.futil b/tests/correctness/sync/sync-two-barriers.futil index 982c6c814..46078dd82 100644 --- a/tests/correctness/sync/sync-two-barriers.futil +++ b/tests/correctness/sync/sync-two-barriers.futil @@ -1,16 +1,17 @@ // tests for having two barriers // expected resolution order: // thread 1: -// no_op; sync; r(1); w(2); sync; +// no_op; sync; r(1); w(2); sync; // thread 2: // w(1); sync; no-op; sync; r(2); import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - @external out = std_mem_d1(32, 5, 3); + @external out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); @@ -55,7 +56,7 @@ component main() -> () { @sync(2); } - //thread 2 + //thread 2 seq { incr_val; @sync(1); diff --git a/tests/correctness/sync/sync-while.futil b/tests/correctness/sync/sync-while.futil index 3af82c8f7..2bff0dbd7 100644 --- a/tests/correctness/sync/sync-while.futil +++ b/tests/correctness/sync/sync-while.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - @external out = std_mem_d1(32, 6, 3); + @external out = comb_mem_d1(32, 6, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/correctness/tcam/lpm.futil b/tests/correctness/tcam/lpm.futil index e1301f9bf..26244b99b 100644 --- a/tests/correctness/tcam/lpm.futil +++ b/tests/correctness/tcam/lpm.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/tcam.futil"; component main() -> () { cells { tcam = TCAM_IPv4(); - @external(1) index = std_mem_d1(5, 1, 1); + @external(1) index = comb_mem_d1(5, 1, 1); } wires { diff --git a/tests/correctness/tcam/no-matches.futil b/tests/correctness/tcam/no-matches.futil index b25c06e1b..4b7c56f7b 100644 --- a/tests/correctness/tcam/no-matches.futil +++ b/tests/correctness/tcam/no-matches.futil @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/tcam.futil"; component main() -> () { cells { tcam = TCAM_IPv4(); - @external(1) index = std_mem_d1(5, 1, 1); + @external(1) index = comb_mem_d1(5, 1, 1); } wires { diff --git a/tests/correctness/while.futil b/tests/correctness/while.futil index a0e83aa0c..03012c04d 100644 --- a/tests/correctness/while.futil +++ b/tests/correctness/while.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) i = std_mem_d1(32, 1, 1); + @external(1) i = comb_mem_d1(32, 1, 1); lt = std_lt(32); lt_reg = std_reg(1); add = std_add(32); diff --git a/tests/errors/comb-component-groups.expect b/tests/errors/comb-component-groups.expect index 05440e2a2..9355e5f7b 100644 --- a/tests/errors/comb-component-groups.expect +++ b/tests/errors/comb-component-groups.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/comb-component-groups.futil -7 | comb group g { +8 | comb group g { | ^^^^^^^^^^^^^^ Malformed Structure: Component `custom_lt` is marked combinational but contains a group `g` diff --git a/tests/errors/comb-component-groups.futil b/tests/errors/comb-component-groups.futil index 7dd484295..d6609a1b0 100644 --- a/tests/errors/comb-component-groups.futil +++ b/tests/errors/comb-component-groups.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; comb component custom_lt(left: 4, right: 4) -> (out: 1) { cells { lt = std_lt(4); diff --git a/tests/errors/comb-component.expect b/tests/errors/comb-component.expect index adbd9082c..76aa199b4 100644 --- a/tests/errors/comb-component.expect +++ b/tests/errors/comb-component.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/comb-component.futil -4 | mem = std_mem_d1(32, 2048, 11); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: Component `custom_lt` is marked combinational but contains non-combinational cell `mem` +5 | mem = comb_mem_d1(32, 2048, 11); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: Component `custom_lt` is marked combinational but contains non-combinational cell `mem` diff --git a/tests/errors/comb-component.futil b/tests/errors/comb-component.futil index a5917d9a8..901d5125b 100644 --- a/tests/errors/comb-component.futil +++ b/tests/errors/comb-component.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; comb component custom_lt(left: 4, right: 4) -> (out: 1) { cells { - mem = std_mem_d1(32, 2048, 11); + mem = comb_mem_d1(32, 2048, 11); lt = std_lt(4); } wires { diff --git a/tests/errors/comb-group-in-control.expect b/tests/errors/comb-group-in-control.expect index df132655c..96b21eb39 100644 --- a/tests/errors/comb-group-in-control.expect +++ b/tests/errors/comb-group-in-control.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/comb-group-in-control.futil -7 | group a { +8 | group a { | ^^^^^^^^^ Malformed Structure: Group with constant done condition is invalid. Use `comb group` instead to define a combinational group. diff --git a/tests/errors/comb-group-in-control.futil b/tests/errors/comb-group-in-control.futil index 7ace9a6c2..929aa6800 100644 --- a/tests/errors/comb-group-in-control.futil +++ b/tests/errors/comb-group-in-control.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/comb-port-in-condition.expect b/tests/errors/comb-port-in-condition.expect index d5d636cce..255fbe7ab 100644 --- a/tests/errors/comb-port-in-condition.expect +++ b/tests/errors/comb-port-in-condition.expect @@ -2,8 +2,8 @@ 1 ---STDERR--- [WARN calyx_opt::passes::well_formed] tests/errors/comb-port-in-condition.futil - 8 | if le.out { seq {} } + 9 | if le.out { seq {} } | ^^^^^^^^^^^^^^^^^^^^ If statement has no comb group and its condition port le.out is unstable Error: tests/errors/comb-port-in-condition.futil -8 | if le.out { seq {} } +9 | if le.out { seq {} } | ^^^^^^^^^^^^^^^^^^^^ [Papercut] Port `le.out` is an output port on combinational primitive `std_le` and will always output 0. Add a `with` statement to the `if` statement to ensure it has a valid value during execution. diff --git a/tests/errors/comb-port-in-condition.futil b/tests/errors/comb-port-in-condition.futil index 23fdec687..73f13b660 100644 --- a/tests/errors/comb-port-in-condition.futil +++ b/tests/errors/comb-port-in-condition.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { le = std_le(32); diff --git a/tests/errors/comb-static-comp.expect b/tests/errors/comb-static-comp.expect index 0663101a2..65cabc7a6 100644 --- a/tests/errors/comb-static-comp.expect +++ b/tests/errors/comb-static-comp.expect @@ -1,9 +1,9 @@ ---CODE--- 1 ---STDERR--- -Error: Failed to parse `tests/errors/comb-static-comp.futil`: --> 2:1 +Error: Failed to parse `tests/errors/comb-static-comp.futil`: --> 3:1 | -2 | comb static<1> component custom_lt(left: 4, right: 4) -> (out: 1) { +3 | comb static<1> component custom_lt(left: 4, right: 4) -> (out: 1) { | ^------------^ | = Cannot have both comb and static annotations diff --git a/tests/errors/comb-static-comp.futil b/tests/errors/comb-static-comp.futil index 9d9a68f20..47b98d299 100644 --- a/tests/errors/comb-static-comp.futil +++ b/tests/errors/comb-static-comp.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; comb static<1> component custom_lt(left: 4, right: 4) -> (out: 1) { cells { lt = std_lt(4); diff --git a/tests/errors/duplicate-cells.expect b/tests/errors/duplicate-cells.expect index c603d3d95..d4c021871 100644 --- a/tests/errors/duplicate-cells.expect +++ b/tests/errors/duplicate-cells.expect @@ -2,8 +2,8 @@ 1 ---STDERR--- Error: tests/errors/duplicate-cells.futil -6 | r = std_reg(32); +7 | r = std_reg(32); | ^^^^^^^^^^^^^^^ Name `r' already bound by cell tests/errors/duplicate-cells.futil -5 | r = std_reg(32); +6 | r = std_reg(32); | ^^^^^^^^^^^^^^^ Previous definition diff --git a/tests/errors/duplicate-cells.futil b/tests/errors/duplicate-cells.futil index 0f3cb0455..1f0ab4535 100644 --- a/tests/errors/duplicate-cells.futil +++ b/tests/errors/duplicate-cells.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/errors/group-comb-conflict.expect b/tests/errors/group-comb-conflict.expect index fc6b166e5..3b91f98c4 100644 --- a/tests/errors/group-comb-conflict.expect +++ b/tests/errors/group-comb-conflict.expect @@ -2,9 +2,9 @@ 1 ---STDERR--- Error: Malformed Structure: Obviously conflicting assignments found: -13 | w1.in = r.out; -10 | w1.in = 32'd10; +14 | w1.in = r.out; +11 | w1.in = 32'd10; tests/errors/group-comb-conflict.futil -21 | do_r; +22 | do_r; | ^^^^^ Assigments activated by group enable diff --git a/tests/errors/group-comb-conflict.futil b/tests/errors/group-comb-conflict.futil index 8c47ff712..88dc8b0f7 100644 --- a/tests/errors/group-comb-conflict.futil +++ b/tests/errors/group-comb-conflict.futil @@ -1,5 +1,6 @@ // -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/group-cont-assign-conflict.expect b/tests/errors/group-cont-assign-conflict.expect index 5206fa7e8..d05a796dd 100644 --- a/tests/errors/group-cont-assign-conflict.expect +++ b/tests/errors/group-cont-assign-conflict.expect @@ -2,9 +2,9 @@ 1 ---STDERR--- Error: Malformed Structure: Obviously conflicting assignments found: -12 | r.in = 32'd10; -15 | r.in = w1.out; +13 | r.in = 32'd10; +16 | r.in = w1.out; tests/errors/group-cont-assign-conflict.futil -18 | do_r; +19 | do_r; | ^^^^^ Assigments activated by group enable diff --git a/tests/errors/group-cont-assign-conflict.futil b/tests/errors/group-cont-assign-conflict.futil index 3e5183957..75ae6f2a5 100644 --- a/tests/errors/group-cont-assign-conflict.futil +++ b/tests/errors/group-cont-assign-conflict.futil @@ -1,5 +1,6 @@ // -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/if-cond-conflict.expect b/tests/errors/if-cond-conflict.expect index 43dc33b37..3db4accd6 100644 --- a/tests/errors/if-cond-conflict.expect +++ b/tests/errors/if-cond-conflict.expect @@ -2,9 +2,9 @@ 1 ---STDERR--- Error: Malformed Structure: Obviously conflicting assignments found: -13 | w1.in = 32'd2; -10 | w1.in = 32'd1; +14 | w1.in = 32'd2; +11 | w1.in = 32'd1; tests/errors/if-cond-conflict.futil -23 | if w1.out with w1_2 { +24 | if w1.out with w1_2 { | ^^^^^^^^^^^^^^^^^^^^^ Assignments from `w1_2' are actived here diff --git a/tests/errors/if-cond-conflict.futil b/tests/errors/if-cond-conflict.futil index 3c41a3e4b..6f32c1f1d 100644 --- a/tests/errors/if-cond-conflict.futil +++ b/tests/errors/if-cond-conflict.futil @@ -1,5 +1,6 @@ // -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/insufficient-params.expect b/tests/errors/insufficient-params.expect index 96605cfd2..0e2c40f03 100644 --- a/tests/errors/insufficient-params.expect +++ b/tests/errors/insufficient-params.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/insufficient-params.futil -5 | d = std_fp_div_pipe(32); +6 | d = std_fp_div_pipe(32); | ^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: primitive `std_fp_div_pipe` requires 3 parameters but instantiation provides 1 parameters diff --git a/tests/errors/insufficient-params.futil b/tests/errors/insufficient-params.futil index 4681c1b76..410703f73 100644 --- a/tests/errors/insufficient-params.futil +++ b/tests/errors/insufficient-params.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/errors/invoke-undefined-port.expect b/tests/errors/invoke-undefined-port.expect index f4e27f8c0..b97359554 100644 --- a/tests/errors/invoke-undefined-port.expect +++ b/tests/errors/invoke-undefined-port.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/invoke-undefined-port.futil -15 | invoke f(b = 32'd10)(); +16 | invoke f(b = 32'd10)(); | ^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: cell `f` (which is an instance of foo) does not have port named `b` diff --git a/tests/errors/invoke-undefined-port.futil b/tests/errors/invoke-undefined-port.futil index 2bfcfc682..abbb5ba70 100644 --- a/tests/errors/invoke-undefined-port.futil +++ b/tests/errors/invoke-undefined-port.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo(a: 32) -> () { cells {} diff --git a/tests/errors/mem-only-reads.futil b/tests/errors/mem-only-reads.futil index 217519694..3307f3adc 100644 --- a/tests/errors/mem-only-reads.futil +++ b/tests/errors/mem-only-reads.futil @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - mem = std_mem_d1(32, 4, 4); + mem = comb_mem_d1(32, 4, 4); r = std_reg(32); } wires { diff --git a/tests/errors/mismatch-widths.expect b/tests/errors/mismatch-widths.expect index 8f2746396..abb735bd9 100644 --- a/tests/errors/mismatch-widths.expect +++ b/tests/errors/mismatch-widths.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/mismatch-widths.futil -8 | add.left = x.out; +9 | add.left = x.out; | ^^^^^^^^^^^^^^^^^ Malformed Structure: Mismatched port widths. Source has size 16 while destination requires 32. diff --git a/tests/errors/mismatch-widths.futil b/tests/errors/mismatch-widths.futil index 83835b485..1b7471d5a 100644 --- a/tests/errors/mismatch-widths.futil +++ b/tests/errors/mismatch-widths.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add = std_add(32); diff --git a/tests/errors/multiple-attr-vals.expect b/tests/errors/multiple-attr-vals.expect index a72462000..d1aa9154d 100644 --- a/tests/errors/multiple-attr-vals.expect +++ b/tests/errors/multiple-attr-vals.expect @@ -1,9 +1,9 @@ ---CODE--- 1 ---STDERR--- -Error: Failed to parse `tests/errors/multiple-attr-vals.futil`: --> 4:5 +Error: Failed to parse `tests/errors/multiple-attr-vals.futil`: --> 5:5 | -4 | @external(1) @external(2) r = std_reg(32); +5 | @external(1) @external(2) r = std_reg(32); | ^-----------------------^ | = Malformed Structure: Multiple entries for attribute: external diff --git a/tests/errors/multiple-attr-vals.futil b/tests/errors/multiple-attr-vals.futil index 9a4abcf30..77f7b2248 100644 --- a/tests/errors/multiple-attr-vals.futil +++ b/tests/errors/multiple-attr-vals.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @external(1) @external(2) r = std_reg(32); diff --git a/tests/errors/multiple-done.expect b/tests/errors/multiple-done.expect index a7b2088bc..f1f9246b4 100644 --- a/tests/errors/multiple-done.expect +++ b/tests/errors/multiple-done.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/multiple-done.futil -11 | do_r[done] = !r.done ? 1'd1; +12 | do_r[done] = !r.done ? 1'd1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: Group `do_r` has multiple done conditions diff --git a/tests/errors/multiple-done.futil b/tests/errors/multiple-done.futil index 68275ddf8..cea4b8803 100644 --- a/tests/errors/multiple-done.futil +++ b/tests/errors/multiple-done.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/no-drive.expect b/tests/errors/no-drive.expect index 0ab030a26..a68436f9a 100644 --- a/tests/errors/no-drive.expect +++ b/tests/errors/no-drive.expect @@ -2,7 +2,7 @@ 1 ---STDERR--- Error: tests/errors/no-drive.futil -8 | group no_drive { +9 | group no_drive { | ^^^^^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. When writing to the port `r.in', the ports [r.write_en] must also be written to. The primitive type `std_reg' requires this invariant. diff --git a/tests/errors/no-drive.futil b/tests/errors/no-drive.futil index 688c0dbb7..3ffd1a67c 100644 --- a/tests/errors/no-drive.futil +++ b/tests/errors/no-drive.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/errors/non-entrypoint-external.expect b/tests/errors/non-entrypoint-external.expect index d67d304df..8a0eee532 100644 --- a/tests/errors/non-entrypoint-external.expect +++ b/tests/errors/non-entrypoint-external.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/non-entrypoint-external.futil -5 | @external r = std_reg(32); +6 | @external r = std_reg(32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: Cell cannot be marked `@external` in non-entrypoint component diff --git a/tests/errors/non-entrypoint-external.futil b/tests/errors/non-entrypoint-external.futil index 02105e3c2..2f1a73f31 100644 --- a/tests/errors/non-entrypoint-external.futil +++ b/tests/errors/non-entrypoint-external.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo() -> () { cells { diff --git a/tests/errors/obvious-conflict.expect b/tests/errors/obvious-conflict.expect index 8d524a605..77fcf9cd9 100644 --- a/tests/errors/obvious-conflict.expect +++ b/tests/errors/obvious-conflict.expect @@ -2,6 +2,6 @@ 1 ---STDERR--- Error: Malformed Structure: Obviously conflicting assignments found: -10 | r.in = w1.out; -11 | r.in = w2.out; +11 | r.in = w1.out; +12 | r.in = w2.out; diff --git a/tests/errors/obvious-conflict.futil b/tests/errors/obvious-conflict.futil index 74e7e4177..150a391cc 100644 --- a/tests/errors/obvious-conflict.futil +++ b/tests/errors/obvious-conflict.futil @@ -1,5 +1,6 @@ // -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/orphan-done.futil b/tests/errors/orphan-done.futil index e48eff237..3199dc534 100644 --- a/tests/errors/orphan-done.futil +++ b/tests/errors/orphan-done.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/errors/papercut/cell-and-group-conflict.expect b/tests/errors/papercut/cell-and-group-conflict.expect index fc9dc62e8..22f79441f 100644 --- a/tests/errors/papercut/cell-and-group-conflict.expect +++ b/tests/errors/papercut/cell-and-group-conflict.expect @@ -2,8 +2,8 @@ 1 ---STDERR--- Error: tests/errors/papercut/cell-and-group-conflict.futil -9 | group incr { - | ^^^^^^^^^^^^ Name `incr' already bound by cell +10 | group incr { + | ^^^^^^^^^^^^ Name `incr' already bound by cell tests/errors/papercut/cell-and-group-conflict.futil -5 | incr = std_add(32); +6 | incr = std_add(32); | ^^^^^^^^^^^^^^^^^^ Previous definition diff --git a/tests/errors/papercut/cell-and-group-conflict.futil b/tests/errors/papercut/cell-and-group-conflict.futil index 8cc9eacc5..b998742d1 100644 --- a/tests/errors/papercut/cell-and-group-conflict.futil +++ b/tests/errors/papercut/cell-and-group-conflict.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/errors/papercut/cell-as-group.expect b/tests/errors/papercut/cell-as-group.expect index 75468a12d..80fb58638 100644 --- a/tests/errors/papercut/cell-as-group.expect +++ b/tests/errors/papercut/cell-as-group.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/papercut/cell-as-group.futil -9 | save; - | ^^^^^ Undefined group name: save +10 | save; + | ^^^^^ Undefined group name: save diff --git a/tests/errors/papercut/cell-as-group.futil b/tests/errors/papercut/cell-as-group.futil index 48c96467b..8e0b75917 100644 --- a/tests/errors/papercut/cell-as-group.futil +++ b/tests/errors/papercut/cell-as-group.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/errors/papercut/multi-done.futil b/tests/errors/papercut/multi-done.futil index c4ab02613..6cf6aecf0 100644 --- a/tests/errors/papercut/multi-done.futil +++ b/tests/errors/papercut/multi-done.futil @@ -1,4 +1,4 @@ -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done read_done: 1, @done(2) write_done: 1) { cells { mem_0 = seq_mem_d1(32, 6, 3); diff --git a/tests/errors/papercut/no-control-no-done.futil b/tests/errors/papercut/no-control-no-done.futil index 4a757e33d..e49674bc0 100644 --- a/tests/errors/papercut/no-control-no-done.futil +++ b/tests/errors/papercut/no-control-no-done.futil @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1) -> (@done done: 1) { // ANCHOR: cells cells { - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); } // ANCHOR_END: cells // ANCHOR: wires diff --git a/tests/errors/papercut/no-done.expect b/tests/errors/papercut/no-done.expect index cd17e0224..265a49f1d 100644 --- a/tests/errors/papercut/no-done.expect +++ b/tests/errors/papercut/no-done.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/papercut/no-done.futil -8 | group no_drive { +9 | group no_drive { | ^^^^^^^^^^^^^^^^ Malformed Structure: No writes to the `done' hole for group `no_drive' diff --git a/tests/errors/papercut/no-done.futil b/tests/errors/papercut/no-done.futil index a1939f605..cbf7247e4 100644 --- a/tests/errors/papercut/no-done.futil +++ b/tests/errors/papercut/no-done.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/errors/papercut/read-missing-write-comb.expect b/tests/errors/papercut/read-missing-write-comb.expect index d13bb3e86..e7c11b899 100644 --- a/tests/errors/papercut/read-missing-write-comb.expect +++ b/tests/errors/papercut/read-missing-write-comb.expect @@ -2,7 +2,7 @@ 1 ---STDERR--- Error: tests/errors/papercut/read-missing-write-comb.futil -10 | comb group check { +11 | comb group check { | ^^^^^^^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. When read the port `mem.read_data', the ports [mem.addr0] must be written to. -The primitive type `std_mem_d1' requires this invariant. +The primitive type `comb_mem_d1' requires this invariant. diff --git a/tests/errors/papercut/read-missing-write-comb.futil b/tests/errors/papercut/read-missing-write-comb.futil index 66bd1ff18..6bd73f7ca 100644 --- a/tests/errors/papercut/read-missing-write-comb.futil +++ b/tests/errors/papercut/read-missing-write-comb.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - mem = std_mem_d1(32, 1, 1); + mem = comb_mem_d1(32, 1, 1); eq = std_add(32); r = std_reg(1); } diff --git a/tests/errors/papercut/read-missing-write.expect b/tests/errors/papercut/read-missing-write.expect index 2efa02191..228667fd5 100644 --- a/tests/errors/papercut/read-missing-write.expect +++ b/tests/errors/papercut/read-missing-write.expect @@ -2,7 +2,7 @@ 1 ---STDERR--- Error: tests/errors/papercut/read-missing-write.futil -10 | group incr { +11 | group incr { | ^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. When read the port `mem.read_data', the ports [mem.addr0] must be written to. -The primitive type `std_mem_d1' requires this invariant. +The primitive type `comb_mem_d1' requires this invariant. diff --git a/tests/errors/papercut/read-missing-write.futil b/tests/errors/papercut/read-missing-write.futil index a8a12040e..8ebe21fe9 100644 --- a/tests/errors/papercut/read-missing-write.futil +++ b/tests/errors/papercut/read-missing-write.futil @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - mem = std_mem_d1(32, 1, 1); + mem = comb_mem_d1(32, 1, 1); add = std_add(32); r = std_reg(32); } diff --git a/tests/errors/redefine-external.futil b/tests/errors/redefine-external.futil index 83b2d65c7..43f659ff2 100644 --- a/tests/errors/redefine-external.futil +++ b/tests/errors/redefine-external.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "./redefine-external.futil" { // This extern is not defined that in that file. primitive exp() -> (); diff --git a/tests/errors/reserved-name.expect b/tests/errors/reserved-name.expect index 7928948bf..17cbf21a8 100644 --- a/tests/errors/reserved-name.expect +++ b/tests/errors/reserved-name.expect @@ -2,5 +2,5 @@ 1 ---STDERR--- Error: tests/errors/reserved-name.futil -4 | reg = std_reg(32); +5 | reg = std_reg(32); | ^^^^^^^^^^^^^^^^^ Use of reserved keyword: reg diff --git a/tests/errors/reserved-name.futil b/tests/errors/reserved-name.futil index 0f8ab176e..3e47af764 100644 --- a/tests/errors/reserved-name.futil +++ b/tests/errors/reserved-name.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { reg = std_reg(32); diff --git a/tests/errors/runtime/multiple-drivers.futil b/tests/errors/runtime/multiple-drivers.futil index 4c98839dc..d3e63cd14 100644 --- a/tests/errors/runtime/multiple-drivers.futil +++ b/tests/errors/runtime/multiple-drivers.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); @@ -14,17 +15,17 @@ component main() -> () { r.write_en = 1'd1; two[done] = r.done; } - // need this group so that r is read from, so that it is - // not removed in the `dead-cell-removal` pass, since we want the error - // to occur. + // need this group so that r is read from, so that it is + // not removed in the `dead-cell-removal` pass, since we want the error + // to occur. group read_r { - r.in = r.out; - r.write_en = 1'd1; - read_r[done] = r.done; + r.in = r.out; + r.write_en = 1'd1; + read_r[done] = r.done; } } control { par { one; two; } - read_r; + read_r; } } diff --git a/tests/errors/while-unstable.expect b/tests/errors/while-unstable.expect index a13735806..28b37eda0 100644 --- a/tests/errors/while-unstable.expect +++ b/tests/errors/while-unstable.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); @@ -20,5 +21,5 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } ---STDERR--- [WARN calyx_opt::passes::well_formed] tests/errors/while-unstable.futil - 19 | while lt.out { + 20 | while lt.out { | ^^^^^^^^^^^^^^ While loop has no comb group and its condition port lt.out is unstable diff --git a/tests/errors/while-unstable.futil b/tests/errors/while-unstable.futil index 8e3bac88a..8b9904b3b 100644 --- a/tests/errors/while-unstable.futil +++ b/tests/errors/while-unstable.futil @@ -1,23 +1,24 @@ //-p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); - lt = std_lt(32); + lt = std_lt(32); } wires { static<2> group A { - r1.write_en = 1'd1; + r1.write_en = 1'd1; r1.in = 32'd2; } - lt.left = r1.out; - lt.right = 32'd4; + lt.left = r1.out; + lt.right = 32'd4; } control { while lt.out { - A; + A; } } } diff --git a/tests/frontend/dahlia/binop_tree.expect b/tests/frontend/dahlia/binop_tree.expect index cf973eb95..fcba7bc35 100644 --- a/tests/frontend/dahlia/binop_tree.expect +++ b/tests/frontend/dahlia/binop_tree.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/combine.expect b/tests/frontend/dahlia/combine.expect index 47309e07c..a4c3679cd 100644 --- a/tests/frontend/dahlia/combine.expect +++ b/tests/frontend/dahlia/combine.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/dot-func.expect b/tests/frontend/dahlia/dot-func.expect index 98ab5c543..01c45727c 100644 --- a/tests/frontend/dahlia/dot-func.expect +++ b/tests/frontend/dahlia/dot-func.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component dot() -> () { cells { diff --git a/tests/frontend/dahlia/fixed-point-add.expect b/tests/frontend/dahlia/fixed-point-add.expect index bd0ce51d5..45b367203 100644 --- a/tests/frontend/dahlia/fixed-point-add.expect +++ b/tests/frontend/dahlia/fixed-point-add.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/for.expect b/tests/frontend/dahlia/for.expect index a1ee6aff3..e86427fc7 100644 --- a/tests/frontend/dahlia/for.expect +++ b/tests/frontend/dahlia/for.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/if.expect b/tests/frontend/dahlia/if.expect index 87d2ad473..bb99de3ac 100644 --- a/tests/frontend/dahlia/if.expect +++ b/tests/frontend/dahlia/if.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/invoke-memory.expect b/tests/frontend/dahlia/invoke-memory.expect index 130d9011a..4e5d380c7 100644 --- a/tests/frontend/dahlia/invoke-memory.expect +++ b/tests/frontend/dahlia/invoke-memory.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component mem_copy(length: 3) -> () { cells { diff --git a/tests/frontend/dahlia/invoke.expect b/tests/frontend/dahlia/invoke.expect index 0564db4aa..d7e33bcaa 100644 --- a/tests/frontend/dahlia/invoke.expect +++ b/tests/frontend/dahlia/invoke.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component add(a: 32, b: 32) -> (@stable(1) out: 32) { cells { diff --git a/tests/frontend/dahlia/matadd-fixed-point.expect b/tests/frontend/dahlia/matadd-fixed-point.expect index a05b8597e..009033928 100644 --- a/tests/frontend/dahlia/matadd-fixed-point.expect +++ b/tests/frontend/dahlia/matadd-fixed-point.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/memory.expect b/tests/frontend/dahlia/memory.expect index 380be213e..9db0d3eaa 100644 --- a/tests/frontend/dahlia/memory.expect +++ b/tests/frontend/dahlia/memory.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/par.expect b/tests/frontend/dahlia/par.expect index 9ae29fe5a..2fbe8e566 100644 --- a/tests/frontend/dahlia/par.expect +++ b/tests/frontend/dahlia/par.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/seq.expect b/tests/frontend/dahlia/seq.expect index d20463630..6b71796fc 100644 --- a/tests/frontend/dahlia/seq.expect +++ b/tests/frontend/dahlia/seq.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/signed_dotproduct.expect b/tests/frontend/dahlia/signed_dotproduct.expect index 262e838c6..ec1645ac1 100644 --- a/tests/frontend/dahlia/signed_dotproduct.expect +++ b/tests/frontend/dahlia/signed_dotproduct.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/dahlia/unroll.expect b/tests/frontend/dahlia/unroll.expect index b2528b0c3..edb79383b 100644 --- a/tests/frontend/dahlia/unroll.expect +++ b/tests/frontend/dahlia/unroll.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/frontend/exp/degree-2-unsigned.expect b/tests/frontend/exp/degree-2-unsigned.expect index 786d17ac9..885bdbbb4 100644 --- a/tests/frontend/exp/degree-2-unsigned.expect +++ b/tests/frontend/exp/degree-2-unsigned.expect @@ -1,5 +1,6 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; +import "primitives/memories/comb.futil"; component exp(x: 32) -> (out: 32) { cells { exponent_value = std_reg(32); @@ -152,8 +153,8 @@ component fp_pow(base: 32, integer_exp: 32) -> (out: 32) { component main() -> () { cells { t = std_reg(32); - @external x = std_mem_d1(32, 1, 1); - @external ret = std_mem_d1(32, 1, 1); + @external x = comb_mem_d1(32, 1, 1); + @external ret = comb_mem_d1(32, 1, 1); e = exp(); } wires { diff --git a/tests/frontend/exp/degree-4-signed.expect b/tests/frontend/exp/degree-4-signed.expect index 0a6a19d0e..bbf5ec0be 100644 --- a/tests/frontend/exp/degree-4-signed.expect +++ b/tests/frontend/exp/degree-4-signed.expect @@ -1,5 +1,6 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; +import "primitives/memories/comb.futil"; component exp(x: 16) -> (out: 16) { cells { exponent_value = std_reg(16); @@ -245,8 +246,8 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { component main() -> () { cells { t = std_reg(16); - @external x = std_mem_d1(16, 1, 1); - @external ret = std_mem_d1(16, 1, 1); + @external x = comb_mem_d1(16, 1, 1); + @external ret = comb_mem_d1(16, 1, 1); e = exp(); } wires { diff --git a/tests/frontend/exp/degree-4-unsigned.expect b/tests/frontend/exp/degree-4-unsigned.expect index 3c8962a8d..98a047cdb 100644 --- a/tests/frontend/exp/degree-4-unsigned.expect +++ b/tests/frontend/exp/degree-4-unsigned.expect @@ -1,5 +1,6 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; +import "primitives/memories/comb.futil"; component exp(x: 16) -> (out: 16) { cells { exponent_value = std_reg(16); @@ -216,8 +217,8 @@ component fp_pow(base: 16, integer_exp: 16) -> (out: 16) { component main() -> () { cells { t = std_reg(16); - @external x = std_mem_d1(16, 1, 1); - @external ret = std_mem_d1(16, 1, 1); + @external x = comb_mem_d1(16, 1, 1); + @external ret = comb_mem_d1(16, 1, 1); e = exp(); } wires { diff --git a/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect b/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect index bb67b80c7..7f93296ae 100644 --- a/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect +++ b/tests/frontend/ntt-pipeline/ntt-4-reduced-2.expect @@ -8,10 +8,11 @@ // +---+-----------------------+-----------------------+ import "primitives/core.futil"; import "primitives/binary_operators.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external a = std_mem_d1(32, 4, 3); - @external phis = std_mem_d1(32, 4, 3); + @external a = comb_mem_d1(32, 4, 3); + @external phis = comb_mem_d1(32, 4, 3); r0 = std_reg(32); r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/frontend/ntt-pipeline/ntt-4.expect b/tests/frontend/ntt-pipeline/ntt-4.expect index 881c1b991..e4ada83fa 100644 --- a/tests/frontend/ntt-pipeline/ntt-4.expect +++ b/tests/frontend/ntt-pipeline/ntt-4.expect @@ -8,10 +8,11 @@ // +---+-----------------------+-----------------------+ import "primitives/core.futil"; import "primitives/binary_operators.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external a = std_mem_d1(32, 4, 3); - @external phis = std_mem_d1(32, 4, 3); + @external a = comb_mem_d1(32, 4, 3); + @external phis = comb_mem_d1(32, 4, 3); r0 = std_reg(32); r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/frontend/relay/batch_flatten-same-dimensions.expect b/tests/frontend/relay/batch_flatten-same-dimensions.expect index cb3fd6cf1..4a0d96ba9 100644 --- a/tests/frontend/relay/batch_flatten-same-dimensions.expect +++ b/tests/frontend/relay/batch_flatten-same-dimensions.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component batch_flatten_2x4096() -> () { diff --git a/tests/frontend/relay/batch_flatten.expect b/tests/frontend/relay/batch_flatten.expect index 61dc9d70d..c508e5619 100644 --- a/tests/frontend/relay/batch_flatten.expect +++ b/tests/frontend/relay/batch_flatten.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component batch_flatten_1x4() -> () { diff --git a/tests/frontend/relay/batch_matmul.expect b/tests/frontend/relay/batch_matmul.expect index 8a2ed0c4c..7b9cbdb27 100644 --- a/tests/frontend/relay/batch_matmul.expect +++ b/tests/frontend/relay/batch_matmul.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component batch_matmul_4x7x7() -> () { diff --git a/tests/frontend/relay/bias_add.expect b/tests/frontend/relay/bias_add.expect index c6b56de9f..cc6d360e0 100644 --- a/tests/frontend/relay/bias_add.expect +++ b/tests/frontend/relay/bias_add.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component bias_add_1x64x512x256() -> () { diff --git a/tests/frontend/relay/broadcast.expect b/tests/frontend/relay/broadcast.expect index 45b6324ca..91ec84086 100644 --- a/tests/frontend/relay/broadcast.expect +++ b/tests/frontend/relay/broadcast.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component add_2x4() -> () { diff --git a/tests/frontend/relay/constant-multiply.expect b/tests/frontend/relay/constant-multiply.expect index 6c883436c..f4ff21b93 100644 --- a/tests/frontend/relay/constant-multiply.expect +++ b/tests/frontend/relay/constant-multiply.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component multiply_1(x1: 32) -> () { diff --git a/tests/frontend/relay/conv2d.expect b/tests/frontend/relay/conv2d.expect index f3a1832c6..629f92dc4 100644 --- a/tests/frontend/relay/conv2d.expect +++ b/tests/frontend/relay/conv2d.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component conv2d_5x512x14x14() -> () { diff --git a/tests/frontend/relay/dense.expect b/tests/frontend/relay/dense.expect index cb332c5a5..aa7c00511 100644 --- a/tests/frontend/relay/dense.expect +++ b/tests/frontend/relay/dense.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component dense_1x10() -> () { diff --git a/tests/frontend/relay/duplicate-relay-call.expect b/tests/frontend/relay/duplicate-relay-call.expect index 10aaa7d1a..1c4919703 100644 --- a/tests/frontend/relay/duplicate-relay-call.expect +++ b/tests/frontend/relay/duplicate-relay-call.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component negative_2x2() -> () { diff --git a/tests/frontend/relay/max_pool2d.expect b/tests/frontend/relay/max_pool2d.expect index 662375225..81cd81874 100644 --- a/tests/frontend/relay/max_pool2d.expect +++ b/tests/frontend/relay/max_pool2d.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component max_pool2d_2x2x2x2() -> () { diff --git a/tests/frontend/relay/negative.expect b/tests/frontend/relay/negative.expect index 1e78284a3..2c6de0938 100644 --- a/tests/frontend/relay/negative.expect +++ b/tests/frontend/relay/negative.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component negative_4() -> () { diff --git a/tests/frontend/relay/relu.expect b/tests/frontend/relay/relu.expect index 1d2dcf36c..30080dd8c 100644 --- a/tests/frontend/relay/relu.expect +++ b/tests/frontend/relay/relu.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component relu_2x4x8x32() -> () { diff --git a/tests/frontend/relay/reshape.expect b/tests/frontend/relay/reshape.expect index 0c9304335..977617197 100644 --- a/tests/frontend/relay/reshape.expect +++ b/tests/frontend/relay/reshape.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component reshape_1x8() -> () { diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index d5302ee3a..cc2a50e36 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component softmax_1x10() -> () { diff --git a/tests/frontend/relay/sqrt.expect b/tests/frontend/relay/sqrt.expect index e370c4c5b..48645d9aa 100644 --- a/tests/frontend/relay/sqrt.expect +++ b/tests/frontend/relay/sqrt.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component sqrt_1x4() -> () { diff --git a/tests/frontend/relay/tensor_add.expect b/tests/frontend/relay/tensor_add.expect index c3bb09851..61e3a0fb4 100644 --- a/tests/frontend/relay/tensor_add.expect +++ b/tests/frontend/relay/tensor_add.expect @@ -1,5 +1,5 @@ import "primitives/core.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; import "primitives/math.futil"; component add_2x4() -> () { diff --git a/tests/frontend/systolic/array-1.expect b/tests/frontend/systolic/array-1.expect index 332495f07..4eaa3b889 100644 --- a/tests/frontend/systolic/array-1.expect +++ b/tests/frontend/systolic/array-1.expect @@ -1,6 +1,7 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; import "primitives/pipelined.futil"; +import "primitives/memories/comb.futil"; static<1> component mac_pe(top: 32, left: 32, mul_ready: 1) -> (out: 32) { cells { acc = std_reg(32); @@ -163,9 +164,9 @@ component main() -> () { cells { systolic_array_component = systolic_array_comp(); post_op_component = default_post_op(); - @external t0 = std_mem_d1(32, 3, 2); - @external l0 = std_mem_d1(32, 3, 2); - @external out_mem_0 = std_mem_d1(32, 1, 1); + @external t0 = comb_mem_d1(32, 3, 2); + @external l0 = comb_mem_d1(32, 3, 2); + @external out_mem_0 = comb_mem_d1(32, 1, 1); systolic_done = std_reg(1); systolic_done_wire = std_wire(1); } diff --git a/tests/import/a.expect b/tests/import/a.expect index 8f2f71276..cd8f25fc8 100644 --- a/tests/import/a.expect +++ b/tests/import/a.expect @@ -4,6 +4,12 @@ extern "/calyx/tests/import/verilog/c.sv" { extern "/calyx/tests/import/verilog/b.sv" { primitive std_max() -> (); } +extern "/calyx/primitives/memories/comb.sv" { + primitive comb_mem_d1[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @read_together @write_together(2) addr3: D3_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); +} extern "/calyx/primitives/core.sv" { comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); @@ -22,10 +28,6 @@ extern "/calyx/primitives/core.sv" { comb primitive std_lsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_rsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_mux<"share"=1>[WIDTH](@data cond: 1, @data tru: WIDTH, @data fal: WIDTH) -> (out: WIDTH); - primitive std_mem_d1[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive std_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive std_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive std_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @read_together @write_together(2) addr3: D3_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); } primitive undef<"share"=1>[WIDTH]() -> (out: WIDTH) { assign out = 'x; diff --git a/tests/import/a.futil b/tests/import/a.futil index 6420ba3d8..f12cb73ef 100644 --- a/tests/import/a.futil +++ b/tests/import/a.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "b.futil"; import "c.futil"; diff --git a/tests/import/b.futil b/tests/import/b.futil index 50c1538b5..5abbe2b55 100644 --- a/tests/import/b.futil +++ b/tests/import/b.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "verilog/b.sv" { primitive std_max() -> (); diff --git a/tests/import/c.futil b/tests/import/c.futil index 6cf01547d..329b203ca 100644 --- a/tests/import/c.futil +++ b/tests/import/c.futil @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "b.futil"; extern "verilog/c.sv" { diff --git a/tests/parsing/guards.expect b/tests/parsing/guards.expect index 27398e5df..3624b8a84 100644 --- a/tests/parsing/guards.expect +++ b/tests/parsing/guards.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { cells { @@ -9,8 +10,8 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don counter = std_reg(3); r_2 = std_reg(32); lt0 = std_lt(3); - mem0 = std_mem_d2(32, 4, 4, 3, 3); - mem1 = std_mem_d2(32, 4, 4, 3, 3); + mem0 = comb_mem_d2(32, 4, 4, 3, 3); + mem1 = comb_mem_d2(32, 4, 4, 3, 3); add1 = std_add(32); sadd = std_sadd(32); fsm = std_reg(2); diff --git a/tests/passes/attr-promotion.expect b/tests/passes/attr-promotion.expect index 3ae433bb6..a72cf49ed 100644 --- a/tests/passes/attr-promotion.expect +++ b/tests/passes/attr-promotion.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/attr-promotion.futil b/tests/passes/attr-promotion.futil index a29870988..a4a62edcb 100644 --- a/tests/passes/attr-promotion.futil +++ b/tests/passes/attr-promotion.futil @@ -1,5 +1,6 @@ // -p attr-promotion import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { @@ -9,19 +10,19 @@ component main() -> () { wires { // dynamic groups simply here to demonstrate compiling static "islands" - // within dynamic control + // within dynamic control group B<"static"=1> { - b.write_en = 1'd1; - b.in = 2'd1; - B[done] = b.done; + b.write_en = 1'd1; + b.in = 2'd1; + B[done] = b.done; } } control { seq { - B; - B; + B; + B; } } } \ No newline at end of file diff --git a/tests/passes/canonical/comb-path.expect b/tests/passes/canonical/comb-path.expect index 6c227f3c7..5d856c089 100644 --- a/tests/passes/canonical/comb-path.expect +++ b/tests/passes/canonical/comb-path.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "/calyx/tests/passes/canonical/dummy.sv" { primitive multi_comb[WIDTH](@read_together addr_a: WIDTH, @read_together(2) addr_b: WIDTH) -> (@read_together out_a: WIDTH, @read_together(2) out_b: WIDTH); } diff --git a/tests/passes/canonical/comb-path.futil b/tests/passes/canonical/comb-path.futil index e1f63bd2c..cde25ed76 100644 --- a/tests/passes/canonical/comb-path.futil +++ b/tests/passes/canonical/comb-path.futil @@ -1,5 +1,6 @@ // -p validate -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "dummy.sv" { // Component with two disjoint combinational paths. diff --git a/tests/passes/canonical/combinational-cycle.futil b/tests/passes/canonical/combinational-cycle.futil index bde5e9184..a480ff6a4 100644 --- a/tests/passes/canonical/combinational-cycle.futil +++ b/tests/passes/canonical/combinational-cycle.futil @@ -1,5 +1,6 @@ // -p well-formed -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add = std_add(4); diff --git a/tests/passes/canonical/dataflow-order.expect b/tests/passes/canonical/dataflow-order.expect index 490bcd569..80a559db2 100644 --- a/tests/passes/canonical/dataflow-order.expect +++ b/tests/passes/canonical/dataflow-order.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add0 = std_add(4); diff --git a/tests/passes/canonical/dataflow-order.futil b/tests/passes/canonical/dataflow-order.futil index c92ad9573..62c4bd123 100644 --- a/tests/passes/canonical/dataflow-order.futil +++ b/tests/passes/canonical/dataflow-order.futil @@ -1,5 +1,6 @@ // -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add0 = std_add(4); diff --git a/tests/passes/canonical/group-done.expect b/tests/passes/canonical/group-done.expect index 6320d914c..3a3fb9792 100644 --- a/tests/passes/canonical/group-done.expect +++ b/tests/passes/canonical/group-done.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) { cells { r = std_reg(1); diff --git a/tests/passes/canonical/group-done.futil b/tests/passes/canonical/group-done.futil index 9f6f33c4d..68236983c 100644 --- a/tests/passes/canonical/group-done.futil +++ b/tests/passes/canonical/group-done.futil @@ -1,6 +1,7 @@ // -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (out: 1) { cells { r = std_reg(1); @@ -10,16 +11,16 @@ component main() -> (out: 1) { group a { r.in = 1'd1; r.write_en = 1'd1; - q.in = 1'd1; - q.write_en = 1'd1; + q.in = 1'd1; + q.write_en = 1'd1; a[done] = r.done & q.done ? 1'd1; } group b { - r.in = 1'd1; - r.write_en = 1'd1; - b[done] = r.done ? 1'd1; + r.in = 1'd1; + r.write_en = 1'd1; + b[done] = r.done ? 1'd1; } - + } control { } } diff --git a/tests/passes/canonical/guard-dataflow.expect b/tests/passes/canonical/guard-dataflow.expect index 522220b58..75a4474a0 100644 --- a/tests/passes/canonical/guard-dataflow.expect +++ b/tests/passes/canonical/guard-dataflow.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add = std_add(4); diff --git a/tests/passes/canonical/guard-dataflow.futil b/tests/passes/canonical/guard-dataflow.futil index 794b85fe5..7cd01eb5b 100644 --- a/tests/passes/canonical/guard-dataflow.futil +++ b/tests/passes/canonical/guard-dataflow.futil @@ -1,5 +1,6 @@ // -p well-formed -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add = std_add(4); diff --git a/tests/passes/canonical/guard.expect b/tests/passes/canonical/guard.expect index 3cf8399f8..a64bead10 100644 --- a/tests/passes/canonical/guard.expect +++ b/tests/passes/canonical/guard.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) { cells { r = std_reg(1); - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); } wires { group b { diff --git a/tests/passes/canonical/guard.futil b/tests/passes/canonical/guard.futil index 68556503b..6c3ebd016 100644 --- a/tests/passes/canonical/guard.futil +++ b/tests/passes/canonical/guard.futil @@ -1,10 +1,11 @@ // -p canonicalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (out: 1) { cells { r = std_reg(1); - @external(1) mem = std_mem_d1(32, 1, 1); + @external(1) mem = comb_mem_d1(32, 1, 1); } wires { group b { diff --git a/tests/passes/cell-share/bounded.expect b/tests/passes/cell-share/bounded.expect index ebb847794..7c990f77b 100644 --- a/tests/passes/cell-share/bounded.expect +++ b/tests/passes/cell-share/bounded.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/bounded.futil b/tests/passes/cell-share/bounded.futil index a66b62b6b..5a2e08b6a 100644 --- a/tests/passes/cell-share/bounded.futil +++ b/tests/passes/cell-share/bounded.futil @@ -1,6 +1,7 @@ // -p cell-share -x cell-share:bounds=2,4,-1 -x cell-share:print-share-freqs= -p dead-cell-removal -p remove-ids // share adders twice, registers 3 times, and mults 4 times import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/passes/cell-share/calyx_2020.expect b/tests/passes/cell-share/calyx_2020.expect index aedb4dd14..3a0b6508f 100644 --- a/tests/passes/cell-share/calyx_2020.expect +++ b/tests/passes/cell-share/calyx_2020.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/calyx_2020.futil b/tests/passes/cell-share/calyx_2020.futil index 83f2d9c43..05ae3a778 100644 --- a/tests/passes/cell-share/calyx_2020.futil +++ b/tests/passes/cell-share/calyx_2020.futil @@ -1,6 +1,7 @@ // -p cell-share -x cell-share:calyx-2020 -x cell-share:print-share-freqs= -p dead-cell-removal -p remove-ids // share adders twice, registers 3 times, and mults 4 times import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/passes/cell-share/comb-groups-invoke.expect b/tests/passes/cell-share/comb-groups-invoke.expect index 057e3ddec..89b5a63a7 100644 --- a/tests/passes/cell-share/comb-groups-invoke.expect +++ b/tests/passes/cell-share/comb-groups-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(1); diff --git a/tests/passes/cell-share/comb-groups-invoke.futil b/tests/passes/cell-share/comb-groups-invoke.futil index c5af38a86..5af46357c 100644 --- a/tests/passes/cell-share/comb-groups-invoke.futil +++ b/tests/passes/cell-share/comb-groups-invoke.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r1 = std_reg(1); @@ -9,20 +10,20 @@ component main() -> () { } wires { comb group cg { - add.left = r1.out; - add.right = 1'd1; - lt.left = add.out; - lt.right = 1'd1; + add.left = r1.out; + add.right = 1'd1; + lt.left = add.out; + lt.right = 1'd1; } group wr_r1{ - r1.write_en = 1'd1; - r1.in = 1'd0; - wr_r1[done] = r1.done; + r1.write_en = 1'd1; + r1.in = 1'd0; + wr_r1[done] = r1.done; } } control { seq{ - wr_r1; + wr_r1; invoke r2(in = lt.out)() with cg; } } diff --git a/tests/passes/cell-share/comb-groups-regs.expect b/tests/passes/cell-share/comb-groups-regs.expect index b1e15cd80..6e3bee908 100644 --- a/tests/passes/cell-share/comb-groups-regs.expect +++ b/tests/passes/cell-share/comb-groups-regs.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r0 = std_reg(32); diff --git a/tests/passes/cell-share/comb-groups-regs.futil b/tests/passes/cell-share/comb-groups-regs.futil index 336acaa91..8421d4c1d 100644 --- a/tests/passes/cell-share/comb-groups-regs.futil +++ b/tests/passes/cell-share/comb-groups-regs.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r0 = std_reg(32); @@ -12,63 +13,63 @@ component main() -> () { wires { comb group rd_r0{ lt.left = r0.out; - lt.right = 32'd5; + lt.right = 32'd5; } comb group rd_r2{ - lt.left = r2.out; + lt.left = r2.out; lt.right = 32'd5; } group wr_r0{ - r0.write_en = 1'd1; - r0.in = 32'd22; - wr_r0[done] = r0.done; + r0.write_en = 1'd1; + r0.in = 32'd22; + wr_r0[done] = r0.done; } group wr_r1{ - r1.write_en = 1'd1; - r1.in = 32'd22; - wr_r1[done] = r1.done; + r1.write_en = 1'd1; + r1.in = 32'd22; + wr_r1[done] = r1.done; } group rd_r1{ - x.write_en = 1'd1; - x.in = r1.out; - rd_r1[done] = x.done; + x.write_en = 1'd1; + x.in = r1.out; + rd_r1[done] = x.done; } group wr_x{ - x.write_en = 1'd1; - x.in = 32'd2; - wr_x[done] = x.done; + x.write_en = 1'd1; + x.in = 32'd2; + wr_x[done] = x.done; } group wr_r2{ - r2.write_en = 1'd1; - r2.in = 32'd22; - wr_r2[done] = r2.done; + r2.write_en = 1'd1; + r2.in = 32'd22; + wr_r2[done] = r2.done; } group wr_r3{ - r3.write_en = 1'd1; - r3.in = 32'd22; - wr_r3[done] = r3.done; + r3.write_en = 1'd1; + r3.in = 32'd22; + wr_r3[done] = r3.done; } group rd_r3{ - x.write_en = 1'd1; - x.in = r3.out; - rd_r3[done] = x.done; + x.write_en = 1'd1; + x.in = r3.out; + rd_r3[done] = x.done; } - + } control { seq{ - wr_r0; - wr_r1; - rd_r1; + wr_r0; + wr_r1; + rd_r1; if lt.out with rd_r0{ wr_x; } wr_r2; while lt.out with rd_r2{ seq{ - wr_r2; - wr_r3; - rd_r3; + wr_r2; + wr_r3; + rd_r3; } } } diff --git a/tests/passes/cell-share/cond-port.expect b/tests/passes/cell-share/cond-port.expect index b4ef48d46..f297d97cc 100644 --- a/tests/passes/cell-share/cond-port.expect +++ b/tests/passes/cell-share/cond-port.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { gt0 = std_gt(32); diff --git a/tests/passes/cell-share/cond-port.futil b/tests/passes/cell-share/cond-port.futil index 4060c6f1e..3aab63b6b 100644 --- a/tests/passes/cell-share/cond-port.futil +++ b/tests/passes/cell-share/cond-port.futil @@ -1,5 +1,6 @@ // -p simplify-with-control -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { gt0 = std_gt(32); diff --git a/tests/passes/cell-share/condition-register.expect b/tests/passes/cell-share/condition-register.expect index b55f41ed1..61590b205 100644 --- a/tests/passes/cell-share/condition-register.expect +++ b/tests/passes/cell-share/condition-register.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { x = std_reg(1); diff --git a/tests/passes/cell-share/condition-register.futil b/tests/passes/cell-share/condition-register.futil index 611658cad..68fd8b1ae 100644 --- a/tests/passes/cell-share/condition-register.futil +++ b/tests/passes/cell-share/condition-register.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { x = std_reg(1); diff --git a/tests/passes/cell-share/continuous-assign-no-groups.expect b/tests/passes/cell-share/continuous-assign-no-groups.expect index 9b6b992f9..9240e1de3 100644 --- a/tests/passes/cell-share/continuous-assign-no-groups.expect +++ b/tests/passes/cell-share/continuous-assign-no-groups.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/continuous-assign-no-groups.futil b/tests/passes/cell-share/continuous-assign-no-groups.futil index 641025f8c..1bfea5a21 100644 --- a/tests/passes/cell-share/continuous-assign-no-groups.futil +++ b/tests/passes/cell-share/continuous-assign-no-groups.futil @@ -1,5 +1,6 @@ // -p validate -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/continuous-assignment.expect b/tests/passes/cell-share/continuous-assignment.expect index 81bd77ee4..a214bf2ef 100644 --- a/tests/passes/cell-share/continuous-assignment.expect +++ b/tests/passes/cell-share/continuous-assignment.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { cells { x_0 = std_reg(32); diff --git a/tests/passes/cell-share/continuous-assignment.futil b/tests/passes/cell-share/continuous-assignment.futil index 276d2cd48..3ad5dadea 100644 --- a/tests/passes/cell-share/continuous-assignment.futil +++ b/tests/passes/cell-share/continuous-assignment.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (x_out: 32) { cells { x_0 = std_reg(32); diff --git a/tests/passes/cell-share/empty-invoke.expect b/tests/passes/cell-share/empty-invoke.expect index 44dde2c37..1b1ddbe98 100644 --- a/tests/passes/cell-share/empty-invoke.expect +++ b/tests/passes/cell-share/empty-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component write_one<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { @data x = std_reg(32); @@ -17,7 +18,7 @@ component write_one<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external @data mem = std_mem_d1(32, 2, 1); + @external @data mem = comb_mem_d1(32, 2, 1); @data x = write_one(); } wires { diff --git a/tests/passes/cell-share/empty-invoke.futil b/tests/passes/cell-share/empty-invoke.futil index 604f39407..9a4ab3792 100644 --- a/tests/passes/cell-share/empty-invoke.futil +++ b/tests/passes/cell-share/empty-invoke.futil @@ -1,5 +1,6 @@ // -p pre-opt -p post-opt import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component write_one() -> (out: 32) { cells { @@ -15,7 +16,7 @@ component write_one() -> (out: 32) { component main() -> () { cells { - @external mem = std_mem_d1(32, 2, 1); + @external mem = comb_mem_d1(32, 2, 1); // these should be shared x = write_one(); y = write_one(); diff --git a/tests/passes/cell-share/escape-boundary.expect b/tests/passes/cell-share/escape-boundary.expect index 3b044d588..2e1c991eb 100644 --- a/tests/passes/cell-share/escape-boundary.expect +++ b/tests/passes/cell-share/escape-boundary.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done done: 1) { cells { x_0 = std_reg(32); diff --git a/tests/passes/cell-share/escape-boundary.futil b/tests/passes/cell-share/escape-boundary.futil index dc9cd6b63..c4d7a96b5 100644 --- a/tests/passes/cell-share/escape-boundary.futil +++ b/tests/passes/cell-share/escape-boundary.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (x_out: 32) { cells { x_0 = std_reg(32); diff --git a/tests/passes/cell-share/ignore_done.expect b/tests/passes/cell-share/ignore_done.expect index a0e409a4b..b6cda1d63 100644 --- a/tests/passes/cell-share/ignore_done.expect +++ b/tests/passes/cell-share/ignore_done.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/cell-share/ignore_done.futil b/tests/passes/cell-share/ignore_done.futil index e05a9d0ec..5b7779fba 100644 --- a/tests/passes/cell-share/ignore_done.futil +++ b/tests/passes/cell-share/ignore_done.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect index b991d54e2..df8211ba2 100644 --- a/tests/passes/cell-share/inline.expect +++ b/tests/passes/cell-share/inline.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: 32, @done done: 1) { cells { @data r = std_reg(32); @@ -17,7 +18,7 @@ component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset r } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external @data mem = std_mem_d1(32, 2, 1); + @external @data mem = comb_mem_d1(32, 2, 1); @generated r = std_reg(32); } wires { diff --git a/tests/passes/cell-share/inline.futil b/tests/passes/cell-share/inline.futil index f3ce49193..910c3111e 100644 --- a/tests/passes/cell-share/inline.futil +++ b/tests/passes/cell-share/inline.futil @@ -1,5 +1,6 @@ // -p pre-opt -p post-opt import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component my_reg<"state_share"=1>(@data in: 32) -> (@stable out: 32) { cells { @@ -15,7 +16,7 @@ component my_reg<"state_share"=1>(@data in: 32) -> (@stable out: 32) { component main() -> () { cells { - @external mem = std_mem_d1(32, 2, 1); + @external mem = comb_mem_d1(32, 2, 1); // the two `std_reg` created after inlining should be shared @inline r0 = my_reg(); @inline r1 = my_reg(); diff --git a/tests/passes/cell-share/invoke.expect b/tests/passes/cell-share/invoke.expect index 38b525221..4bbcaa902 100644 --- a/tests/passes/cell-share/invoke.expect +++ b/tests/passes/cell-share/invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { adder = std_add(32); diff --git a/tests/passes/cell-share/invoke.futil b/tests/passes/cell-share/invoke.futil index bfe63ddb7..f97c9caa4 100644 --- a/tests/passes/cell-share/invoke.futil +++ b/tests/passes/cell-share/invoke.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32) -> (out: 32) { cells { diff --git a/tests/passes/cell-share/live-register-analysis.expect b/tests/passes/cell-share/live-register-analysis.expect index b0d10593d..083051529 100644 --- a/tests/passes/cell-share/live-register-analysis.expect +++ b/tests/passes/cell-share/live-register-analysis.expect @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external A0 = std_mem_d1(32, 32, 6); + @external A0 = comb_mem_d1(32, 32, 6); A_read0_0 = std_reg(32); - @external B0 = std_mem_d1(32, 32, 6); + @external B0 = comb_mem_d1(32, 32, 6); B_read0_0 = std_reg(32); - @external C0 = std_mem_d1(32, 32, 6); + @external C0 = comb_mem_d1(32, 32, 6); add0 = std_add(6); i0 = std_reg(6); le0 = std_le(6); diff --git a/tests/passes/cell-share/live-register-analysis.futil b/tests/passes/cell-share/live-register-analysis.futil index 2d79dd21a..2b00c1ca0 100644 --- a/tests/passes/cell-share/live-register-analysis.futil +++ b/tests/passes/cell-share/live-register-analysis.futil @@ -1,12 +1,13 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,32,6); + @external(1) A0 = comb_mem_d1(32,32,6); A_read0_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,32,6); + @external(1) B0 = comb_mem_d1(32,32,6); B_read0_0 = std_reg(32); - @external(1) C0 = std_mem_d1(32,32,6); + @external(1) C0 = comb_mem_d1(32,32,6); C_read0_0 = std_reg(32); add0 = std_add(6); add1 = std_add(6); diff --git a/tests/passes/cell-share/multiple-adders.expect b/tests/passes/cell-share/multiple-adders.expect index b62415eba..877d540e0 100644 --- a/tests/passes/cell-share/multiple-adders.expect +++ b/tests/passes/cell-share/multiple-adders.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add0 = std_add(32); diff --git a/tests/passes/cell-share/multiple-adders.futil b/tests/passes/cell-share/multiple-adders.futil index b7ad21928..898896e7d 100644 --- a/tests/passes/cell-share/multiple-adders.futil +++ b/tests/passes/cell-share/multiple-adders.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add0 = std_add(32); diff --git a/tests/passes/cell-share/nested-par.expect b/tests/passes/cell-share/nested-par.expect index f9c323be7..b5a99ac05 100644 --- a/tests/passes/cell-share/nested-par.expect +++ b/tests/passes/cell-share/nested-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { b0 = std_reg(32); diff --git a/tests/passes/cell-share/nested-par.futil b/tests/passes/cell-share/nested-par.futil index 173637067..6077ffba3 100644 --- a/tests/passes/cell-share/nested-par.futil +++ b/tests/passes/cell-share/nested-par.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { b0 = std_reg(32); diff --git a/tests/passes/cell-share/par-if-while.expect b/tests/passes/cell-share/par-if-while.expect index b331a1eef..29d86e1c6 100644 --- a/tests/passes/cell-share/par-if-while.expect +++ b/tests/passes/cell-share/par-if-while.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/par-if-while.futil b/tests/passes/cell-share/par-if-while.futil index 9acd5cc49..9674b6bbd 100644 --- a/tests/passes/cell-share/par-if-while.futil +++ b/tests/passes/cell-share/par-if-while.futil @@ -1,7 +1,8 @@ // -p cell-share -p dead-cell-removal -p remove-ids -// should not share registers b/c we don't know if either of the writes will -// actually happen +// should not share registers b/c we don't know if either of the writes will +// actually happen import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { @@ -13,55 +14,55 @@ component main() -> () { wires { group write_r3{ - r3.write_en = 1'd1; - r3.in = 32'd2; - write_r3[done] = r3.done; + r3.write_en = 1'd1; + r3.in = 32'd2; + write_r3[done] = r3.done; } group write_r2{ - r2.write_en = 1'd1; - r2.in = 32'd2; + r2.write_en = 1'd1; + r2.in = 32'd2; write_r2[done] = r2.done; } group read_r3{ - mult.go = 1'd1; - mult.left = r3.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r3.out; + mult.right = 32'd2; read_r3[done] = mult.done; } comb group cg{ - lt.left = 32'd2; - lt.right = 32'd4; + lt.left = 32'd2; + lt.right = 32'd4; } group no_read{ - mult.go = 1'd1; - mult.left = 32'd2; - mult.right = 32'd2; - no_read[done] = mult.done; + mult.go = 1'd1; + mult.left = 32'd2; + mult.right = 32'd2; + no_read[done] = mult.done; } group no_read2{ - mult.go = 1'd1; - mult.left = 32'd2; - mult.right = 32'd2; - no_read[done] = mult.done; + mult.go = 1'd1; + mult.left = 32'd2; + mult.right = 32'd2; + no_read[done] = mult.done; } } control { seq { - write_r2; + write_r2; par{ - no_read; + no_read; seq{ no_read2; if lt.out with cg{ - write_r3; + write_r3; } while lt.out with cg{ write_r3; } - } + } } - read_r3; + read_r3; } } } diff --git a/tests/passes/cell-share/par-if.expect b/tests/passes/cell-share/par-if.expect index 441295db7..91c6067bc 100644 --- a/tests/passes/cell-share/par-if.expect +++ b/tests/passes/cell-share/par-if.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add0 = std_add(32); diff --git a/tests/passes/cell-share/par-if.futil b/tests/passes/cell-share/par-if.futil index 0fcb79bd5..d3daeaf05 100644 --- a/tests/passes/cell-share/par-if.futil +++ b/tests/passes/cell-share/par-if.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add0 = std_add(32); @@ -12,25 +13,25 @@ component main() -> () { } wires { comb group cg1{ - add0.left = 32'd2; - add0.right = 32'd4; - add1.left = 32'd4; - add1.right = 32'd6; - lt1.left = add0.out; - lt1.left = add1.out; + add0.left = 32'd2; + add0.right = 32'd4; + add1.left = 32'd4; + add1.right = 32'd6; + lt1.left = add0.out; + lt1.left = add1.out; } comb group cg2{ - add2.left = 32'd2; - add2.right = 32'd4; - add3.left = 32'd4; - add3.right = 32'd6; - lt2.left = add2.out; - lt2.left = add3.out; + add2.left = 32'd2; + add2.right = 32'd4; + add3.left = 32'd4; + add3.right = 32'd6; + lt2.left = add2.out; + lt2.left = add3.out; } group A{ - r.write_en = 1'd1; - r.in = 32'd2; - A[done] = r.done; + r.write_en = 1'd1; + r.in = 32'd2; + A[done] = r.done; } } control { diff --git a/tests/passes/cell-share/par-invoke-adders.expect b/tests/passes/cell-share/par-invoke-adders.expect index e5efa45ce..1b8714f5b 100644 --- a/tests/passes/cell-share/par-invoke-adders.expect +++ b/tests/passes/cell-share/par-invoke-adders.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out1: 32, out2: 32, @done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/cell-share/par-invoke-adders.futil b/tests/passes/cell-share/par-invoke-adders.futil index a6aeb1911..db2d38b80 100644 --- a/tests/passes/cell-share/par-invoke-adders.futil +++ b/tests/passes/cell-share/par-invoke-adders.futil @@ -1,5 +1,6 @@ //-p well-formed -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32) -> (out1: 32, out2: 32) { cells { @@ -7,12 +8,12 @@ component dbg<"state_share"=1>(in: 32) -> (out1: 32, out2: 32) { } wires { group A { - r.write_en = 1'd1; + r.write_en = 1'd1; r.in = in; A[done] = r.done; } out1 = r.out; - out2 = r.out; + out2 = r.out; } control { diff --git a/tests/passes/cell-share/par-invoke.expect b/tests/passes/cell-share/par-invoke.expect index 71055147a..9ea0ced3a 100644 --- a/tests/passes/cell-share/par-invoke.expect +++ b/tests/passes/cell-share/par-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/cell-share/par-invoke.futil b/tests/passes/cell-share/par-invoke.futil index 81f91859a..217d06cef 100644 --- a/tests/passes/cell-share/par-invoke.futil +++ b/tests/passes/cell-share/par-invoke.futil @@ -1,5 +1,6 @@ //-p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5) -> (out: 32) { cells { @@ -7,7 +8,7 @@ component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5) -> (out: 32) { } wires { group A { - r.write_en = 1'd1; + r.write_en = 1'd1; r.in = in; A[done] = r.done; } diff --git a/tests/passes/cell-share/par-seq.expect b/tests/passes/cell-share/par-seq.expect index 27fefb1d1..da117f133 100644 --- a/tests/passes/cell-share/par-seq.expect +++ b/tests/passes/cell-share/par-seq.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/par-seq.futil b/tests/passes/cell-share/par-seq.futil index a8fdea14f..3974e4269 100644 --- a/tests/passes/cell-share/par-seq.futil +++ b/tests/passes/cell-share/par-seq.futil @@ -1,6 +1,7 @@ // -p cell-share -p dead-cell-removal -p remove-ids -// should share registers +// should share registers import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { @@ -11,41 +12,41 @@ component main() -> () { wires { group write_r3{ - r3.write_en = 1'd1; - r3.in = 32'd2; - write_r3[done] = r3.done; + r3.write_en = 1'd1; + r3.in = 32'd2; + write_r3[done] = r3.done; } group read_r3{ - mult.go = 1'd1; - mult.left = r3.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r3.out; + mult.right = 32'd2; read_r3[done] = mult.done; } group no_read{ - mult.go = 1'd1; - mult.left = 32'd2; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = 32'd2; + mult.right = 32'd2; read_r3[done] = mult.done; } group read_r3_another{ - mult.go = 1'd1; - mult.left = r3.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r3.out; + mult.right = 32'd2; read_r3_another[done] = mult.done; } group read_r2{ - mult.go = 1'd1; - mult.left = r2.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r2.out; + mult.right = 32'd2; read_r2[done] = mult.done; } } control { seq { - read_r2; + read_r2; par{ - no_read; + no_read; seq{ write_r3; read_r3;} } } diff --git a/tests/passes/cell-share/par-seq2.expect b/tests/passes/cell-share/par-seq2.expect index c20f270b9..587b87712 100644 --- a/tests/passes/cell-share/par-seq2.expect +++ b/tests/passes/cell-share/par-seq2.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/cell-share/par-seq2.futil b/tests/passes/cell-share/par-seq2.futil index edacff3bc..c285c5056 100644 --- a/tests/passes/cell-share/par-seq2.futil +++ b/tests/passes/cell-share/par-seq2.futil @@ -1,6 +1,7 @@ // -p cell-share -p dead-cell-removal -p remove-ids // should not share registers because of "read_r3_another" import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { @@ -11,41 +12,41 @@ component main() -> () { wires { group write_r3{ - r3.write_en = 1'd1; - r3.in = 32'd2; - write_r3[done] = r3.done; + r3.write_en = 1'd1; + r3.in = 32'd2; + write_r3[done] = r3.done; } group read_r3{ - mult.go = 1'd1; - mult.left = r3.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r3.out; + mult.right = 32'd2; read_r3[done] = mult.done; } group no_read{ - mult.go = 1'd1; - mult.left = 32'd2; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = 32'd2; + mult.right = 32'd2; read_r3[done] = mult.done; } group read_r3_another{ - mult.go = 1'd1; - mult.left = r3.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r3.out; + mult.right = 32'd2; read_r3_another[done] = mult.done; } group read_r2{ - mult.go = 1'd1; - mult.left = r2.out; - mult.right = 32'd2; + mult.go = 1'd1; + mult.left = r2.out; + mult.right = 32'd2; read_r2[done] = mult.done; } } control { seq { - read_r2; + read_r2; par{ - read_r3_another; + read_r3_another; seq{ write_r3; read_r3;} } } diff --git a/tests/passes/cell-share/par-while-liveness.expect b/tests/passes/cell-share/par-while-liveness.expect index 7e892de2e..092a2364c 100644 --- a/tests/passes/cell-share/par-while-liveness.expect +++ b/tests/passes/cell-share/par-while-liveness.expect @@ -1,16 +1,17 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external a_src0 = std_mem_d1(32, 8, 4); + @external a_src0 = comb_mem_d1(32, 8, 4); a_src_read0_0 = std_reg(32); - @external a_tar0 = std_mem_d1(32, 8, 4); + @external a_tar0 = comb_mem_d1(32, 8, 4); add0 = std_add(4); add1 = std_add(4); - @external b_src0 = std_mem_d1(32, 8, 4); + @external b_src0 = comb_mem_d1(32, 8, 4); b_src_read0_0 = std_reg(32); - @external b_tar0 = std_mem_d1(32, 8, 4); - @external c_src0 = std_mem_d1(32, 8, 4); - @external c_tar0 = std_mem_d1(32, 8, 4); + @external b_tar0 = comb_mem_d1(32, 8, 4); + @external c_src0 = comb_mem_d1(32, 8, 4); + @external c_tar0 = comb_mem_d1(32, 8, 4); const0 = std_const(4, 0); const1 = std_const(4, 7); const2 = std_const(4, 1); diff --git a/tests/passes/cell-share/par-while-liveness.futil b/tests/passes/cell-share/par-while-liveness.futil index 3df6e9cc8..3c8091be8 100644 --- a/tests/passes/cell-share/par-while-liveness.futil +++ b/tests/passes/cell-share/par-while-liveness.futil @@ -1,18 +1,19 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) a_src0 = std_mem_d1(32,8,4); + @external(1) a_src0 = comb_mem_d1(32,8,4); a_src_read0_0 = std_reg(32); - @external(1) a_tar0 = std_mem_d1(32,8,4); + @external(1) a_tar0 = comb_mem_d1(32,8,4); add0 = std_add(4); add1 = std_add(4); add2 = std_add(4); - @external(1) b_src0 = std_mem_d1(32,8,4); + @external(1) b_src0 = comb_mem_d1(32,8,4); b_src_read0_0 = std_reg(32); - @external(1) b_tar0 = std_mem_d1(32,8,4); - @external(1) c_src0 = std_mem_d1(32,8,4); - @external(1) c_tar0 = std_mem_d1(32,8,4); + @external(1) b_tar0 = comb_mem_d1(32,8,4); + @external(1) c_src0 = comb_mem_d1(32,8,4); + @external(1) c_tar0 = comb_mem_d1(32,8,4); c_tar_read0_0 = std_reg(32); const0 = std_const(4,0); const1 = std_const(4,7); diff --git a/tests/passes/cell-share/par-write.expect b/tests/passes/cell-share/par-write.expect index 5a6193d86..8eef4d364 100644 --- a/tests/passes/cell-share/par-write.expect +++ b/tests/passes/cell-share/par-write.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { x = std_reg(32); diff --git a/tests/passes/cell-share/par-write.futil b/tests/passes/cell-share/par-write.futil index 10e28cd3e..194b851a3 100644 --- a/tests/passes/cell-share/par-write.futil +++ b/tests/passes/cell-share/par-write.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/cell-share/repeat.expect b/tests/passes/cell-share/repeat.expect index 3b020e00b..e063b23e6 100644 --- a/tests/passes/cell-share/repeat.expect +++ b/tests/passes/cell-share/repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/cell-share/repeat.futil b/tests/passes/cell-share/repeat.futil index e29268f3f..a14a251f3 100644 --- a/tests/passes/cell-share/repeat.futil +++ b/tests/passes/cell-share/repeat.futil @@ -1,12 +1,13 @@ // -p simplify-with-control -p cell-share -p remove-ids -// shouldn't share in this case +// shouldn't share in this case import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - r1 = std_reg(32); + r1 = std_reg(32); r2 = std_reg(32); - x = std_reg(1); + x = std_reg(1); lt = std_lt(32); } wires { @@ -21,27 +22,27 @@ component main() -> () { wr_r2[done] = r2.done; } group read_r1 { - lt.left = r1.out; - lt.right = 32'd2; - x.in = lt.out; - x.write_en = 1'd1; - read_r1[done] = x.done; + lt.left = r1.out; + lt.right = 32'd2; + x.in = lt.out; + x.write_en = 1'd1; + read_r1[done] = x.done; } group read_r2 { - lt.left = r2.out; - lt.right = 32'd2; - x.in = lt.out; - x.write_en = 1'd1; - read_r2[done] = x.done; + lt.left = r2.out; + lt.right = 32'd2; + x.in = lt.out; + x.write_en = 1'd1; + read_r2[done] = x.done; } } control { seq { - wr_r1; + wr_r1; repeat 3 { - read_r1; - wr_r2; - read_r2; + read_r1; + wr_r2; + read_r2; } } } diff --git a/tests/passes/cell-share/seq-invoke.expect b/tests/passes/cell-share/seq-invoke.expect index b6a443810..bae0629c1 100644 --- a/tests/passes/cell-share/seq-invoke.expect +++ b/tests/passes/cell-share/seq-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/cell-share/seq-invoke.futil b/tests/passes/cell-share/seq-invoke.futil index 0b888db37..2e2cb1325 100644 --- a/tests/passes/cell-share/seq-invoke.futil +++ b/tests/passes/cell-share/seq-invoke.futil @@ -1,5 +1,6 @@ //-p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5) -> (out: 32) { cells { @@ -7,7 +8,7 @@ component dbg<"state_share"=1>(in: 32, prefix: 32, length: 5) -> (out: 32) { } wires { group A { - r.write_en = 1'd1; + r.write_en = 1'd1; r.in = in; A[done] = r.done; } diff --git a/tests/passes/cell-share/share-adders.expect b/tests/passes/cell-share/share-adders.expect index c79eae4ec..84c5c86d6 100644 --- a/tests/passes/cell-share/share-adders.expect +++ b/tests/passes/cell-share/share-adders.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add0 = std_add(32); diff --git a/tests/passes/cell-share/share-adders.futil b/tests/passes/cell-share/share-adders.futil index dbc9a56db..400938794 100644 --- a/tests/passes/cell-share/share-adders.futil +++ b/tests/passes/cell-share/share-adders.futil @@ -1,6 +1,7 @@ //-p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { add0 = std_add(32); diff --git a/tests/passes/cell-share/share-comp.expect b/tests/passes/cell-share/share-comp.expect index b83ecc0da..8be17dc7e 100644 --- a/tests/passes/cell-share/share-comp.expect +++ b/tests/passes/cell-share/share-comp.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add_5<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { add = std_add(32); diff --git a/tests/passes/cell-share/share-comp.futil b/tests/passes/cell-share/share-comp.futil index a3c88bdf3..a3268028f 100644 --- a/tests/passes/cell-share/share-comp.futil +++ b/tests/passes/cell-share/share-comp.futil @@ -1,6 +1,7 @@ //-p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add_5<"state_share"=1>(in:32) -> (out: 32) { cells { add = std_add(32); @@ -8,16 +9,16 @@ component add_5<"state_share"=1>(in:32) -> (out: 32) { } wires { group add_group{ - add.left = 32'd5; - add.right = in; - r.write_en = 1'd1; - r.in = add.out; + add.left = 32'd5; + add.right = in; + r.write_en = 1'd1; + r.in = add.out; add_group[done] = r.done; } - out = r.out; + out = r.out; } control { - add_group; + add_group; } } @@ -29,12 +30,12 @@ component main() -> () { } wires { group upd0 { - add0.go = 1'd1; + add0.go = 1'd1; add0.in = 32'd5; upd0[done] = add0.done; } group upd1 { - add1.go = 1'd1; + add1.go = 1'd1; add1.in = 32'd8; upd1[done] = add1.done; } diff --git a/tests/passes/cell-share/share-mult.expect b/tests/passes/cell-share/share-mult.expect index 91dae2166..b22aca167 100644 --- a/tests/passes/cell-share/share-mult.expect +++ b/tests/passes/cell-share/share-mult.expect @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external A0 = std_mem_d1(32, 2, 2); + @external A0 = comb_mem_d1(32, 2, 2); A_read0_0 = std_reg(32); A_read1_0 = std_reg(32); - @external B0 = std_mem_d1(32, 2, 2); + @external B0 = comb_mem_d1(32, 2, 2); B_read0_0 = std_reg(32); B_read1_0 = std_reg(32); bin_read0_0 = std_reg(32); diff --git a/tests/passes/cell-share/share-mult.futil b/tests/passes/cell-share/share-mult.futil index 502d77991..9ff15b0f6 100644 --- a/tests/passes/cell-share/share-mult.futil +++ b/tests/passes/cell-share/share-mult.futil @@ -1,14 +1,15 @@ //-p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,2,2); + @external(1) A0 = comb_mem_d1(32,2,2); A_read0_0 = std_reg(32); A_read1_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,2,2); + @external(1) B0 = comb_mem_d1(32,2,2); B_read0_0 = std_reg(32); B_read1_0 = std_reg(32); bin_read0_0 = std_reg(32); @@ -27,7 +28,7 @@ component main() -> () { mult_pipe0.left = A_read0_0.out; mult_pipe0.right = B_read0_0.out; mult_pipe0.go = 1'd1; - prelet0[done] = mult_pipe0.done; + prelet0[done] = mult_pipe0.done; } group let0{ bin_read0_0.in = mult_pipe0.out; @@ -43,7 +44,7 @@ component main() -> () { mult_pipe1.left = A_read1_0.out; mult_pipe1.right = B_read1_0.out; mult_pipe1.go = 1'd1; - prelet2[done] = mult_pipe1.done; + prelet2[done] = mult_pipe1.done; } group let2{ bin_read1_0.in = mult_pipe1.out; diff --git a/tests/passes/cell-share/simple-liveness.expect b/tests/passes/cell-share/simple-liveness.expect index 60d90bc8f..161633f02 100644 --- a/tests/passes/cell-share/simple-liveness.expect +++ b/tests/passes/cell-share/simple-liveness.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { b = std_reg(32); diff --git a/tests/passes/cell-share/simple-liveness.futil b/tests/passes/cell-share/simple-liveness.futil index 1b813f1a5..7c7862127 100644 --- a/tests/passes/cell-share/simple-liveness.futil +++ b/tests/passes/cell-share/simple-liveness.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { b = std_reg(32); diff --git a/tests/passes/cell-share/static-par.expect b/tests/passes/cell-share/static-par.expect index 05d751389..72cfc3e57 100644 --- a/tests/passes/cell-share/static-par.expect +++ b/tests/passes/cell-share/static-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/cell-share/static-par.futil b/tests/passes/cell-share/static-par.futil index aa38fdf43..c188a3ac0 100644 --- a/tests/passes/cell-share/static-par.futil +++ b/tests/passes/cell-share/static-par.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { lt = std_lt(32); diff --git a/tests/passes/cell-share/thread-local.expect b/tests/passes/cell-share/thread-local.expect index 45858b221..cffddea2d 100644 --- a/tests/passes/cell-share/thread-local.expect +++ b/tests/passes/cell-share/thread-local.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { x = std_reg(32); diff --git a/tests/passes/cell-share/thread-local.futil b/tests/passes/cell-share/thread-local.futil index 7cf758d6a..fa7e6e878 100644 --- a/tests/passes/cell-share/thread-local.futil +++ b/tests/passes/cell-share/thread-local.futil @@ -1,5 +1,6 @@ // -p well-formed -p simplify-with-control -p cell-share -p dead-cell-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/cell-share/while-no-share.expect b/tests/passes/cell-share/while-no-share.expect index df857fd80..11f5fca16 100644 --- a/tests/passes/cell-share/while-no-share.expect +++ b/tests/passes/cell-share/while-no-share.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/cell-share/while-no-share.futil b/tests/passes/cell-share/while-no-share.futil index 2e878a5aa..f1b2da5e3 100644 --- a/tests/passes/cell-share/while-no-share.futil +++ b/tests/passes/cell-share/while-no-share.futil @@ -1,5 +1,6 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; // testing that r1 and r2 don't get shared. component main() -> () { @@ -11,28 +12,28 @@ component main() -> () { wires { group wr_r1{ r1.write_en = 1'd1; - r1.in = 32'd0; - wr_r1[done] = r1.done; + r1.in = 32'd0; + wr_r1[done] = r1.done; } group rd_r1{ - x.write_en = 1'd1; - x.in = r1.out; + x.write_en = 1'd1; + x.in = r1.out; rd_r1[done] = x.done; } group wr_r2{ r2.write_en = 1'd1; - r2.in = 32'd7; - wr_r2[done] = r2.done; + r2.in = 32'd7; + wr_r2[done] = r2.done; } group rd_r2{ - x.write_en = 1'd1; - x.in = r2.out; - rd_r2[done] = x.done; + x.write_en = 1'd1; + x.in = r2.out; + rd_r2[done] = x.done; } } control { seq { - wr_r1; + wr_r1; while x.out { seq{ rd_r1; diff --git a/tests/passes/cell-share/while-write-guard.expect b/tests/passes/cell-share/while-write-guard.expect index d15018a28..c195e1f98 100644 --- a/tests/passes/cell-share/while-write-guard.expect +++ b/tests/passes/cell-share/while-write-guard.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/cell-share/while-write-guard.futil b/tests/passes/cell-share/while-write-guard.futil index 279703019..4f3466a1d 100644 --- a/tests/passes/cell-share/while-write-guard.futil +++ b/tests/passes/cell-share/while-write-guard.futil @@ -1,8 +1,9 @@ // -p cell-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; // testing that r1 and r2 don't get shared. Previous versions of LiveRangeAnalysis -// killed the value in r1 in the while loop. +// killed the value in r1 in the while loop. component main() -> () { cells { r1 = std_reg(32); @@ -12,27 +13,27 @@ component main() -> () { wires { group wr_r1{ r1.write_en = 1'd1; - r1.in = 32'd0; - wr_r1[done] = r1.done; + r1.in = 32'd0; + wr_r1[done] = r1.done; } group wr_r2{ r2.write_en = 1'd1; - r2.in = 32'd7; - wr_r2[done] = r2.done; + r2.in = 32'd7; + wr_r2[done] = r2.done; } group rd_r2{ - x.write_en = 1'd1; - x.in = r2.out; - rd_r2[done] = x.done; + x.write_en = 1'd1; + x.in = r2.out; + rd_r2[done] = x.done; } } control { seq { - wr_r1; + wr_r1; wr_r2; - rd_r2; + rd_r2; while r1.out { - wr_r1; + wr_r1; } } } diff --git a/tests/passes/clk-insertion.expect b/tests/passes/clk-insertion.expect index 1bfaf0d00..8808409bd 100644 --- a/tests/passes/clk-insertion.expect +++ b/tests/passes/clk-insertion.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; comb component layout_hw0() -> (flat_port_addr0: 4) { cells { add_0 = std_add(4); diff --git a/tests/passes/clk-insertion.futil b/tests/passes/clk-insertion.futil index ac7131248..3ab37fd8c 100644 --- a/tests/passes/clk-insertion.futil +++ b/tests/passes/clk-insertion.futil @@ -1,5 +1,6 @@ // -p well-formed -p clk-insertion import "primitives/core.futil"; +import "primitives/memories/comb.futil"; comb component layout_hw0() -> (flat_port_addr0: 4) { cells { add_0 = std_add(4); diff --git a/tests/passes/comb-prop/comb-prop.expect b/tests/passes/comb-prop/comb-prop.expect index ee385f80b..c1bad09ed 100644 --- a/tests/passes/comb-prop/comb-prop.expect +++ b/tests/passes/comb-prop/comb-prop.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(a: 4, b: 4, c: 1, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { w1 = std_wire(4); diff --git a/tests/passes/comb-prop/comb-prop.futil b/tests/passes/comb-prop/comb-prop.futil index 0529112cd..cc646e770 100644 --- a/tests/passes/comb-prop/comb-prop.futil +++ b/tests/passes/comb-prop/comb-prop.futil @@ -1,5 +1,6 @@ // -p validate -p comb-prop import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(a: 4, b: 4, c: 1) -> () { cells { w1 = std_wire(4); @@ -21,9 +22,9 @@ component main(a: 4, b: 4, c: 1) -> () { lt.right = r.out; } comb group cond1 { - // w4 should be replaced by c - lt1.left = w4.out; - lt1.right = 1'd1; + // w4 should be replaced by c + lt1.left = w4.out; + lt1.right = 1'd1; } w1.in = a; diff --git a/tests/passes/comb-prop/inline-write.expect b/tests/passes/comb-prop/inline-write.expect index de7aac917..a815d9be4 100644 --- a/tests/passes/comb-prop/inline-write.expect +++ b/tests/passes/comb-prop/inline-write.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { w1 = std_wire(32); diff --git a/tests/passes/comb-prop/inline-write.futil b/tests/passes/comb-prop/inline-write.futil index 9f7acd998..0c43743b4 100644 --- a/tests/passes/comb-prop/inline-write.futil +++ b/tests/passes/comb-prop/inline-write.futil @@ -1,5 +1,6 @@ // -p well-formed -p comb-prop import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { w1 = std_wire(32); diff --git a/tests/passes/comb-prop/multiple-reads-from-write.expect b/tests/passes/comb-prop/multiple-reads-from-write.expect index 74e598fce..7808fb89f 100644 --- a/tests/passes/comb-prop/multiple-reads-from-write.expect +++ b/tests/passes/comb-prop/multiple-reads-from-write.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { w1 = std_wire(32); diff --git a/tests/passes/comb-prop/multiple-reads-from-write.futil b/tests/passes/comb-prop/multiple-reads-from-write.futil index 2b18b0da1..8d578b168 100644 --- a/tests/passes/comb-prop/multiple-reads-from-write.futil +++ b/tests/passes/comb-prop/multiple-reads-from-write.futil @@ -1,5 +1,6 @@ // -p well-formed -p comb-prop import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { w1 = std_wire(32); diff --git a/tests/passes/comb-prop/visible-write.expect b/tests/passes/comb-prop/visible-write.expect index 088a13803..3dc5afe6b 100644 --- a/tests/passes/comb-prop/visible-write.expect +++ b/tests/passes/comb-prop/visible-write.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { wire1 = std_wire(32); diff --git a/tests/passes/comb-prop/visible-write.futil b/tests/passes/comb-prop/visible-write.futil index 4e132e7e6..0380f28dd 100644 --- a/tests/passes/comb-prop/visible-write.futil +++ b/tests/passes/comb-prop/visible-write.futil @@ -1,5 +1,6 @@ // -p validate -p comb-prop import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32) -> (out: 32) { cells { wire1 = std_wire(32); diff --git a/tests/passes/compile-empty.expect b/tests/passes/compile-empty.expect index ad8b766ae..1591cf539 100644 --- a/tests/passes/compile-empty.expect +++ b/tests/passes/compile-empty.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(1); diff --git a/tests/passes/compile-empty.futil b/tests/passes/compile-empty.futil index 7867f0565..81acd3d70 100644 --- a/tests/passes/compile-empty.futil +++ b/tests/passes/compile-empty.futil @@ -1,5 +1,6 @@ // -p compile-empty import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/compile-invoke/compile-invoke.expect b/tests/passes/compile-invoke/compile-invoke.expect index c7b74e24d..0d521e273 100644 --- a/tests/passes/compile-invoke/compile-invoke.expect +++ b/tests/passes/compile-invoke/compile-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component exponent(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { pow = std_reg(32); diff --git a/tests/passes/compile-invoke/compile-invoke.futil b/tests/passes/compile-invoke/compile-invoke.futil index 052683356..d7ac4ca2d 100644 --- a/tests/passes/compile-invoke/compile-invoke.futil +++ b/tests/passes/compile-invoke/compile-invoke.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component exponent(base: 32, exp: 4) -> (out: 32) { cells { pow = std_reg(32); } diff --git a/tests/passes/compile-invoke/compile-static-invoke.expect b/tests/passes/compile-invoke/compile-static-invoke.expect index 91fb7a0e1..a9a93a2b7 100644 --- a/tests/passes/compile-invoke/compile-static-invoke.expect +++ b/tests/passes/compile-invoke/compile-static-invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<4> component exponent(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { pow = std_reg(32); diff --git a/tests/passes/compile-invoke/compile-static-invoke.futil b/tests/passes/compile-invoke/compile-static-invoke.futil index 2b58bfa49..9582f46bf 100644 --- a/tests/passes/compile-invoke/compile-static-invoke.futil +++ b/tests/passes/compile-invoke/compile-static-invoke.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<4> component exponent(base: 32, exp: 4) -> (out: 32) { cells { pow = std_reg(32); } diff --git a/tests/passes/compile-invoke/static-ref.expect b/tests/passes/compile-invoke/static-ref.expect index d6547a511..396100802 100644 --- a/tests/passes/compile-invoke/static-ref.expect +++ b/tests/passes/compile-invoke/static-ref.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<2> component add_one(@go go: 1, @clk clk: 1, @reset reset: 1, out_read_data: 32, out_done: 1) -> (@done done: 1, out_addr0: 1, out_write_data: 32, out_write_en: 1) { cells { add = std_add(32); @@ -27,7 +28,7 @@ static<2> component add_one(@go go: 1, @clk clk: 1, @reset reset: 1, out_read_da component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { adder = add_one(); - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); add = std_add(32); r = std_reg(32); } diff --git a/tests/passes/compile-invoke/static-ref.futil b/tests/passes/compile-invoke/static-ref.futil index e81531852..a2979b36b 100644 --- a/tests/passes/compile-invoke/static-ref.futil +++ b/tests/passes/compile-invoke/static-ref.futil @@ -1,11 +1,12 @@ // -p well-formed -p compile-invoke import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<2> component add_one() -> () { cells { add = std_add(32); r = std_reg(32); - ref out = std_mem_d1(32, 1, 1); + ref out = comb_mem_d1(32, 1, 1); } wires { @@ -33,7 +34,7 @@ static<2> component add_one() -> () { component main() -> () { cells { adder = add_one(); - @external mem = std_mem_d1(32, 1, 1); + @external mem = comb_mem_d1(32, 1, 1); add = std_add(32); r = std_reg(32); } diff --git a/tests/passes/compile-repeat/nested.expect b/tests/passes/compile-repeat/nested.expect index fbc82c45a..6ccc5309a 100644 --- a/tests/passes/compile-repeat/nested.expect +++ b/tests/passes/compile-repeat/nested.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/compile-repeat/nested.futil b/tests/passes/compile-repeat/nested.futil index 0c24f7f78..60420b824 100644 --- a/tests/passes/compile-repeat/nested.futil +++ b/tests/passes/compile-repeat/nested.futil @@ -1,5 +1,6 @@ // -p compile-repeat import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -7,15 +8,15 @@ component main() -> () { } wires { group write_r1 { - r1.in = 32'd2; - r1.write_en = 1'd1; - write_r1[done] = r1.done; + r1.in = 32'd2; + r1.write_en = 1'd1; + write_r1[done] = r1.done; } } control { repeat 4 { repeat 2 { - write_r1; + write_r1; } } } diff --git a/tests/passes/compile-repeat/simple.expect b/tests/passes/compile-repeat/simple.expect index feba5eaef..c34f92c71 100644 --- a/tests/passes/compile-repeat/simple.expect +++ b/tests/passes/compile-repeat/simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/compile-repeat/simple.futil b/tests/passes/compile-repeat/simple.futil index e901a7253..3abc75b6f 100644 --- a/tests/passes/compile-repeat/simple.futil +++ b/tests/passes/compile-repeat/simple.futil @@ -1,5 +1,6 @@ // -p compile-repeat import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -8,33 +9,33 @@ component main() -> () { } wires { group write_r1 { - r1.in = 32'd2; - r1.write_en = 1'd1; - write_r1[done] = r1.done; + r1.in = 32'd2; + r1.write_en = 1'd1; + write_r1[done] = r1.done; } group write_r2 { - r2.in = 32'd2; - r2.write_en = 1'd1; - write_r2[done] = r2.done; + r2.in = 32'd2; + r2.write_en = 1'd1; + write_r2[done] = r2.done; } } control { repeat 4 { seq { write_r1; - write_r2; + write_r2; } } repeat 0 { seq { write_r1; - write_r2; + write_r2; } } repeat 1 { seq { write_r1; - write_r2; + write_r2; } } } diff --git a/tests/passes/compile-static-interface-one-cycle.expect b/tests/passes/compile-static-interface-one-cycle.expect index fec73d83a..1e5f4db95 100644 --- a/tests/passes/compile-static-interface-one-cycle.expect +++ b/tests/passes/compile-static-interface-one-cycle.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<1> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add = std_add(32); diff --git a/tests/passes/compile-static-interface-one-cycle.futil b/tests/passes/compile-static-interface-one-cycle.futil index d58915b95..f88fff692 100644 --- a/tests/passes/compile-static-interface-one-cycle.futil +++ b/tests/passes/compile-static-interface-one-cycle.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p static-inline -p add-guard -p compile-static-interface import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<1> component do_add(left: 32, right: 32) -> () { cells { diff --git a/tests/passes/compile-static-interface-repeat.expect b/tests/passes/compile-static-interface-repeat.expect index 718af6314..0fe8e6944 100644 --- a/tests/passes/compile-static-interface-repeat.expect +++ b/tests/passes/compile-static-interface-repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<6> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add = std_add(32); diff --git a/tests/passes/compile-static-interface-repeat.futil b/tests/passes/compile-static-interface-repeat.futil index f3e0f7da6..a6a0e8ba0 100644 --- a/tests/passes/compile-static-interface-repeat.futil +++ b/tests/passes/compile-static-interface-repeat.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<6> component do_add(left: 32, right: 32) -> () { cells { diff --git a/tests/passes/compile-static-interface.expect b/tests/passes/compile-static-interface.expect index 05f01bd8d..b80ce81c6 100644 --- a/tests/passes/compile-static-interface.expect +++ b/tests/passes/compile-static-interface.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<2> component do_add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add = std_add(32); diff --git a/tests/passes/compile-static-interface.futil b/tests/passes/compile-static-interface.futil index a9cf82aac..d3086d795 100644 --- a/tests/passes/compile-static-interface.futil +++ b/tests/passes/compile-static-interface.futil @@ -1,5 +1,6 @@ // -p validate -p compile-invoke -p static-inline -p add-guard -p simplify-static-guards -p compile-static-interface import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<2> component do_add(left: 32, right: 32) -> () { cells { diff --git a/tests/passes/compile-static/rewrite-group-go.expect b/tests/passes/compile-static/rewrite-group-go.expect index 5b44b35b5..2cf93b9b8 100644 --- a/tests/passes/compile-static/rewrite-group-go.expect +++ b/tests/passes/compile-static/rewrite-group-go.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/compile-static/rewrite-group-go.futil b/tests/passes/compile-static/rewrite-group-go.futil index dd310a3ad..c6f6e2072 100644 --- a/tests/passes/compile-static/rewrite-group-go.futil +++ b/tests/passes/compile-static/rewrite-group-go.futil @@ -1,10 +1,11 @@ -// -p well-formed -p compile-static -p dead-group-removal -p remove-ids +// -p well-formed -p compile-static -p dead-group-removal -p remove-ids -// in addition to turning A and run_A_thrice into dynamic groups using fsms, the +// in addition to turning A and run_A_thrice into dynamic groups using fsms, the // pass should also rewrite the assignment A[go] to early_reset_A[go] // and create a wrapper group for run_A_thrice (no wrapper necessary for A) import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { @@ -16,17 +17,17 @@ component main() -> () { wires { // dynamic groups simply here to demonstrate compiling static "islands" - // within dynamic control + // within dynamic control group dyn_B { - b.write_en = 1'd1; - b.in = 2'd1; - dyn_B[done] = b.done; + b.write_en = 1'd1; + b.in = 2'd1; + dyn_B[done] = b.done; } - + group dyn_C { - c.write_en = 1'd1; - c.in = 2'd1; - dyn_C[done] = c.done; + c.write_en = 1'd1; + c.in = 2'd1; + dyn_C[done] = c.done; } static<2> group A{ @@ -37,14 +38,14 @@ component main() -> () { } static<6> group run_A_thrice{ - A[go] = 1'd1; + A[go] = 1'd1; } } control { seq { - dyn_B; - dyn_C; + dyn_B; + dyn_C; run_A_thrice; } } diff --git a/tests/passes/compile-static/rewrite-static-while-nested.expect b/tests/passes/compile-static/rewrite-static-while-nested.expect index 8e8a8d83f..d1409b17d 100644 --- a/tests/passes/compile-static/rewrite-static-while-nested.expect +++ b/tests/passes/compile-static/rewrite-static-while-nested.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external p = std_mem_d1(3, 1, 1); + @external p = comb_mem_d1(3, 1, 1); incr = std_add(3); l = std_lt(3); r = std_reg(3); diff --git a/tests/passes/compile-static/rewrite-static-while-nested.futil b/tests/passes/compile-static/rewrite-static-while-nested.futil index 6b60d480e..b605ed7f4 100644 --- a/tests/passes/compile-static/rewrite-static-while-nested.futil +++ b/tests/passes/compile-static/rewrite-static-while-nested.futil @@ -1,11 +1,12 @@ -// -p well-formed -p static-inline -p compile-static -p dead-group-removal -p remove-ids +// -p well-formed -p static-inline -p compile-static -p dead-group-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main () -> () { cells { - @external p = std_mem_d1(3,1,1); + @external p = comb_mem_d1(3,1,1); incr = std_add(3); l = std_lt(3); r = std_reg(3); @@ -29,7 +30,7 @@ component main () -> () { r_cond.write_en = 1'd1; p.addr0 = 1'd0; } - + group B { p.write_data = 3'd0; p.write_en = 1'd1; @@ -44,7 +45,7 @@ component main () -> () { r.write_en = 1'd1; C[done] = r.done; } - + comb group comp { l2.left = r.out; l2.right = 3'd3; @@ -59,7 +60,7 @@ component main () -> () { static seq {A; A2;} } C; - } + } } } } \ No newline at end of file diff --git a/tests/passes/compile-static/rewrite-static-while.expect b/tests/passes/compile-static/rewrite-static-while.expect index 00656c54e..d16b50314 100644 --- a/tests/passes/compile-static/rewrite-static-while.expect +++ b/tests/passes/compile-static/rewrite-static-while.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/compile-static/rewrite-static-while.futil b/tests/passes/compile-static/rewrite-static-while.futil index 788c191cd..ef34fc744 100644 --- a/tests/passes/compile-static/rewrite-static-while.futil +++ b/tests/passes/compile-static/rewrite-static-while.futil @@ -1,6 +1,7 @@ -// -p well-formed -p static-inline -p compile-static -p dead-group-removal -p remove-ids +// -p well-formed -p static-inline -p compile-static -p dead-group-removal -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main () -> () { @@ -17,14 +18,14 @@ component main () -> () { incr.right = 3'd1; p.in = incr.out; p.write_en = %0 ? 1'd1; - } + } static<1> group B { l.left = p.out; l.right = 3'd6; r.in = l.out; r.write_en = 1'd1; } - + } control { diff --git a/tests/passes/compile-static/separate-fsms.expect b/tests/passes/compile-static/separate-fsms.expect index fed018914..7c95cc05a 100644 --- a/tests/passes/compile-static/separate-fsms.expect +++ b/tests/passes/compile-static/separate-fsms.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/compile-static/separate-fsms.futil b/tests/passes/compile-static/separate-fsms.futil index 9a7dc0f00..590af80f0 100644 --- a/tests/passes/compile-static/separate-fsms.futil +++ b/tests/passes/compile-static/separate-fsms.futil @@ -1,8 +1,9 @@ -// -p well-formed -p compile-static -p dead-group-removal -p remove-ids +// -p well-formed -p compile-static -p dead-group-removal -p remove-ids -// Test that we need separate FSMS: a) across par blocks and b) when a group -// triggers the "go" hole of another group +// Test that we need separate FSMS: a) across par blocks and b) when a group +// triggers the "go" hole of another group import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/pipelined.futil"; component main() -> () { @@ -31,15 +32,15 @@ component main() -> () { d.write_en = %0 ? 1'd1; } static<6> group run_A_and_D{ - A[go] = %[0:4] ? 1'd1; - D[go] = %[4:6] ? 1'd1; + A[go] = %[0:4] ? 1'd1; + D[go] = %[4:6] ? 1'd1; } } control { par { par {run_A_and_D; B;} - C; + C; } } } \ No newline at end of file diff --git a/tests/passes/compile-sync-without-sync-reg/sync-simple.expect b/tests/passes/compile-sync-without-sync-reg/sync-simple.expect index fc1bb864b..edaac3c98 100644 --- a/tests/passes/compile-sync-without-sync-reg/sync-simple.expect +++ b/tests/passes/compile-sync-without-sync-reg/sync-simple.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - out = std_mem_d1(32, 1, 3); + out = comb_mem_d1(32, 1, 3); val = std_reg(32); add_0 = std_add(32); no_use = std_reg(32); diff --git a/tests/passes/compile-sync-without-sync-reg/sync-simple.futil b/tests/passes/compile-sync-without-sync-reg/sync-simple.futil index e59735535..8632632b5 100644 --- a/tests/passes/compile-sync-without-sync-reg/sync-simple.futil +++ b/tests/passes/compile-sync-without-sync-reg/sync-simple.futil @@ -1,11 +1,12 @@ // -p validate -p compile-sync-without-sync-reg import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - out = std_mem_d1(32, 1, 3); + out = comb_mem_d1(32, 1, 3); val = std_reg(32); add_0 = std_add(32); no_use = std_reg(32); diff --git a/tests/passes/compile-sync/compile-sync-if-asym.expect b/tests/passes/compile-sync/compile-sync-if-asym.expect index 0e91f5aec..4be395401 100644 --- a/tests/passes/compile-sync/compile-sync-if-asym.expect +++ b/tests/passes/compile-sync/compile-sync-if-asym.expect @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - in_0 = std_mem_d1(32, 6, 3); - in_1 = std_mem_d1(32, 6, 3); - out = std_mem_d1(32, 6, 3); + in_0 = comb_mem_d1(32, 6, 3); + in_1 = comb_mem_d1(32, 6, 3); + out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/tests/passes/compile-sync/compile-sync-if-asym.futil b/tests/passes/compile-sync/compile-sync-if-asym.futil index a682b6f75..cba864524 100644 --- a/tests/passes/compile-sync/compile-sync-if-asym.futil +++ b/tests/passes/compile-sync/compile-sync-if-asym.futil @@ -1,13 +1,14 @@ // -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - in_0 = std_mem_d1(32, 6, 3); - in_1 = std_mem_d1(32, 6, 3); - out = std_mem_d1(32, 6, 3); + in_0 = comb_mem_d1(32, 6, 3); + in_1 = comb_mem_d1(32, 6, 3); + out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/tests/passes/compile-sync/compile-sync-if.expect b/tests/passes/compile-sync/compile-sync-if.expect index a961c87ac..b1c1ab0a0 100644 --- a/tests/passes/compile-sync/compile-sync-if.expect +++ b/tests/passes/compile-sync/compile-sync-if.expect @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - in_0 = std_mem_d1(32, 6, 3); - in_1 = std_mem_d1(32, 6, 3); - out = std_mem_d1(32, 6, 3); + in_0 = comb_mem_d1(32, 6, 3); + in_1 = comb_mem_d1(32, 6, 3); + out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/tests/passes/compile-sync/compile-sync-if.futil b/tests/passes/compile-sync/compile-sync-if.futil index 4359f9cb3..a6f17f5e7 100644 --- a/tests/passes/compile-sync/compile-sync-if.futil +++ b/tests/passes/compile-sync/compile-sync-if.futil @@ -1,13 +1,14 @@ // -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main () -> () { cells { - in_0 = std_mem_d1(32, 6, 3); - in_1 = std_mem_d1(32, 6, 3); - out = std_mem_d1(32, 6, 3); + in_0 = comb_mem_d1(32, 6, 3); + in_1 = comb_mem_d1(32, 6, 3); + out = comb_mem_d1(32, 6, 3); idx = std_reg(3); prod = std_reg(32); st = std_reg(1); diff --git a/tests/passes/compile-sync/compile-sync-nested.expect b/tests/passes/compile-sync/compile-sync-nested.expect index 6a8bcba76..2681e828f 100644 --- a/tests/passes/compile-sync/compile-sync-nested.expect +++ b/tests/passes/compile-sync/compile-sync-nested.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/compile-sync/compile-sync-nested.futil b/tests/passes/compile-sync/compile-sync-nested.futil index a15f46d08..d36701427 100644 --- a/tests/passes/compile-sync/compile-sync-nested.futil +++ b/tests/passes/compile-sync/compile-sync-nested.futil @@ -1,11 +1,12 @@ -// -p validate -p compile-sync +// -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/compile-sync/compile-sync-no-sync.expect b/tests/passes/compile-sync/compile-sync-no-sync.expect index 07316d812..e065cb599 100644 --- a/tests/passes/compile-sync/compile-sync-no-sync.expect +++ b/tests/passes/compile-sync/compile-sync-no-sync.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/compile-sync/compile-sync-no-sync.futil b/tests/passes/compile-sync/compile-sync-no-sync.futil index 62507546a..a0c106089 100644 --- a/tests/passes/compile-sync/compile-sync-no-sync.futil +++ b/tests/passes/compile-sync/compile-sync-no-sync.futil @@ -1,5 +1,6 @@ // -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/compile-sync/compile-sync-simple.expect b/tests/passes/compile-sync/compile-sync-simple.expect index 243d83771..1d95acd42 100644 --- a/tests/passes/compile-sync/compile-sync-simple.expect +++ b/tests/passes/compile-sync/compile-sync-simple.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - out = std_mem_d1(32, 1, 3); + out = comb_mem_d1(32, 1, 3); val = std_reg(32); add_0 = std_add(32); no_use = std_reg(32); diff --git a/tests/passes/compile-sync/compile-sync-simple.futil b/tests/passes/compile-sync/compile-sync-simple.futil index d5dbb1ecc..c69a48640 100644 --- a/tests/passes/compile-sync/compile-sync-simple.futil +++ b/tests/passes/compile-sync/compile-sync-simple.futil @@ -1,11 +1,12 @@ -// -p validate -p compile-sync +// -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - out = std_mem_d1(32, 1, 3); + out = comb_mem_d1(32, 1, 3); val = std_reg(32); add_0 = std_add(32); no_use = std_reg(32); diff --git a/tests/passes/compile-sync/compile-sync-two-barriers.expect b/tests/passes/compile-sync/compile-sync-two-barriers.expect index 78ddff719..d0c9bbb97 100644 --- a/tests/passes/compile-sync/compile-sync-two-barriers.expect +++ b/tests/passes/compile-sync/compile-sync-two-barriers.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/compile-sync/compile-sync-two-barriers.futil b/tests/passes/compile-sync/compile-sync-two-barriers.futil index 1b70b593b..bafd6f2dc 100644 --- a/tests/passes/compile-sync/compile-sync-two-barriers.futil +++ b/tests/passes/compile-sync/compile-sync-two-barriers.futil @@ -1,11 +1,12 @@ -// -p validate -p compile-sync +// -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/compile-sync/compile-sync.expect b/tests/passes/compile-sync/compile-sync.expect index 8efa66eda..5760cafbf 100644 --- a/tests/passes/compile-sync/compile-sync.expect +++ b/tests/passes/compile-sync/compile-sync.expect @@ -1,8 +1,9 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/compile-sync/compile-sync.futil b/tests/passes/compile-sync/compile-sync.futil index 2c7a9871e..ee21316b4 100644 --- a/tests/passes/compile-sync/compile-sync.futil +++ b/tests/passes/compile-sync/compile-sync.futil @@ -1,11 +1,12 @@ -// -p validate -p compile-sync +// -p validate -p compile-sync import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/sync.futil"; component main() -> () { cells { - out = std_mem_d1(32, 5, 3); + out = comb_mem_d1(32, 5, 3); val = std_reg(32); add_0 = std_add(32); addr = std_reg(3); diff --git a/tests/passes/dead-assign-removal/simple.expect b/tests/passes/dead-assign-removal/simple.expect index 9e6e8fbf7..a4fefa433 100644 --- a/tests/passes/dead-assign-removal/simple.expect +++ b/tests/passes/dead-assign-removal/simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/dead-assign-removal/simple.futil b/tests/passes/dead-assign-removal/simple.futil index fe498dc32..8fb59d8cc 100644 --- a/tests/passes/dead-assign-removal/simple.futil +++ b/tests/passes/dead-assign-removal/simple.futil @@ -1,6 +1,7 @@ // -p validate -p dead-assign-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); } diff --git a/tests/passes/dead-assign-removal/unused-cont.expect b/tests/passes/dead-assign-removal/unused-cont.expect index adee51f21..649e7bd00 100644 --- a/tests/passes/dead-assign-removal/unused-cont.expect +++ b/tests/passes/dead-assign-removal/unused-cont.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(x: 16, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r = std_reg(8); diff --git a/tests/passes/dead-assign-removal/unused-cont.futil b/tests/passes/dead-assign-removal/unused-cont.futil index 9821828b9..762e3ca14 100644 --- a/tests/passes/dead-assign-removal/unused-cont.futil +++ b/tests/passes/dead-assign-removal/unused-cont.futil @@ -1,5 +1,6 @@ // -p validate -p dead-assign-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(x: 16) -> (out: 8) { cells { diff --git a/tests/passes/dead-assign-removal/used-cont.expect b/tests/passes/dead-assign-removal/used-cont.expect index ba00db327..8fe2dec2c 100644 --- a/tests/passes/dead-assign-removal/used-cont.expect +++ b/tests/passes/dead-assign-removal/used-cont.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(x: 16, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r = std_reg(8); diff --git a/tests/passes/dead-assign-removal/used-cont.futil b/tests/passes/dead-assign-removal/used-cont.futil index 371a37d4a..8612a2d67 100644 --- a/tests/passes/dead-assign-removal/used-cont.futil +++ b/tests/passes/dead-assign-removal/used-cont.futil @@ -1,5 +1,6 @@ // -p validate -p dead-assign-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(x: 16) -> (out: 8) { cells { diff --git a/tests/passes/dead-cell-removal.expect b/tests/passes/dead-cell-removal.expect index 67ceb5819..fbd4b06cc 100644 --- a/tests/passes/dead-cell-removal.expect +++ b/tests/passes/dead-cell-removal.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { adder = std_add(32); diff --git a/tests/passes/dead-cell-removal.futil b/tests/passes/dead-cell-removal.futil index 8eca93166..8a0fce538 100644 --- a/tests/passes/dead-cell-removal.futil +++ b/tests/passes/dead-cell-removal.futil @@ -1,5 +1,6 @@ // -p dead-cell-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32) -> (out: 32) { cells { diff --git a/tests/passes/dead-group-removal.expect b/tests/passes/dead-group-removal.expect index bba645617..f51ab2dfb 100644 --- a/tests/passes/dead-group-removal.expect +++ b/tests/passes/dead-group-removal.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/dead-group-removal.futil b/tests/passes/dead-group-removal.futil index 824b001ba..fe5fb23c9 100644 --- a/tests/passes/dead-group-removal.futil +++ b/tests/passes/dead-group-removal.futil @@ -1,5 +1,6 @@ // -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); diff --git a/tests/passes/discover-external.expect b/tests/passes/discover-external.expect index 5542fcc63..18ab7cba1 100644 --- a/tests/passes/discover-external.expect +++ b/tests/passes/discover-external.expect @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component mlir_funcSYCL_class_vector_addition<"toplevel"=1>(@clk clk: 1, @reset reset: 1, @go go: 1) -> (@done done: 1) { cells { add = std_add(32); - @external @generated ext_mem0 = std_mem_d1(32, 16, 1); - @external @generated ext_mem1 = std_mem_d1(32, 16, 1); + @external @generated ext_mem0 = comb_mem_d1(32, 16, 1); + @external @generated ext_mem1 = comb_mem_d1(32, 16, 1); } wires { group incr { @@ -21,5 +22,5 @@ component mlir_funcSYCL_class_vector_addition<"toplevel"=1>(@clk clk: 1, @reset } } ---STDERR--- -[WARN calyx_opt::passes::discover_external] Unable to infer parameter value for ext_mem0_ in std_mem_d1, defaulting to 16 -[WARN calyx_opt::passes::discover_external] Unable to infer parameter value for ext_mem1_ in std_mem_d1, defaulting to 16 +[WARN calyx_opt::passes::discover_external] Unable to infer parameter value for ext_mem0_ in comb_mem_d1, defaulting to 16 +[WARN calyx_opt::passes::discover_external] Unable to infer parameter value for ext_mem1_ in comb_mem_d1, defaulting to 16 diff --git a/tests/passes/discover-external.futil b/tests/passes/discover-external.futil index 00fa42f66..ccb57d068 100644 --- a/tests/passes/discover-external.futil +++ b/tests/passes/discover-external.futil @@ -1,5 +1,6 @@ // -p validate -p discover-external -p validate -x discover-external:default=16 -x discover-external:strip-suffix=_ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component mlir_funcSYCL_class_vector_addition<"toplevel"=1>( ext_mem0_read_data: 32, ext_mem0_done: 1, diff --git a/tests/passes/dom-map-static/par-if.expect b/tests/passes/dom-map-static/par-if.expect index 3a2320013..d5a3c54d5 100644 --- a/tests/passes/dom-map-static/par-if.expect +++ b/tests/passes/dom-map-static/par-if.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/dom-map-static/par-if.futil b/tests/passes/dom-map-static/par-if.futil index be64d1fa9..9a804589e 100644 --- a/tests/passes/dom-map-static/par-if.futil +++ b/tests/passes/dom-map-static/par-if.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-static-analysis= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/dom-map-static/repeat.expect b/tests/passes/dom-map-static/repeat.expect index 43f194af5..c044c6479 100644 --- a/tests/passes/dom-map-static/repeat.expect +++ b/tests/passes/dom-map-static/repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/dom-map-static/repeat.futil b/tests/passes/dom-map-static/repeat.futil index 0abe05068..da22ca6fc 100644 --- a/tests/passes/dom-map-static/repeat.futil +++ b/tests/passes/dom-map-static/repeat.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-static-analysis= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/blank.expect b/tests/passes/domination-map/blank.expect index a39721f4a..f3c069de9 100644 --- a/tests/passes/domination-map/blank.expect +++ b/tests/passes/domination-map/blank.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells {} wires {} diff --git a/tests/passes/domination-map/blank.futil b/tests/passes/domination-map/blank.futil index 7a2afca20..c2dd2ae35 100644 --- a/tests/passes/domination-map/blank.futil +++ b/tests/passes/domination-map/blank.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { } diff --git a/tests/passes/domination-map/complex-test.expect b/tests/passes/domination-map/complex-test.expect index 09dd24db2..437e2ac0b 100644 --- a/tests/passes/domination-map/complex-test.expect +++ b/tests/passes/domination-map/complex-test.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/complex-test.futil b/tests/passes/domination-map/complex-test.futil index 9baf56c15..71f2f3518 100644 --- a/tests/passes/domination-map/complex-test.futil +++ b/tests/passes/domination-map/complex-test.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/dyn-repeat.expect b/tests/passes/domination-map/dyn-repeat.expect index b8b0311ab..9eea81440 100644 --- a/tests/passes/domination-map/dyn-repeat.expect +++ b/tests/passes/domination-map/dyn-repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/dyn-repeat.futil b/tests/passes/domination-map/dyn-repeat.futil index e7a23ead2..fcd45b99e 100644 --- a/tests/passes/domination-map/dyn-repeat.futil +++ b/tests/passes/domination-map/dyn-repeat.futil @@ -1,6 +1,7 @@ // -p infer-share -x infer-share:print-dmap= // should ignore `repeat 0` stmts in domination map import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/empty-fbranch.expect b/tests/passes/domination-map/empty-fbranch.expect index 96ff3d24b..29120c139 100644 --- a/tests/passes/domination-map/empty-fbranch.expect +++ b/tests/passes/domination-map/empty-fbranch.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/empty-fbranch.futil b/tests/passes/domination-map/empty-fbranch.futil index def20b08d..abc1625df 100644 --- a/tests/passes/domination-map/empty-fbranch.futil +++ b/tests/passes/domination-map/empty-fbranch.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/if-dominated.expect b/tests/passes/domination-map/if-dominated.expect index 4a595b512..24268d309 100644 --- a/tests/passes/domination-map/if-dominated.expect +++ b/tests/passes/domination-map/if-dominated.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/if-dominated.futil b/tests/passes/domination-map/if-dominated.futil index 6bc279281..66f22f9d1 100644 --- a/tests/passes/domination-map/if-dominated.futil +++ b/tests/passes/domination-map/if-dominated.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/nested-seq.expect b/tests/passes/domination-map/nested-seq.expect index 8631bb043..f0eececbb 100644 --- a/tests/passes/domination-map/nested-seq.expect +++ b/tests/passes/domination-map/nested-seq.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/nested-seq.futil b/tests/passes/domination-map/nested-seq.futil index fb44dbfcc..60bf5993a 100644 --- a/tests/passes/domination-map/nested-seq.futil +++ b/tests/passes/domination-map/nested-seq.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/par-if-nested.expect b/tests/passes/domination-map/par-if-nested.expect index 77203957d..1803d8130 100644 --- a/tests/passes/domination-map/par-if-nested.expect +++ b/tests/passes/domination-map/par-if-nested.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/par-if-nested.futil b/tests/passes/domination-map/par-if-nested.futil index 2c93a3b4b..8af0cb631 100644 --- a/tests/passes/domination-map/par-if-nested.futil +++ b/tests/passes/domination-map/par-if-nested.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/static-par.expect b/tests/passes/domination-map/static-par.expect index f8f526239..2e1241142 100644 --- a/tests/passes/domination-map/static-par.expect +++ b/tests/passes/domination-map/static-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/static-par.futil b/tests/passes/domination-map/static-par.futil index 12f1ba48b..d8abd4680 100644 --- a/tests/passes/domination-map/static-par.futil +++ b/tests/passes/domination-map/static-par.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/while-nested.expect b/tests/passes/domination-map/while-nested.expect index ae1d1e8fa..193f5b0a3 100644 --- a/tests/passes/domination-map/while-nested.expect +++ b/tests/passes/domination-map/while-nested.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/domination-map/while-nested.futil b/tests/passes/domination-map/while-nested.futil index d3fd05223..f1f8812e9 100644 --- a/tests/passes/domination-map/while-nested.futil +++ b/tests/passes/domination-map/while-nested.futil @@ -1,5 +1,6 @@ // -p infer-share -x infer-share:print-dmap= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> () { cells { lt = std_lt(4); diff --git a/tests/passes/externalize.expect b/tests/passes/externalize.expect index 497447dbf..5fe7b8e82 100644 --- a/tests/passes/externalize.expect +++ b/tests/passes/externalize.expect @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1, A_read_data: 32, A_done: 1) -> (@done done: 1, A_addr0: 4, A_write_data: 32, A_write_en: 1, A_clk: 1, A_reset: 1) { cells { - B = std_mem_d1(32, 16, 4); + B = comb_mem_d1(32, 16, 4); state = std_reg(32); } wires { diff --git a/tests/passes/externalize.futil b/tests/passes/externalize.futil index f98c5ae07..f6aa724df 100644 --- a/tests/passes/externalize.futil +++ b/tests/passes/externalize.futil @@ -1,11 +1,12 @@ // -p externalize import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { - @external(1) A = std_mem_d1(32, 16, 4); - B = std_mem_d1(32, 16, 4); + @external(1) A = comb_mem_d1(32, 16, 4); + B = comb_mem_d1(32, 16, 4); state = std_reg(32); } wires { diff --git a/tests/passes/go-insertion.expect b/tests/passes/go-insertion.expect index 0dcd0b1ef..f2bd4b4fd 100644 --- a/tests/passes/go-insertion.expect +++ b/tests/passes/go-insertion.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { add = std_add(32); diff --git a/tests/passes/go-insertion.futil b/tests/passes/go-insertion.futil index ef453fa78..d3ddb927e 100644 --- a/tests/passes/go-insertion.futil +++ b/tests/passes/go-insertion.futil @@ -1,6 +1,7 @@ // -p go-insertion import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/group2invoke/multi-go-done-component.expect b/tests/passes/group2invoke/multi-go-done-component.expect index ba34f669b..c8640237c 100644 --- a/tests/passes/group2invoke/multi-go-done-component.expect +++ b/tests/passes/group2invoke/multi-go-done-component.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; extern "/calyx/tests/passes/group2invoke/multi-go-done-component.futil" { primitive real_mem(@static @go read_en: 1, @static(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); diff --git a/tests/passes/group2invoke/multi-go-done-component.futil b/tests/passes/group2invoke/multi-go-done-component.futil index 5525ee256..cbc5edcfc 100644 --- a/tests/passes/group2invoke/multi-go-done-component.futil +++ b/tests/passes/group2invoke/multi-go-done-component.futil @@ -1,6 +1,7 @@ // -p group2invoke import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; extern "./multi-go-done-component.futil" { primitive real_mem( diff --git a/tests/passes/group2invoke/multi-go-done.expect b/tests/passes/group2invoke/multi-go-done.expect index ae463e0bd..d19c857f0 100644 --- a/tests/passes/group2invoke/multi-go-done.expect +++ b/tests/passes/group2invoke/multi-go-done.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "/calyx/tests/passes/group2invoke/multi-go-done.futil" { primitive real_mem(@static @go read_en: 1, @static(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); } diff --git a/tests/passes/group2invoke/multi-go-done.futil b/tests/passes/group2invoke/multi-go-done.futil index efd454179..27903f1d1 100644 --- a/tests/passes/group2invoke/multi-go-done.futil +++ b/tests/passes/group2invoke/multi-go-done.futil @@ -1,5 +1,6 @@ // -p well-formed -p group2invoke import "primitives/core.futil"; +import "primitives/memories/comb.futil"; extern "./multi-go-done.futil" { primitive real_mem( diff --git a/tests/passes/group2invoke/no_transform.expect b/tests/passes/group2invoke/no_transform.expect index 7780450d0..1a52d5271 100644 --- a/tests/passes/group2invoke/no_transform.expect +++ b/tests/passes/group2invoke/no_transform.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/group2invoke/no_transform.futil b/tests/passes/group2invoke/no_transform.futil index a0ecbcc4e..4f1df3d89 100644 --- a/tests/passes/group2invoke/no_transform.futil +++ b/tests/passes/group2invoke/no_transform.futil @@ -1,5 +1,6 @@ // -p group2invoke -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); @@ -7,11 +8,11 @@ component main() -> () { } wires { group chain{ - r.write_en = !r.done ? 1'd1; - r.in = 32'd2; - a.in = 32'd7; - a.write_en = r.done; - chain[done] = a.done; + r.write_en = !r.done ? 1'd1; + r.in = 32'd2; + a.in = 32'd7; + a.write_en = r.done; + chain[done] = a.done; } } control { diff --git a/tests/passes/group2invoke/no_transform_simple.expect b/tests/passes/group2invoke/no_transform_simple.expect index 7738f0fb1..be24f8997 100644 --- a/tests/passes/group2invoke/no_transform_simple.expect +++ b/tests/passes/group2invoke/no_transform_simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { e = std_eq(32); diff --git a/tests/passes/group2invoke/no_transform_simple.futil b/tests/passes/group2invoke/no_transform_simple.futil index 0091b9304..ce58619a5 100644 --- a/tests/passes/group2invoke/no_transform_simple.futil +++ b/tests/passes/group2invoke/no_transform_simple.futil @@ -1,5 +1,6 @@ //-p validate -p group2seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { e = std_eq(32); diff --git a/tests/passes/group2invoke/transform.expect b/tests/passes/group2invoke/transform.expect index 06b507962..6d7c79d79 100644 --- a/tests/passes/group2invoke/transform.expect +++ b/tests/passes/group2invoke/transform.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/group2invoke/transform.futil b/tests/passes/group2invoke/transform.futil index d79001fe6..9efcfc41d 100644 --- a/tests/passes/group2invoke/transform.futil +++ b/tests/passes/group2invoke/transform.futil @@ -1,5 +1,6 @@ // -p group2invoke -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r = std_reg(32); @@ -21,7 +22,7 @@ component main() -> () { add.left = 32'd2; add.right = 32'd3; } - // multiple guarded assignments to r.in + // multiple guarded assignments to r.in group g{ r.write_en = 1'd1; r.in = 1'd0 ? 32'd1; diff --git a/tests/passes/group_to_seq/dahlia_mult.expect b/tests/passes/group_to_seq/dahlia_mult.expect index 6c94e2871..c42887b24 100644 --- a/tests/passes/group_to_seq/dahlia_mult.expect +++ b/tests/passes/group_to_seq/dahlia_mult.expect @@ -1,11 +1,12 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external A0 = std_mem_d1(32, 2, 2); + @external A0 = comb_mem_d1(32, 2, 2); A_read0_0 = std_reg(32); A_read1_0 = std_reg(32); - @external B0 = std_mem_d1(32, 2, 2); + @external B0 = comb_mem_d1(32, 2, 2); B_read0_0 = std_reg(32); B_read1_0 = std_reg(32); bin_read0_0 = std_reg(32); diff --git a/tests/passes/group_to_seq/dahlia_mult.futil b/tests/passes/group_to_seq/dahlia_mult.futil index f2a7111fa..180393e6a 100644 --- a/tests/passes/group_to_seq/dahlia_mult.futil +++ b/tests/passes/group_to_seq/dahlia_mult.futil @@ -1,13 +1,14 @@ // -p validate -p group2seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) A0 = std_mem_d1(32,2,2); + @external(1) A0 = comb_mem_d1(32,2,2); A_read0_0 = std_reg(32); A_read1_0 = std_reg(32); - @external(1) B0 = std_mem_d1(32,2,2); + @external(1) B0 = comb_mem_d1(32,2,2); B_read0_0 = std_reg(32); B_read1_0 = std_reg(32); bin_read0_0 = std_reg(32); diff --git a/tests/passes/group_to_seq/no_transform.expect b/tests/passes/group_to_seq/no_transform.expect index 7d16e85d2..0e26f0b30 100644 --- a/tests/passes/group_to_seq/no_transform.expect +++ b/tests/passes/group_to_seq/no_transform.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/group_to_seq/no_transform.futil b/tests/passes/group_to_seq/no_transform.futil index 683786c73..bf460d6d0 100644 --- a/tests/passes/group_to_seq/no_transform.futil +++ b/tests/passes/group_to_seq/no_transform.futil @@ -1,6 +1,7 @@ //-p validate -p group2seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main<"state_share"=1>(in:32) -> () { cells { @@ -11,14 +12,14 @@ component main<"state_share"=1>(in:32) -> () { x_0 = std_reg(32); } wires { - // no A.go = B.done (or vice versa), and group's done is not in correct form + // no A.go = B.done (or vice versa), and group's done is not in correct form group writeAB{ - A.write_en = 1'd1; - A.in = 32'd5; - B.write_en = 1'd1; - B.in = 32'd7; + A.write_en = 1'd1; + A.in = 32'd5; + B.write_en = 1'd1; + B.in = 32'd7; writeAB[done]= A.done & B.done? 1'd1; - } + } } control { seq{ diff --git a/tests/passes/group_to_seq/should_transform.expect b/tests/passes/group_to_seq/should_transform.expect index 569d2a736..64bbe0ff7 100644 --- a/tests/passes/group_to_seq/should_transform.expect +++ b/tests/passes/group_to_seq/should_transform.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/group_to_seq/should_transform.futil b/tests/passes/group_to_seq/should_transform.futil index 4ac8d3c56..ac8851291 100644 --- a/tests/passes/group_to_seq/should_transform.futil +++ b/tests/passes/group_to_seq/should_transform.futil @@ -1,6 +1,7 @@ //-p validate -p group2seq -p dead-assign-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main<"state_share"=1>(in:32) -> () { cells { @@ -13,24 +14,24 @@ component main<"state_share"=1>(in:32) -> () { } wires { group two { - A.write_en = !A.done ? 1'd1; - A.in = 32'd4; - mult_pipe0.go = A.done; - mult_pipe0.left = A.out; + A.write_en = !A.done ? 1'd1; + A.in = 32'd4; + mult_pipe0.go = A.done; + mult_pipe0.left = A.out; mult_pipe0.right = 32'd4; - two[done] = mult_pipe0.done; + two[done] = mult_pipe0.done; } group write_a{ - A.in = 32'd2; - A.write_en = 1'd1; - write_a[done] = A.done; + A.in = 32'd2; + A.write_en = 1'd1; + write_a[done] = A.done; } group write_bmult{ - B.in = 32'd2; - B.write_en = A.done & !B.done ? 1'd1; - mult_pipe0.go = B.done; - mult_pipe0.left = B.out; - mult_pipe0.right = B.out; + B.in = 32'd2; + B.write_en = A.done & !B.done ? 1'd1; + mult_pipe0.go = B.done; + mult_pipe0.left = B.out; + mult_pipe0.right = B.out; write_bmult[done] = mult_pipe0.done; } group chain_plus_adders { diff --git a/tests/passes/infer-share-pass/invoke.expect b/tests/passes/infer-share-pass/invoke.expect index 10d761902..9f3550fa9 100644 --- a/tests/passes/infer-share-pass/invoke.expect +++ b/tests/passes/infer-share-pass/invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component share<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/invoke.futil b/tests/passes/infer-share-pass/invoke.futil index 317fea0b4..6dc38c1ac 100644 --- a/tests/passes/infer-share-pass/invoke.futil +++ b/tests/passes/infer-share-pass/invoke.futil @@ -1,16 +1,17 @@ //-p infer-share import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -// share is just some user defined component that should be shareable -// share1 makes sure that invoke component(..)(..) counts as a write to component. -// share2 is making sure that invoke component(..)(out = a.in) counts a write to a. -// share3 is making sure that for invoke component()(), if outputs are empty, it +// share is just some user defined component that should be shareable +// share1 makes sure that invoke component(..)(..) counts as a write to component. +// share2 is making sure that invoke component(..)(out = a.in) counts a write to a. +// share3 is making sure that for invoke component()(), if outputs are empty, it // *doesn't* count as a read of component. -// non_share makes sure that invoke component(in = a.out .. )(..), it counts as a read of a. -// non_share2 is making sure that for invoke component(..)(out = ..) counts as a -// read of component, since outputs are nonemtpy. +// non_share makes sure that invoke component(in = a.out .. )(..), it counts as a read of a. +// non_share2 is making sure that for invoke component(..)(out = ..) counts as a +// read of component, since outputs are nonemtpy. component share(in: 32) -> (out: 32) { cells { @@ -19,8 +20,8 @@ component share(in: 32) -> (out: 32) { } wires { group A { - add_32.left = in; - add_32.right = 32'd5; + add_32.left = in; + add_32.right = 32'd5; r.in = add_32.out; r.write_en = 1'd1; A[done] = r.done; @@ -39,11 +40,11 @@ component share1(in: 32) -> (out: 32) { } wires { group readS { - r.write_en = 1'd1; - r.in = s.out; - readS[done] = r.done; + r.write_en = 1'd1; + r.in = s.out; + readS[done] = r.done; } - out = r.out; + out = r.out; } control { seq{ @@ -61,20 +62,20 @@ component share2(in: 32) -> (out: 32) { } wires { group readR{ - q.write_en = 1'd1; - q.in = r.out; - readR[done] = q.done; + q.write_en = 1'd1; + q.in = r.out; + readR[done] = q.done; } group wrS{ - s.go = 1'd1; - s.in = 32'd5; - wrS[done] = s.done; + s.go = 1'd1; + s.in = 32'd5; + wrS[done] = s.done; } - out = q.out; + out = q.out; } control { seq{ - wrS; + wrS; invoke s(in = in)(out = r.in); readR; } @@ -119,7 +120,7 @@ component non_share2(in: 32) -> (out: 32) { r = std_reg(32); } wires { - out = s.out; + out = s.out; } control { seq{ diff --git a/tests/passes/infer-share-pass/maybe-write.expect b/tests/passes/infer-share-pass/maybe-write.expect index f7b756503..4cac89d74 100644 --- a/tests/passes/infer-share-pass/maybe-write.expect +++ b/tests/passes/infer-share-pass/maybe-write.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component no_share(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/maybe-write.futil b/tests/passes/infer-share-pass/maybe-write.futil index 3058bb3d5..89f8d9855 100644 --- a/tests/passes/infer-share-pass/maybe-write.futil +++ b/tests/passes/infer-share-pass/maybe-write.futil @@ -4,6 +4,7 @@ // to lt.out), in which case it does *not* count as a guaranteed write. import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component no_share(in: 32) -> (out: 32) { @@ -11,29 +12,29 @@ component no_share(in: 32) -> (out: 32) { b = std_reg(32); c = std_reg(32); d = std_reg(32); - lt = std_lt(32); + lt = std_lt(32); } wires { group wrCD{ - lt.left = 32'd2; - lt.right = 32'd4; - c.write_en = lt.out; - c.in = 32'd20; + lt.left = 32'd2; + lt.right = 32'd4; + c.write_en = lt.out; + c.in = 32'd20; d.write_en = !lt.out ? 1'd1; - d.in = 32'd15; - wrCD[done] = c.done | d.done ? 1'd1; + d.in = 32'd15; + wrCD[done] = c.done | d.done ? 1'd1; } group readC{ b.in = c.out; - b.write_en = 1'd1; - readC[done] = b.done; + b.write_en = 1'd1; + readC[done] = b.done; } out = b.out; } control { seq{ wrCD; - readC; + readC; } } } diff --git a/tests/passes/infer-share-pass/par-if.expect b/tests/passes/infer-share-pass/par-if.expect index 962bcba17..154aedb44 100644 --- a/tests/passes/infer-share-pass/par-if.expect +++ b/tests/passes/infer-share-pass/par-if.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component noshare(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/par-if.futil b/tests/passes/infer-share-pass/par-if.futil index cabd2c07b..3e3686bf3 100644 --- a/tests/passes/infer-share-pass/par-if.futil +++ b/tests/passes/infer-share-pass/par-if.futil @@ -1,11 +1,12 @@ //-p infer-share -// noshare should not be shared since the if statement means that -// the write to b may not dominate the read from b -// share should be shared. It makes sure that it treats pars as "definitely" -// occuring, so that it sees par {wrB wrC} and knows both will occur. +// noshare should not be shared since the if statement means that +// the write to b may not dominate the read from b +// share should be shared. It makes sure that it treats pars as "definitely" +// occuring, so that it sees par {wrB wrC} and knows both will occur. import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component noshare(in:32) -> (out: 32) { @@ -18,39 +19,39 @@ component noshare(in:32) -> (out: 32) { } wires { group wrR { - r.write_en = 1'd1; - r.in = 32'd4; - wrR[done] = r.done; + r.write_en = 1'd1; + r.in = 32'd4; + wrR[done] = r.done; } comb group rlt10{ - lt.left = r.out; + lt.left = r.out; lt.right = 32'd5; } group readB{ - a.write_en = 1'd1; - a.in = b.out; - readB[done] = a.done; + a.write_en = 1'd1; + a.in = b.out; + readB[done] = a.done; } group wrB{ - b.write_en = 1'd1; - b.in = 32'd2; - wrB[done] = b.done; + b.write_en = 1'd1; + b.in = 32'd2; + wrB[done] = b.done; } group wrC{ - c.write_en = 1'd1; - c.in = 32'd2; - wrC[done] = c.done; + c.write_en = 1'd1; + c.in = 32'd2; + wrC[done] = c.done; } group readC{ - a.write_en = 1'd1; - a.in = c.out; - wrC[done] = a.done; + a.write_en = 1'd1; + a.in = c.out; + wrC[done] = a.done; } out = a.out; } control { seq{ - wrR; + wrR; if lt.out with rlt10{ wrB; } @@ -70,50 +71,50 @@ component share(in:32) -> (out: 32) { } wires { group wrR { - r.write_en = 1'd1; - r.in = 32'd4; - wrR[done] = r.done; + r.write_en = 1'd1; + r.in = 32'd4; + wrR[done] = r.done; } comb group rlt10{ - lt.left = r.out; + lt.left = r.out; lt.right = 32'd5; } group readB{ - a.write_en = 1'd1; - a.in = b.out; - readB[done] = a.done; + a.write_en = 1'd1; + a.in = b.out; + readB[done] = a.done; } group wrB{ - b.write_en = 1'd1; - b.in = 32'd2; - wrB[done] = b.done; + b.write_en = 1'd1; + b.in = 32'd2; + wrB[done] = b.done; } group wrC{ - c.write_en = 1'd1; - c.in = 32'd2; - wrC[done] = c.done; + c.write_en = 1'd1; + c.in = 32'd2; + wrC[done] = c.done; } group rdR{ - a.write_en = 1'd1; - a.in = r.out; - wrC[done] = a.done; + a.write_en = 1'd1; + a.in = r.out; + wrC[done] = a.done; } group readC{ - a.write_en = 1'd1; - a.in = c.out; - wrC[done] = a.done; + a.write_en = 1'd1; + a.in = c.out; + wrC[done] = a.done; } out = a.out; } control { seq{ - wrR; + wrR; if lt.out with rlt10{ seq{ par {wrB; wrC;} readB; readC; - } + } } rdR; } diff --git a/tests/passes/infer-share-pass/seq-dominate.expect b/tests/passes/infer-share-pass/seq-dominate.expect index 5546bc8a2..cf262097e 100644 --- a/tests/passes/infer-share-pass/seq-dominate.expect +++ b/tests/passes/infer-share-pass/seq-dominate.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component share<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out1: 32, out2: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/seq-dominate.futil b/tests/passes/infer-share-pass/seq-dominate.futil index 2fa46d3c1..73e001c20 100644 --- a/tests/passes/infer-share-pass/seq-dominate.futil +++ b/tests/passes/infer-share-pass/seq-dominate.futil @@ -1,11 +1,12 @@ //-p infer-share -// share checks for the situation when there are writes to registers, but -// each time they are dominated by a read. -// non_share checks the same the same situation, except this time there is one read, -// in group wrC, that is not dominated by a write and is therefore not shareable. +// share checks for the situation when there are writes to registers, but +// each time they are dominated by a read. +// non_share checks the same the same situation, except this time there is one read, +// in group wrC, that is not dominated by a write and is therefore not shareable. import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component share(in: 32) -> (out1: 32, out2: 32) { @@ -18,26 +19,26 @@ component share(in: 32) -> (out1: 32, out2: 32) { } wires { group wrC { - c.write_en = 1'd1; - c.in = b.out; + c.write_en = 1'd1; + c.in = b.out; wrC[done] = c.done; } group wrA{ - add_32.left = c.out; - add_32.right = in; - a.write_en = 1'd1; - a.in = add_32.out; + add_32.left = c.out; + add_32.right = in; + a.write_en = 1'd1; + a.in = add_32.out; wrA[done] = a.done; } group wrB{ - add_32.left = in; - add_32.right = 32'd20; - b.write_en = 1'd1; - b.in = add_32.out; + add_32.left = in; + add_32.right = 32'd20; + b.write_en = 1'd1; + b.in = add_32.out; wrB[done] = b.done; } - out1 = a.out; - out2 = b.out; + out1 = a.out; + out2 = b.out; } control { seq{ @@ -58,26 +59,26 @@ component non_share(in: 32) -> (out1: 32, out2: 32) { } wires { group wrC { - c.write_en = 1'd1; - c.in = b.out; + c.write_en = 1'd1; + c.in = b.out; wrC[done] = c.done; } group wrA{ - add_32.left = c.out; - add_32.right = in; - a.write_en = 1'd1; - a.in = add_32.out; + add_32.left = c.out; + add_32.right = in; + a.write_en = 1'd1; + a.in = add_32.out; wrA[done] = a.done; } group wrB{ - add_32.left = in; - add_32.right = 32'd20; - b.write_en = 1'd1; - b.in = add_32.out; + add_32.left = in; + add_32.right = 32'd20; + b.write_en = 1'd1; + b.in = add_32.out; wrB[done] = b.done; } - out1 = a.out; - out2 = b.out; + out1 = a.out; + out2 = b.out; } control { seq{ diff --git a/tests/passes/infer-share-pass/simple-dominate.expect b/tests/passes/infer-share-pass/simple-dominate.expect index c5093d0cd..9aae6923c 100644 --- a/tests/passes/infer-share-pass/simple-dominate.expect +++ b/tests/passes/infer-share-pass/simple-dominate.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component add_5<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/simple-dominate.futil b/tests/passes/infer-share-pass/simple-dominate.futil index 10b583414..3f8bb2de8 100644 --- a/tests/passes/infer-share-pass/simple-dominate.futil +++ b/tests/passes/infer-share-pass/simple-dominate.futil @@ -1,9 +1,10 @@ //-p infer-share -// add_5 checks for a situation when r is written but never read. -// count checks for situation when a read and write occur in the same group +// add_5 checks for a situation when r is written but never read. +// count checks for situation when a read and write occur in the same group import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; @@ -14,8 +15,8 @@ component add_5(in: 32) -> (out: 32) { } wires { group A { - add_32.left = in; - add_32.right = 32'd5; + add_32.left = in; + add_32.right = 32'd5; r.in = add_32.out; r.write_en = 1'd1; A[done] = r.done; @@ -34,8 +35,8 @@ component count(in: 32) -> (out: 32) { } wires { group A { - add_32.left = r.out; - add_32.right = 32'd1; + add_32.left = r.out; + add_32.right = 32'd1; r.in = add_32.out; r.write_en = 1'd1; A[done] = r.done; diff --git a/tests/passes/infer-share-pass/static-par.expect b/tests/passes/infer-share-pass/static-par.expect index 1d1772973..0afb1ef39 100644 --- a/tests/passes/infer-share-pass/static-par.expect +++ b/tests/passes/infer-share-pass/static-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component example<"state_share"=1>(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/infer-share-pass/static-par.futil b/tests/passes/infer-share-pass/static-par.futil index 3823b4fa2..a5aff7ca0 100644 --- a/tests/passes/infer-share-pass/static-par.futil +++ b/tests/passes/infer-share-pass/static-par.futil @@ -3,6 +3,7 @@ // import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; @@ -14,24 +15,24 @@ component example(in: 32) -> (out: 32) { } wires { static<1> group A { - a.in = 32'd2; - a.write_en = 1'd1; + a.in = 32'd2; + a.write_en = 1'd1; } static<1> group B { - b.write_en = 1'd1; - b.in = 32'd7; + b.write_en = 1'd1; + b.in = 32'd7; } static<1> group read_A { - adder.left = a.out; - adder.right = 32'd2; - a.in = adder.out; - a.write_en = 1'd1; + adder.left = a.out; + adder.right = 32'd2; + a.in = adder.out; + a.write_en = 1'd1; } out = a.out; } control { static par { - A; + A; static seq {B; read_A; } } } diff --git a/tests/passes/infer-share-pass/user_defined_non_share.expect b/tests/passes/infer-share-pass/user_defined_non_share.expect index 1a6f9feff..a962ea643 100644 --- a/tests/passes/infer-share-pass/user_defined_non_share.expect +++ b/tests/passes/infer-share-pass/user_defined_non_share.expect @@ -1,10 +1,11 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component no_share(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r = std_reg(32); add_32 = std_add(32); - @external B = std_mem_d2(32, 2, 2, 4, 4); + @external B = comb_mem_d2(32, 2, 2, 4, 4); } wires { out = r.out; diff --git a/tests/passes/infer-share-pass/user_defined_non_share.futil b/tests/passes/infer-share-pass/user_defined_non_share.futil index 70165b3f6..1f7ffddca 100644 --- a/tests/passes/infer-share-pass/user_defined_non_share.futil +++ b/tests/passes/infer-share-pass/user_defined_non_share.futil @@ -1,16 +1,17 @@ //-p infer-share -// no_share uses std_mem so it should not be shared. -// uses_no_share uses no_share so it should not be shared. +// no_share uses std_mem so it should not be shared. +// uses_no_share uses no_share so it should not be shared. import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component no_share(in: 32) -> (out: 32) { cells { r = std_reg(32); add_32 = std_add(32); - @external(1) B = std_mem_d2(32,2,2,4,4); + @external(1) B = comb_mem_d2(32,2,2,4,4); } wires { out = r.out; @@ -25,9 +26,9 @@ component uses_no_share(in: 32) -> (out: 32) { } wires { group A { - c.go = 1'd1; - c.in = 32'd10; - A[done] = c.done; + c.go = 1'd1; + c.in = 32'd10; + A[done] = c.done; } out = c.out; } diff --git a/tests/passes/infer-share-pass/uses_ref.expect b/tests/passes/infer-share-pass/uses_ref.expect index 4a51153ef..9754e2c9f 100644 --- a/tests/passes/infer-share-pass/uses_ref.expect +++ b/tests/passes/infer-share-pass/uses_ref.expect @@ -1,7 +1,8 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component uses_ref<"state_share"=1>(i: 3, j: 3, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { - ref mem = std_mem_d2(32, 5, 5, 3, 3); + ref mem = comb_mem_d2(32, 5, 5, 3, 3); r = std_reg(32); } wires { diff --git a/tests/passes/infer-share-pass/uses_ref.futil b/tests/passes/infer-share-pass/uses_ref.futil index 811dd14c4..50984fb06 100644 --- a/tests/passes/infer-share-pass/uses_ref.futil +++ b/tests/passes/infer-share-pass/uses_ref.futil @@ -1,25 +1,26 @@ //-p infer-share -p remove-ids import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component uses_ref(i: 3, j:3) -> (out: 32) { cells { - ref mem = std_mem_d2(32, 5,5, 3,3); + ref mem = comb_mem_d2(32, 5,5, 3,3); r = std_reg(32); } wires { group read_mem { - r.in = mem.read_data; - r.write_en = 1'd1; - read_mem[done] = r.done; + r.in = mem.read_data; + r.write_en = 1'd1; + read_mem[done] = r.done; } group write_mem{ mem.addr0 = j; - mem.addr1 = i; + mem.addr1 = i; mem.write_data = 32'd9; - mem.write_en = 1'd1; - write_mem[done] = mem.done; + mem.write_en = 1'd1; + write_mem[done] = mem.done; } - out = r.out; + out = r.out; } control { seq{ diff --git a/tests/passes/inliner.expect b/tests/passes/inliner.expect index f43ada70c..28dbb7be6 100644 --- a/tests/passes/inliner.expect +++ b/tests/passes/inliner.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/inliner.futil b/tests/passes/inliner.futil index adae38705..4ebf4b630 100644 --- a/tests/passes/inliner.futil +++ b/tests/passes/inliner.futil @@ -1,6 +1,7 @@ // -p go-insertion -p hole-inliner import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/inliner/always.expect b/tests/passes/inliner/always.expect index 7ff8f59c4..198ea80a3 100644 --- a/tests/passes/inliner/always.expect +++ b/tests/passes/inliner/always.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component check(left: 4, right: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/inliner/always.futil b/tests/passes/inliner/always.futil index ce74141d4..e6740d5ea 100644 --- a/tests/passes/inliner/always.futil +++ b/tests/passes/inliner/always.futil @@ -1,5 +1,6 @@ // -p validate -p inline -x inline:always import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component check(left: 4, right: 4) -> (out: 1) { cells { diff --git a/tests/passes/inliner/invoke_reg.expect b/tests/passes/inliner/invoke_reg.expect index 4572fc7c8..9ebad5ca4 100644 --- a/tests/passes/inliner/invoke_reg.expect +++ b/tests/passes/inliner/invoke_reg.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { f_reg = std_reg(32); diff --git a/tests/passes/inliner/invoke_reg.futil b/tests/passes/inliner/invoke_reg.futil index 9198beb4c..339631b9b 100644 --- a/tests/passes/inliner/invoke_reg.futil +++ b/tests/passes/inliner/invoke_reg.futil @@ -1,15 +1,16 @@ // -p validate -p inline import "primitives/core.futil"; +import "primitives/memories/comb.futil"; -// just some component +// just some component component foo(in: 32) -> (out: 32) { cells { f_reg = std_reg(32); } wires { group foo_group { - f_reg.in = in; - f_reg.write_en = 1'd1; + f_reg.in = in; + f_reg.write_en = 1'd1; foo_group[done] = f_reg.done; } out= f_reg.out; diff --git a/tests/passes/inliner/simple.expect b/tests/passes/inliner/simple.expect index 7ff8f59c4..198ea80a3 100644 --- a/tests/passes/inliner/simple.expect +++ b/tests/passes/inliner/simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component check(left: 4, right: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 1, @done done: 1) { cells { lt = std_lt(4); diff --git a/tests/passes/inliner/simple.futil b/tests/passes/inliner/simple.futil index 3504e0745..18f56860e 100644 --- a/tests/passes/inliner/simple.futil +++ b/tests/passes/inliner/simple.futil @@ -1,5 +1,6 @@ // -p validate -p inline import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component check(left: 4, right: 4) -> (out: 1) { cells { diff --git a/tests/passes/lower-guards.expect b/tests/passes/lower-guards.expect index b1b7ce81e..8acd5f953 100644 --- a/tests/passes/lower-guards.expect +++ b/tests/passes/lower-guards.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/lower-guards.futil b/tests/passes/lower-guards.futil index 32172d04e..6e674e9e5 100644 --- a/tests/passes/lower-guards.futil +++ b/tests/passes/lower-guards.futil @@ -1,5 +1,6 @@ // -p validate -p lower-guards import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { diff --git a/tests/passes/merge-assign.expect b/tests/passes/merge-assign.expect index 0dbfcddb8..bf142be31 100644 --- a/tests/passes/merge-assign.expect +++ b/tests/passes/merge-assign.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(4); diff --git a/tests/passes/merge-assign.futil b/tests/passes/merge-assign.futil index 1a5038c71..287222c13 100644 --- a/tests/passes/merge-assign.futil +++ b/tests/passes/merge-assign.futil @@ -1,6 +1,7 @@ // -p merge-assigns import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/papercut-multi-done.expect b/tests/passes/papercut-multi-done.expect index c9747fb03..5e37f8477 100644 --- a/tests/passes/papercut-multi-done.expect +++ b/tests/passes/papercut-multi-done.expect @@ -1,4 +1,4 @@ -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done read_done: 1, @done(2) write_done: 1) { cells { mem_0 = seq_mem_d1(32, 6, 3); diff --git a/tests/passes/papercut-multi-done.futil b/tests/passes/papercut-multi-done.futil index 82656a484..7084ea516 100644 --- a/tests/passes/papercut-multi-done.futil +++ b/tests/passes/papercut-multi-done.futil @@ -1,6 +1,6 @@ // -p papercut -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done read_done: 1, @done(2) write_done: 1) { cells { diff --git a/tests/passes/par-timing-map/nested-par.expect b/tests/passes/par-timing-map/nested-par.expect index 9f3ca69d9..979afd35b 100644 --- a/tests/passes/par-timing-map/nested-par.expect +++ b/tests/passes/par-timing-map/nested-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-timing-map/nested-par.futil b/tests/passes/par-timing-map/nested-par.futil index 1cc81fa62..b7e3f132d 100644 --- a/tests/passes/par-timing-map/nested-par.futil +++ b/tests/passes/par-timing-map/nested-par.futil @@ -1,5 +1,6 @@ // -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-timing-map/nested-while.expect b/tests/passes/par-timing-map/nested-while.expect index 532e7a034..925f335e2 100644 --- a/tests/passes/par-timing-map/nested-while.expect +++ b/tests/passes/par-timing-map/nested-while.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-timing-map/nested-while.futil b/tests/passes/par-timing-map/nested-while.futil index b2fd1b0e9..f7b6ce5a9 100644 --- a/tests/passes/par-timing-map/nested-while.futil +++ b/tests/passes/par-timing-map/nested-while.futil @@ -1,5 +1,6 @@ // -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-timing-map/simple.expect b/tests/passes/par-timing-map/simple.expect index 9e82b2ae6..1a4924bfa 100644 --- a/tests/passes/par-timing-map/simple.expect +++ b/tests/passes/par-timing-map/simple.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-timing-map/simple.futil b/tests/passes/par-timing-map/simple.futil index 5399026bc..1419c5d93 100644 --- a/tests/passes/par-timing-map/simple.futil +++ b/tests/passes/par-timing-map/simple.futil @@ -1,5 +1,6 @@ // -p cell-share -x cell-share:print-par-timing= import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component comp(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { lt = std_lt(32); diff --git a/tests/passes/par-to-seq/ignore-this-comp.expect b/tests/passes/par-to-seq/ignore-this-comp.expect index 9bc179a24..5172a341a 100644 --- a/tests/passes/par-to-seq/ignore-this-comp.expect +++ b/tests/passes/par-to-seq/ignore-this-comp.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out1: 32, out2: 32, @done done: 1) { cells { r0 = std_reg(32); diff --git a/tests/passes/par-to-seq/ignore-this-comp.futil b/tests/passes/par-to-seq/ignore-this-comp.futil index 6fbc4cac2..7a63dadf7 100644 --- a/tests/passes/par-to-seq/ignore-this-comp.futil +++ b/tests/passes/par-to-seq/ignore-this-comp.futil @@ -1,5 +1,6 @@ // -p validate -p par-to-seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32) -> (out1: 32, out2: 32) { cells { r0 = std_reg(32); diff --git a/tests/passes/par-to-seq/no-order.futil b/tests/passes/par-to-seq/no-order.futil index 5374f5a32..c005358fa 100644 --- a/tests/passes/par-to-seq/no-order.futil +++ b/tests/passes/par-to-seq/no-order.futil @@ -1,5 +1,6 @@ // -p validate -p par-to-seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r1 = std_reg(32); diff --git a/tests/passes/par-to-seq/reorder.expect b/tests/passes/par-to-seq/reorder.expect index 5594c7aaa..80d3f1b35 100644 --- a/tests/passes/par-to-seq/reorder.expect +++ b/tests/passes/par-to-seq/reorder.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r0 = std_reg(32); diff --git a/tests/passes/par-to-seq/reorder.futil b/tests/passes/par-to-seq/reorder.futil index caf106da3..4f3c2bc0c 100644 --- a/tests/passes/par-to-seq/reorder.futil +++ b/tests/passes/par-to-seq/reorder.futil @@ -1,5 +1,6 @@ // -p validate -p par-to-seq import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { r0 = std_reg(32); diff --git a/tests/passes/regressions/group-multi-drive.expect b/tests/passes/regressions/group-multi-drive.expect index 5941ab1d8..dea72219f 100644 --- a/tests/passes/regressions/group-multi-drive.expect +++ b/tests/passes/regressions/group-multi-drive.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @data r = std_reg(32); diff --git a/tests/passes/regressions/group-multi-drive.futil b/tests/passes/regressions/group-multi-drive.futil index dc40a8f69..e3eec6b13 100644 --- a/tests/passes/regressions/group-multi-drive.futil +++ b/tests/passes/regressions/group-multi-drive.futil @@ -1,5 +1,6 @@ // -p all -d static-promotion -d well-formed -d papercut -d cell-share -d group2invoke import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/schedule-compaction/continuous-compaction.expect b/tests/passes/schedule-compaction/continuous-compaction.expect index 102e5e38f..ed17ad912 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-compaction.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r0 = std_reg(8); diff --git a/tests/passes/schedule-compaction/continuous-compaction.futil b/tests/passes/schedule-compaction/continuous-compaction.futil index c64f8c02d..0f59d3826 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-compaction.futil @@ -1,6 +1,7 @@ // -p validate -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (out: 8) { cells { diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.expect b/tests/passes/schedule-compaction/continuous-no-compaction.expect index 740d15bff..842386793 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-no-compaction.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r0 = std_reg(8); diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.futil b/tests/passes/schedule-compaction/continuous-no-compaction.futil index 3f91dd934..af10d44b0 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-no-compaction.futil @@ -1,6 +1,7 @@ // -p validate -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> (out: 8) { cells { diff --git a/tests/passes/schedule-compaction/fixup-necessary.expect b/tests/passes/schedule-compaction/fixup-necessary.expect index a6129a88c..6aa7c76a4 100644 --- a/tests/passes/schedule-compaction/fixup-necessary.expect +++ b/tests/passes/schedule-compaction/fixup-necessary.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example(@go @static go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r0 = std_reg(8); @@ -20,7 +21,7 @@ component example(@go @static go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @ } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { - @external mem = std_mem_d1(8, 1, 1); + @external mem = comb_mem_d1(8, 1, 1); ex = example(); } wires {} diff --git a/tests/passes/schedule-compaction/fixup-necessary.futil b/tests/passes/schedule-compaction/fixup-necessary.futil index 990087667..e971a9aad 100644 --- a/tests/passes/schedule-compaction/fixup-necessary.futil +++ b/tests/passes/schedule-compaction/fixup-necessary.futil @@ -1,6 +1,7 @@ // -p validate -p static-inference -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component example() -> (out: 8) { cells { @@ -20,7 +21,7 @@ component example() -> (out: 8) { component main() -> () { cells { - @external mem = std_mem_d1(8, 1, 1); + @external mem = comb_mem_d1(8, 1, 1); ex = example(); } wires {} diff --git a/tests/passes/schedule-compaction/no-compact.expect b/tests/passes/schedule-compaction/no-compact.expect index af889a0e9..c4630e85e 100644 --- a/tests/passes/schedule-compaction/no-compact.expect +++ b/tests/passes/schedule-compaction/no-compact.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a_reg = std_reg(32); diff --git a/tests/passes/schedule-compaction/no-compact.futil b/tests/passes/schedule-compaction/no-compact.futil index d0b3adcec..4f1887e8c 100644 --- a/tests/passes/schedule-compaction/no-compact.futil +++ b/tests/passes/schedule-compaction/no-compact.futil @@ -1,6 +1,7 @@ // -p validate -p static-inference -p schedule-compaction -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/schedule-compaction/partial-compaction.expect b/tests/passes/schedule-compaction/partial-compaction.expect index 5acae484d..648214a17 100644 --- a/tests/passes/schedule-compaction/partial-compaction.expect +++ b/tests/passes/schedule-compaction/partial-compaction.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a_reg = std_reg(32); diff --git a/tests/passes/schedule-compaction/partial-compaction.futil b/tests/passes/schedule-compaction/partial-compaction.futil index bb7c49221..32add36bf 100644 --- a/tests/passes/schedule-compaction/partial-compaction.futil +++ b/tests/passes/schedule-compaction/partial-compaction.futil @@ -17,6 +17,7 @@ // B D // So we can compact the execution schedule to respect this data dependency import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main () -> () { cells { diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect index 1fb6f1e05..2cff214a6 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.expect +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a_reg = std_reg(32); diff --git a/tests/passes/schedule-compaction/schedule-compaction.futil b/tests/passes/schedule-compaction/schedule-compaction.futil index 26f0f04bf..719d587ea 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.futil +++ b/tests/passes/schedule-compaction/schedule-compaction.futil @@ -17,6 +17,7 @@ // B D // So we can compact the execution schedule to respect this data dependency import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main () -> () { cells { diff --git a/tests/passes/simplify-static-guards/basic.expect b/tests/passes/simplify-static-guards/basic.expect index d1a14635c..ff0a5e13d 100644 --- a/tests/passes/simplify-static-guards/basic.expect +++ b/tests/passes/simplify-static-guards/basic.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/simplify-static-guards/basic.futil b/tests/passes/simplify-static-guards/basic.futil index 4351d57eb..847390bc4 100644 --- a/tests/passes/simplify-static-guards/basic.futil +++ b/tests/passes/simplify-static-guards/basic.futil @@ -1,6 +1,7 @@ // -p simplify-static-guards import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/simplify-static-guards/simplify-or.expect b/tests/passes/simplify-static-guards/simplify-or.expect index b126ad06c..4a62efc6e 100644 --- a/tests/passes/simplify-static-guards/simplify-or.expect +++ b/tests/passes/simplify-static-guards/simplify-or.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/simplify-static-guards/simplify-or.futil b/tests/passes/simplify-static-guards/simplify-or.futil index a01944f16..091655f2f 100644 --- a/tests/passes/simplify-static-guards/simplify-or.futil +++ b/tests/passes/simplify-static-guards/simplify-or.futil @@ -1,6 +1,7 @@ // -p simplify-static-guards import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/simplify-with-control/comb-with-static.expect b/tests/passes/simplify-with-control/comb-with-static.expect index 756ac7c8a..fc4f23257 100644 --- a/tests/passes/simplify-with-control/comb-with-static.expect +++ b/tests/passes/simplify-with-control/comb-with-static.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/simplify-with-control/comb-with-static.futil -3 |static<1> component main(@go go: 1, in: 32) -> (@done done: 1) { +4 |static<1> component main(@go go: 1, in: 32) -> (@done done: 1) { |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Pass `simplify-with-control` assumption violated: Static Component main has combinational groups which is not supported diff --git a/tests/passes/simplify-with-control/comb-with-static.futil b/tests/passes/simplify-with-control/comb-with-static.futil index ff9c5bf5f..1a0ad73ce 100644 --- a/tests/passes/simplify-with-control/comb-with-static.futil +++ b/tests/passes/simplify-with-control/comb-with-static.futil @@ -1,5 +1,6 @@ // -p simplify-with-control import "primitives/core.futil"; +import "primitives/memories/comb.futil"; static<1> component main(@go go: 1, in: 32) -> (@done done: 1) { cells { e0 = std_eq(32); diff --git a/tests/passes/simplify-with-control/invoke-with.expect b/tests/passes/simplify-with-control/invoke-with.expect index 4764250c5..972590aa7 100644 --- a/tests/passes/simplify-with-control/invoke-with.expect +++ b/tests/passes/simplify-with-control/invoke-with.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/simplify-with-control/invoke-with.futil b/tests/passes/simplify-with-control/invoke-with.futil index 198ea9da9..1b6945621 100644 --- a/tests/passes/simplify-with-control/invoke-with.futil +++ b/tests/passes/simplify-with-control/invoke-with.futil @@ -1,5 +1,6 @@ // -p simplify-with-control import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { diff --git a/tests/passes/simplify-with-control/multi-use.expect b/tests/passes/simplify-with-control/multi-use.expect index 51972d5f0..1b4a56078 100644 --- a/tests/passes/simplify-with-control/multi-use.expect +++ b/tests/passes/simplify-with-control/multi-use.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { e0 = std_eq(32); diff --git a/tests/passes/simplify-with-control/multi-use.futil b/tests/passes/simplify-with-control/multi-use.futil index 1b5e23167..5aa693045 100644 --- a/tests/passes/simplify-with-control/multi-use.futil +++ b/tests/passes/simplify-with-control/multi-use.futil @@ -1,5 +1,6 @@ // -p simplify-with-control import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(in: 32) -> () { cells { e0 = std_eq(32); diff --git a/tests/passes/static-inference-promotion/component.expect b/tests/passes/static-inference-promotion/component.expect index 8870d0317..04ffd77b2 100644 --- a/tests/passes/static-inference-promotion/component.expect +++ b/tests/passes/static-inference-promotion/component.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/component.futil b/tests/passes/static-inference-promotion/component.futil index 4ff396973..27efe57a0 100644 --- a/tests/passes/static-inference-promotion/component.futil +++ b/tests/passes/static-inference-promotion/component.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/groups.expect b/tests/passes/static-inference-promotion/groups.expect index 7fab699b8..9c524c842 100644 --- a/tests/passes/static-inference-promotion/groups.expect +++ b/tests/passes/static-inference-promotion/groups.expect @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle<"promote_static"=1> { diff --git a/tests/passes/static-inference-promotion/groups.futil b/tests/passes/static-inference-promotion/groups.futil index 8d3b35ae5..679ab9499 100644 --- a/tests/passes/static-inference-promotion/groups.futil +++ b/tests/passes/static-inference-promotion/groups.futil @@ -1,11 +1,12 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1) -> (done: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle { diff --git a/tests/passes/static-inference-promotion/if-diff.expect b/tests/passes/static-inference-promotion/if-diff.expect index 3a8b024a0..aed5e1c4a 100644 --- a/tests/passes/static-inference-promotion/if-diff.expect +++ b/tests/passes/static-inference-promotion/if-diff.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/if-diff.futil b/tests/passes/static-inference-promotion/if-diff.futil index 1144bfab6..13bfa4142 100644 --- a/tests/passes/static-inference-promotion/if-diff.futil +++ b/tests/passes/static-inference-promotion/if-diff.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -x static-promotion:if-diff-limit=3 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/if-no-else.expect b/tests/passes/static-inference-promotion/if-no-else.expect index 7513abda0..779e5f91c 100644 --- a/tests/passes/static-inference-promotion/if-no-else.expect +++ b/tests/passes/static-inference-promotion/if-no-else.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/if-no-else.futil b/tests/passes/static-inference-promotion/if-no-else.futil index 618a07947..a658eac11 100644 --- a/tests/passes/static-inference-promotion/if-no-else.futil +++ b/tests/passes/static-inference-promotion/if-no-else.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/invoke.expect b/tests/passes/static-inference-promotion/invoke.expect index c8070785d..71203c3e5 100644 --- a/tests/passes/static-inference-promotion/invoke.expect +++ b/tests/passes/static-inference-promotion/invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/static-inference-promotion/invoke.futil b/tests/passes/static-inference-promotion/invoke.futil index 0d03e4399..ecc2a9d41 100644 --- a/tests/passes/static-inference-promotion/invoke.futil +++ b/tests/passes/static-inference-promotion/invoke.futil @@ -1,5 +1,6 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; /** * Tests the infer-static-timing pass. `exponent` is intentionally placed diff --git a/tests/passes/static-inference-promotion/multi-static.expect b/tests/passes/static-inference-promotion/multi-static.expect index 0b1a4d422..cd0020aef 100644 --- a/tests/passes/static-inference-promotion/multi-static.expect +++ b/tests/passes/static-inference-promotion/multi-static.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/static-inference-promotion/multi-static.futil b/tests/passes/static-inference-promotion/multi-static.futil index 53eed79bb..2361e05f9 100644 --- a/tests/passes/static-inference-promotion/multi-static.futil +++ b/tests/passes/static-inference-promotion/multi-static.futil @@ -1,5 +1,6 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; /** * Tests the infer-static-timing pass. `exponent` is intentionally placed diff --git a/tests/passes/static-inference-promotion/no_promote_loop.expect b/tests/passes/static-inference-promotion/no_promote_loop.expect index 82016867e..17c3546b0 100644 --- a/tests/passes/static-inference-promotion/no_promote_loop.expect +++ b/tests/passes/static-inference-promotion/no_promote_loop.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/no_promote_loop.futil b/tests/passes/static-inference-promotion/no_promote_loop.futil index 72032baae..cb90f4fe8 100644 --- a/tests/passes/static-inference-promotion/no_promote_loop.futil +++ b/tests/passes/static-inference-promotion/no_promote_loop.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:cycle-limit=25 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/par.expect b/tests/passes/static-inference-promotion/par.expect index 4385a77a2..395862f29 100644 --- a/tests/passes/static-inference-promotion/par.expect +++ b/tests/passes/static-inference-promotion/par.expect @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group mult_wrts_to_done { diff --git a/tests/passes/static-inference-promotion/par.futil b/tests/passes/static-inference-promotion/par.futil index 828153760..5604bf10b 100644 --- a/tests/passes/static-inference-promotion/par.futil +++ b/tests/passes/static-inference-promotion/par.futil @@ -1,11 +1,12 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1) -> (done: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle { diff --git a/tests/passes/static-inference-promotion/promote-nested.expect b/tests/passes/static-inference-promotion/promote-nested.expect index 303bf0379..a999c1d0a 100644 --- a/tests/passes/static-inference-promotion/promote-nested.expect +++ b/tests/passes/static-inference-promotion/promote-nested.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/promote-nested.futil b/tests/passes/static-inference-promotion/promote-nested.futil index 70179c484..de8435d99 100644 --- a/tests/passes/static-inference-promotion/promote-nested.futil +++ b/tests/passes/static-inference-promotion/promote-nested.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:threshold=5 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/threshold.expect b/tests/passes/static-inference-promotion/threshold.expect index 66810105d..ee2863035 100644 --- a/tests/passes/static-inference-promotion/threshold.expect +++ b/tests/passes/static-inference-promotion/threshold.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/threshold.futil b/tests/passes/static-inference-promotion/threshold.futil index f254159ce..3e6e8d046 100644 --- a/tests/passes/static-inference-promotion/threshold.futil +++ b/tests/passes/static-inference-promotion/threshold.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal -x static-promotion:threshold=4 import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference-promotion/upgrade-bound.expect b/tests/passes/static-inference-promotion/upgrade-bound.expect index ceecd138e..0bf3df2e8 100644 --- a/tests/passes/static-inference-promotion/upgrade-bound.expect +++ b/tests/passes/static-inference-promotion/upgrade-bound.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference-promotion/upgrade-bound.futil b/tests/passes/static-inference-promotion/upgrade-bound.futil index 40fc88bea..63247fbf1 100644 --- a/tests/passes/static-inference-promotion/upgrade-bound.futil +++ b/tests/passes/static-inference-promotion/upgrade-bound.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference -p static-promotion -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference/component.expect b/tests/passes/static-inference/component.expect index bf2c58deb..ea7df95b7 100644 --- a/tests/passes/static-inference/component.expect +++ b/tests/passes/static-inference/component.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference/component.futil b/tests/passes/static-inference/component.futil index 43d857c8a..443f59fae 100644 --- a/tests/passes/static-inference/component.futil +++ b/tests/passes/static-inference/component.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference/groups.expect b/tests/passes/static-inference/groups.expect index fba56d479..82a468db4 100644 --- a/tests/passes/static-inference/groups.expect +++ b/tests/passes/static-inference/groups.expect @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle<"promote_static"=1> { diff --git a/tests/passes/static-inference/groups.futil b/tests/passes/static-inference/groups.futil index f6571c0e1..f96c81b90 100644 --- a/tests/passes/static-inference/groups.futil +++ b/tests/passes/static-inference/groups.futil @@ -1,11 +1,12 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1) -> (done: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle { diff --git a/tests/passes/static-inference/if-no-else.expect b/tests/passes/static-inference/if-no-else.expect index a0c3588a2..710fa1138 100644 --- a/tests/passes/static-inference/if-no-else.expect +++ b/tests/passes/static-inference/if-no-else.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference/if-no-else.futil b/tests/passes/static-inference/if-no-else.futil index 42ae5f611..ee1813983 100644 --- a/tests/passes/static-inference/if-no-else.futil +++ b/tests/passes/static-inference/if-no-else.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference/invoke.expect b/tests/passes/static-inference/invoke.expect index ae63e3984..bc14f1aaf 100644 --- a/tests/passes/static-inference/invoke.expect +++ b/tests/passes/static-inference/invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/static-inference/invoke.futil b/tests/passes/static-inference/invoke.futil index a3ea2f77d..d09f1135e 100644 --- a/tests/passes/static-inference/invoke.futil +++ b/tests/passes/static-inference/invoke.futil @@ -1,5 +1,6 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; /** * Tests the infer-static-timing pass. `exponent` is intentionally placed diff --git a/tests/passes/static-inference/par.expect b/tests/passes/static-inference/par.expect index 356396105..9bcbe955d 100644 --- a/tests/passes/static-inference/par.expect +++ b/tests/passes/static-inference/par.expect @@ -1,9 +1,10 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (done: 1, @done done0: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle<"promote_static"=1> { diff --git a/tests/passes/static-inference/par.futil b/tests/passes/static-inference/par.futil index 4dede6857..16b994a4b 100644 --- a/tests/passes/static-inference/par.futil +++ b/tests/passes/static-inference/par.futil @@ -1,12 +1,13 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(go: 1, clk: 1) -> (done: 1) { cells { r0 = std_reg(1); r1 = std_reg(1); - m0 = std_mem_d1(32, 1, 1); + m0 = comb_mem_d1(32, 1, 1); } wires { group one_cycle { diff --git a/tests/passes/static-inference/promote-nested.expect b/tests/passes/static-inference/promote-nested.expect index bbb3e51b4..2a16eb259 100644 --- a/tests/passes/static-inference/promote-nested.expect +++ b/tests/passes/static-inference/promote-nested.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference/promote-nested.futil b/tests/passes/static-inference/promote-nested.futil index acc8e181e..9a6d61d64 100644 --- a/tests/passes/static-inference/promote-nested.futil +++ b/tests/passes/static-inference/promote-nested.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inference/promote-repeat.expect b/tests/passes/static-inference/promote-repeat.expect index c1d43dec1..afa151804 100644 --- a/tests/passes/static-inference/promote-repeat.expect +++ b/tests/passes/static-inference/promote-repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inference/promote-repeat.futil b/tests/passes/static-inference/promote-repeat.futil index 043bb0839..76991eb12 100644 --- a/tests/passes/static-inference/promote-repeat.futil +++ b/tests/passes/static-inference/promote-repeat.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inference import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-inliner/nested-repeat.expect b/tests/passes/static-inliner/nested-repeat.expect index e95a1f2a4..b938fb694 100644 --- a/tests/passes/static-inliner/nested-repeat.expect +++ b/tests/passes/static-inliner/nested-repeat.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inliner/nested-repeat.futil b/tests/passes/static-inliner/nested-repeat.futil index a6788d538..000aae662 100644 --- a/tests/passes/static-inliner/nested-repeat.futil +++ b/tests/passes/static-inliner/nested-repeat.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inline -p simplify-static-guards -p remove-ids -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -21,6 +22,6 @@ component main() -> () { } } } - + } } \ No newline at end of file diff --git a/tests/passes/static-inliner/par-if.expect b/tests/passes/static-inliner/par-if.expect index 8d4f177a1..50b19d958 100644 --- a/tests/passes/static-inliner/par-if.expect +++ b/tests/passes/static-inliner/par-if.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/static-inliner/par-if.futil b/tests/passes/static-inliner/par-if.futil index 4bcc3e8e9..82dfb3225 100644 --- a/tests/passes/static-inliner/par-if.futil +++ b/tests/passes/static-inliner/par-if.futil @@ -1,9 +1,10 @@ // -p well-formed -p static-inline -p simplify-static-guards -p remove-ids -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -// you can see how static-inliner currently adds unnecessary guards +// you can see how static-inliner currently adds unnecessary guards component main() -> () { cells { @@ -24,9 +25,9 @@ component main() -> () { } static<3> group A3 { - mult.left = 2'd1; + mult.left = 2'd1; mult.right = 2'd3; - mult.go = 1'd1; + mult.go = 1'd1; } static<1> group C { @@ -46,6 +47,6 @@ component main() -> () { static if r1.out { A; } else { C; } static seq { A3; D; } } - + } } \ No newline at end of file diff --git a/tests/passes/static-inliner/repeat-seq.expect b/tests/passes/static-inliner/repeat-seq.expect index af437aedc..44a102da6 100644 --- a/tests/passes/static-inliner/repeat-seq.expect +++ b/tests/passes/static-inliner/repeat-seq.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-inliner/repeat-seq.futil b/tests/passes/static-inliner/repeat-seq.futil index 81db86f82..7706cb695 100644 --- a/tests/passes/static-inliner/repeat-seq.futil +++ b/tests/passes/static-inliner/repeat-seq.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-inline -p simplify-static-guards -p remove-ids -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -12,14 +13,14 @@ component main() -> () { wires { group dyn_A { - a.write_en = 1'd1; - a.in = 2'd2; - dyn_A[done] = a.done; + a.write_en = 1'd1; + a.in = 2'd2; + dyn_A[done] = a.done; } group dyn_B { - b.write_en = 1'd1; - b.in = 2'd2; - dyn_B[done] = b.done; + b.write_en = 1'd1; + b.in = 2'd2; + dyn_B[done] = b.done; } static<2> group A{ a.in = 2'd0; @@ -42,12 +43,12 @@ component main() -> () { control { seq { - dyn_A; + dyn_A; static repeat 3 { static seq { A; C; D;} } dyn_B; } - + } } \ No newline at end of file diff --git a/tests/passes/static-passes/both-passes-promote.expect b/tests/passes/static-passes/both-passes-promote.expect index 014ad2d58..6601ce520 100644 --- a/tests/passes/static-passes/both-passes-promote.expect +++ b/tests/passes/static-passes/both-passes-promote.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { a = std_reg(2); diff --git a/tests/passes/static-passes/both-passes-promote.futil b/tests/passes/static-passes/both-passes-promote.futil index 2eb86d18c..fa0bd0db5 100644 --- a/tests/passes/static-passes/both-passes-promote.futil +++ b/tests/passes/static-passes/both-passes-promote.futil @@ -2,6 +2,7 @@ // Compaction should promote the body, promotion should promote the loop. import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/static-promotion/fixup-necessary.expect b/tests/passes/static-promotion/fixup-necessary.expect index c9b37d6c9..4e6976dbd 100644 --- a/tests/passes/static-promotion/fixup-necessary.expect +++ b/tests/passes/static-promotion/fixup-necessary.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/static-promotion/fixup-necessary.futil b/tests/passes/static-promotion/fixup-necessary.futil index 49ddd85e6..24c8e406e 100644 --- a/tests/passes/static-promotion/fixup-necessary.futil +++ b/tests/passes/static-promotion/fixup-necessary.futil @@ -1,6 +1,7 @@ // -p well-formed -p static-promotion -x static-promotion:threshold=5 -p dead-group-removal import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component foo(base: 32, exp: 4, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { diff --git a/tests/passes/tdcc/branch-at-start.futil b/tests/passes/tdcc/branch-at-start.futil index f8d9fdf04..811523c40 100644 --- a/tests/passes/tdcc/branch-at-start.futil +++ b/tests/passes/tdcc/branch-at-start.futil @@ -1,5 +1,6 @@ // -x tdcc:dump-fsm -d static-promotion -d attr-promotion -d post-opt -d lower -d group2invoke -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(is_valid: 1) -> () { cells { is_even = std_reg(1); diff --git a/tests/passes/tdcc/empty-exit.futil b/tests/passes/tdcc/empty-exit.futil index 695f08907..e614447e9 100644 --- a/tests/passes/tdcc/empty-exit.futil +++ b/tests/passes/tdcc/empty-exit.futil @@ -1,5 +1,6 @@ // -x tdcc:dump-fsm -d post-opt -d static-promotion -d attr-promotion -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/if.futil b/tests/passes/tdcc/if.futil index cad49f1cb..2915ad4f8 100644 --- a/tests/passes/tdcc/if.futil +++ b/tests/passes/tdcc/if.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/nested-while.futil b/tests/passes/tdcc/nested-while.futil index 7873ad358..4514a376a 100644 --- a/tests/passes/tdcc/nested-while.futil +++ b/tests/passes/tdcc/nested-while.futil @@ -1,5 +1,6 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/new-fsm-nested.futil b/tests/passes/tdcc/new-fsm-nested.futil index 616fa5562..167594a44 100644 --- a/tests/passes/tdcc/new-fsm-nested.futil +++ b/tests/passes/tdcc/new-fsm-nested.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/new-fsm-seq.futil b/tests/passes/tdcc/new-fsm-seq.futil index 3eb1c43cc..5750df841 100644 --- a/tests/passes/tdcc/new-fsm-seq.futil +++ b/tests/passes/tdcc/new-fsm-seq.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { @@ -49,6 +50,6 @@ component main() -> () { A; @new_fsm seq {C; D; E;} B; - } + } } } diff --git a/tests/passes/tdcc/par.futil b/tests/passes/tdcc/par.futil index d8eee0905..4f7b1a782 100644 --- a/tests/passes/tdcc/par.futil +++ b/tests/passes/tdcc/par.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/seq-with-same-done.futil b/tests/passes/tdcc/seq-with-same-done.futil index d5b14e3e1..bf68799db 100644 --- a/tests/passes/tdcc/seq-with-same-done.futil +++ b/tests/passes/tdcc/seq-with-same-done.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(1); diff --git a/tests/passes/tdcc/seq.futil b/tests/passes/tdcc/seq.futil index cbb20f8c6..cbeda6d2b 100644 --- a/tests/passes/tdcc/seq.futil +++ b/tests/passes/tdcc/seq.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/tdcc/while-if.futil b/tests/passes/tdcc/while-if.futil index 19864ccad..034d995ed 100644 --- a/tests/passes/tdcc/while-if.futil +++ b/tests/passes/tdcc/while-if.futil @@ -1,5 +1,6 @@ // -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { is_even = std_reg(1); diff --git a/tests/passes/tdcc/while.futil b/tests/passes/tdcc/while.futil index 938da9a96..c2cf39b59 100644 --- a/tests/passes/tdcc/while.futil +++ b/tests/passes/tdcc/while.futil @@ -1,6 +1,7 @@ // -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/unroll-bound.expect b/tests/passes/unroll-bound.expect index f280d1f0b..ee4edbb30 100644 --- a/tests/passes/unroll-bound.expect +++ b/tests/passes/unroll-bound.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/unroll-bound.futil b/tests/passes/unroll-bound.futil index ad1438356..564b6584d 100644 --- a/tests/passes/unroll-bound.futil +++ b/tests/passes/unroll-bound.futil @@ -1,5 +1,6 @@ // -p validate -p unroll-bound import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/unsharing/continuous.expect b/tests/passes/unsharing/continuous.expect index 7c259ed3a..63904ee94 100644 --- a/tests/passes/unsharing/continuous.expect +++ b/tests/passes/unsharing/continuous.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/unsharing/continuous.futil b/tests/passes/unsharing/continuous.futil index 5fbde95c2..efb99043f 100644 --- a/tests/passes/unsharing/continuous.futil +++ b/tests/passes/unsharing/continuous.futil @@ -1,5 +1,6 @@ // -p register-unsharing import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/unsharing/invoke.expect b/tests/passes/unsharing/invoke.expect index e1a83b8e6..bbde9be77 100644 --- a/tests/passes/unsharing/invoke.expect +++ b/tests/passes/unsharing/invoke.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { adder = std_add(32); diff --git a/tests/passes/unsharing/invoke.futil b/tests/passes/unsharing/invoke.futil index 9c228e61f..612890b8c 100644 --- a/tests/passes/unsharing/invoke.futil +++ b/tests/passes/unsharing/invoke.futil @@ -1,5 +1,6 @@ // -p register-unsharing import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component add(left: 32, right: 32) -> (out: 32) { cells { diff --git a/tests/passes/unsharing/unshare-par.expect b/tests/passes/unsharing/unshare-par.expect index d73261dc2..721d2e863 100644 --- a/tests/passes/unsharing/unshare-par.expect +++ b/tests/passes/unsharing/unshare-par.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { x = std_reg(32); diff --git a/tests/passes/unsharing/unshare-par.futil b/tests/passes/unsharing/unshare-par.futil index bb0ae1b48..326fe8c5b 100644 --- a/tests/passes/unsharing/unshare-par.futil +++ b/tests/passes/unsharing/unshare-par.futil @@ -1,5 +1,6 @@ // -p register-unsharing import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/unsharing/unsharing.expect b/tests/passes/unsharing/unsharing.expect index d285ab164..73327427a 100644 --- a/tests/passes/unsharing/unsharing.expect +++ b/tests/passes/unsharing/unsharing.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/unsharing/unsharing.futil b/tests/passes/unsharing/unsharing.futil index 411e4b9b9..c13386fce 100644 --- a/tests/passes/unsharing/unsharing.futil +++ b/tests/passes/unsharing/unsharing.futil @@ -1,5 +1,6 @@ // -p register-unsharing import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/unsharing/while.expect b/tests/passes/unsharing/while.expect index 86ba4bb27..6d459dda2 100644 --- a/tests/passes/unsharing/while.expect +++ b/tests/passes/unsharing/while.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r = std_reg(32); diff --git a/tests/passes/unsharing/while.futil b/tests/passes/unsharing/while.futil index e864f205a..a5240f17e 100644 --- a/tests/passes/unsharing/while.futil +++ b/tests/passes/unsharing/while.futil @@ -1,5 +1,6 @@ // -p register-unsharing import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tests/passes/well-formed/constant-ref-cell.expect b/tests/passes/well-formed/constant-ref-cell.expect index 41d477a6d..813c25ba8 100644 --- a/tests/passes/well-formed/constant-ref-cell.expect +++ b/tests/passes/well-formed/constant-ref-cell.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/well-formed/constant-ref-cell.futil -8 | ref m2 = std_const(2, 1); +9 | ref m2 = std_const(2, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: constant not allowed for ref cells diff --git a/tests/passes/well-formed/constant-ref-cell.futil b/tests/passes/well-formed/constant-ref-cell.futil index f14435d4a..01dd7d31a 100644 --- a/tests/passes/well-formed/constant-ref-cell.futil +++ b/tests/passes/well-formed/constant-ref-cell.futil @@ -1,5 +1,6 @@ -// -p well-formed +// -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/well-formed/guard-out-of-bounds.expect b/tests/passes/well-formed/guard-out-of-bounds.expect index 604c4d76f..59d0f68b7 100644 --- a/tests/passes/well-formed/guard-out-of-bounds.expect +++ b/tests/passes/well-formed/guard-out-of-bounds.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/well-formed/guard-out-of-bounds.futil -10 | r1.write_en = %2 ? 1'd1; +11 | r1.write_en = %2 ? 1'd1; | ^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: Static Timing Guard has interval `%2`, which is out of bounds since its static group has latency 2 diff --git a/tests/passes/well-formed/guard-out-of-bounds.futil b/tests/passes/well-formed/guard-out-of-bounds.futil index d127b9960..cc7437dc9 100644 --- a/tests/passes/well-formed/guard-out-of-bounds.futil +++ b/tests/passes/well-formed/guard-out-of-bounds.futil @@ -1,5 +1,6 @@ //-p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { @@ -7,7 +8,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires { static<2> group A { - r1.write_en = %2 ? 1'd1; + r1.write_en = %2 ? 1'd1; r1.in = 32'd2; } } diff --git a/tests/passes/well-formed/main-ref-cell.expect b/tests/passes/well-formed/main-ref-cell.expect index 88b55b6bd..c21429aaa 100644 --- a/tests/passes/well-formed/main-ref-cell.expect +++ b/tests/passes/well-formed/main-ref-cell.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/well-formed/main-ref-cell.futil -7 | ref m = std_const(2,1); +8 | ref m = std_const(2,1); | ^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: ref cells are not allowed for main component diff --git a/tests/passes/well-formed/main-ref-cell.futil b/tests/passes/well-formed/main-ref-cell.futil index 4bf01bd78..f7f43bcaf 100644 --- a/tests/passes/well-formed/main-ref-cell.futil +++ b/tests/passes/well-formed/main-ref-cell.futil @@ -1,5 +1,6 @@ // -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/well-formed/ref-incorrect-name.futil b/tests/passes/well-formed/ref-incorrect-name.futil index 06e0c564f..c64e68e19 100644 --- a/tests/passes/well-formed/ref-incorrect-name.futil +++ b/tests/passes/well-formed/ref-incorrect-name.futil @@ -1,5 +1,6 @@ //-p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/well-formed/ref-invoke-unmentioned.expect b/tests/passes/well-formed/ref-invoke-unmentioned.expect index bf33a7e74..e97a4b06c 100644 --- a/tests/passes/well-formed/ref-invoke-unmentioned.expect +++ b/tests/passes/well-formed/ref-invoke-unmentioned.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/well-formed/ref-invoke-unmentioned.futil -32 | invoke f()(); +33 | invoke f()(); | ^^^^^^^^^^^^^ Malformed Control: unmentioned ref cell: m diff --git a/tests/passes/well-formed/ref-invoke-unmentioned.futil b/tests/passes/well-formed/ref-invoke-unmentioned.futil index 1ce5ec239..34a3b8372 100644 --- a/tests/passes/well-formed/ref-invoke-unmentioned.futil +++ b/tests/passes/well-formed/ref-invoke-unmentioned.futil @@ -1,5 +1,6 @@ -// -p well-formed +// -p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/well-formed/ref-type-mismatch.expect b/tests/passes/well-formed/ref-type-mismatch.expect index 864ebaef8..bc687225a 100644 --- a/tests/passes/well-formed/ref-type-mismatch.expect +++ b/tests/passes/well-formed/ref-type-mismatch.expect @@ -1,4 +1,4 @@ ---STDERR--- Error: tests/passes/well-formed/ref-type-mismatch.futil -32 | invoke f[m = k1]()(); +33 | invoke f[m = k1]()(); | ^^^^^^^^^^^^^^^^^^^^^ Malformed Control: Unexpected type for ref cell. Expected `std_reg(32)`, received `std_reg(16)` diff --git a/tests/passes/well-formed/ref-type-mismatch.futil b/tests/passes/well-formed/ref-type-mismatch.futil index 64bae88f9..d926f0798 100644 --- a/tests/passes/well-formed/ref-type-mismatch.futil +++ b/tests/passes/well-formed/ref-type-mismatch.futil @@ -1,5 +1,6 @@ //-p well-formed import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/wire-inliner.expect b/tests/passes/wire-inliner.expect index f70637c5c..8a0502f64 100644 --- a/tests/passes/wire-inliner.expect +++ b/tests/passes/wire-inliner.expect @@ -1,4 +1,5 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { r1 = std_reg(32); diff --git a/tests/passes/wire-inliner.futil b/tests/passes/wire-inliner.futil index 8013cd7cb..072ebed35 100644 --- a/tests/passes/wire-inliner.futil +++ b/tests/passes/wire-inliner.futil @@ -1,6 +1,7 @@ // -p go-insertion -p wire-inliner import "primitives/core.futil"; +import "primitives/memories/comb.futil"; component main() -> () { cells { diff --git a/tools/btor2/core/std_mem_d1.btor b/tools/btor2/core/std_mem_d1.btor index 93d0096b8..34918fe27 100644 --- a/tools/btor2/core/std_mem_d1.btor +++ b/tools/btor2/core/std_mem_d1.btor @@ -1,4 +1,4 @@ -; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d1. +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module comb_mem_d1. 1 sort bitvec 4 2 input 1 addr0 ; core.sv:232.38-232.43 3 sort bitvec 1 diff --git a/tools/btor2/core/std_mem_d2.btor b/tools/btor2/core/std_mem_d2.btor index f6e415d6f..9144f1ebf 100644 --- a/tools/btor2/core/std_mem_d2.btor +++ b/tools/btor2/core/std_mem_d2.btor @@ -1,4 +1,4 @@ -; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d2. +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module comb_mem_d2. 1 sort bitvec 4 2 input 1 addr0 ; core.sv:272.41-272.46 3 input 1 addr1 ; core.sv:273.41-273.46 diff --git a/tools/btor2/core/std_mem_d3.btor b/tools/btor2/core/std_mem_d3.btor index e6377b484..2d35a0c1a 100644 --- a/tools/btor2/core/std_mem_d3.btor +++ b/tools/btor2/core/std_mem_d3.btor @@ -1,4 +1,4 @@ -; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d3. +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module comb_mem_d3. 1 sort bitvec 4 2 input 1 addr0 ; core.sv:317.41-317.46 3 input 1 addr1 ; core.sv:318.41-318.46 diff --git a/tools/btor2/core/std_mem_d4.btor b/tools/btor2/core/std_mem_d4.btor index 03079b834..16d6bf7d3 100644 --- a/tools/btor2/core/std_mem_d4.btor +++ b/tools/btor2/core/std_mem_d4.btor @@ -1,4 +1,4 @@ -; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module std_mem_d4. +; BTOR description generated by Yosys 0.33+65 (git sha1 90124dce5, clang 15.0.0 -fPIC -Os) for module comb_mem_d4. 1 sort bitvec 4 2 input 1 addr0 ; core.sv:367.41-367.46 3 input 1 addr1 ; core.sv:368.41-368.46 diff --git a/tools/data_gen/src/main.rs b/tools/data_gen/src/main.rs index cbcbdba15..504af8647 100644 --- a/tools/data_gen/src/main.rs +++ b/tools/data_gen/src/main.rs @@ -23,11 +23,11 @@ lazy_static::lazy_static! { "seq_mem_d4", vec!["D0_SIZE", "D1_SIZE", "D2_SIZE", "D3_SIZE"], ), - ("std_mem_d1", vec!["SIZE"]), - ("std_mem_d2", vec!["D0_SIZE", "D1_SIZE"]), - ("std_mem_d3", vec!["D0_SIZE", "D1_SIZE", "D2_SIZE"]), + ("comb_mem_d1", vec!["SIZE"]), + ("comb_mem_d2", vec!["D0_SIZE", "D1_SIZE"]), + ("comb_mem_d3", vec!["D0_SIZE", "D1_SIZE", "D2_SIZE"]), ( - "std_mem_d4", + "comb_mem_d4", vec!["D0_SIZE", "D1_SIZE", "D2_SIZE", "D3_SIZE"], ), ] @@ -38,7 +38,7 @@ lazy_static::lazy_static! { /// Holds data for std_mem cells, including name of cell, width, and sizes /// Name is the name of cell itself, not its type. Sizes is a vector -/// that holds the dimensions of the cell (ex: for a 2 x 3 std_mem_d2 cell it would be [2,3]) +/// that holds the dimensions of the cell (ex: for a 2 x 3 comb_mem_d2 cell it would be [2,3]) struct CellData { name: String, width: u64, diff --git a/tools/data_gen/tests/all.futil b/tools/data_gen/tests/all.futil index 1a1e77378..b354cbc6d 100644 --- a/tools/data_gen/tests/all.futil +++ b/tools/data_gen/tests/all.futil @@ -1,15 +1,16 @@ import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; component main() -> () { cells { - @external(1) d4_ex = std_mem_d4(32,2,3,5,2,4,4,4,4); - @external(1) d3_ex = std_mem_d3(32,3,2,6,4,4,4); - @external(1) d2_ex= std_mem_d2(32,4,2,4,4); - @external(1) d1_ex= std_mem_d1(32,5,4); - @external(1) d2_ex2= std_mem_d2(32,5,3,4,4); + @external(1) d4_ex = comb_mem_d4(32,2,3,5,2,4,4,4,4); + @external(1) d3_ex = comb_mem_d3(32,3,2,6,4,4,4); + @external(1) d2_ex= comb_mem_d2(32,4,2,4,4); + @external(1) d1_ex= comb_mem_d1(32,5,4); + @external(1) d2_ex2= comb_mem_d2(32,5,3,4,4); } wires { - + } control { } diff --git a/tools/firrtl/templates/std_mem_d1.fir b/tools/firrtl/templates/std_mem_d1.fir index 83bbd340b..674acc9de 100644 --- a/tools/firrtl/templates/std_mem_d1.fir +++ b/tools/firrtl/templates/std_mem_d1.fir @@ -1,4 +1,4 @@ - module std_mem_d1_WIDTH_SIZE_IDX_SIZE : + module comb_mem_d1_WIDTH_SIZE_IDX_SIZE : input add0 : UInt input write_data : UInt input write_en : UInt<1> diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index f28f30d2d..6e5b1db55 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -8,13 +8,14 @@ // It assumes a bus data width of 32. // This hardcoded work will be used to guide generation work of AXI moving forward. -// it is somewhat messy and is hopefully destined to be removed from the repo eventually. +// it is somewhat messy and is hopefully destined to be removed from the repo eventually. // ### import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/compile.futil"; import "primitives/math.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; // ############################# @@ -37,7 +38,7 @@ component m_arread_channel( // for restrictions ARSIZE: 3, // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - ARLEN : 8, + ARLEN : 8, // 00 for fixed, 01 for incrementing, 2 for wrap, // needs to be incr for RTL kernels (can't use wrapped or fixed) ARBURST : 2, @@ -51,7 +52,7 @@ component m_arread_channel( // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` // but for now will live here. ref curr_addr_axi = std_reg(64); - + // number of trasfers in a transaction. This is sent to subordinate txn_len = std_reg(8); @@ -79,7 +80,7 @@ component m_arread_channel( group do_ar_transfer { //assert ARVALID as long as this is the first time we are asserting it is_arvalid.in = !ar_handshake_occurred.out ? 1'b1; - + // This makes ARVALID go low after a single cycle. // Without it it stays high for 2 cycles @@ -91,11 +92,11 @@ component m_arread_channel( ar_handshake_occurred.write_en = !(is_arvalid.out & ARREADY) & !ar_handshake_occurred.out ? 1'b1; - // drive output signals for transfer + // drive output signals for transfer ARADDR = curr_addr_axi.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - ARSIZE = 3'b010; + ARSIZE = 3'b010; // For now this can be taken from .yxi, as size of mem, because we are assuming // data_bus width that matches size of memory cells // If we want to use bigger mems need to be able to update base addr @@ -158,7 +159,7 @@ component m_read_channel( ARESET : 1, RVALID : 1, RLAST : 1, - RDATA : 32, + RDATA : 32, RRESP : 2, // Note: This is generated in subordinate! had this backwards in earlier version ) -> ( // NOTE: In general, according to ZipCPU we want xREADY signals to be registered @@ -174,7 +175,7 @@ component m_read_channel( ref curr_addr_internal_mem = std_reg(64); //need to increment this ref curr_addr_axi = std_reg(64); - + // registered because RLAST is high with last transfer, not after // before this was registered we were terminating immediately with // last transfer and not servicing it @@ -188,7 +189,7 @@ component m_read_channel( curr_addr_axi_adder = std_add(64); // block_transfer reg to avoid combinational loops - // Used to block any servicing until handshake occurs. + // Used to block any servicing until handshake occurs. bt_reg = std_reg(1); } @@ -228,7 +229,7 @@ component m_read_channel( n_RLAST.in = RLAST ? 1'b0; n_RLAST.in = !RLAST ? 1'b1; n_RLAST.write_en = 1'b1; - + // we are done after handshake bt_reg.in = is_rdy.out & RVALID ? 1'b1; @@ -399,7 +400,7 @@ component m_awwrite_channel( // for restrictions AWSIZE: 3, // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - AWLEN : 8, + AWLEN : 8, // 00 for fixed, 01 for incrementing, 2 for wrap, // needs to be incr for RTL kernels (can't use wrapped or fixed) AWBURST : 2, @@ -416,7 +417,7 @@ component m_awwrite_channel( //we write to this here and read from it in m_write_channel ref max_trnsfrs = std_reg(8); - + // number of transfers in a transaction. This is sent to subordinate txn_len = std_reg(8); @@ -444,7 +445,7 @@ component m_awwrite_channel( group do_aw_transfer { //assert AWVALID is_awvalid.in = !(is_awvalid.out & AWREADY) & !aw_handshake_occurred.out ? 1'b1; - + // TODO(nathanielnrn): in theory should be able to get rid of aw_handshake_occurred // but for now we will be explicit and reduce this in generation maybe. Not sure // it even matters. @@ -456,11 +457,11 @@ component m_awwrite_channel( aw_handshake_occurred.write_en = !aw_handshake_occurred.out ? 1'b1; - // drive output signals for transfer + // drive output signals for transfer AWADDR = curr_addr_axi.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - AWSIZE = 3'b010; + AWSIZE = 3'b010; // For now this can be taken from .yxi, as size of mem, because we are assuming // data_bus width that matches size of memory cells // If we want to use bigger mems need to be able to update base addr @@ -473,7 +474,7 @@ component m_awwrite_channel( // TODO(nathanielnrn): This is used to tell write_channel how many transfers to do // we eventually want this to correspond to AWLEN // (need a case statement or mux or something) - // for now hardcoding to 15 for 16 transfers + // for now hardcoding to 15 for 16 transfers max_trnsfrs.in = 8'd7; max_trnsfrs.write_en = 1'b1; @@ -529,7 +530,7 @@ component m_write_channel( ) -> ( WVALID : 1, WLAST : 1, - WDATA : 32, + WDATA : 32, ) { cells { // 16 is due to dot-product vector length assumption @@ -541,7 +542,7 @@ component m_write_channel( // used internally to access our seq_mem_d1 ref curr_addr_internal_mem = std_reg(64); ref curr_addr_axi = std_reg(64); - + //this increments curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count //this is number of transfer we want to do @@ -586,17 +587,17 @@ component m_write_channel( w_handshake_occurred.in = wvalid.out & WREADY ? 1'b1; w_handshake_occurred.write_en = !w_handshake_occurred.out ? 1'b1; - + // set data output based on curr_addr_internal_mem register internal_mem.addr0 = curr_addr_internal_mem.out; internal_mem.read_en = 1'b1; WDATA = internal_mem.read_data; - + //set wlast WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; - - //set high only when WLAST is high and a handshake occurs. + + //set high only when WLAST is high and a handshake occurs. n_finished_last_trnsfr.in = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b0; n_finished_last_trnsfr.write_en = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b1; @@ -616,7 +617,7 @@ component m_write_channel( curr_addr_internal_mem.write_en = 1'b1; incr_curr_addr_internal_mem[done] = curr_addr_internal_mem.done; } - + group incr_curr_addr_axi{ curr_addr_axi_adder.left = 64'd4; //32-bit/8. TODO:parameterize via mem width curr_addr_axi_adder.right = curr_addr_axi.out; @@ -721,10 +722,10 @@ component main( // Used only for waveform tracing. Not sent anywhere // Note AXI4 has this at 2 bits, while latest has it at 3. m0_BRESP : 2, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m0_RID : 1, - + m1_ARESET : 1, m1_ARREADY : 1, @@ -743,7 +744,7 @@ component main( // Used only for waveform tracing. Not sent anywhere // Note AXI4 has this at 2 bits, while latest has it at 3. m1_BRESP : 2, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m1_RID : 1, @@ -766,14 +767,14 @@ component main( // Used only for waveform tracing. Not sent anywhere // Note AXI4 has this at 2 bits, while latest has it at 3. m2_BRESP : 2, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m2_RID : 1 ) -> ( m0_ARVALID : 1, m0_ARADDR : 64, m0_ARSIZE : 3, - m0_ARLEN : 8, + m0_ARLEN : 8, m0_ARBURST : 2, m0_RREADY : 1, @@ -781,7 +782,7 @@ component main( m0_AWVALID : 1, m0_AWADDR : 64, m0_AWSIZE : 3, - m0_AWLEN : 8, + m0_AWLEN : 8, m0_AWBURST : 2, m0_AWPROT : 3, @@ -790,17 +791,17 @@ component main( m0_WDATA : 32, m0_BREADY : 1, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m0_ARID : 1, m0_AWID : 1, m0_WID : 1, m0_BID : 1, - + m1_ARVALID : 1, m1_ARADDR : 64, m1_ARSIZE : 3, - m1_ARLEN : 8, + m1_ARLEN : 8, m1_ARBURST : 2, m1_RREADY : 1, @@ -808,7 +809,7 @@ component main( m1_AWVALID : 1, m1_AWADDR : 64, m1_AWSIZE : 3, - m1_AWLEN : 8, + m1_AWLEN : 8, m1_AWBURST : 2, m1_AWPROT : 3, @@ -817,7 +818,7 @@ component main( m1_WDATA : 32, m1_BREADY : 1, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m1_ARID : 1, m1_AWID : 1, @@ -828,7 +829,7 @@ component main( m2_ARVALID : 1, m2_ARADDR : 64, m2_ARSIZE : 3, - m2_ARLEN : 8, + m2_ARLEN : 8, m2_ARBURST : 2, m2_RREADY : 1, @@ -836,7 +837,7 @@ component main( m2_AWVALID : 1, m2_AWADDR : 64, m2_AWSIZE : 3, - m2_AWLEN : 8, + m2_AWLEN : 8, m2_AWBURST : 2, m2_AWPROT : 3, @@ -845,7 +846,7 @@ component main( m2_WDATA : 32, m2_BREADY : 1, - + //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. m2_ARID : 1, m2_AWID : 1, @@ -877,10 +878,10 @@ component main( // original vec_add and we raised them to top level. A0 = seq_mem_d1(32,8,64); B0 = seq_mem_d1(32,8,64); - Sum0 = seq_mem_d1(32,8,64); + Sum0 = seq_mem_d1(32,8,64); vec_add_cell = vec_add();//end vec add stuff - + //original write stuff max_trnsfrs = std_reg(8); diff --git a/yxi/axi-calyx/axi-reads-calyx.futil b/yxi/axi-calyx/axi-reads-calyx.futil index 903b97dd5..b566cbe5c 100644 --- a/yxi/axi-calyx/axi-reads-calyx.futil +++ b/yxi/axi-calyx/axi-reads-calyx.futil @@ -11,9 +11,10 @@ // ### import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/compile.futil"; import "primitives/math.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; //this goes m->s unlike read channel @@ -31,7 +32,7 @@ component m_arread_channel( // for restrictions ARSIZE: 3, // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - ARLEN : 8, + ARLEN : 8, // 00 for fixed, 01 for incrementing, 2 for wrap, // needs to be incr for RTL kernels (can't use wrapped of fixed ARBURST : 2, @@ -45,7 +46,7 @@ component m_arread_channel( // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` // but for now will live here. ref base_addr = std_reg(64); - + // number of trasfers in a transaction. This is sent to subordinate txn_len = std_reg(8); @@ -85,7 +86,7 @@ component m_arread_channel( group do_ar_transfer { //assert ARVALID is_arvalid.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - + // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high // but for now we will be explicit and reduce this in generation maybe. Not sure // it even matters. @@ -97,11 +98,11 @@ component m_arread_channel( arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - // drive output signals for transfer + // drive output signals for transfer ARADDR = base_addr.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - ARSIZE = 3'b010; + ARSIZE = 3'b010; // For now this can be taken from .yxi, as size of mem, because we are assuming // data_bus width that matches size of memory cells // If we want to use bigger mems need to be able to update base addr @@ -125,7 +126,7 @@ component m_arread_channel( txn_count.in = 32'b0; txn_count.write_en = 1'b1; txn_count_init[done] = txn_count.done; - + } group txn_len_init { @@ -175,7 +176,7 @@ component m_read_channel( ARESET : 1, RVALID : 1, RLAST : 1, - RDATA : 32, + RDATA : 32, RRESP : 2, // Note: This is generated in subordinate! had this backwards in earlier version ) -> ( // NOTE: In general, according to ZipCPU we want xREADY signals to be registered @@ -188,8 +189,8 @@ component m_read_channel( // on the data we read from cocotb ref data_received = seq_mem_d1(32, 16, 64); is_rdy = std_reg(1); - ref curr_addr = std_reg(64); - + ref curr_addr = std_reg(64); + // registered because RLAST is high with last transfer, not after // before this was registered we were terminating immediately with // last transfer and not servicing it @@ -216,7 +217,7 @@ component m_read_channel( init_n_RLAST[done] = n_RLAST.done; } - // Used to block any servicing until handshake occurs. + // Used to block any servicing until handshake occurs. group reset_bt { bt_reg.in = 1'b0; bt_reg.write_en = 1'b1; @@ -250,7 +251,7 @@ component m_read_channel( n_RLAST.in = RLAST ? 1'b0; n_RLAST.in = !RLAST ? 1'b1; n_RLAST.write_en = 1'b1; - + // we are done after handshake bt_reg.in = is_rdy.out & RVALID ? 1'b1; @@ -309,7 +310,7 @@ component main( m_ARVALID : 1, m_ARADDR: 64, m_ARSIZE: 3, - m_ARLEN : 8, + m_ARLEN : 8, m_ARBURST : 2, m_RREADY : 1, diff --git a/yxi/axi-calyx/axi-writes-calyx.futil b/yxi/axi-calyx/axi-writes-calyx.futil index c10e5e095..402d9f8a4 100644 --- a/yxi/axi-calyx/axi-writes-calyx.futil +++ b/yxi/axi-calyx/axi-writes-calyx.futil @@ -11,9 +11,10 @@ // ### import "primitives/core.futil"; +import "primitives/memories/comb.futil"; import "primitives/compile.futil"; import "primitives/math.futil"; -import "primitives/memories.futil"; +import "primitives/memories/seq.futil"; //this goes m->s @@ -31,7 +32,7 @@ component m_awwrite_channel( // for restrictions AWSIZE: 3, // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - AWLEN : 8, + AWLEN : 8, // 00 for fixed, 01 for incrementing, 2 for wrap, // needs to be incr for RTL kernels (can't use wrapped or fixed) AWBURST : 2, @@ -48,7 +49,7 @@ component m_awwrite_channel( //we write to this here and read from it in m_write_channel ref max_trnsfrs = std_reg(8); - + // number of trasfers in a transaction. This is sent to subordinate txn_len = std_reg(8); @@ -88,7 +89,7 @@ component m_awwrite_channel( group do_aw_transfer { //assert AWVALID is_awvalid.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - + // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high // but for now we will be explicit and reduce this in generation maybe. Not sure // it even matters. @@ -100,11 +101,11 @@ component m_awwrite_channel( awvalid_was_high.write_en = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - // drive output signals for transfer + // drive output signals for transfer AWADDR = base_addr.out; // see link above, needs to match data width to host. // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - AWSIZE = 3'b010; + AWSIZE = 3'b010; // For now this can be taken from .yxi, as size of mem, because we are assuming // data_bus width that matches size of memory cells // If we want to use bigger mems need to be able to update base addr @@ -117,7 +118,7 @@ component m_awwrite_channel( // TODO(nathanielnrn): This is used to tell write_channel how many transfers to do // we eventually want this to correspond to AWLEN // (need a case statement or mux or something) - // for now hardcoding to 15 for 16 transfers + // for now hardcoding to 15 for 16 transfers max_trnsfrs.in = 8'd15; max_trnsfrs.write_en = 1'b1; @@ -135,7 +136,7 @@ component m_awwrite_channel( txn_count.in = 32'b0; txn_count.write_en = 1'b1; txn_count_init[done] = txn_count.done; - + } group txn_len_init { @@ -187,7 +188,7 @@ component m_write_channel( ) -> ( WVALID : 1, WLAST : 1, - WDATA : 32, + WDATA : 32, ) { cells { // 16 is due to dot-product vector length assumption @@ -197,8 +198,8 @@ component m_write_channel( wvalid = std_reg(1); wvalid_was_high = std_reg(1); // used internally to access our seq_mem_d1 - ref curr_addr = std_reg(64); - + ref curr_addr = std_reg(64); + //this increments curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count //this is number of transfer we want to do @@ -272,7 +273,7 @@ component m_write_channel( init_n_finished_last_trnsfr[done] = n_finished_last_trnsfr.done; } - //Used to block any servicing until handshake occurs. + //Used to block any servicing until handshake occurs. group reset_bt { bt_reg.in = 1'b0; bt_reg.write_en = 1'b1; @@ -299,17 +300,17 @@ component m_write_channel( wvalid_was_high.in = 1'b1; wvalid_was_high.write_en = !(wvalid.out & WREADY) & !wvalid_was_high.out ? 1'b1; - + // set data output based on curr_addr register internal_mem.addr0 = curr_addr.out; internal_mem.read_en = 1'b1; WDATA = internal_mem.read_data; - + //set wlast WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; - - //set high only when WLAST is high and a handshake occurs. + + //set high only when WLAST is high and a handshake occurs. n_finished_last_trnsfr.in = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b0; n_finished_last_trnsfr.write_en = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b1; @@ -437,7 +438,7 @@ component main( m_AWVALID : 1, m_AWADDR: 64, m_AWSIZE: 3, - m_AWLEN : 8, + m_AWLEN : 8, m_AWBURST : 2, m_AWPROT : 3, From deeae3e5c01ff535019fcf67196b38fc72e57e75 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro <36107281+ayakayorihiro@users.noreply.github.com> Date: Wed, 7 Feb 2024 13:45:17 -0500 Subject: [PATCH 169/189] [Calyx-FIRRTL] Debugged FIRRTL implementations of primitives (#1907) * Debug std_reg FIRRTL implementation * Fix std_const template typo * Fix std_lsh FIRRTL primitive * Fixed std_reg bug that was causing to fail --- .../firrtl/generate-firrtl-with-primitives.py | 6 +++++- tools/firrtl/templates/std_const.fir | 2 +- tools/firrtl/templates/std_lsh.fir | 2 +- tools/firrtl/templates/std_reg.fir | 20 +++++++++++-------- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/tools/firrtl/generate-firrtl-with-primitives.py b/tools/firrtl/generate-firrtl-with-primitives.py index b6d216393..b1f8be670 100644 --- a/tools/firrtl/generate-firrtl-with-primitives.py +++ b/tools/firrtl/generate-firrtl-with-primitives.py @@ -1,4 +1,5 @@ import json +import math import os import sys @@ -13,6 +14,9 @@ def generate_replacement_map(inst): replacement_map["DIFF"] = replacement_map["OUT_WIDTH"] - replacement_map["IN_WIDTH"] elif inst["name"] == "std_slice": replacement_map["DIFF"] = replacement_map["IN_WIDTH"] - replacement_map["OUT_WIDTH"] + elif inst["name"] == "std_lsh": + width = replacement_map["WIDTH"] + replacement_map["BITS"] = math.ceil(math.log(width, 2)) + 1 return replacement_map @@ -62,4 +66,4 @@ def main(): generate(sys.argv[1], sys.argv[2]) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/tools/firrtl/templates/std_const.fir b/tools/firrtl/templates/std_const.fir index 27a66a93d..9c0fc5473 100644 --- a/tools/firrtl/templates/std_const.fir +++ b/tools/firrtl/templates/std_const.fir @@ -1,3 +1,3 @@ - module std_const_WIDTH_VAL : + module std_const_WIDTH_VALUE : output out : UInt out <= UInt(VALUE) diff --git a/tools/firrtl/templates/std_lsh.fir b/tools/firrtl/templates/std_lsh.fir index 934883c08..adae3394e 100644 --- a/tools/firrtl/templates/std_lsh.fir +++ b/tools/firrtl/templates/std_lsh.fir @@ -3,4 +3,4 @@ input right : UInt output out : UInt - out <= dshl(left, right) + out <= dshl(left, bits(right, BITS, 0)) diff --git a/tools/firrtl/templates/std_reg.fir b/tools/firrtl/templates/std_reg.fir index fe9a4192f..1ecc93cc2 100644 --- a/tools/firrtl/templates/std_reg.fir +++ b/tools/firrtl/templates/std_reg.fir @@ -7,13 +7,17 @@ output done : UInt<1> reg internal_reg : UInt, clk - out <= UInt(0) - when eq(write_en, UInt(1)): - out <= in - done <= UInt(1) + reg done_reg : UInt<1>, clk + + when eq(reset, UInt(1)): + internal_reg <= UInt(0) + done_reg <= UInt(0) else: - when eq(reset, UInt(1)): - done <= UInt(0) - out <= UInt(0) + when eq(write_en, UInt(1)): + internal_reg <= in + done_reg <= UInt(1) else: - done <= UInt(0) + done_reg <= UInt(0) + + out <= internal_reg + done <= done_reg From 35ca2021b90ab7cb76be885561ff62ad61064b4b Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Fri, 9 Feb 2024 10:54:53 -0500 Subject: [PATCH 170/189] Deprecate `@static` (#1897) * replace static w// interval * change primitives to @interval * modified tests * promte_static -> promotable * get rid of static * remove attribute_promotion * py frontend uses promotable * rewrite exp tests * corrected some tests * overwrite tests * overwrite failing tests * change interface * add tests * add well formed check * change compile_invoke * add tests * compile invoke test * change iterface * adjustments * fix borrow error * clippy * move files * fix test * rewrite mlir test * always promote @interval * interp tests * documentation * dummy change * static->interval * update tests * add documentation to compile-static-interface * well formed check' * small change * done * tests * rewrite test * dummy change * github workflow * docker file checks out main * checkout master * checkout specific version * go back to og dockerfile * checkout specific commit * does this work * still not working * dummy change so non-merge commit * chatgpt no cache * does this change things * modify relay tests --- Dockerfile | 4 +- calyx-frontend/src/attribute.rs | 24 +++-- calyx-ir/src/control.rs | 5 ++ calyx-ir/src/from_ast.rs | 73 +++++++++++++-- calyx-opt/src/analysis/compute_static.rs | 11 +-- calyx-opt/src/analysis/inference_analysis.rs | 46 +++++++--- calyx-opt/src/analysis/promotion_analysis.rs | 25 +++--- calyx-opt/src/default_passes.rs | 10 +-- calyx-opt/src/passes/add_guard.rs | 2 +- calyx-opt/src/passes/attribute_promotion.rs | 87 ------------------ calyx-opt/src/passes/compile_empty.rs | 90 ------------------- calyx-opt/src/passes/compile_invoke.rs | 29 ++++-- calyx-opt/src/passes/compile_repeat.rs | 4 +- .../src/passes/compile_static_interface.rs | 77 ++++++++++------ calyx-opt/src/passes/mod.rs | 4 - calyx-opt/src/passes/schedule_compaction.rs | 16 +++- calyx-opt/src/passes/static_inference.rs | 6 +- calyx-opt/src/passes/static_promotion.rs | 47 +++++----- .../src/passes/top_down_compile_control.rs | 2 +- calyx-opt/src/passes/well_formed.rs | 89 +++++++++++++++--- calyx-py/calyx/py_ast.py | 2 +- calyx-py/test/correctness/reduction_tree.py | 4 +- calyx-py/test/invoke.expect | 4 +- examples/futil/dot-product.futil | 14 +-- examples/futil/simple.futil | 2 +- examples/futil/vectorized-add.futil | 10 +-- interp/tests/control/if.futil | 6 +- interp/tests/control/if_reg.futil | 6 +- interp/tests/control/par_mem.futil | 6 +- interp/tests/control/par_reg.futil | 6 +- primitives/binary_operators.futil | 8 +- primitives/compile.futil | 2 +- primitives/core.futil | 1 - primitives/memories/comb.futil | 8 +- tests/backend/mlir/attributes.expect | 6 +- tests/backend/mlir/attributes.futil | 6 +- tests/backend/yxi/dot-product.futil | 14 +-- .../use-both-interfaces-one-cycle.expect | 5 ++ .../use-both-interfaces-one-cycle.futil | 77 ++++++++++++++++ .../use-both-interfaces-one-cycle.futil.data | 12 +++ .../use-both-interfaces.expect | 5 ++ .../use-both-interfaces.futil | 81 +++++++++++++++++ .../use-both-interfaces.futil.data | 12 +++ tests/frontend/dahlia/binop_tree.expect | 14 +-- tests/frontend/dahlia/combine.expect | 8 +- tests/frontend/dahlia/dot-func.expect | 12 +-- tests/frontend/dahlia/fixed-point-add.expect | 4 +- tests/frontend/dahlia/for.expect | 4 +- tests/frontend/dahlia/if.expect | 4 +- tests/frontend/dahlia/invoke-memory.expect | 8 +- tests/frontend/dahlia/invoke.expect | 6 +- .../frontend/dahlia/matadd-fixed-point.expect | 14 +-- tests/frontend/dahlia/memory.expect | 6 +- tests/frontend/dahlia/par.expect | 4 +- tests/frontend/dahlia/seq.expect | 4 +- .../frontend/dahlia/signed_dotproduct.expect | 18 ++-- tests/frontend/dahlia/unroll.expect | 14 +-- tests/frontend/exp/degree-2-unsigned.expect | 8 +- tests/frontend/exp/degree-4-signed.expect | 16 ++-- tests/frontend/exp/degree-4-unsigned.expect | 16 ++-- .../batch_flatten-same-dimensions.expect | 16 ++-- tests/frontend/relay/batch_flatten.expect | 20 ++--- tests/frontend/relay/batch_matmul.expect | 44 ++++----- tests/frontend/relay/bias_add.expect | 22 ++--- tests/frontend/relay/broadcast.expect | 14 +-- tests/frontend/relay/constant-multiply.expect | 10 +-- tests/frontend/relay/conv2d.expect | 52 +++++------ tests/frontend/relay/dense.expect | 24 ++--- .../relay/duplicate-relay-call.expect | 12 +-- tests/frontend/relay/max_pool2d.expect | 44 ++++----- tests/frontend/relay/negative.expect | 8 +- tests/frontend/relay/relu.expect | 24 ++--- tests/frontend/relay/reshape.expect | 24 ++--- tests/frontend/relay/softmax.expect | 74 +++++++-------- tests/frontend/relay/sqrt.expect | 12 +-- tests/frontend/relay/tensor_add.expect | 14 +-- tests/import/a.expect | 10 +-- tests/parsing/attributes.expect | 4 +- tests/passes/attr-promotion.expect | 20 ----- tests/passes/attr-promotion.futil | 28 ------ .../cell-share/continuous-assignment.expect | 4 +- .../cell-share/continuous-assignment.futil | 4 +- tests/passes/cell-share/empty-invoke.expect | 6 +- .../passes/cell-share/escape-boundary.expect | 4 +- tests/passes/cell-share/escape-boundary.futil | 4 +- tests/passes/cell-share/inline.expect | 2 +- .../cell-share/live-register-analysis.expect | 20 ++--- .../cell-share/live-register-analysis.futil | 20 ++--- .../passes/cell-share/multiple-adders.expect | 4 +- tests/passes/cell-share/multiple-adders.futil | 4 +- tests/passes/cell-share/nested-par.expect | 12 +-- tests/passes/cell-share/nested-par.futil | 12 +-- .../cell-share/par-while-liveness.expect | 24 ++--- .../cell-share/par-while-liveness.futil | 24 ++--- tests/passes/cell-share/share-mult.expect | 12 +-- tests/passes/cell-share/share-mult.futil | 12 +-- .../passes/cell-share/simple-liveness.expect | 8 +- tests/passes/cell-share/simple-liveness.futil | 8 +- tests/passes/compile-empty.expect | 29 ------ tests/passes/compile-empty.futil | 22 ----- .../compile-invoke/compile-invoke.expect | 8 +- .../compile-invoke/compile-invoke.futil | 4 +- .../compile-invoke/static-invoke-reg.expect | 15 ++++ .../compile-invoke/static-invoke-reg.futil | 13 +++ tests/passes/compile-repeat/nested.expect | 8 +- tests/passes/compile-repeat/simple.expect | 4 +- .../compile-static-interface-one-cycle.expect | 0 .../compile-static-interface-one-cycle.futil | 0 .../compile-static-interface-repeat.expect | 0 .../compile-static-interface-repeat.futil | 0 .../compile-static-interface.expect | 0 .../compile-static-interface.futil | 0 .../multi-go-done-component.expect | 2 +- .../multi-go-done-component.futil | 4 +- .../passes/group2invoke/multi-go-done.expect | 2 +- tests/passes/group2invoke/multi-go-done.futil | 4 +- tests/passes/group_to_seq/dahlia_mult.expect | 12 +-- tests/passes/group_to_seq/dahlia_mult.futil | 16 ++-- tests/passes/inliner/always.expect | 6 +- tests/passes/inliner/always.futil | 4 +- tests/passes/inliner/simple.expect | 6 +- tests/passes/inliner/simple.futil | 4 +- .../continuous-compaction.expect | 2 +- .../continuous-compaction.futil | 18 ++-- .../continuous-no-compaction.expect | 20 ++--- .../continuous-no-compaction.futil | 20 ++--- .../fixup-necessary.expect | 10 +-- .../schedule-compaction/no-compact.expect | 14 +-- .../schedule-compaction/no-compact.futil | 6 +- .../partial-compaction.expect | 12 +-- .../partial-compaction.futil | 20 ++--- .../schedule-compaction.expect | 2 +- .../schedule-compaction.futil | 18 ++-- .../static-inference-promotion/groups.expect | 4 +- .../static-inference-promotion/if-diff.expect | 2 +- .../static-inference-promotion/invoke.expect | 2 +- .../multi-static.expect | 2 +- .../threshold.expect | 6 +- .../passes/static-inference/component.expect | 14 +-- tests/passes/static-inference/groups.expect | 16 ++-- .../passes/static-inference/if-no-else.expect | 6 +- tests/passes/static-inference/invoke.expect | 20 ++--- tests/passes/static-inference/par.expect | 12 +-- .../static-inference/promote-nested.expect | 36 ++++---- .../static-inference/promote-repeat.expect | 36 ++++---- .../static-passes/both-passes-promote.expect | 8 +- .../static-promotion/fixup-invoke.expect | 57 ++++++++++++ .../static-promotion/fixup-invoke.futil | 60 +++++++++++++ .../static-promotion/fixup-necessary.expect | 4 +- .../static-promotion/fixup-necessary.futil | 38 ++++---- tests/passes/tdcc/branch-at-start.futil | 2 +- tests/passes/tdcc/empty-exit.futil | 2 +- tests/passes/tdcc/if.futil | 2 +- tests/passes/tdcc/nested-while.futil | 4 +- tests/passes/tdcc/new-fsm-nested.futil | 2 +- tests/passes/tdcc/new-fsm-seq.futil | 2 +- tests/passes/tdcc/par.futil | 2 +- tests/passes/tdcc/seq-with-same-done.futil | 2 +- tests/passes/tdcc/seq.futil | 2 +- tests/passes/tdcc/while-if.futil | 2 +- tests/passes/tdcc/while.futil | 2 +- tests/passes/well-formed/interval-attr.expect | 4 + tests/passes/well-formed/interval-attr.futil | 34 +++++++ .../passes/well-formed/interval-attr2.expect | 4 + tests/passes/well-formed/interval-attr2.futil | 34 +++++++ .../passes/well-formed/interval-attr3.expect | 4 + tests/passes/well-formed/interval-attr3.futil | 33 +++++++ tests/passes/well-formed/interval-cont.expect | 68 ++++++++++++++ tests/passes/well-formed/interval-cont.futil | 76 ++++++++++++++++ 169 files changed, 1591 insertions(+), 1086 deletions(-) delete mode 100644 calyx-opt/src/passes/attribute_promotion.rs delete mode 100644 calyx-opt/src/passes/compile_empty.rs create mode 100644 tests/correctness/static-interface/use-both-interfaces-one-cycle.expect create mode 100644 tests/correctness/static-interface/use-both-interfaces-one-cycle.futil create mode 100644 tests/correctness/static-interface/use-both-interfaces-one-cycle.futil.data create mode 100644 tests/correctness/static-interface/use-both-interfaces.expect create mode 100644 tests/correctness/static-interface/use-both-interfaces.futil create mode 100644 tests/correctness/static-interface/use-both-interfaces.futil.data delete mode 100644 tests/passes/attr-promotion.expect delete mode 100644 tests/passes/attr-promotion.futil delete mode 100644 tests/passes/compile-empty.expect delete mode 100644 tests/passes/compile-empty.futil create mode 100644 tests/passes/compile-invoke/static-invoke-reg.expect create mode 100644 tests/passes/compile-invoke/static-invoke-reg.futil rename tests/passes/{ => compile-static-interface}/compile-static-interface-one-cycle.expect (100%) rename tests/passes/{ => compile-static-interface}/compile-static-interface-one-cycle.futil (100%) rename tests/passes/{ => compile-static-interface}/compile-static-interface-repeat.expect (100%) rename tests/passes/{ => compile-static-interface}/compile-static-interface-repeat.futil (100%) rename tests/passes/{ => compile-static-interface}/compile-static-interface.expect (100%) rename tests/passes/{ => compile-static-interface}/compile-static-interface.futil (100%) create mode 100644 tests/passes/static-promotion/fixup-invoke.expect create mode 100644 tests/passes/static-promotion/fixup-invoke.futil create mode 100644 tests/passes/well-formed/interval-attr.expect create mode 100644 tests/passes/well-formed/interval-attr.futil create mode 100644 tests/passes/well-formed/interval-attr2.expect create mode 100644 tests/passes/well-formed/interval-attr2.futil create mode 100644 tests/passes/well-formed/interval-attr3.expect create mode 100644 tests/passes/well-formed/interval-attr3.futil create mode 100644 tests/passes/well-formed/interval-cont.expect create mode 100644 tests/passes/well-formed/interval-cont.futil diff --git a/Dockerfile b/Dockerfile index 530a656a8..f5cbbfcd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,10 +47,10 @@ RUN python3 setup.py bdist_wheel && python3 -m pip install --user dist/tvm-*.whl # Install Dahlia WORKDIR /home -RUN git clone https://github.com/cucapra/dahlia.git +RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia ## Checkout specific version -RUN git checkout a352e60 +RUN git checkout 51954e7 RUN sbt "; getHeaders; assembly" # Add the Calyx source code from the build context diff --git a/calyx-frontend/src/attribute.rs b/calyx-frontend/src/attribute.rs index 242b0a01f..37a11fe07 100644 --- a/calyx-frontend/src/attribute.rs +++ b/calyx-frontend/src/attribute.rs @@ -4,7 +4,7 @@ use strum::EnumCount; use strum_macros::{AsRefStr, EnumCount, EnumString, FromRepr}; /// Attributes that have been deprecated. -pub const DEPRECATED_ATTRIBUTES: &[&str] = &[]; +pub const DEPRECATED_ATTRIBUTES: &[&str] = &["static"]; #[derive( EnumCount, @@ -62,7 +62,7 @@ pub enum BoolAttr { /// Inline this subcomponent Inline, #[strum(serialize = "promoted")] - /// denotes a static component promoted from dynamic + /// denotes a static component or control promoted from dynamic Promoted, } impl From for Attribute { @@ -97,18 +97,23 @@ pub enum NumAttr { #[strum(serialize = "bound")] /// The bound of a while loop Bound, - #[strum(serialize = "static")] - /// Latency information - Static, #[strum(serialize = "pos")] /// Source location position for this node Pos, - #[strum(serialize = "promote_static")] - /// Promote the group or control to static with the annotated latency - PromoteStatic, + #[strum(serialize = "promotable")] + /// Can promote the group, control, or @go port of the component to static + /// with the annotated latency + Promotable, #[strum(serialize = "compactable")] /// suggest that the current static seq block is compactable Compactable, + #[strum(serialize = "interval")] + /// Placed on @go ports of components to denote the II of a component, which + /// is the same as the latency for non pipelined components. + /// This indicates the component can serve ``double-duty'' as both static and + /// dynamic. + /// Therefore, we only place if we can *guarantee* the interval of the component. + Interval, } impl From for Attribute { fn from(attr: NumAttr) -> Self { @@ -173,6 +178,9 @@ impl FromStr for Attribute { } else if let Ok(n) = NumAttr::from_str(s) { Ok(Attribute::Num(n)) } else { + if DEPRECATED_ATTRIBUTES.contains(&s) { + log::warn!("The attribute @{s} is deprecated and will be ignored by the compiler."); + } // Reject attributes that all caps since those are reserved for internal attributes if s.to_uppercase() == s { return Err(Error::misc(format!("Invalid attribute: {}. All caps attributes are reserved for internal use.", s))); diff --git a/calyx-ir/src/control.rs b/calyx-ir/src/control.rs index 10dac5ea7..e7f1e027e 100644 --- a/calyx-ir/src/control.rs +++ b/calyx-ir/src/control.rs @@ -578,6 +578,11 @@ impl Control { matches!(self, Control::Static(_)) } + pub fn is_empty(&self) -> bool { + matches!(self, Control::Static(StaticControl::Empty(_))) + || matches!(self, Control::Empty(_)) + } + pub fn get_latency(&self) -> Option { match self { Control::Static(sc) => Some(sc.get_latency()), diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index 7479045c5..9930d0d1d 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -5,7 +5,7 @@ use super::{ RESERVED_NAMES, RRC, }; use crate::{Nothing, PortComp, StaticTiming}; -use calyx_frontend::{ast, BoolAttr, Workspace}; +use calyx_frontend::{ast, BoolAttr, NumAttr, Workspace}; use calyx_utils::{CalyxResult, Error, GPosIdx, WithPos}; use itertools::Itertools; @@ -24,12 +24,73 @@ struct SigCtx { lib: LibrarySignatures, } -// assumes cell has a name (i.e., not a constant/ThisComponent) -// uses sig_ctx to check the latency of comp_name (if not static, then None) +// Assumes cell has a name (i.e., not a constant/ThisComponent) +// uses sig_ctx to check the latency of comp_name, either thru static or +// @interval(n) fn get_comp_latency( sig_ctx: &SigCtx, cell: RRC, attrs: &Attributes, +) -> CalyxResult> { + let comp_name = cell + .borrow() + .type_name() + .unwrap_or_else(|| unreachable!("invoked component without a name")); + if let Some(prim) = sig_ctx.lib.find_primitive(comp_name) { + match prim.latency { + Some(val) => Ok(Some(val)), + None => { + let prim_sig = &prim.signature; + // We can just look at any go port, since if there is an + // @interval(n), it must be the same for all ports. + let interval_value = prim_sig + .iter() + .find(|port_def| port_def.attributes.has(NumAttr::Go)) + .and_then(|go_port| { + go_port.attributes.get(NumAttr::Interval) + }); + // Annoying thing we have to do bc NonZeroU64. + match interval_value { + Some(lat) => Ok(NonZeroU64::new(lat)), + None => Ok(None), + } + } + } + } else if let Some((comp_sig, latency)) = sig_ctx.comp_sigs.get(&comp_name) + { + match latency { + Some(val) => Ok(Some(*val)), + None => { + // We can just look at any go port, since if there is an + // @interval(n), it must be the same for all ports. + let interval_value = comp_sig + .iter() + .find(|port_def| port_def.attributes.has(NumAttr::Go)) + .and_then(|go_port| { + go_port.attributes.get(NumAttr::Interval) + }); + // Annoying thing we have to do bc NonZeroU64. + match interval_value { + Some(lat) => Ok(NonZeroU64::new(lat)), + None => Ok(None), + } + } + } + } else { + return Err(Error::undefined( + comp_name, + "primitive or component".to_string(), + ) + .with_pos(attrs)); + } +} + +// Assumes cell has a name (i.e., not a constant/ThisComponent) +// uses sig_ctx to check the latency of comp_name, but only checks static latency +fn get_static_latency( + sig_ctx: &SigCtx, + cell: RRC, + attrs: &Attributes, ) -> CalyxResult> { let comp_name = cell .borrow() @@ -766,7 +827,7 @@ fn build_static_control( v } else { return Err(Error::malformed_control(format!( - "non-static component {} is statically invoked", + "component {} is statically invoked, but is neither static nor does it have @interval attribute its @go port", comp_name )) .with_pos(&attributes)); @@ -951,7 +1012,7 @@ fn build_control( v } else { return Err(Error::malformed_control(format!( - "non-static component {} is statically invoked", + "component {} is statically invoked, but is neither static nor does it have @interval attribute its @go port", comp_name )) .with_pos(&attributes)); @@ -1040,7 +1101,7 @@ fn build_control( }); // Error to dynamically invoke static component - if get_comp_latency(sig_ctx, Rc::clone(&cell), &attributes)? + if get_static_latency(sig_ctx, Rc::clone(&cell), &attributes)? .is_some() { return Err(Error::malformed_control(format!( diff --git a/calyx-opt/src/analysis/compute_static.rs b/calyx-opt/src/analysis/compute_static.rs index 0eb965e49..169e1e223 100644 --- a/calyx-opt/src/analysis/compute_static.rs +++ b/calyx-opt/src/analysis/compute_static.rs @@ -25,7 +25,7 @@ where fn update_static(&mut self, extra: &Self::Info) -> Option { if let Some(time) = self.compute_static(extra) { self.get_mut_attributes() - .insert(ir::NumAttr::PromoteStatic, time); + .insert(ir::NumAttr::Promotable, time); Some(time) } else { None @@ -62,11 +62,8 @@ impl WithStatic for ir::Enable { fn compute_static(&mut self, _: &Self::Info) -> Option { // Attempt to get the latency from the attribute on the enable first, or // failing that, from the group. - self.attributes.get(ir::NumAttr::PromoteStatic).or_else(|| { - self.group - .borrow() - .attributes - .get(ir::NumAttr::PromoteStatic) + self.attributes.get(ir::NumAttr::Promotable).or_else(|| { + self.group.borrow().attributes.get(ir::NumAttr::Promotable) }) } } @@ -74,7 +71,7 @@ impl WithStatic for ir::Enable { impl WithStatic for ir::Invoke { type Info = CompTime; fn compute_static(&mut self, extra: &Self::Info) -> Option { - self.attributes.get(ir::NumAttr::PromoteStatic).or_else(|| { + self.attributes.get(ir::NumAttr::Promotable).or_else(|| { let comp = self.comp.borrow().type_name()?; extra.get(&comp).cloned() }) diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs index e13d3998b..0b425649a 100644 --- a/calyx-opt/src/analysis/inference_analysis.rs +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -71,7 +71,8 @@ impl From<&ir::Primitive> for GoDone { let go_ports = prim .find_all_with_attr(ir::NumAttr::Go) .filter_map(|pd| { - pd.attributes.get(ir::NumAttr::Static).and_then(|st| { + // Primitives only have @interval. + pd.attributes.get(ir::NumAttr::Interval).and_then(|st| { done_ports .get(&pd.attributes.get(ir::NumAttr::Go)) .map(|done_port| (pd.name(), *done_port, st)) @@ -96,11 +97,19 @@ impl From<&ir::Cell> for GoDone { .find_all_with_attr(ir::NumAttr::Go) .filter_map(|pr| { let port = pr.borrow(); - port.attributes.get(ir::NumAttr::Static).and_then(|st| { - done_ports + // Get static interval thru either @interval or @promotable. + let st = match port.attributes.get(ir::NumAttr::Interval) { + Some(st) => Some(st), + None => port.attributes.get(ir::NumAttr::Promotable), + }; + if let Some(static_latency) = st { + return done_ports .get(&port.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (port.name, *done_port, st)) - }) + .map(|done_port| { + (port.name, *done_port, static_latency) + }); + } + None }) .collect_vec(); GoDone::new(go_ports) @@ -151,11 +160,20 @@ impl InferenceAnalysis { .find_all_with_attr(ir::NumAttr::Go) .filter_map(|pd| { let pd_ref = pd.borrow(); - pd_ref.attributes.get(ir::NumAttr::Static).and_then(|st| { - done_ports + // Get static interval thru either @interval or @promotable. + let st = match pd_ref.attributes.get(ir::NumAttr::Interval) + { + Some(st) => Some(st), + None => pd_ref.attributes.get(ir::NumAttr::Promotable), + }; + if let Some(static_latency) = st { + return done_ports .get(&pd_ref.attributes.get(ir::NumAttr::Go)) - .map(|done_port| (pd_ref.name, *done_port, st)) - }) + .map(|done_port| { + (pd_ref.name, *done_port, static_latency) + }); + } + None }) .collect_vec(); @@ -442,7 +460,7 @@ impl InferenceAnalysis { pub fn get_possible_latency(c: &ir::Control) -> Option { match c { ir::Control::Static(sc) => Some(sc.get_latency()), - _ => c.get_attribute(ir::NumAttr::PromoteStatic), + _ => c.get_attribute(ir::NumAttr::Promotable), } } @@ -450,13 +468,13 @@ impl InferenceAnalysis { for stmt in &mut seq.stmts { Self::remove_promotable_attribute(stmt); } - seq.get_mut_attributes().remove(ir::NumAttr::PromoteStatic); + seq.get_mut_attributes().remove(ir::NumAttr::Promotable); } /// Removes the @promotable attribute from the control program. /// Recursively visits the children of the control. pub fn remove_promotable_attribute(c: &mut ir::Control) { - c.get_mut_attributes().remove(ir::NumAttr::PromoteStatic); + c.get_mut_attributes().remove(ir::NumAttr::Promotable); match c { ir::Control::Empty(_) | ir::Control::Invoke(_) @@ -512,7 +530,7 @@ impl InferenceAnalysis { group .borrow_mut() .attributes - .remove(ir::NumAttr::PromoteStatic); + .remove(ir::NumAttr::Promotable); } } @@ -523,7 +541,7 @@ impl InferenceAnalysis { group .borrow_mut() .attributes - .insert(ir::NumAttr::PromoteStatic, latency); + .insert(ir::NumAttr::Promotable, latency); } } diff --git a/calyx-opt/src/analysis/promotion_analysis.rs b/calyx-opt/src/analysis/promotion_analysis.rs index 271d14a7d..938ba31ac 100644 --- a/calyx-opt/src/analysis/promotion_analysis.rs +++ b/calyx-opt/src/analysis/promotion_analysis.rs @@ -15,8 +15,7 @@ impl PromotionAnalysis { pub fn get_inferred_latency(c: &ir::Control) -> u64 { let ir::Control::Static(sc) = c else { - let Some(latency) = c.get_attribute(ir::NumAttr::PromoteStatic) - else { + let Some(latency) = c.get_attribute(ir::NumAttr::Promotable) else { unreachable!("Called get_latency on control that is neither static nor promotable") }; return latency; @@ -27,7 +26,7 @@ impl PromotionAnalysis { /// Returns true if a control statement is already static, or has the static /// attributes pub fn can_be_promoted(c: &ir::Control) -> bool { - c.is_static() || c.has_attribute(ir::NumAttr::PromoteStatic) + c.is_static() || c.has_attribute(ir::NumAttr::Promotable) } /// If we've already constructed the static group then use the already existing @@ -65,7 +64,7 @@ impl PromotionAnalysis { s: &mut ir::Enable, builder: &mut ir::Builder, ) -> ir::StaticControl { - s.attributes.remove(ir::NumAttr::PromoteStatic); + s.attributes.remove(ir::NumAttr::Promotable); ir::StaticControl::Enable(ir::StaticEnable { // upgrading group to static group group: self.construct_static_group( @@ -75,7 +74,7 @@ impl PromotionAnalysis { .borrow() .get_attributes() .unwrap() - .get(ir::NumAttr::PromoteStatic) + .get(ir::NumAttr::Promotable) .unwrap(), ), attributes: std::mem::take(&mut s.attributes), @@ -91,8 +90,8 @@ impl PromotionAnalysis { s.comb_group.is_none(), "Shouldn't Promote to Static if there is a Comb Group", ); - let latency = s.attributes.get(ir::NumAttr::PromoteStatic).unwrap(); - s.attributes.remove(ir::NumAttr::PromoteStatic); + let latency = s.attributes.get(ir::NumAttr::Promotable).unwrap(); + s.attributes.remove(ir::NumAttr::Promotable); let s_inv = ir::StaticInvoke { comp: Rc::clone(&s.comp), inputs: std::mem::take(&mut s.inputs), @@ -113,7 +112,7 @@ impl PromotionAnalysis { builder: &mut ir::Builder, ) -> ir::StaticControl { assert!( - c.has_attribute(ir::NumAttr::PromoteStatic) || c.is_static(), + c.has_attribute(ir::NumAttr::Promotable) || c.is_static(), "Called convert_to_static control that is neither static nor promotable" ); // Need to get bound_attribute here, because we cannot borrow `c` within the @@ -127,7 +126,7 @@ impl PromotionAnalysis { ir::Control::Enable(s) => self.convert_enable_to_static(s, builder), ir::Control::Seq(ir::Seq { stmts, attributes }) => { // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); + attributes.remove(ir::NumAttr::Promotable); // The resulting static seq should be compactable. attributes.insert(ir::NumAttr::Compactable, 1); let static_stmts = @@ -143,7 +142,7 @@ impl PromotionAnalysis { } ir::Control::Par(ir::Par { stmts, attributes }) => { // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); + attributes.remove(ir::NumAttr::Promotable); // Convert stmts to static let static_stmts = self.convert_vec_to_static(builder, std::mem::take(stmts)); @@ -166,7 +165,7 @@ impl PromotionAnalysis { attributes, }) => { // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); + attributes.remove(ir::NumAttr::Promotable); let sc = self.convert_to_static(body, builder); let latency = (*num_repeats) * sc.get_latency(); Self::check_latencies_match(latency, inferred_latency); @@ -181,7 +180,7 @@ impl PromotionAnalysis { body, attributes, .. }) => { // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); + attributes.remove(ir::NumAttr::Promotable); // Removing the `bound` attribute bc we don't need it anymore attributes.remove(ir::NumAttr::Bound); let sc = self.convert_to_static(body, builder); @@ -203,7 +202,7 @@ impl PromotionAnalysis { .. }) => { // Removing the `promote_static` attribute bc we don't need it anymore - attributes.remove(ir::NumAttr::PromoteStatic); + attributes.remove(ir::NumAttr::Promotable); let static_tbranch = self.convert_to_static(tbranch, builder); let static_fbranch = self.convert_to_static(fbranch, builder); let latency = std::cmp::max( diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 824df1bbe..20989f605 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -1,9 +1,8 @@ //! Defines the default passes available to [PassManager]. use crate::passes::{ - AddGuard, AttributePromotion, Canonicalize, CellShare, ClkInsertion, - CollapseControl, CombProp, CompileEmpty, CompileInvoke, CompileRepeat, - CompileStatic, CompileStaticInterface, CompileSync, - CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, + AddGuard, Canonicalize, CellShare, ClkInsertion, CollapseControl, CombProp, + CompileInvoke, CompileRepeat, CompileStatic, CompileStaticInterface, + CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, @@ -30,7 +29,6 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -40,7 +38,6 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; - pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; @@ -96,7 +93,6 @@ impl PassManager { CellShare, // LiveRangeAnalaysis should handle comb groups SimplifyWithControl, // Must run before compile-invoke CompileInvoke, // creates dead comb groups - AttributePromotion, StaticInference, ScheduleCompaction, StaticPromotion, diff --git a/calyx-opt/src/passes/add_guard.rs b/calyx-opt/src/passes/add_guard.rs index 8e7abc63a..157b2f53b 100644 --- a/calyx-opt/src/passes/add_guard.rs +++ b/calyx-opt/src/passes/add_guard.rs @@ -10,7 +10,7 @@ impl Named for AddGuard { } fn description() -> &'static str { - "add guard %[0: n] where n is latency of static component for each assignment in the static enable of static component." + "Add guard %[0: n] where n is latency of static component for each assignment in the static enable of static component." } } diff --git a/calyx-opt/src/passes/attribute_promotion.rs b/calyx-opt/src/passes/attribute_promotion.rs deleted file mode 100644 index 0d8fdb380..000000000 --- a/calyx-opt/src/passes/attribute_promotion.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::traversal::{Action, Named, VisResult, Visitor}; -use calyx_ir::{self as ir, LibrarySignatures}; -use std::collections::HashMap; - -#[derive(Default)] -/// Removes NODE_ID, BEGIN_ID, and END_ID from each control statement -pub struct AttributePromotion { - /// maps dynamic group names its corresponding upgraded static group - /// Then we use this to replace regular groups - upgraded_groups: HashMap>, -} - -impl Named for AttributePromotion { - fn name() -> &'static str { - "attr-promotion" - } - - fn description() -> &'static str { - "upgrades @static and @bound annotations to appropriate static control" - } -} - -impl Visitor for AttributePromotion { - fn start( - &mut self, - comp: &mut ir::Component, - sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - // drain groups - let comp_groups: Vec> = - comp.get_groups_mut().drain().collect(); - let mut builder = ir::Builder::new(comp, sigs); - let mut non_upgraded_groups = Vec::new(); - - for group in comp_groups { - let group_rc_clone = std::rc::Rc::clone(&group); - let mut gr = group.borrow_mut(); - // if group has static annotation, then create corresponding static group, and add to self.upgraded_groups - // otherwise just add back to component.groups - if let Some(lat) = gr.attributes.get(ir::NumAttr::Static) { - let sg = builder.add_static_group(gr.name(), lat); - for assignment in gr.assignments.drain(..) { - // don't add done signal to static group - if !(assignment.dst.borrow().is_hole() - && assignment.dst.borrow().name == "done") - { - let static_s = ir::Assignment::from(assignment); - sg.borrow_mut().assignments.push(static_s); - } - } - self.upgraded_groups.insert(gr.name(), sg); - } else { - non_upgraded_groups.push(group_rc_clone); - } - } - - builder - .component - .get_groups_mut() - .append(non_upgraded_groups.into_iter()); - - Ok(Action::Continue) - } - - fn enable( - &mut self, - s: &mut ir::Enable, - _comp: &mut ir::Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - // check if this groups is indeed an "upgraded_group". If so, then change - // to static enable. Otherwise continue. - if let Some(static_group) = - self.upgraded_groups.get(&s.group.borrow().name()) - { - let static_enable = ir::StaticControl::Enable(ir::StaticEnable { - group: std::rc::Rc::clone(static_group), - attributes: s.attributes.clone(), - }); - Ok(Action::change(ir::Control::Static(static_enable))) - } else { - Ok(Action::Continue) - } - } -} diff --git a/calyx-opt/src/passes/compile_empty.rs b/calyx-opt/src/passes/compile_empty.rs deleted file mode 100644 index e9d886ec1..000000000 --- a/calyx-opt/src/passes/compile_empty.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::traversal::{Action, Named, VisResult, Visitor}; -use calyx_ir::{self as ir, Component, Control, LibrarySignatures}; -use calyx_ir::{build_assignments, structure}; -use std::rc::Rc; - -#[derive(Default)] -/// Compiles away all [`ir::Empty`](calyx_ir::Empty) statements into an -/// [`ir::Enable`](calyx_ir::Enable). -/// -/// The generated program enables the following group: -/// ```calyx -/// cells { -/// @generated empty_reg = std_reg(1); -/// } -/// -/// group _empty { -/// empty_reg.write_en = 1'd1; -/// empty_reg.in = 1'd1; -/// _empty["done"] = empty_reg.done; -/// } -/// ``` -pub struct CompileEmpty { - // Name of the empty group if it has been created. - group_name: Option, -} - -impl Named for CompileEmpty { - fn name() -> &'static str { - "compile-empty" - } - - fn description() -> &'static str { - "Rewrites empty control to invocation to empty group" - } -} - -impl Visitor for CompileEmpty { - fn empty( - &mut self, - _s: &mut ir::Empty, - comp: &mut Component, - sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - let group_ref = match self.group_name { - Some(g) => comp.find_group(g).unwrap(), - None => { - let mut builder = ir::Builder::new(comp, sigs); - - // Build the new group - let empty_group = builder.add_group("_empty"); - empty_group - .borrow_mut() - .attributes - .insert(ir::NumAttr::Static, 1); - - // Add this signal empty_group[done] = 1'd1; - structure!(builder; - let signal_on = constant(1, 1); - let empty_reg = prim std_reg(1); - ); - let assigns = build_assignments!(builder; - empty_reg["write_en"] = ? signal_on["out"]; - empty_reg["in"] = ? signal_on["out"]; - empty_group["done"] = ? empty_reg["done"]; - ); - empty_group.borrow_mut().assignments.extend(assigns); - - // Register the name of the group to the pass - self.group_name = Some(empty_group.borrow().name()); - - empty_group - } - }; - - Ok(Action::change(Control::enable(Rc::clone(&group_ref)))) - } - - fn finish( - &mut self, - _comp: &mut Component, - _sigs: &LibrarySignatures, - _comps: &[ir::Component], - ) -> VisResult { - // The empty group, if created, is only defined for this component. - // Deregister it before walking over another group. - self.group_name = None; - Ok(Action::Continue) - } -} diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 09becaf60..3bc81493d 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -331,20 +331,20 @@ impl Visitor for CompileInvoke { .extend(cg.assignments.iter().cloned()) } - // Copy "static" annotation from the `invoke` statement if present - if let Some(time) = s.attributes.get(ir::NumAttr::Static) { + // Copy "promotable" annotation from the `invoke` statement if present + if let Some(time) = s.attributes.get(ir::NumAttr::Promotable) { invoke_group .borrow_mut() .attributes - .insert(ir::NumAttr::Static, time); + .insert(ir::NumAttr::Promotable, time); } let mut en = ir::Enable { group: invoke_group, attributes: Attributes::default(), }; - if let Some(time) = s.attributes.get(ir::NumAttr::Static) { - en.attributes.insert(ir::NumAttr::Static, time); + if let Some(time) = s.attributes.get(ir::NumAttr::Promotable) { + en.attributes.insert(ir::NumAttr::Promotable, time); } Ok(Action::change(ir::Control::Enable(en))) @@ -373,12 +373,25 @@ impl Visitor for CompileInvoke { // Get the go port let go_port = get_go_port(Rc::clone(&s.comp))?; - // define first cycle guard - let first_cycle = ir::Guard::Info(ir::StaticTiming::new((0, 1))); + // Checks whether compe is a static component or an @interval(n) component. + let go_guard = if s + .comp + .borrow() + .ports + .iter() + .any(|port| port.borrow().attributes.has(ir::NumAttr::Interval)) + { + // For @interval(n) components, we do not guard the comp.go + // We trigger the go signal for the entire interval. + ir::Guard::True + } else { + // For static components, we guard the comp.go with %[0:1] + ir::Guard::Info(ir::StaticTiming::new((0, 1))) + }; // Build assignemnts let go_assign: ir::Assignment = builder - .build_assignment(go_port, one.borrow().get("out"), first_cycle); + .build_assignment(go_port, one.borrow().get("out"), go_guard); invoke_group.borrow_mut().assignments.push(go_assign); // Generate argument assignments diff --git a/calyx-opt/src/passes/compile_repeat.rs b/calyx-opt/src/passes/compile_repeat.rs index 17c35ace4..953112783 100644 --- a/calyx-opt/src/passes/compile_repeat.rs +++ b/calyx-opt/src/passes/compile_repeat.rs @@ -69,7 +69,7 @@ impl Visitor for CompileRepeat { init_group .borrow_mut() .attributes - .insert(ir::NumAttr::PromoteStatic, 1); + .insert(ir::NumAttr::Promotable, 1); // incr_group: // 1) writes results of idx + 1 into idx (i.e., increments idx) // 2) writes the result of (idx + 1 < num_repeats) into cond_reg, @@ -91,7 +91,7 @@ impl Visitor for CompileRepeat { incr_group .borrow_mut() .attributes - .insert(ir::NumAttr::PromoteStatic, 1); + .insert(ir::NumAttr::Promotable, 1); // create control: // init_group; while cond_reg.out {repeat_body; incr_group;} let while_body = ir::Control::seq(vec![ diff --git a/calyx-opt/src/passes/compile_static_interface.rs b/calyx-opt/src/passes/compile_static_interface.rs index cb884123e..3a0d47764 100644 --- a/calyx-opt/src/passes/compile_static_interface.rs +++ b/calyx-opt/src/passes/compile_static_interface.rs @@ -23,6 +23,7 @@ impl Named for CompileStaticInterface { } } +// Looks recursively thru guard to %[0:n] into %0 | %[1:n]. fn separate_first_cycle( guard: ir::Guard, ) -> ir::Guard { @@ -56,6 +57,7 @@ fn separate_first_cycle( } } +// Looks recursively thru assignment's guard to %[0:n] into %0 | %[1:n]. fn separate_first_cycle_assign( assign: ir::Assignment, ) -> ir::Assignment { @@ -67,6 +69,8 @@ fn separate_first_cycle_assign( } } +// Used for guards in a one cycle static component. +// Replaces %0 with comp.go. fn make_guard_dyn_one_cycle_static_comp( guard: ir::Guard, comp_sig: RRC, @@ -92,12 +96,10 @@ fn make_guard_dyn_one_cycle_static_comp( ir::Guard::Not(Box::new(f)) } ir::Guard::Info(t) => { - let (beg, end) = t.get_interval(); - if beg != 0 || end != 1 { - unreachable!("This function is implemented for 1 cycle static components, only %0 can exist as timing guard") - } else { - let g = guard!(comp_sig["go"]); - g + match t.get_interval() { + (0, 1) => guard!(comp_sig["go"]), + _ => unreachable!("This function is implemented for 1 cycle static components, only %0 can exist as timing guard"), + } } ir::Guard::CompOp(op, l, r) => ir::Guard::CompOp(op, l, r), @@ -106,6 +108,8 @@ fn make_guard_dyn_one_cycle_static_comp( } } +// Used for assignments in a one cycle static component. +// Replaces %0 with comp.go in the assignment's guard. fn make_assign_dyn_one_cycle_static_comp( assign: ir::Assignment, comp_sig: RRC, @@ -122,6 +126,9 @@ fn make_assign_dyn_one_cycle_static_comp( } impl CompileStaticInterface { + // Takes the assignments within a static component, and instantiates + // an FSM (i.e., counter) to convert %[i:j] into i<= fsm < j. + // Also includes logic to make fsm reset to 0 once it gets to n-1. fn make_early_reset_assigns_static_component( &mut self, sgroup_assigns: &mut Vec>, @@ -161,32 +168,39 @@ impl CompileStaticInterface { let adder = prim std_add(fsm_size); let const_one = constant(1, fsm_size); let first_state = constant(0, fsm_size); - let penultimate_state = constant(latency-1, fsm_size); + let final_state = constant(latency-1, fsm_size); ); let g1: Guard = guard!(this["go"]); let g2: Guard = guard!(fsm["out"] == first_state["out"]); let trigger_guard = ir::Guard::and(g1, g2); let g3: Guard = guard!(fsm["out"] != first_state["out"]); - let g4: Guard = guard!(fsm["out"] != penultimate_state["out"]); + let g4: Guard = guard!(fsm["out"] != final_state["out"]); let incr_guard = ir::Guard::and(g3, g4); let stop_guard: Guard = - guard!(fsm["out"] == penultimate_state["out"]); + guard!(fsm["out"] == final_state["out"]); let fsm_incr_assigns = build_assignments!( builder; - // increments the fsm + // Incrementsthe fsm adder["left"] = ? fsm["out"]; adder["right"] = ? const_one["out"]; + // Always write into fsm. fsm["write_en"] = ? signal_on["out"]; + // If fsm == 0 and comp.go is high, then we start an execution. fsm["in"] = trigger_guard ? const_one["out"]; + // If 1 < fsm < n - 1, then we unconditionally increment the fsm. fsm["in"] = incr_guard ? adder["out"]; - // resets the fsm early + // If fsm == n -1 , then we reset the FSM. fsm["in"] = stop_guard ? first_state["out"]; + // Otherwise the FSM is not assigned to, so it defaults to 0. + // If we want, we could add an explicit assignment here that sets it + // to zero. ); dyn_assigns.extend(fsm_incr_assigns); dyn_assigns } + // Makes `done` signal for promoted static component. fn make_done_signal_for_promoted_component( &mut self, fsm: ir::RRC, @@ -208,18 +222,22 @@ impl CompileStaticInterface { let first_state = constant(0, fsm_size); ); let go_guard = guard!(comp_sig["go"]); - let done_guard = guard!(comp_sig["done"]); - let on_guard = go_guard & !done_guard; + let not_go_guard = !guard!(comp_sig["go"]); let first_state_guard = guard!(fsm["out"] == first_state["out"]); - let signal_on_guard = guard!(sig_reg["out"]); - let comp_done_guard = first_state_guard & signal_on_guard; - let done_guard_2 = guard!(comp_sig["done"]); + let comp_done_guard = + guard!(fsm["out"] == first_state["out"]) & guard!(sig_reg["out"]); let assigns = build_assignments!(builder; - sig_reg["in"] = on_guard ? one["out"]; - sig_reg["write_en"] = on_guard ? one["out"]; + // Only write to sig_reg when fsm == 0 + sig_reg["write_en"] = first_state_guard ? one["out"]; + // If fsm == 0 and comp.go is high, it means we are starting an execution, + // so we set signal_reg to high. Note that this happens regardless of + // whether comp.done is high. + sig_reg["in"] = go_guard ? one["out"]; + // Otherwise, we set `sig_reg` to low. + sig_reg["in"] = not_go_guard ? zero["out"]; + // comp.done is high when FSM == 0 and sig_reg is high, + // since that means we have just finished an execution. comp_sig["done"] = comp_done_guard ? one["out"]; - sig_reg["in"] = done_guard_2 ? zero["out"]; - sig_reg["write_en"] = done_guard_2 ? one["out"]; ); assigns.to_vec() } @@ -235,16 +253,17 @@ impl CompileStaticInterface { let zero = constant(0, 1); ); let go_guard = guard!(comp_sig["go"]); - let done_guard = guard!(comp_sig["done"]); - let on_guard = go_guard & !done_guard; + let not_go = !guard!(comp_sig["go"]); let signal_on_guard = guard!(sig_reg["out"]); - let done_guard_2 = guard!(comp_sig["done"]); let assigns = build_assignments!(builder; - sig_reg["in"] = on_guard ? one["out"]; - sig_reg["write_en"] = on_guard ? one["out"]; + // For one cycle components, comp.done is just whatever comp.go + // was during the previous cycle. + // signal_reg serves as a forwarding register that delays + // the `go` signal for one cycle. + sig_reg["in"] = go_guard ? one["out"]; + sig_reg["in"] = not_go ? zero["out"]; + sig_reg["write_en"] = ? one["out"]; comp_sig["done"] = signal_on_guard ? one["out"]; - sig_reg["in"] = done_guard_2 ? zero["out"]; - sig_reg["write_en"] = done_guard_2 ? one["out"]; ); assigns.to_vec() } @@ -259,6 +278,7 @@ impl Visitor for CompileStaticInterface { _comps: &[ir::Component], ) -> VisResult { if comp.is_static() && s.get_latency() > 1 { + // Handle components with latency > 1. let latency = s.get_latency(); if let ir::StaticControl::Enable(sen) = s { let mut builder = ir::Builder::new(comp, sigs); @@ -292,6 +312,7 @@ impl Visitor for CompileStaticInterface { } } } else if comp.is_static() && s.get_latency() == 1 { + // Handle components with latency == 1. if let ir::StaticControl::Enable(sen) = s { let assignments = std::mem::take(&mut sen.group.borrow_mut().assignments); @@ -325,8 +346,8 @@ impl Visitor for CompileStaticInterface { _sigs: &ir::LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { + // Remove the control. if comp.is_static() { - //let _c = std::mem::replace(&mut comp.control, Rc::new(RefCell::new(ir::Control::Static(ir::StaticControl::Empty(ir::Empty{attributes:Attributes::default()}))))); let _c = std::mem::replace( &mut comp.control, Rc::new(RefCell::new(ir::Control::Empty(ir::Empty { diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index 932e37b5f..b9aa04c15 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -1,11 +1,9 @@ //! Passes for the Calyx compiler. -mod attribute_promotion; mod canonical; mod cell_share; mod clk_insertion; mod collapse_control; mod comb_prop; -mod compile_empty; mod compile_invoke; mod compile_repeat; mod compile_static; @@ -47,13 +45,11 @@ mod well_formed; mod wire_inliner; mod wrap_main; -pub use attribute_promotion::AttributePromotion; pub use canonical::Canonicalize; pub use cell_share::CellShare; pub use clk_insertion::ClkInsertion; pub use collapse_control::CollapseControl; pub use comb_prop::CombProp; -pub use compile_empty::CompileEmpty; pub use compile_invoke::CompileInvoke; pub use compile_repeat::CompileRepeat; pub use compile_static::CompileStatic; diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index ee20290f8..69f051bea 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -267,7 +267,7 @@ impl Visitor for ScheduleCompaction { let mut builder = ir::Builder::new(comp, sigs); - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { // If entire seq is promotable, then we can compact entire thing // and replace it with a static construct. return Ok(Action::Change(Box::new(self.compact_control_vec( @@ -325,14 +325,22 @@ impl Visitor for ScheduleCompaction { let comp_sig = comp.signature.borrow(); let go_ports: Vec<_> = comp_sig.find_all_with_attr(ir::NumAttr::Go).collect_vec(); + // We only need to check for the @promotable attribute. + // The @interval attribute means the component's control is entirely + // static, meaning it's interval/latency is already locked in, so + // we know we can't change its control, so no need to change its + // signature. if go_ports.iter().any(|go_port| { - go_port.borrow_mut().attributes.has(ir::NumAttr::Static) + go_port.borrow_mut().attributes.has(ir::NumAttr::Promotable) }) { // Getting current latency let cur_latency = go_ports .iter() .filter_map(|go_port| { - go_port.borrow_mut().attributes.get(ir::NumAttr::Static) + go_port + .borrow_mut() + .attributes + .get(ir::NumAttr::Promotable) }) .next() .unwrap(); @@ -350,7 +358,7 @@ impl Visitor for ScheduleCompaction { go_port .borrow_mut() .attributes - .insert(ir::NumAttr::Static, new_latency); + .insert(ir::NumAttr::Promotable, new_latency); } } }; diff --git a/calyx-opt/src/passes/static_inference.rs b/calyx-opt/src/passes/static_inference.rs index 0c1b54d61..c758ef941 100644 --- a/calyx-opt/src/passes/static_inference.rs +++ b/calyx-opt/src/passes/static_inference.rs @@ -6,7 +6,7 @@ use calyx_ir::{self as ir, LibrarySignatures}; use calyx_utils::CalyxResult; use itertools::Itertools; -/// Infer "promote_static" (potentially to be renamed @promotable) annotation +/// Infer @promotable annotation /// for groups and control. /// Inference occurs whenever possible. pub struct StaticInference { @@ -58,12 +58,12 @@ impl Visitor for StaticInference { let comp_sig = comp.signature.borrow(); let mut go_ports: Vec<_> = comp_sig.find_all_with_attr(ir::NumAttr::Go).collect(); - // Insert @static attribute on the go ports. + // Insert @promotable attribute on the go ports. for go_port in &mut go_ports { go_port .borrow_mut() .attributes - .insert(ir::NumAttr::Static, val); + .insert(ir::NumAttr::Promotable, val); } let mut done_ports: Vec<_> = comp_sig.find_all_with_attr(ir::NumAttr::Done).collect(); diff --git a/calyx-opt/src/passes/static_promotion.rs b/calyx-opt/src/passes/static_promotion.rs index 6d2e0fc49..475d0f9f9 100644 --- a/calyx-opt/src/passes/static_promotion.rs +++ b/calyx-opt/src/passes/static_promotion.rs @@ -284,7 +284,9 @@ impl Visitor for StaticPromotion { let go_ports = comp_sig.find_all_with_attr(ir::NumAttr::Go).collect_vec(); if go_ports.iter().any(|go_port| { - go_port.borrow_mut().attributes.has(ir::NumAttr::Static) + let go_ref = go_port.borrow_mut(); + go_ref.attributes.has(ir::NumAttr::Promotable) + || go_ref.attributes.has(ir::NumAttr::Interval) }) { if comp.control.borrow().is_static() { // We ended up promoting it @@ -301,20 +303,21 @@ impl Visitor for StaticPromotion { .unwrap(), ); } else { - // We decided not to promote, so we need to update data structures - // and remove @static attribute from the signature. - - // Updating `static_info`. + // We decided not to promote, so we need to update data structures. + // This case should only happen on @promotable components + // (i.e., it shouldn't happen with @interval components). self.inference_analysis.remove_component(comp.name); - // Removing `@static` from the go ports. - for go_port in go_ports { - go_port - .borrow_mut() - .attributes - .remove(ir::NumAttr::Static); - } } }; + // Either we have upgraded component to static or we have decided + // not to promote component at all. Either way, we can remove the + // @promotable attribute. + for go_port in go_ports { + go_port + .borrow_mut() + .attributes + .remove(ir::NumAttr::Promotable); + } } // Remove @promotable (i.e., @promote_static) attribute from control. // Probably not necessary, since we'll ignore it anyways, but makes for @@ -345,7 +348,7 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { // Convert to static if enable is // within cycle limit and size is above threshold. if self.within_cycle_limit(latency) @@ -367,7 +370,7 @@ impl Visitor for StaticPromotion { _sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { // Convert to static if within cycle limit and size is above threshold. if self.within_cycle_limit(latency) && (APPROX_ENABLE_SIZE > self.threshold) @@ -389,7 +392,7 @@ impl Visitor for StaticPromotion { ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); // Checking if entire seq is promotable - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { // If seq is too small to promote, then continue without doing anything. if Self::approx_control_vec_size(&s.stmts) <= self.threshold { return Ok(Action::Continue); @@ -449,7 +452,7 @@ impl Visitor for StaticPromotion { ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); // Check if entire par is promotable - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { let approx_size: u64 = s.stmts.iter().map(Self::approx_size).sum(); if approx_size <= self.threshold { // Par is too small to promote, continue. @@ -497,7 +500,7 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { let approx_size_if = Self::approx_size(&s.tbranch) + Self::approx_size(&s.fbranch) + APPROX_IF_SIZE; @@ -531,7 +534,7 @@ impl Visitor for StaticPromotion { // This isn't strictly necessary, but it is helpful for parent control // programs applying heuristics. if !(self.within_cycle_limit(latency)) { - s.attributes.remove(ir::NumAttr::PromoteStatic); + s.attributes.remove(ir::NumAttr::Promotable); } } Ok(Action::Continue) @@ -547,7 +550,7 @@ impl Visitor for StaticPromotion { ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); // First check that while loop is promotable - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { let approx_size = Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; // Then check that it fits the heuristics @@ -576,7 +579,7 @@ impl Visitor for StaticPromotion { // This isn't strictly necessary, but it is helpful for parent control // programs applying heuristics. if !(self.within_cycle_limit(latency)) { - s.attributes.remove(ir::NumAttr::PromoteStatic); + s.attributes.remove(ir::NumAttr::Promotable); } } Ok(Action::Continue) @@ -591,7 +594,7 @@ impl Visitor for StaticPromotion { _comps: &[ir::Component], ) -> VisResult { let mut builder = ir::Builder::new(comp, sigs); - if let Some(latency) = s.attributes.get(ir::NumAttr::PromoteStatic) { + if let Some(latency) = s.attributes.get(ir::NumAttr::Promotable) { let approx_size = Self::approx_size(&s.body) + APPROX_WHILE_REPEAT_SIZE; if approx_size > self.threshold && self.within_cycle_limit(latency) @@ -615,7 +618,7 @@ impl Visitor for StaticPromotion { // This isn't strictly necessary, but it is helpful for parent control // programs applying heuristics. if !(self.within_cycle_limit(latency)) { - s.attributes.remove(ir::NumAttr::PromoteStatic); + s.attributes.remove(ir::NumAttr::Promotable); } } Ok(Action::Continue) diff --git a/calyx-opt/src/passes/top_down_compile_control.rs b/calyx-opt/src/passes/top_down_compile_control.rs index 44c31cc50..8a95ddd98 100644 --- a/calyx-opt/src/passes/top_down_compile_control.rs +++ b/calyx-opt/src/passes/top_down_compile_control.rs @@ -454,7 +454,7 @@ impl Schedule<'_, '_> { ir::Control::Par(_) => unreachable!(), ir::Control::Repeat(_) => unreachable!("`repeat` statements should have been compiled away. Run `{}` before this pass.", passes::CompileRepeat::name()), ir::Control::Invoke(_) => unreachable!("`invoke` statements should have been compiled away. Run `{}` before this pass.", passes::CompileInvoke::name()), - ir::Control::Empty(_) => unreachable!("`empty` statements should have been compiled away. Run `{}` before this pass.", passes::CompileEmpty::name()), + ir::Control::Empty(_) => unreachable!("`calculate_states_recur` should not see an `empty` control."), ir::Control::Static(_) => unreachable!("static control should have been compiled away. Run the static compilation passes before this pass") } } diff --git a/calyx-opt/src/passes/well_formed.rs b/calyx-opt/src/passes/well_formed.rs index 3f918e662..eb4d54dd5 100644 --- a/calyx-opt/src/passes/well_formed.rs +++ b/calyx-opt/src/passes/well_formed.rs @@ -94,19 +94,8 @@ impl ConstructVisitor for WellFormed { let reserved_names = RESERVED_NAMES.iter().map(|s| ir::Id::from(*s)).collect(); - for prim in ctx.lib.signatures() { - if prim.attributes.has(ir::NumAttr::Static) { - return Err(Error::malformed_structure(format!("Primitive `{}`: Defining @static attributes on components is deprecated. Place the @static attribute on the port marked as @go", prim.name))); - } - } - let mut ref_cell_types = HashMap::new(); for comp in ctx.components.iter() { - // Defining @static on the component is meaningless - if comp.attributes.has(ir::NumAttr::Static) { - return Err(Error::malformed_structure(format!("Component `{}`: Defining @static attributes on components is deprecated. Place the @static attribute on the port marked as @go", comp.name))); - } - // Main component cannot use `ref` cells if comp.name == ctx.entrypoint { for cell in comp.cells.iter() { @@ -308,6 +297,80 @@ impl Visitor for WellFormed { ); } + // Checking that @interval annotations are placed correctly. + // There are two options for @interval annotations: + // 1. You have written only continuous assignments (this is similar + // to primitives written in Verilog). + // 2. You are using static control. + let comp_sig = &comp.signature.borrow(); + let go_ports = + comp_sig.find_all_with_attr(ir::NumAttr::Go).collect_vec(); + if go_ports.iter().any(|go_port| { + go_port.borrow().attributes.has(ir::NumAttr::Interval) + }) { + match &*comp.control.borrow() { + ir::Control::Static(_) | ir::Control::Empty(_) => (), + _ => return Err(Error::malformed_structure( + format!("component {} has dynamic control but has @interval annotations", comp.name), + ) + .with_pos(&comp.attributes)), + }; + if !comp.control.borrow().is_empty() { + // Getting "reference value" should be the same for all go ports and + // the control. + let reference_val = match go_ports[0] + .borrow() + .attributes + .get(ir::NumAttr::Interval) + { + Some(val) => val, + None => { + return Err(Error::malformed_structure( + "@interval(n) attribute on all @go ports since there is static control", + ) + .with_pos(&comp.attributes)) + } + }; + // Checking go ports. + for go_port in &go_ports { + let go_port_val = match go_port + .borrow() + .attributes + .get(ir::NumAttr::Interval) + { + Some(val) => val, + None => { + return Err(Error::malformed_structure(format!( + "@go port expected @interval({reference_val}) attribute on all ports \ + since the component has static control", + )) + .with_pos(&comp.attributes)) + } + }; + if go_port_val != reference_val { + return Err(Error::malformed_structure(format!( + "@go port expected @interval {reference_val}, got @interval {go_port_val}", + )) + .with_pos(&go_port.borrow().attributes)); + } + // Checking control latency + match comp.control.borrow().get_latency() { + None => { + unreachable!("already checked control is static") + } + Some(control_latency) => { + if control_latency != reference_val { + return Err(Error::malformed_structure(format!( + "component {} expected @interval {reference_val}, got @interval {control_latency}", comp.name, + )) + .with_pos(&comp.attributes)); + } + } + } + } + } + } + // For each non-combinational group, check if there is at least one write to the done // signal of that group and that the write is to the group's done signal. for gr in comp.get_groups().iter() { @@ -467,11 +530,11 @@ impl Visitor for WellFormed { // A group with "static"=0 annotation if group .attributes - .get(ir::NumAttr::Static) + .get(ir::NumAttr::Promotable) .map(|v| v == 0) .unwrap_or(false) { - return Err(Error::malformed_structure("Group with annotation \"static\"=0 is invalid. Use `comb group` instead to define a combinational group or if the group's done condition is not constant, provide the correct \"static\" annotation.").with_pos(&group.attributes)); + return Err(Error::malformed_structure("Group with annotation \"promotable\"=0 is invalid. Use `comb group` instead to define a combinational group or if the group's done condition is not constant, provide the correct \"static\" annotation.").with_pos(&group.attributes)); } // Check if the group has obviously conflicting assignments with the continuous assignments and the active combinational groups diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index e22fdf894..4b0269840 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -205,7 +205,7 @@ class Group(Structure): def doc(self) -> str: static_delay_attr = ( - "" if self.static_delay is None else f'<"static"={self.static_delay}>' + "" if self.static_delay is None else f'<"promotable"={self.static_delay}>' ) return block( f"group {self.id.doc()}{static_delay_attr}", diff --git a/calyx-py/test/correctness/reduction_tree.py b/calyx-py/test/correctness/reduction_tree.py index a9bdd8a6f..b4133e871 100644 --- a/calyx-py/test/correctness/reduction_tree.py +++ b/calyx-py/test/correctness/reduction_tree.py @@ -51,7 +51,7 @@ def use_tree_ports_provided(comp, group, port0, port1, port2, port3, tree, ans_m tree.leaf1 = port1 tree.leaf2 = port2 tree.leaf3 = port3 - tree.go = cb.HI + tree.go = ~tree.done @ cb.HI ans_mem.addr0 = tree.done @ 0 ans_mem.write_data = tree.done @ tree.sum ans_mem.write_en = tree.done @ 1 @@ -79,7 +79,7 @@ def use_tree_ports_calculated( tree.leaf1 = mem_b.read_data tree.leaf2 = mem_c.read_data tree.leaf3 = mem_d.read_data - tree.go = cb.HI + tree.go = ~tree.done @ cb.HI ans_reg.write_en = tree.done @ 1 ans_reg.in_ = tree.done @ tree.sum tree_use.done = ans_reg.done diff --git a/calyx-py/test/invoke.expect b/calyx-py/test/invoke.expect index e3699b676..b735c6401 100644 --- a/calyx-py/test/invoke.expect +++ b/calyx-py/test/invoke.expect @@ -5,7 +5,7 @@ component foo(a: 32) -> (out: 32) { temp = std_reg(32); } wires { - group let<"static"=1> { + group let<"promotable"=1> { temp.in = a; temp.write_en = 1'd1; let[done] = temp.done; @@ -26,7 +26,7 @@ component main() -> () { foo0 = foo(); } wires { - group write_constant<"static"=1> { + group write_constant<"promotable"=1> { b.in = cst.out; b.write_en = 1'd1; write_constant[done] = b.done; diff --git a/examples/futil/dot-product.futil b/examples/futil/dot-product.futil index a4f5bfbe0..d2356b259 100644 --- a/examples/futil/dot-product.futil +++ b/examples/futil/dot-product.futil @@ -25,12 +25,12 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=4> { + group let1<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let1[done] = bin_read0_0.done; @@ -38,24 +38,24 @@ component main() -> () { mult_pipe0.right = B_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { dot_0.in = bin_read0_0.out; dot_0.write_en = 1'd1; let2[done] = dot_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = i0.out; A_read0_0.in = 1'd1 ? A0.read_data; upd0[done] = A_read0_0.done ? 1'd1; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = i0.out; B_read0_0.in = 1'd1 ? B0.read_data; upd1[done] = B_read0_0.done ? 1'd1; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { v0.write_en = 1'd1; add0.left = v0.read_data; add0.right = dot_0.out; @@ -63,7 +63,7 @@ component main() -> () { v0.write_data = 1'd1 ? add0.out; upd2[done] = v0.done ? 1'd1; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { i0.write_en = 1'd1; add1.left = i0.out; add1.right = const3.out; diff --git a/examples/futil/simple.futil b/examples/futil/simple.futil index 172d7a800..4dbd1d332 100644 --- a/examples/futil/simple.futil +++ b/examples/futil/simple.futil @@ -19,7 +19,7 @@ component main() -> () { } wires { - group add_constants<"static"=1> { // This group will finish in 1 cycle. + group add_constants<"promotable"=1> { // This group will finish in 1 cycle. add.left = const0.out; // 4 add.right = const1.out; // 5 reg0.in = add.out; // 4 + 5 = 9 diff --git a/examples/futil/vectorized-add.futil b/examples/futil/vectorized-add.futil index 926c718b2..350e2719b 100644 --- a/examples/futil/vectorized-add.futil +++ b/examples/futil/vectorized-add.futil @@ -20,24 +20,24 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = i0.out; A_read0_0.in = 1'd1 ? A0.read_data; upd0[done] = A_read0_0.done ? 1'd1; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = i0.out; B_read0_0.in = 1'd1 ? B0.read_data; upd1[done] = B_read0_0.done ? 1'd1; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { Sum0.addr0 = i0.out; Sum0.write_en = 1'd1; add0.left = A_read0_0.out; @@ -45,7 +45,7 @@ component main() -> () { Sum0.write_data = 1'd1 ? add0.out; upd2[done] = Sum0.done ? 1'd1; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { i0.write_en = 1'd1; add1.left = i0.out; add1.right = const2.out; diff --git a/interp/tests/control/if.futil b/interp/tests/control/if.futil index 1803ceacc..51479fc45 100644 --- a/interp/tests/control/if.futil +++ b/interp/tests/control/if.futil @@ -8,21 +8,21 @@ component main() -> () { } wires { - comb group cond<"static"=0> { + comb group cond<"promotable"=0> { //b/c lt is used in this distinctly not-last group, //by end of execution all its ports are 0/X/not asserted. lt.left = 32'd9; lt.right = 32'd16; } - group true<"static"=1> { + group true<"promotable"=1> { mem.write_en = 1'd1; mem.addr0 = 1'd0; mem.write_data = 32'd4; true[done] = mem.done; } - group false<"static"=1> { + group false<"promotable"=1> { //since this isn't a single group //execution, mem also has a done of 0 mem.write_en = 1'd1; diff --git a/interp/tests/control/if_reg.futil b/interp/tests/control/if_reg.futil index 3ee480e34..9ae81a7b5 100644 --- a/interp/tests/control/if_reg.futil +++ b/interp/tests/control/if_reg.futil @@ -11,7 +11,7 @@ component main() -> () { } wires { - group cond<"static"=1> { + group cond<"promotable"=1> { reg0.write_en = 1'd1; lt0.left = const0.out; lt0.right = const1.out; @@ -19,13 +19,13 @@ component main() -> () { cond[done] = reg0.done; } - group true<"static"=1> { + group true<"promotable"=1> { reg1.write_en = 1'd1; reg1.in = 32'd15; true[done] = reg1.done; } - group false<"static"=1> { + group false<"promotable"=1> { reg1.write_en = 1'd1; reg1.in = 32'd10; false[done] = reg1.done; diff --git a/interp/tests/control/par_mem.futil b/interp/tests/control/par_mem.futil index d0d1dabe2..cb77b176d 100644 --- a/interp/tests/control/par_mem.futil +++ b/interp/tests/control/par_mem.futil @@ -9,21 +9,21 @@ component main() -> () { } wires { - group wr_a<"static"=1> { + group wr_a<"promotable"=1> { a.addr0 = 1'b0; a.write_en = 1'b1; a.write_data = 32'd1; wr_a[done] = a.done; } - group wr_b<"static"=1> { + group wr_b<"promotable"=1> { b.addr0 = 1'b0; b.write_en = 1'b1; b.write_data = 32'd1; wr_b[done] = b.done; } - group wr_c<"static"=1> { + group wr_c<"promotable"=1> { c.addr0 = 1'b0; c.write_en = 1'b1; c.write_data = 32'd1; diff --git a/interp/tests/control/par_reg.futil b/interp/tests/control/par_reg.futil index d4e1b0d35..55b327d6b 100644 --- a/interp/tests/control/par_reg.futil +++ b/interp/tests/control/par_reg.futil @@ -9,19 +9,19 @@ component main() -> () { } wires { - group wr_a<"static"=1> { + group wr_a<"promotable"=1> { a.in = 32'd1; a.write_en = 1'd1; wr_a[done] = a.done; } - group wr_b<"static"=1> { + group wr_b<"promotable"=1> { b.in = 32'd1; b.write_en = 1'd1; wr_b[done] = b.done; } - group wr_c<"static"=1> { + group wr_c<"promotable"=1> { c.in = 32'd1; c.write_en = 1'd1; wr_c[done] = c.done; diff --git a/primitives/binary_operators.futil b/primitives/binary_operators.futil index 7672dc726..9ce0907ea 100644 --- a/primitives/binary_operators.futil +++ b/primitives/binary_operators.futil @@ -13,7 +13,7 @@ extern "binary_operators.sv" { ]( @clk clk: 1, @reset reset: 1, - @write_together(1) @static(3) @go go: 1, + @write_together(1) @interval(3) @go go: 1, @write_together(1) @data left: WIDTH, @write_together(1) @data right: WIDTH ) -> ( @@ -53,7 +53,7 @@ extern "binary_operators.sv" { ]( @clk clk: 1, @reset reset: 1, - @write_together(1) @static(3) @go go: 1, + @write_together(1) @interval(3) @go go: 1, @write_together(1) @data left: WIDTH, @write_together(1) @data right: WIDTH ) -> ( @@ -89,7 +89,7 @@ extern "binary_operators.sv" { primitive std_mult_pipe<"state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, - @write_together(1) @static(3) @go go: 1, + @write_together(1) @interval(3) @go go: 1, @write_together(1) @data left: WIDTH, @write_together(1) @data right: WIDTH ) -> ( @@ -116,7 +116,7 @@ extern "binary_operators.sv" { primitive std_smult_pipe<"state_share"=1>[WIDTH]( @clk clk: 1, @reset reset: 1, - @write_together(1) @static(3) @go go: 1, + @write_together(1) @interval(3) @go go: 1, @write_together(1) @data left: WIDTH, @write_together(1) @data right: WIDTH ) -> ( diff --git a/primitives/compile.futil b/primitives/compile.futil index 9ff400098..30b5eac06 100644 --- a/primitives/compile.futil +++ b/primitives/compile.futil @@ -22,7 +22,7 @@ comb primitive std_add<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) // ANCHOR: std_reg_def primitive std_reg<"state_share"=1>[WIDTH]( @write_together(1) @data in: WIDTH, - @write_together(1) @static(1) @go write_en: 1, + @write_together(1) @interval(1) @go write_en: 1, @clk clk: 1, @reset reset: 1 ) -> ( diff --git a/primitives/core.futil b/primitives/core.futil index 1e13daa5d..7965cc5e9 100644 --- a/primitives/core.futil +++ b/primitives/core.futil @@ -23,5 +23,4 @@ extern "core.sv" { comb primitive std_lsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_rsh<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_mux<"share"=1>[WIDTH](@data cond: 1, @data tru: WIDTH, @data fal: WIDTH) -> (out: WIDTH); - } diff --git a/primitives/memories/comb.futil b/primitives/memories/comb.futil index 434775241..cbe4754ae 100644 --- a/primitives/memories/comb.futil +++ b/primitives/memories/comb.futil @@ -7,7 +7,7 @@ extern "comb.sv" { primitive comb_mem_d1[WIDTH, SIZE, IDX_SIZE]( @read_together(1) addr0: IDX_SIZE, @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, + @write_together(1) @interval(1) @go write_en: 1, @clk clk: 1, @reset reset: 1 ) -> ( @@ -19,7 +19,7 @@ extern "comb.sv" { @read_together(1) @write_together(2) addr0: D0_IDX_SIZE, @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, + @write_together(1) @interval(1) @go write_en: 1, @clk clk: 1, @reset reset: 1 ) -> ( @@ -40,7 +40,7 @@ extern "comb.sv" { @read_together(1) @write_together(2) addr1: D1_IDX_SIZE, @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, + @write_together(1) @interval(1) @go write_en: 1, @clk clk: 1, @reset reset: 1 ) -> ( @@ -64,7 +64,7 @@ extern "comb.sv" { @read_together(1) @write_together(2) addr2: D2_IDX_SIZE, @read_together(1) @write_together(2) addr3: D3_IDX_SIZE, @write_together(1) @data write_data: WIDTH, - @write_together(1) @static(1) @go write_en: 1, + @write_together(1) @interval(1) @go write_en: 1, @clk clk: 1 ) -> ( @read_together(1) read_data: WIDTH, diff --git a/tests/backend/mlir/attributes.expect b/tests/backend/mlir/attributes.expect index 07f2a7c68..8c6d3352c 100644 --- a/tests/backend/mlir/attributes.expect +++ b/tests/backend/mlir/attributes.expect @@ -1,5 +1,5 @@ module attributes {calyx.entrypoint = "main" } { -calyx.component @main(%in: i32 {foo=32}, %go: i1 {static=10, go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i32 {static=0}, %done: i1 {done=1}) { +calyx.component @main(%in: i32 {foo=32}, %go: i1 {promotable=10, go=1}, %clk: i1 {clk=1}, %reset: i1 {reset=1}) -> (%out: i32 {promotable=0}, %done: i1 {done=1}) { %r.in, %r.write_en, %r.clk, %r.reset, %r.out, %r.done = calyx.register @r {precious=1} : i32, i1, i1, i1, i32, i1 %le.left, %le.right, %le.out = calyx.std_le @le {bar=32} : i32, i32, i1 calyx.wires { @@ -7,12 +7,12 @@ calyx.component @main(%in: i32 {foo=32}, %go: i1 {static=10, go=1}, %clk: i1 {cl calyx.group_done %r.done : i1 } {stable=1} calyx.comb_group @cond { - } {static=0} + } {promotable=0} } calyx.control { calyx.while %le.out with @cond { - calyx.enable @upd {static=2} + calyx.enable @upd {promotable=2} } {bound=32} } } diff --git a/tests/backend/mlir/attributes.futil b/tests/backend/mlir/attributes.futil index fa05d9fa8..75a6eb42c 100644 --- a/tests/backend/mlir/attributes.futil +++ b/tests/backend/mlir/attributes.futil @@ -2,7 +2,7 @@ import "primitives/core.futil"; import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; -component main<"state_share"=1>(@foo(32) in: 32, @static(10) @go go: 1, @clk clk: 1, @reset reset: 1) -> (@static(0) out: 32, @done done: 1) { +component main<"state_share"=1>(@foo(32) in: 32, @promotable(10) @go go: 1, @clk clk: 1, @reset reset: 1) -> (@promotable(0) out: 32, @done done: 1) { cells { @precious r = std_reg(32); @bar(32) le = std_le(32); @@ -11,12 +11,12 @@ component main<"state_share"=1>(@foo(32) in: 32, @static(10) @go go: 1, @clk clk group upd<"stable"=1> { upd[done] = r.done; } - comb group cond<"static"=0> { + comb group cond<"promotable"=0> { } } control { @bound(32) while le.out with cond { - @static(2) upd; + @promotable(2) upd; } } } diff --git a/tests/backend/yxi/dot-product.futil b/tests/backend/yxi/dot-product.futil index bc922fa88..22168796c 100644 --- a/tests/backend/yxi/dot-product.futil +++ b/tests/backend/yxi/dot-product.futil @@ -26,12 +26,12 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=4> { + group let1<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let1[done] = bin_read0_0.done; @@ -39,24 +39,24 @@ component main() -> () { mult_pipe0.right = B_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { dot_0.in = bin_read0_0.out; dot_0.write_en = 1'd1; let2[done] = dot_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = i0.out; A_read0_0.in = 1'd1 ? A0.read_data; upd0[done] = A_read0_0.done ? 1'd1; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = i0.out; B_read0_0.in = 1'd1 ? B0.read_data; upd1[done] = B_read0_0.done ? 1'd1; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { v0.write_en = 1'd1; add0.left = v0.read_data; add0.right = dot_0.out; @@ -64,7 +64,7 @@ component main() -> () { v0.write_data = 1'd1 ? add0.out; upd2[done] = v0.done ? 1'd1; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { i0.write_en = 1'd1; add1.left = i0.out; add1.right = const3.out; diff --git a/tests/correctness/static-interface/use-both-interfaces-one-cycle.expect b/tests/correctness/static-interface/use-both-interfaces-one-cycle.expect new file mode 100644 index 000000000..29b0445a4 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces-one-cycle.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 100 + ] +} diff --git a/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil b/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil new file mode 100644 index 000000000..e50a7e878 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil @@ -0,0 +1,77 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component mac(in: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = r.out; + add.right = in; + r.in = add.out; + r.write_en = 1'd1; + } + out = r.out; + } + control { + a; + } +} + +component main () -> () { + cells { + my_mac = mac(); + acc = std_reg(32); + adder = std_add(32); + counter = std_reg(32); + my_lt = std_lt(32); + @external out = comb_mem_d1(32, 1, 1); + + dummy = std_reg(32); + } + wires { + group mac_five { + my_mac.go = 1'd1; + my_mac.in = 32'd5; + mac_five[done] = my_mac.done; + } + group write_mem { + out.write_data = my_mac.out; + out.addr0 = 1'd0; + out.write_en = 1'd1; + write_mem[done] = out.done; + } + group incr_counter { + // Very dumb, but we don't want to infer this as promotable + // and this effects the promotion heuristics ... bottom line, + // we need to check both static and dynamic contexts + dummy.in = 32'd2; + dummy.write_en = 1'd1; + + adder.left = 32'd1; + adder.right = counter.out; + counter.in = adder.out; + counter.write_en = 1'd1; + incr_counter[done] = counter.done & dummy.done ? 1'd1; + } + my_lt.left = counter.out; + my_lt.right = 32'd10; + } + + control { + repeat 10 { + // Should be promoted to static + mac_five; + } + while my_lt.out { + seq { + // Should not be promoted to static, use done signal + mac_five; + incr_counter; + } + } + write_mem; + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil.data b/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces-one-cycle.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/use-both-interfaces.expect b/tests/correctness/static-interface/use-both-interfaces.expect new file mode 100644 index 000000000..9d3725238 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces.expect @@ -0,0 +1,5 @@ +{ + "out": [ + 300 + ] +} diff --git a/tests/correctness/static-interface/use-both-interfaces.futil b/tests/correctness/static-interface/use-both-interfaces.futil new file mode 100644 index 000000000..4ba833fe5 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces.futil @@ -0,0 +1,81 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component triple_mac(in: 32) -> (out: 32) { + cells { + add = std_add(32); + r = std_reg(32); + } + wires { + static<1> group a { + add.left = r.out; + add.right = in; + r.in = add.out; + r.write_en = 1'd1; + } + out = r.out; + } + control { + static seq { + a; + a; + a; + } + } +} + +component main () -> () { + cells { + my_mac = triple_mac(); + acc = std_reg(32); + adder = std_add(32); + counter = std_reg(32); + my_lt = std_lt(32); + @external out = comb_mem_d1(32, 1, 1); + + dummy = std_reg(32); + } + wires { + group mac_five { + my_mac.go = 1'd1; + my_mac.in = 32'd5; + mac_five[done] = my_mac.done; + } + group write_mem { + out.write_data = my_mac.out; + out.addr0 = 1'd0; + out.write_en = 1'd1; + write_mem[done] = out.done; + } + group incr_counter { + // Very dumb, but we don't want to infer this as promotable + // and this effects the promotion heuristics ... bottom line, + // we need to check both static and dynamic contexts + dummy.in = 32'd2; + dummy.write_en = 1'd1; + + adder.left = 32'd1; + adder.right = counter.out; + counter.in = adder.out; + counter.write_en = 1'd1; + incr_counter[done] = counter.done & dummy.done ? 1'd1; + } + my_lt.left = counter.out; + my_lt.right = 32'd10; + } + + control { + repeat 10 { + // Should be promoted to static + mac_five; + } + while my_lt.out { + seq { + // Should not be promoted to static + mac_five; + incr_counter; + } + } + write_mem; + } +} \ No newline at end of file diff --git a/tests/correctness/static-interface/use-both-interfaces.futil.data b/tests/correctness/static-interface/use-both-interfaces.futil.data new file mode 100644 index 000000000..cf2477695 --- /dev/null +++ b/tests/correctness/static-interface/use-both-interfaces.futil.data @@ -0,0 +1,12 @@ +{ + "out": { + "data": [ + 0 + ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/frontend/dahlia/binop_tree.expect b/tests/frontend/dahlia/binop_tree.expect index fcba7bc35..516fbb854 100644 --- a/tests/frontend/dahlia/binop_tree.expect +++ b/tests/frontend/dahlia/binop_tree.expect @@ -22,32 +22,32 @@ component main() -> () { x_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { a_0.in = const0.out; a_0.write_en = 1'd1; let0[done] = a_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { b_0.in = const1.out; b_0.write_en = 1'd1; let1[done] = b_0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { c_0.in = const2.out; c_0.write_en = 1'd1; let2[done] = c_0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { d_0.in = const3.out; d_0.write_en = 1'd1; let3[done] = d_0.done; } - group let4<"static"=1> { + group let4<"promotable"=1> { e_0.in = const4.out; e_0.write_en = 1'd1; let4[done] = e_0.done; } - group let5<"static"=4> { + group let5<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let5[done] = bin_read0_0.done; @@ -63,7 +63,7 @@ component main() -> () { div_pipe0.right = e_0.out; div_pipe0.go = !div_pipe0.done ? 1'd1; } - group let7<"static"=1> { + group let7<"promotable"=1> { x_0.in = add1.out; x_0.write_en = 1'd1; let7[done] = x_0.done; diff --git a/tests/frontend/dahlia/combine.expect b/tests/frontend/dahlia/combine.expect index a4c3679cd..d4d9e5cce 100644 --- a/tests/frontend/dahlia/combine.expect +++ b/tests/frontend/dahlia/combine.expect @@ -19,26 +19,26 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=2> { + group let1<"promotable"=2> { acc_0.in = A.read_data; acc_0.write_en = A.read_done; let1[done] = acc_0.done; A.addr0 = i0.out; A.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { res_0.write_en = 1'd1; add0.left = res_0.out; add0.right = acc_0.out; res_0.in = add0.out; upd0[done] = res_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { i0.write_en = 1'd1; add1.left = i0.out; add1.right = const2.out; diff --git a/tests/frontend/dahlia/dot-func.expect b/tests/frontend/dahlia/dot-func.expect index 01c45727c..9363646fa 100644 --- a/tests/frontend/dahlia/dot-func.expect +++ b/tests/frontend/dahlia/dot-func.expect @@ -22,26 +22,26 @@ component dot() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=2> { + group let1<"promotable"=2> { A_read0_0.in = A.read_data; A_read0_0.write_en = A.read_done; let1[done] = A_read0_0.done; A.addr0 = i0.out; A.read_en = 1'd1; } - group let2<"static"=2> { + group let2<"promotable"=2> { B_read0_0.in = B.read_data; B_read0_0.write_en = B.read_done; let2[done] = B_read0_0.done; B.addr0 = i0.out; B.read_en = 1'd1; } - group let3<"static"=4> { + group let3<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let3[done] = bin_read0_0.done; @@ -49,13 +49,13 @@ component dot() -> () { mult_pipe0.right = B_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { out.addr0 = i0.out; out.write_en = 1'd1; out.write_data = bin_read0_0.out; upd0[done] = out.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = const2.out; diff --git a/tests/frontend/dahlia/fixed-point-add.expect b/tests/frontend/dahlia/fixed-point-add.expect index 45b367203..df5133e72 100644 --- a/tests/frontend/dahlia/fixed-point-add.expect +++ b/tests/frontend/dahlia/fixed-point-add.expect @@ -10,12 +10,12 @@ component main() -> () { y_0 = std_reg(4); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = fp_const0.out; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = add0.out; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/frontend/dahlia/for.expect b/tests/frontend/dahlia/for.expect index e86427fc7..74e333c9b 100644 --- a/tests/frontend/dahlia/for.expect +++ b/tests/frontend/dahlia/for.expect @@ -15,12 +15,12 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = const2.out; diff --git a/tests/frontend/dahlia/if.expect b/tests/frontend/dahlia/if.expect index bb99de3ac..5ff4bfdf3 100644 --- a/tests/frontend/dahlia/if.expect +++ b/tests/frontend/dahlia/if.expect @@ -16,12 +16,12 @@ component main() -> () { lt0.left = const0.out; lt0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = const2.out; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = const3.out; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/frontend/dahlia/invoke-memory.expect b/tests/frontend/dahlia/invoke-memory.expect index 4e5d380c7..2c868faba 100644 --- a/tests/frontend/dahlia/invoke-memory.expect +++ b/tests/frontend/dahlia/invoke-memory.expect @@ -15,19 +15,19 @@ component mem_copy(length: 3) -> () { lt0.left = i_0.out; lt0.right = length; } - group let0<"static"=1> { + group let0<"promotable"=1> { i_0.in = const0.out; i_0.write_en = 1'd1; let0[done] = i_0.done; } - group let1<"static"=2> { + group let1<"promotable"=2> { src_read0_0.in = src.read_data; src_read0_0.write_en = src.read_done; let1[done] = src_read0_0.done; src.addr0 = i_0.out; src.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { dest.addr0 = i_0.out; dest.write_en = 1'd1; dest.write_data = src_read0_0.out; @@ -55,7 +55,7 @@ component main() -> () { @external(1) s = seq_mem_d1(32,5,3); } wires { - group let2<"static"=1> { + group let2<"promotable"=1> { len_0.in = const1.out; len_0.write_en = 1'd1; let2[done] = len_0.done; diff --git a/tests/frontend/dahlia/invoke.expect b/tests/frontend/dahlia/invoke.expect index d7e33bcaa..de3bb1bca 100644 --- a/tests/frontend/dahlia/invoke.expect +++ b/tests/frontend/dahlia/invoke.expect @@ -7,7 +7,7 @@ component add(a: 32, b: 32) -> (@stable(1) out: 32) { tmp_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { tmp_0.in = add0.out; tmp_0.write_en = 1'd1; let0[done] = tmp_0.done; @@ -30,12 +30,12 @@ component main() -> () { sum_0 = std_reg(32); } wires { - group let1<"static"=1> { + group let1<"promotable"=1> { lhs_0.in = const0.out; lhs_0.write_en = 1'd1; let1[done] = lhs_0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { rhs_0.in = const1.out; rhs_0.write_en = 1'd1; let2[done] = rhs_0.done; diff --git a/tests/frontend/dahlia/matadd-fixed-point.expect b/tests/frontend/dahlia/matadd-fixed-point.expect index 009033928..c631be0b1 100644 --- a/tests/frontend/dahlia/matadd-fixed-point.expect +++ b/tests/frontend/dahlia/matadd-fixed-point.expect @@ -31,17 +31,17 @@ component main() -> () { le1.left = j0.out; le1.right = const3.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { j0.in = const2.out; j0.write_en = 1'd1; let1[done] = j0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { a0_0_read0_0.in = a0_0.read_data; a0_0_read0_0.write_en = a0_0.read_done; let2[done] = a0_0_read0_0.done; @@ -49,7 +49,7 @@ component main() -> () { a0_0.addr0 = i0.out; a0_0.read_en = 1'd1; } - group let3<"static"=2> { + group let3<"promotable"=2> { b0_0_read0_0.in = b0_0.read_data; b0_0_read0_0.write_en = b0_0.read_done; let3[done] = b0_0_read0_0.done; @@ -57,7 +57,7 @@ component main() -> () { b0_0.addr0 = i0.out; b0_0.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { result0_0.addr1 = j0.out; result0_0.addr0 = i0.out; result0_0.write_en = 1'd1; @@ -66,14 +66,14 @@ component main() -> () { result0_0.write_data = add0.out; upd0[done] = result0_0.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { j0.write_en = 1'd1; add1.left = j0.out; add1.right = const4.out; j0.in = add1.out; upd1[done] = j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { i0.write_en = 1'd1; add2.left = i0.out; add2.right = const5.out; diff --git a/tests/frontend/dahlia/memory.expect b/tests/frontend/dahlia/memory.expect index 9db0d3eaa..0e9773a1a 100644 --- a/tests/frontend/dahlia/memory.expect +++ b/tests/frontend/dahlia/memory.expect @@ -17,20 +17,20 @@ component main() -> () { const8 = std_const(4,0); } wires { - group upd0<"static"=1> { + group upd0<"promotable"=1> { A.addr0 = const1.out; A.write_en = 1'd1; A.write_data = const0.out; upd0[done] = A.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B.addr1 = const4.out; B.addr0 = const3.out; B.write_en = 1'd1; B.write_data = const2.out; upd1[done] = B.write_done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { C.addr2 = const8.out; C.addr1 = const7.out; C.addr0 = const6.out; diff --git a/tests/frontend/dahlia/par.expect b/tests/frontend/dahlia/par.expect index 2fbe8e566..fe9fa9c2d 100644 --- a/tests/frontend/dahlia/par.expect +++ b/tests/frontend/dahlia/par.expect @@ -9,12 +9,12 @@ component main() -> () { y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = const0.out; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = const1.out; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/frontend/dahlia/seq.expect b/tests/frontend/dahlia/seq.expect index 6b71796fc..0c9369db3 100644 --- a/tests/frontend/dahlia/seq.expect +++ b/tests/frontend/dahlia/seq.expect @@ -9,12 +9,12 @@ component main() -> () { y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = const0.out; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = const1.out; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/frontend/dahlia/signed_dotproduct.expect b/tests/frontend/dahlia/signed_dotproduct.expect index ec1645ac1..d73788461 100644 --- a/tests/frontend/dahlia/signed_dotproduct.expect +++ b/tests/frontend/dahlia/signed_dotproduct.expect @@ -28,17 +28,17 @@ component main() -> () { le0.left = i0.out; le0.right = const2.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { res_0.in = const0.out; res_0.write_en = 1'd1; let0[done] = res_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { i0.in = const1.out; i0.write_en = 1'd1; let1[done] = i0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { a0_read0_0.in = a0.read_data; a0_read0_0.write_en = a0.read_done; let2[done] = a0_read0_0.done; @@ -46,7 +46,7 @@ component main() -> () { slice0.in = i0.out; a0.read_en = 1'd1; } - group let3<"static"=2> { + group let3<"promotable"=2> { b0_read0_0.in = b0.read_data; b0_read0_0.write_en = b0.read_done; let3[done] = b0_read0_0.done; @@ -54,7 +54,7 @@ component main() -> () { slice1.in = i0.out; b0.read_en = 1'd1; } - group let4<"static"=4> { + group let4<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let4[done] = bin_read0_0.done; @@ -62,26 +62,26 @@ component main() -> () { mult_pipe0.right = b0_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let5<"static"=1> { + group let5<"promotable"=1> { v_0.in = bin_read0_0.out; v_0.write_en = 1'd1; let5[done] = v_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { res_0.write_en = 1'd1; add0.left = res_0.out; add0.right = v_0.out; res_0.in = add0.out; upd0[done] = res_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { i0.write_en = 1'd1; add1.left = i0.out; add1.right = const3.out; i0.in = add1.out; upd1[done] = i0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { result.write_en = 1'd1; result.in = res_0.out; upd2[done] = result.done; diff --git a/tests/frontend/dahlia/unroll.expect b/tests/frontend/dahlia/unroll.expect index edb79383b..367e11f3f 100644 --- a/tests/frontend/dahlia/unroll.expect +++ b/tests/frontend/dahlia/unroll.expect @@ -32,12 +32,12 @@ component main() -> () { le0.left = i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group upd0<"static"=2> { + group upd0<"promotable"=2> { acc_00.write_en = A0.read_done; A0.addr0 = slice0.out; slice0.in = i0.out; @@ -45,7 +45,7 @@ component main() -> () { acc_00.in = A0.read_data; upd0[done] = acc_00.done; } - group upd1<"static"=2> { + group upd1<"promotable"=2> { acc_10.write_en = A1.read_done; A1.addr0 = slice1.out; slice1.in = i0.out; @@ -53,7 +53,7 @@ component main() -> () { acc_10.in = A1.read_data; upd1[done] = acc_10.done; } - group upd2<"static"=2> { + group upd2<"promotable"=2> { acc_20.write_en = A2.read_done; A2.addr0 = slice2.out; slice2.in = i0.out; @@ -61,7 +61,7 @@ component main() -> () { acc_20.in = A2.read_data; upd2[done] = acc_20.done; } - group upd3<"static"=2> { + group upd3<"promotable"=2> { acc_30.write_en = A3.read_done; A3.addr0 = slice3.out; slice3.in = i0.out; @@ -69,7 +69,7 @@ component main() -> () { acc_30.in = A3.read_data; upd3[done] = acc_30.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { res_0.write_en = 1'd1; add3.left = res_0.out; add3.right = add2.out; @@ -82,7 +82,7 @@ component main() -> () { res_0.in = add3.out; upd4[done] = res_0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { i0.write_en = 1'd1; add4.left = i0.out; add4.right = const2.out; diff --git a/tests/frontend/exp/degree-2-unsigned.expect b/tests/frontend/exp/degree-2-unsigned.expect index 885bdbbb4..a322142f5 100644 --- a/tests/frontend/exp/degree-2-unsigned.expect +++ b/tests/frontend/exp/degree-2-unsigned.expect @@ -24,7 +24,7 @@ component exp(x: 32) -> (out: 32) { pow2 = fp_pow(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { exponent_value.write_en = 1'd1; exponent_value.in = x; init[done] = exponent_value.done; @@ -42,7 +42,7 @@ component exp(x: 32) -> (out: 32) { frac_x.in = and1.out; split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } - group consume_pow2<"static"=1> { + group consume_pow2<"promotable"=1> { p2.write_en = 1'd1; p2.in = pow2.out; consume_pow2[done] = p2.done ? 1'd1; @@ -55,14 +55,14 @@ component exp(x: 32) -> (out: 32) { product2.in = mult_pipe2.out; mult_by_reciprocal_factorial2[done] = product2.done; } - group sum_round1_1<"static"=1> { + group sum_round1_1<"promotable"=1> { add1.left = frac_x.out; add1.right = product2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round1_1[done] = sum1.done; } - group add_degree_zero<"static"=1> { + group add_degree_zero<"promotable"=1> { add1.left = sum1.out; add1.right = one.out; sum1.write_en = 1'd1; diff --git a/tests/frontend/exp/degree-4-signed.expect b/tests/frontend/exp/degree-4-signed.expect index bbf5ec0be..2d4bf16b3 100644 --- a/tests/frontend/exp/degree-4-signed.expect +++ b/tests/frontend/exp/degree-4-signed.expect @@ -41,7 +41,7 @@ component exp(x: 16) -> (out: 16) { pow4 = fp_pow(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { exponent_value.write_en = 1'd1; exponent_value.in = x; init[done] = exponent_value.done; @@ -79,17 +79,17 @@ component exp(x: 16) -> (out: 16) { m.in = div_pipe.out_quotient; reciprocal[done] = m.done; } - group consume_pow2<"static"=1> { + group consume_pow2<"promotable"=1> { p2.write_en = 1'd1; p2.in = pow2.out; consume_pow2[done] = p2.done ? 1'd1; } - group consume_pow3<"static"=1> { + group consume_pow3<"promotable"=1> { p3.write_en = 1'd1; p3.in = pow3.out; consume_pow3[done] = p3.done ? 1'd1; } - group consume_pow4<"static"=1> { + group consume_pow4<"promotable"=1> { p4.write_en = 1'd1; p4.in = pow4.out; consume_pow4[done] = p4.done ? 1'd1; @@ -118,28 +118,28 @@ component exp(x: 16) -> (out: 16) { product4.in = mult_pipe4.out; mult_by_reciprocal_factorial4[done] = product4.done; } - group sum_round1_1<"static"=1> { + group sum_round1_1<"promotable"=1> { add1.left = frac_x.out; add1.right = product2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round1_1[done] = sum1.done; } - group sum_round1_2<"static"=1> { + group sum_round1_2<"promotable"=1> { add2.left = product3.out; add2.right = product4.out; sum2.write_en = 1'd1; sum2.in = add2.out; sum_round1_2[done] = sum2.done; } - group sum_round2_1<"static"=1> { + group sum_round2_1<"promotable"=1> { add1.left = sum1.out; add1.right = sum2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round2_1[done] = sum1.done; } - group add_degree_zero<"static"=1> { + group add_degree_zero<"promotable"=1> { add1.left = sum1.out; add1.right = one.out; sum1.write_en = 1'd1; diff --git a/tests/frontend/exp/degree-4-unsigned.expect b/tests/frontend/exp/degree-4-unsigned.expect index 98a047cdb..4e0c1f85d 100644 --- a/tests/frontend/exp/degree-4-unsigned.expect +++ b/tests/frontend/exp/degree-4-unsigned.expect @@ -38,7 +38,7 @@ component exp(x: 16) -> (out: 16) { pow4 = fp_pow(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { exponent_value.write_en = 1'd1; exponent_value.in = x; init[done] = exponent_value.done; @@ -56,17 +56,17 @@ component exp(x: 16) -> (out: 16) { frac_x.in = and1.out; split_bits[done] = (int_x.done & frac_x.done) ? 1'd1; } - group consume_pow2<"static"=1> { + group consume_pow2<"promotable"=1> { p2.write_en = 1'd1; p2.in = pow2.out; consume_pow2[done] = p2.done ? 1'd1; } - group consume_pow3<"static"=1> { + group consume_pow3<"promotable"=1> { p3.write_en = 1'd1; p3.in = pow3.out; consume_pow3[done] = p3.done ? 1'd1; } - group consume_pow4<"static"=1> { + group consume_pow4<"promotable"=1> { p4.write_en = 1'd1; p4.in = pow4.out; consume_pow4[done] = p4.done ? 1'd1; @@ -95,28 +95,28 @@ component exp(x: 16) -> (out: 16) { product4.in = mult_pipe4.out; mult_by_reciprocal_factorial4[done] = product4.done; } - group sum_round1_1<"static"=1> { + group sum_round1_1<"promotable"=1> { add1.left = frac_x.out; add1.right = product2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round1_1[done] = sum1.done; } - group sum_round1_2<"static"=1> { + group sum_round1_2<"promotable"=1> { add2.left = product3.out; add2.right = product4.out; sum2.write_en = 1'd1; sum2.in = add2.out; sum_round1_2[done] = sum2.done; } - group sum_round2_1<"static"=1> { + group sum_round2_1<"promotable"=1> { add1.left = sum1.out; add1.right = sum2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round2_1[done] = sum1.done; } - group add_degree_zero<"static"=1> { + group add_degree_zero<"promotable"=1> { add1.left = sum1.out; add1.right = one.out; sum1.write_en = 1'd1; diff --git a/tests/frontend/relay/batch_flatten-same-dimensions.expect b/tests/frontend/relay/batch_flatten-same-dimensions.expect index 4a0d96ba9..3babccb72 100644 --- a/tests/frontend/relay/batch_flatten-same-dimensions.expect +++ b/tests/frontend/relay/batch_flatten-same-dimensions.expect @@ -33,22 +33,22 @@ component batch_flatten_2x4096() -> () { le1.left = __j0.out; le1.right = const4.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __k_0.in = const0.out; __k_0.write_en = 1'd1; let0[done] = __k_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __i0.in = const1.out; __i0.write_en = 1'd1; let1[done] = __i0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __j0.in = const3.out; __j0.write_en = 1'd1; let2[done] = __j0.done; } - group let3<"static"=2> { + group let3<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let3[done] = x_read0_0.done; @@ -56,28 +56,28 @@ component batch_flatten_2x4096() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __k_0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __k_0.write_en = 1'd1; add0.left = __k_0.out; add0.right = const5.out; __k_0.in = add0.out; upd1[done] = __k_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __j0.write_en = 1'd1; add1.left = __j0.out; add1.right = const6.out; __j0.in = add1.out; upd2[done] = __j0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __i0.write_en = 1'd1; add2.left = __i0.out; add2.right = const7.out; diff --git a/tests/frontend/relay/batch_flatten.expect b/tests/frontend/relay/batch_flatten.expect index c508e5619..8b4a51f52 100644 --- a/tests/frontend/relay/batch_flatten.expect +++ b/tests/frontend/relay/batch_flatten.expect @@ -43,27 +43,27 @@ component batch_flatten_1x4() -> () { le2.left = __k0.out; le2.right = const6.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __l_0.in = const0.out; __l_0.write_en = 1'd1; let0[done] = __l_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __i0.in = const1.out; __i0.write_en = 1'd1; let1[done] = __i0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __j0.in = const3.out; __j0.write_en = 1'd1; let2[done] = __j0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __k0.in = const5.out; __k0.write_en = 1'd1; let3[done] = __k0.done; } - group let4<"static"=2> { + group let4<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let4[done] = x_read0_0.done; @@ -72,35 +72,35 @@ component batch_flatten_1x4() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __l_0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __l_0.write_en = 1'd1; add0.left = __l_0.out; add0.right = const7.out; __l_0.in = add0.out; upd1[done] = __l_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __k0.write_en = 1'd1; add1.left = __k0.out; add1.right = const8.out; __k0.in = add1.out; upd2[done] = __k0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __j0.write_en = 1'd1; add2.left = __j0.out; add2.right = const9.out; __j0.in = add2.out; upd3[done] = __j0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __i0.write_en = 1'd1; add3.left = __i0.out; add3.right = const10.out; diff --git a/tests/frontend/relay/batch_matmul.expect b/tests/frontend/relay/batch_matmul.expect index 7b9cbdb27..fead34bc0 100644 --- a/tests/frontend/relay/batch_matmul.expect +++ b/tests/frontend/relay/batch_matmul.expect @@ -88,22 +88,22 @@ component batch_matmul_4x7x7() -> () { le6.left = __k0.out; le6.right = const16.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __batch0.in = const0.out; __batch0.write_en = 1'd1; let0[done] = __batch0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __i0.in = const2.out; __i0.write_en = 1'd1; let1[done] = __i0.done; } - group let10<"static"=1> { + group let10<"promotable"=1> { __product_0.in = bin_read0_0.out; __product_0.write_en = 1'd1; let10[done] = __product_0.done; } - group let11<"static"=2> { + group let11<"promotable"=2> { red_read00.in = x.read_data; red_read00.write_en = x.read_done; let11[done] = red_read00.done; @@ -112,12 +112,12 @@ component batch_matmul_4x7x7() -> () { x.addr0 = __batch1.out; x.read_en = 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { __j0.in = const4.out; __j0.write_en = 1'd1; let2[done] = __j0.done; } - group let3<"static"=2> { + group let3<"promotable"=2> { b_read0_0.in = b.read_data; b_read0_0.write_en = b.read_done; let3[done] = b_read0_0.done; @@ -126,27 +126,27 @@ component batch_matmul_4x7x7() -> () { b.addr0 = __batch0.out; b.read_en = 1'd1; } - group let4<"static"=1> { + group let4<"promotable"=1> { __batch1.in = const9.out; __batch1.write_en = 1'd1; let4[done] = __batch1.done; } - group let5<"static"=1> { + group let5<"promotable"=1> { __i1.in = const11.out; __i1.write_en = 1'd1; let5[done] = __i1.done; } - group let6<"static"=1> { + group let6<"promotable"=1> { __j1.in = const13.out; __j1.write_en = 1'd1; let6[done] = __j1.done; } - group let7<"static"=1> { + group let7<"promotable"=1> { __k0.in = const15.out; __k0.write_en = 1'd1; let7[done] = __k0.done; } - group let8<"static"=2> { + group let8<"promotable"=2> { a_read0_0.in = a.read_data; a_read0_0.write_en = a.read_done; let8[done] = a_read0_0.done; @@ -155,7 +155,7 @@ component batch_matmul_4x7x7() -> () { a.addr0 = __batch1.out; a.read_en = 1'd1; } - group let9<"static"=4> { + group let9<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let9[done] = bin_read0_0.done; @@ -163,7 +163,7 @@ component batch_matmul_4x7x7() -> () { mult_pipe0.right = __transpose_b_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { __transpose_b0_0_0.addr2 = __i0.out; __transpose_b0_0_0.addr1 = __j0.out; __transpose_b0_0_0.addr0 = __batch0.out; @@ -171,28 +171,28 @@ component batch_matmul_4x7x7() -> () { __transpose_b0_0_0.write_data = b_read0_0.out; upd0[done] = __transpose_b0_0_0.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add0.left = __j0.out; add0.right = const6.out; __j0.in = add0.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add1.left = __i0.out; add1.right = const7.out; __i0.in = add1.out; upd2[done] = __i0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __batch0.write_en = 1'd1; add2.left = __batch0.out; add2.right = const8.out; __batch0.in = add2.out; upd3[done] = __batch0.done; } - group upd4<"static"=2> { + group upd4<"promotable"=2> { __transpose_b_read0_0.write_en = __transpose_b0_0_0.read_done; __transpose_b0_0_0.addr2 = __j1.out; __transpose_b0_0_0.addr1 = __k0.out; @@ -201,7 +201,7 @@ component batch_matmul_4x7x7() -> () { __transpose_b_read0_0.in = __transpose_b0_0_0.read_data; upd4[done] = __transpose_b_read0_0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { x.addr2 = __j1.out; x.addr1 = __i1.out; x.addr0 = __batch1.out; @@ -211,28 +211,28 @@ component batch_matmul_4x7x7() -> () { x.write_data = add3.out; upd5[done] = x.write_done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { __k0.write_en = 1'd1; add4.left = __k0.out; add4.right = const17.out; __k0.in = add4.out; upd6[done] = __k0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { __j1.write_en = 1'd1; add5.left = __j1.out; add5.right = const18.out; __j1.in = add5.out; upd7[done] = __j1.done; } - group upd8<"static"=1> { + group upd8<"promotable"=1> { __i1.write_en = 1'd1; add6.left = __i1.out; add6.right = const19.out; __i1.in = add6.out; upd8[done] = __i1.done; } - group upd9<"static"=1> { + group upd9<"promotable"=1> { __batch1.write_en = 1'd1; add7.left = __batch1.out; add7.right = const20.out; diff --git a/tests/frontend/relay/bias_add.expect b/tests/frontend/relay/bias_add.expect index cc6d360e0..afd34c5ab 100644 --- a/tests/frontend/relay/bias_add.expect +++ b/tests/frontend/relay/bias_add.expect @@ -52,27 +52,27 @@ component bias_add_1x64x512x256() -> () { le3.left = __l0.out; le3.right = const7.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __k0.in = const4.out; __k0.write_en = 1'd1; let2[done] = __k0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __l0.in = const6.out; __l0.write_en = 1'd1; let3[done] = __l0.done; } - group let4<"static"=2> { + group let4<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let4[done] = x_read0_0.done; @@ -82,14 +82,14 @@ component bias_add_1x64x512x256() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let5<"static"=2> { + group let5<"promotable"=2> { bias_read0_0.in = bias.read_data; bias_read0_0.write_en = bias.read_done; let5[done] = bias_read0_0.done; bias.addr0 = __j0.out; bias.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; @@ -100,28 +100,28 @@ component bias_add_1x64x512x256() -> () { x1.write_data = add0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __l0.write_en = 1'd1; add1.left = __l0.out; add1.right = const8.out; __l0.in = add1.out; upd1[done] = __l0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __k0.write_en = 1'd1; add2.left = __k0.out; add2.right = const9.out; __k0.in = add2.out; upd2[done] = __k0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __j0.write_en = 1'd1; add3.left = __j0.out; add3.right = const10.out; __j0.in = add3.out; upd3[done] = __j0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __i0.write_en = 1'd1; add4.left = __i0.out; add4.right = const11.out; diff --git a/tests/frontend/relay/broadcast.expect b/tests/frontend/relay/broadcast.expect index 91ec84086..93b0f564f 100644 --- a/tests/frontend/relay/broadcast.expect +++ b/tests/frontend/relay/broadcast.expect @@ -33,17 +33,17 @@ component add_2x4() -> () { le1.left = __j0.out; le1.right = const3.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let2[done] = x_read0_0.done; @@ -51,7 +51,7 @@ component add_2x4() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let3<"static"=2> { + group let3<"promotable"=2> { y_read0_0.in = y.read_data; y_read0_0.write_en = y.read_done; let3[done] = y_read0_0.done; @@ -59,7 +59,7 @@ component add_2x4() -> () { y.addr0 = __i0.out; y.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; @@ -68,14 +68,14 @@ component add_2x4() -> () { x1.write_data = add0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add1.left = __j0.out; add1.right = const5.out; __j0.in = add1.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add2.left = __i0.out; add2.right = const6.out; diff --git a/tests/frontend/relay/constant-multiply.expect b/tests/frontend/relay/constant-multiply.expect index f4ff21b93..e843c9127 100644 --- a/tests/frontend/relay/constant-multiply.expect +++ b/tests/frontend/relay/constant-multiply.expect @@ -21,19 +21,19 @@ component multiply_1(x1: 32) -> () { le0.left = __i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=2> { + group let1<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let1[done] = x_read0_0.done; x.addr0 = __i0.out; x.read_en = 1'd1; } - group let2<"static"=4> { + group let2<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let2[done] = bin_read0_0.done; @@ -41,13 +41,13 @@ component multiply_1(x1: 32) -> () { mult_pipe0.right = x1; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x2.addr0 = __i0.out; x2.write_en = 1'd1; x2.write_data = bin_read0_0.out; upd0[done] = x2.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __i0.write_en = 1'd1; add0.left = __i0.out; add0.right = const2.out; diff --git a/tests/frontend/relay/conv2d.expect b/tests/frontend/relay/conv2d.expect index 629f92dc4..b755a86ce 100644 --- a/tests/frontend/relay/conv2d.expect +++ b/tests/frontend/relay/conv2d.expect @@ -141,17 +141,17 @@ component conv2d_5x512x14x14() -> () { lt1.left = __kernel_x_0.out; lt1.right = const21.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __b0.in = const0.out; __b0.write_en = 1'd1; let0[done] = __b0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __c0.in = const2.out; __c0.write_en = 1'd1; let1[done] = __c0.done; } - group let10<"static"=4> { + group let10<"promotable"=4> { bin_read1_0.in = mult_pipe1.out; bin_read1_0.write_en = mult_pipe1.done; let10[done] = bin_read1_0.done; @@ -159,19 +159,19 @@ component conv2d_5x512x14x14() -> () { mult_pipe1.right = __x0.out; mult_pipe1.go = !mult_pipe1.done ? 1'd1; } - group let11<"static"=1> { + group let11<"promotable"=1> { __kernel_x_0.in = add1.out; __kernel_x_0.write_en = 1'd1; let11[done] = __kernel_x_0.done; add1.left = bin_read1_0.out; add1.right = __dx0.out; } - group let12<"static"=1> { + group let12<"promotable"=1> { __padded_tensor_val_0.in = const17.out; __padded_tensor_val_0.write_en = 1'd1; let12[done] = __padded_tensor_val_0.done; } - group let13<"static"=2> { + group let13<"promotable"=2> { data_read0_0.in = data.read_data; data_read0_0.write_en = data.read_done; let13[done] = data_read0_0.done; @@ -189,7 +189,7 @@ component conv2d_5x512x14x14() -> () { slice0.in = __b0.out; data.read_en = 1'd1; } - group let14<"static"=2> { + group let14<"promotable"=2> { weight_read0_0.in = weight.read_data; weight_read0_0.write_en = weight.read_done; let14[done] = weight_read0_0.done; @@ -203,7 +203,7 @@ component conv2d_5x512x14x14() -> () { slice4.in = __c0.out; weight.read_en = 1'd1; } - group let15<"static"=4> { + group let15<"promotable"=4> { bin_read2_0.in = mult_pipe2.out; bin_read2_0.write_en = mult_pipe2.done; let15[done] = bin_read2_0.done; @@ -211,37 +211,37 @@ component conv2d_5x512x14x14() -> () { mult_pipe2.right = weight_read0_0.out; mult_pipe2.go = !mult_pipe2.done ? 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { __y0.in = const4.out; __y0.write_en = 1'd1; let2[done] = __y0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __x0.in = const6.out; __x0.write_en = 1'd1; let3[done] = __x0.done; } - group let4<"static"=1> { + group let4<"promotable"=1> { __sum_0.in = const8.out; __sum_0.write_en = 1'd1; let4[done] = __sum_0.done; } - group let5<"static"=1> { + group let5<"promotable"=1> { __k0.in = const9.out; __k0.write_en = 1'd1; let5[done] = __k0.done; } - group let6<"static"=1> { + group let6<"promotable"=1> { __dy0.in = const11.out; __dy0.write_en = 1'd1; let6[done] = __dy0.done; } - group let7<"static"=1> { + group let7<"promotable"=1> { __dx0.in = const13.out; __dx0.write_en = 1'd1; let7[done] = __dx0.done; } - group let8<"static"=4> { + group let8<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let8[done] = bin_read0_0.done; @@ -249,47 +249,47 @@ component conv2d_5x512x14x14() -> () { mult_pipe0.right = __y0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let9<"static"=1> { + group let9<"promotable"=1> { __kernel_y_0.in = add0.out; __kernel_y_0.write_en = 1'd1; let9[done] = __kernel_y_0.done; add0.left = bin_read0_0.out; add0.right = __dy0.out; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { __padded_tensor_val_0.write_en = 1'd1; __padded_tensor_val_0.in = data_read0_0.out; upd0[done] = __padded_tensor_val_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __sum_0.write_en = 1'd1; add2.left = __sum_0.out; add2.right = bin_read2_0.out; __sum_0.in = add2.out; upd1[done] = __sum_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __dx0.write_en = 1'd1; add3.left = __dx0.out; add3.right = const24.out; __dx0.in = add3.out; upd2[done] = __dx0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __dy0.write_en = 1'd1; add4.left = __dy0.out; add4.right = const25.out; __dy0.in = add4.out; upd3[done] = __dy0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __k0.write_en = 1'd1; add5.left = __k0.out; add5.right = const26.out; __k0.in = add5.out; upd4[done] = __k0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { x.addr3 = slice11.out; slice11.in = __x0.out; x.addr2 = slice10.out; @@ -302,28 +302,28 @@ component conv2d_5x512x14x14() -> () { x.write_data = __sum_0.out; upd5[done] = x.write_done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { __x0.write_en = 1'd1; add6.left = __x0.out; add6.right = const27.out; __x0.in = add6.out; upd6[done] = __x0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { __y0.write_en = 1'd1; add7.left = __y0.out; add7.right = const28.out; __y0.in = add7.out; upd7[done] = __y0.done; } - group upd8<"static"=1> { + group upd8<"promotable"=1> { __c0.write_en = 1'd1; add8.left = __c0.out; add8.right = const29.out; __c0.in = add8.out; upd8[done] = __c0.done; } - group upd9<"static"=1> { + group upd9<"promotable"=1> { __b0.write_en = 1'd1; add9.left = __b0.out; add9.right = const30.out; diff --git a/tests/frontend/relay/dense.expect b/tests/frontend/relay/dense.expect index aa7c00511..39d9f12c7 100644 --- a/tests/frontend/relay/dense.expect +++ b/tests/frontend/relay/dense.expect @@ -46,22 +46,22 @@ component dense_1x10() -> () { le2.left = __k0.out; le2.right = const5.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __k0.in = const4.out; __k0.write_en = 1'd1; let2[done] = __k0.done; } - group let3<"static"=2> { + group let3<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let3[done] = x_read0_0.done; @@ -69,7 +69,7 @@ component dense_1x10() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let4<"static"=2> { + group let4<"promotable"=2> { y_read0_0.in = y.read_data; y_read0_0.write_en = y.read_done; let4[done] = y_read0_0.done; @@ -77,7 +77,7 @@ component dense_1x10() -> () { y.addr0 = __j0.out; y.read_en = 1'd1; } - group let5<"static"=4> { + group let5<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let5[done] = bin_read0_0.done; @@ -85,12 +85,12 @@ component dense_1x10() -> () { mult_pipe0.right = y_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let6<"static"=1> { + group let6<"promotable"=1> { __product_0.in = bin_read0_0.out; __product_0.write_en = 1'd1; let6[done] = __product_0.done; } - group let7<"static"=2> { + group let7<"promotable"=2> { red_read00.in = x1.read_data; red_read00.write_en = x1.read_done; let7[done] = red_read00.done; @@ -98,7 +98,7 @@ component dense_1x10() -> () { x1.addr0 = __i0.out; x1.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; @@ -107,21 +107,21 @@ component dense_1x10() -> () { x1.write_data = add0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __k0.write_en = 1'd1; add1.left = __k0.out; add1.right = const6.out; __k0.in = add1.out; upd1[done] = __k0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __j0.write_en = 1'd1; add2.left = __j0.out; add2.right = const7.out; __j0.in = add2.out; upd2[done] = __j0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __i0.write_en = 1'd1; add3.left = __i0.out; add3.right = const8.out; diff --git a/tests/frontend/relay/duplicate-relay-call.expect b/tests/frontend/relay/duplicate-relay-call.expect index 1c4919703..13b64c01d 100644 --- a/tests/frontend/relay/duplicate-relay-call.expect +++ b/tests/frontend/relay/duplicate-relay-call.expect @@ -31,17 +31,17 @@ component negative_2x2() -> () { le1.left = __j0.out; le1.right = const3.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let2[done] = x_read0_0.done; @@ -49,7 +49,7 @@ component negative_2x2() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; @@ -58,14 +58,14 @@ component negative_2x2() -> () { x1.write_data = sub0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add0.left = __j0.out; add0.right = const5.out; __j0.in = add0.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add1.left = __i0.out; add1.right = const6.out; diff --git a/tests/frontend/relay/max_pool2d.expect b/tests/frontend/relay/max_pool2d.expect index 81cd81874..0df1a3990 100644 --- a/tests/frontend/relay/max_pool2d.expect +++ b/tests/frontend/relay/max_pool2d.expect @@ -99,36 +99,36 @@ component max_pool2d_2x2x2x2() -> () { gt0.left = __current_0.out; gt0.right = __max_0.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __b0.in = const0.out; __b0.write_en = 1'd1; let0[done] = __b0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __c0.in = const2.out; __c0.write_en = 1'd1; let1[done] = __c0.done; } - group let10<"static"=1> { + group let10<"promotable"=1> { __n0.in = const12.out; __n0.write_en = 1'd1; let10[done] = __n0.done; } - group let11<"static"=1> { + group let11<"promotable"=1> { __pool_y_0.in = add0.out; __pool_y_0.write_en = 1'd1; let11[done] = __pool_y_0.done; add0.left = __stride_y_0.out; add0.right = __m0.out; } - group let12<"static"=1> { + group let12<"promotable"=1> { __pool_x_0.in = add1.out; __pool_x_0.write_en = 1'd1; let12[done] = __pool_x_0.done; add1.left = __stride_x_0.out; add1.right = __n0.out; } - group let13<"static"=2> { + group let13<"promotable"=2> { __current_0.in = data.read_data; __current_0.write_en = data.read_done; let13[done] = __current_0.done; @@ -142,17 +142,17 @@ component max_pool2d_2x2x2x2() -> () { slice4.in = __b0.out; data.read_en = 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { __y0.in = const4.out; __y0.write_en = 1'd1; let2[done] = __y0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __x0.in = const6.out; __x0.write_en = 1'd1; let3[done] = __x0.done; } - group let4<"static"=4> { + group let4<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let4[done] = bin_read0_0.done; @@ -160,12 +160,12 @@ component max_pool2d_2x2x2x2() -> () { mult_pipe0.right = const8.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let5<"static"=1> { + group let5<"promotable"=1> { __stride_y_0.in = bin_read0_0.out; __stride_y_0.write_en = 1'd1; let5[done] = __stride_y_0.done; } - group let6<"static"=4> { + group let6<"promotable"=4> { bin_read1_0.in = mult_pipe1.out; bin_read1_0.write_en = mult_pipe1.done; let6[done] = bin_read1_0.done; @@ -173,12 +173,12 @@ component max_pool2d_2x2x2x2() -> () { mult_pipe1.right = const9.out; mult_pipe1.go = !mult_pipe1.done ? 1'd1; } - group let7<"static"=1> { + group let7<"promotable"=1> { __stride_x_0.in = bin_read1_0.out; __stride_x_0.write_en = 1'd1; let7[done] = __stride_x_0.done; } - group let8<"static"=2> { + group let8<"promotable"=2> { __max_0.in = data.read_data; __max_0.write_en = data.read_done; let8[done] = __max_0.done; @@ -192,31 +192,31 @@ component max_pool2d_2x2x2x2() -> () { slice0.in = __b0.out; data.read_en = 1'd1; } - group let9<"static"=1> { + group let9<"promotable"=1> { __m0.in = const10.out; __m0.write_en = 1'd1; let9[done] = __m0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { __max_0.write_en = 1'd1; __max_0.in = __current_0.out; upd0[done] = __max_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __n0.write_en = 1'd1; add2.left = __n0.out; add2.right = const14.out; __n0.in = add2.out; upd1[done] = __n0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __m0.write_en = 1'd1; add3.left = __m0.out; add3.right = const15.out; __m0.in = add3.out; upd2[done] = __m0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { result.addr3 = slice11.out; slice11.in = __x0.out; result.addr2 = slice10.out; @@ -229,28 +229,28 @@ component max_pool2d_2x2x2x2() -> () { result.write_data = __max_0.out; upd3[done] = result.write_done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __x0.write_en = 1'd1; add4.left = __x0.out; add4.right = const16.out; __x0.in = add4.out; upd4[done] = __x0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { __y0.write_en = 1'd1; add5.left = __y0.out; add5.right = const17.out; __y0.in = add5.out; upd5[done] = __y0.done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { __c0.write_en = 1'd1; add6.left = __c0.out; add6.right = const18.out; __c0.in = add6.out; upd6[done] = __c0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { __b0.write_en = 1'd1; add7.left = __b0.out; add7.right = const19.out; diff --git a/tests/frontend/relay/negative.expect b/tests/frontend/relay/negative.expect index 2c6de0938..5770fa359 100644 --- a/tests/frontend/relay/negative.expect +++ b/tests/frontend/relay/negative.expect @@ -21,19 +21,19 @@ component negative_4() -> () { le0.left = __i0.out; le0.right = const1.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=2> { + group let1<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let1[done] = x_read0_0.done; x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr0 = __i0.out; x1.write_en = 1'd1; sub0.left = const2.out; @@ -41,7 +41,7 @@ component negative_4() -> () { x1.write_data = sub0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __i0.write_en = 1'd1; add0.left = __i0.out; add0.right = const3.out; diff --git a/tests/frontend/relay/relu.expect b/tests/frontend/relay/relu.expect index 30080dd8c..3031812ea 100644 --- a/tests/frontend/relay/relu.expect +++ b/tests/frontend/relay/relu.expect @@ -57,27 +57,27 @@ component relu_2x4x8x32() -> () { gt0.left = x_read0_0.out; gt0.right = fp_const0.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __k0.in = const4.out; __k0.write_en = 1'd1; let2[done] = __k0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __l0.in = const6.out; __l0.write_en = 1'd1; let3[done] = __l0.done; } - group let4<"static"=2> { + group let4<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let4[done] = x_read0_0.done; @@ -87,7 +87,7 @@ component relu_2x4x8x32() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let5<"static"=2> { + group let5<"promotable"=2> { x_read1_0.in = x.read_data; x_read1_0.write_en = x.read_done; let5[done] = x_read1_0.done; @@ -97,7 +97,7 @@ component relu_2x4x8x32() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; @@ -106,7 +106,7 @@ component relu_2x4x8x32() -> () { x1.write_data = x_read1_0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; @@ -115,28 +115,28 @@ component relu_2x4x8x32() -> () { x1.write_data = fp_const1.out; upd1[done] = x1.write_done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __l0.write_en = 1'd1; add0.left = __l0.out; add0.right = const8.out; __l0.in = add0.out; upd2[done] = __l0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __k0.write_en = 1'd1; add1.left = __k0.out; add1.right = const9.out; __k0.in = add1.out; upd3[done] = __k0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __j0.write_en = 1'd1; add2.left = __j0.out; add2.right = const10.out; __j0.in = add2.out; upd4[done] = __j0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { __i0.write_en = 1'd1; add3.left = __i0.out; add3.right = const11.out; diff --git a/tests/frontend/relay/reshape.expect b/tests/frontend/relay/reshape.expect index 977617197..51e398d78 100644 --- a/tests/frontend/relay/reshape.expect +++ b/tests/frontend/relay/reshape.expect @@ -54,32 +54,32 @@ component reshape_1x8() -> () { le3.left = __l0.out; le3.right = const8.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __m_0.in = const0.out; __m_0.write_en = 1'd1; let0[done] = __m_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __i0.in = const1.out; __i0.write_en = 1'd1; let1[done] = __i0.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { __j0.in = const3.out; __j0.write_en = 1'd1; let2[done] = __j0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { __k0.in = const5.out; __k0.write_en = 1'd1; let3[done] = __k0.done; } - group let4<"static"=1> { + group let4<"promotable"=1> { __l0.in = const7.out; __l0.write_en = 1'd1; let4[done] = __l0.done; } - group let5<"static"=2> { + group let5<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let5[done] = x_read0_0.done; @@ -89,42 +89,42 @@ component reshape_1x8() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __m_0.out; x1.addr0 = const9.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __m_0.write_en = 1'd1; add0.left = __m_0.out; add0.right = const10.out; __m_0.in = add0.out; upd1[done] = __m_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __l0.write_en = 1'd1; add1.left = __l0.out; add1.right = const11.out; __l0.in = add1.out; upd2[done] = __l0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __k0.write_en = 1'd1; add2.left = __k0.out; add2.right = const12.out; __k0.in = add2.out; upd3[done] = __k0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __j0.write_en = 1'd1; add3.left = __j0.out; add3.right = const13.out; __j0.in = add3.out; upd4[done] = __j0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { __i0.write_en = 1'd1; add4.left = __i0.out; add4.right = const14.out; diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index cc2a50e36..b66310665 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -83,7 +83,7 @@ component softmax_1x10() -> () { le4.left = __k0.out; le4.right = const14.out; } - group let0<"static"=2> { + group let0<"promotable"=2> { __max_0.in = x.read_data; __max_0.write_en = x.read_done; let0[done] = __max_0.done; @@ -91,7 +91,7 @@ component softmax_1x10() -> () { x.addr0 = const0.out; x.read_en = 1'd1; } - group let1<"static"=1> { + group let1<"promotable"=1> { __i0.in = const2.out; __i0.write_en = 1'd1; let1[done] = __i0.done; @@ -101,12 +101,12 @@ component softmax_1x10() -> () { __t1_0.write_en = 1'd1; let10[done] = __t1_0.done; } - group let11<"static"=1> { + group let11<"promotable"=1> { __k0.in = const13.out; __k0.write_en = 1'd1; let11[done] = __k0.done; } - group let12<"static"=2> { + group let12<"promotable"=2> { x_read3_0.in = x.read_data; x_read3_0.write_en = x.read_done; let12[done] = x_read3_0.done; @@ -114,7 +114,7 @@ component softmax_1x10() -> () { x.addr0 = __i1.out; x.read_en = 1'd1; } - group let13<"static"=1> { + group let13<"promotable"=1> { __t2_0.in = sub1.out; __t2_0.write_en = 1'd1; let13[done] = __t2_0.done; @@ -134,12 +134,12 @@ component softmax_1x10() -> () { div_pipe0.right = __exp_sum_0.out; div_pipe0.go = !div_pipe0.done ? 1'd1; } - group let2<"static"=1> { + group let2<"promotable"=1> { __j0.in = const4.out; __j0.write_en = 1'd1; let2[done] = __j0.done; } - group let3<"static"=2> { + group let3<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let3[done] = x_read0_0.done; @@ -147,7 +147,7 @@ component softmax_1x10() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let4<"static"=2> { + group let4<"promotable"=2> { x_read1_0.in = x.read_data; x_read1_0.write_en = x.read_done; let4[done] = x_read1_0.done; @@ -155,22 +155,22 @@ component softmax_1x10() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let5<"static"=1> { + group let5<"promotable"=1> { __i1.in = const8.out; __i1.write_en = 1'd1; let5[done] = __i1.done; } - group let6<"static"=1> { + group let6<"promotable"=1> { __exp_sum_0.in = fp_const0.out; __exp_sum_0.write_en = 1'd1; let6[done] = __exp_sum_0.done; } - group let7<"static"=1> { + group let7<"promotable"=1> { __j1.in = const10.out; __j1.write_en = 1'd1; let7[done] = __j1.done; } - group let8<"static"=2> { + group let8<"promotable"=2> { x_read2_0.in = x.read_data; x_read2_0.write_en = x.read_done; let8[done] = x_read2_0.done; @@ -178,61 +178,61 @@ component softmax_1x10() -> () { x.addr0 = __i1.out; x.read_en = 1'd1; } - group let9<"static"=1> { + group let9<"promotable"=1> { __t0_0.in = sub0.out; __t0_0.write_en = 1'd1; let9[done] = __t0_0.done; sub0.left = x_read2_0.out; sub0.right = __max_0.out; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { __max_0.write_en = 1'd1; __max_0.in = x_read1_0.out; upd0[done] = __max_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add0.left = __j0.out; add0.right = const6.out; __j0.in = add0.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add1.left = __i0.out; add1.right = const7.out; __i0.in = add1.out; upd2[done] = __i0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { __exp_sum_0.write_en = 1'd1; add2.left = __exp_sum_0.out; add2.right = __t1_0.out; __exp_sum_0.in = add2.out; upd3[done] = __exp_sum_0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { __j1.write_en = 1'd1; add3.left = __j1.out; add3.right = const12.out; __j1.in = add3.out; upd4[done] = __j1.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { x1.addr1 = __k0.out; x1.addr0 = __i1.out; x1.write_en = 1'd1; x1.write_data = bin_read0_0.out; upd5[done] = x1.write_done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { __k0.write_en = 1'd1; add4.left = __k0.out; add4.right = const15.out; __k0.in = add4.out; upd6[done] = __k0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { __i1.write_en = 1'd1; add5.left = __i1.out; add5.right = const16.out; @@ -363,7 +363,7 @@ component exp(x: 32) -> (out: 32) { pow8 = fp_pow(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { exponent_value.write_en = 1'd1; exponent_value.in = x; init[done] = exponent_value.done; @@ -401,37 +401,37 @@ component exp(x: 32) -> (out: 32) { m.in = div_pipe.out_quotient; reciprocal[done] = m.done; } - group consume_pow2<"static"=1> { + group consume_pow2<"promotable"=1> { p2.write_en = 1'd1; p2.in = pow2.out; consume_pow2[done] = p2.done ? 1'd1; } - group consume_pow3<"static"=1> { + group consume_pow3<"promotable"=1> { p3.write_en = 1'd1; p3.in = pow3.out; consume_pow3[done] = p3.done ? 1'd1; } - group consume_pow4<"static"=1> { + group consume_pow4<"promotable"=1> { p4.write_en = 1'd1; p4.in = pow4.out; consume_pow4[done] = p4.done ? 1'd1; } - group consume_pow5<"static"=1> { + group consume_pow5<"promotable"=1> { p5.write_en = 1'd1; p5.in = pow5.out; consume_pow5[done] = p5.done ? 1'd1; } - group consume_pow6<"static"=1> { + group consume_pow6<"promotable"=1> { p6.write_en = 1'd1; p6.in = pow6.out; consume_pow6[done] = p6.done ? 1'd1; } - group consume_pow7<"static"=1> { + group consume_pow7<"promotable"=1> { p7.write_en = 1'd1; p7.in = pow7.out; consume_pow7[done] = p7.done ? 1'd1; } - group consume_pow8<"static"=1> { + group consume_pow8<"promotable"=1> { p8.write_en = 1'd1; p8.in = pow8.out; consume_pow8[done] = p8.done ? 1'd1; @@ -492,56 +492,56 @@ component exp(x: 32) -> (out: 32) { product8.in = mult_pipe8.out; mult_by_reciprocal_factorial8[done] = product8.done; } - group sum_round1_1<"static"=1> { + group sum_round1_1<"promotable"=1> { add1.left = frac_x.out; add1.right = product2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round1_1[done] = sum1.done; } - group sum_round1_2<"static"=1> { + group sum_round1_2<"promotable"=1> { add2.left = product3.out; add2.right = product4.out; sum2.write_en = 1'd1; sum2.in = add2.out; sum_round1_2[done] = sum2.done; } - group sum_round1_3<"static"=1> { + group sum_round1_3<"promotable"=1> { add3.left = product5.out; add3.right = product6.out; sum3.write_en = 1'd1; sum3.in = add3.out; sum_round1_3[done] = sum3.done; } - group sum_round1_4<"static"=1> { + group sum_round1_4<"promotable"=1> { add4.left = product7.out; add4.right = product8.out; sum4.write_en = 1'd1; sum4.in = add4.out; sum_round1_4[done] = sum4.done; } - group sum_round2_1<"static"=1> { + group sum_round2_1<"promotable"=1> { add1.left = sum1.out; add1.right = sum2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round2_1[done] = sum1.done; } - group sum_round2_2<"static"=1> { + group sum_round2_2<"promotable"=1> { add2.left = sum3.out; add2.right = sum4.out; sum2.write_en = 1'd1; sum2.in = add2.out; sum_round2_2[done] = sum2.done; } - group sum_round3_1<"static"=1> { + group sum_round3_1<"promotable"=1> { add1.left = sum1.out; add1.right = sum2.out; sum1.write_en = 1'd1; sum1.in = add1.out; sum_round3_1[done] = sum1.done; } - group add_degree_zero<"static"=1> { + group add_degree_zero<"promotable"=1> { add1.left = sum1.out; add1.right = one.out; sum1.write_en = 1'd1; diff --git a/tests/frontend/relay/sqrt.expect b/tests/frontend/relay/sqrt.expect index 48645d9aa..c6b20dcb3 100644 --- a/tests/frontend/relay/sqrt.expect +++ b/tests/frontend/relay/sqrt.expect @@ -31,17 +31,17 @@ component sqrt_1x4() -> () { le1.left = __j0.out; le1.right = const3.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let2[done] = x_read0_0.done; @@ -54,21 +54,21 @@ component sqrt_1x4() -> () { __tmp_0.write_en = 1'd1; let3[done] = __tmp_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = __tmp_0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add0.left = __j0.out; add0.right = const4.out; __j0.in = add0.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add1.left = __i0.out; add1.right = const5.out; diff --git a/tests/frontend/relay/tensor_add.expect b/tests/frontend/relay/tensor_add.expect index 61e3a0fb4..6900f3583 100644 --- a/tests/frontend/relay/tensor_add.expect +++ b/tests/frontend/relay/tensor_add.expect @@ -32,17 +32,17 @@ component add_2x4() -> () { le1.left = __j0.out; le1.right = const3.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { __i0.in = const0.out; __i0.write_en = 1'd1; let0[done] = __i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { __j0.in = const2.out; __j0.write_en = 1'd1; let1[done] = __j0.done; } - group let2<"static"=2> { + group let2<"promotable"=2> { x_read0_0.in = x.read_data; x_read0_0.write_en = x.read_done; let2[done] = x_read0_0.done; @@ -50,7 +50,7 @@ component add_2x4() -> () { x.addr0 = __i0.out; x.read_en = 1'd1; } - group let3<"static"=2> { + group let3<"promotable"=2> { y_read0_0.in = y.read_data; y_read0_0.write_en = y.read_done; let3[done] = y_read0_0.done; @@ -58,7 +58,7 @@ component add_2x4() -> () { y.addr0 = __i0.out; y.read_en = 1'd1; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; @@ -67,14 +67,14 @@ component add_2x4() -> () { x1.write_data = add0.out; upd0[done] = x1.write_done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { __j0.write_en = 1'd1; add1.left = __j0.out; add1.right = const4.out; __j0.in = add1.out; upd1[done] = __j0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { __i0.write_en = 1'd1; add2.left = __i0.out; add2.right = const5.out; diff --git a/tests/import/a.expect b/tests/import/a.expect index cd8f25fc8..ea7847939 100644 --- a/tests/import/a.expect +++ b/tests/import/a.expect @@ -5,10 +5,10 @@ extern "/calyx/tests/import/verilog/b.sv" { primitive std_max() -> (); } extern "/calyx/primitives/memories/comb.sv" { - primitive comb_mem_d1[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive comb_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive comb_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); - primitive comb_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @read_together @write_together(2) addr3: D3_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d1[WIDTH, SIZE, IDX_SIZE](@read_together addr0: IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @interval @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @interval @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @interval @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@read_together read_data: WIDTH, @done done: 1); + primitive comb_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE](@read_together @write_together(2) addr0: D0_IDX_SIZE, @read_together @write_together(2) addr1: D1_IDX_SIZE, @read_together @write_together(2) addr2: D2_IDX_SIZE, @read_together @write_together(2) addr3: D3_IDX_SIZE, @write_together @data write_data: WIDTH, @write_together @interval @go write_en: 1, @clk clk: 1) -> (@read_together read_data: WIDTH, @done done: 1); } extern "/calyx/primitives/core.sv" { comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); @@ -41,7 +41,7 @@ comb primitive std_wire<"share"=1>[WIDTH](@data in: WIDTH) -> (out: WIDTH) { comb primitive std_add<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH) { assign out = left + right; } -primitive std_reg<"state_share"=1>[WIDTH](@write_together @data in: WIDTH, @write_together @static @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1) { +primitive std_reg<"state_share"=1>[WIDTH](@write_together @data in: WIDTH, @write_together @interval @go write_en: 1, @clk clk: 1, @reset reset: 1) -> (@stable out: WIDTH, @done done: 1) { always_ff @(posedge clk) begin if (reset) begin out <= 0; diff --git a/tests/parsing/attributes.expect b/tests/parsing/attributes.expect index ecd9ac2df..d1e89a371 100644 --- a/tests/parsing/attributes.expect +++ b/tests/parsing/attributes.expect @@ -1,6 +1,6 @@ import "primitives/core.futil"; import "primitives/binary_operators.futil"; -component main<"static"=1>(@foo(32) @go_port in: 32, go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (@static(0) out: 32, done: 1, @done done0: 1) { +component main(@foo(32) @go_port in: 32, go: 1, clk: 1, @interval @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (@interval(0) out: 32, done: 1, @done done0: 1) { cells { @precious r = std_reg(32); @bar(32) le = std_le(32); @@ -9,7 +9,7 @@ component main<"static"=1>(@foo(32) @go_port in: 32, go: 1, clk: 1, @go go0: 1, group upd<"stable"=1> { @dead upd[done] = r.done; } - comb group cond<"static"=0> { + comb group cond<"promotable"=0> { } } control { diff --git a/tests/passes/attr-promotion.expect b/tests/passes/attr-promotion.expect deleted file mode 100644 index a72cf49ed..000000000 --- a/tests/passes/attr-promotion.expect +++ /dev/null @@ -1,20 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; -import "primitives/pipelined.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - b = std_reg(2); - } - wires { - static<1> group B0 { - b.write_en = 1'd1; - b.in = 2'd1; - } - } - control { - seq { - B0; - B0; - } - } -} diff --git a/tests/passes/attr-promotion.futil b/tests/passes/attr-promotion.futil deleted file mode 100644 index a4a62edcb..000000000 --- a/tests/passes/attr-promotion.futil +++ /dev/null @@ -1,28 +0,0 @@ -// -p attr-promotion -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; -import "primitives/pipelined.futil"; - -component main() -> () { - cells { - b = std_reg(2); - } - - wires { - // dynamic groups simply here to demonstrate compiling static "islands" - // within dynamic control - group B<"static"=1> { - b.write_en = 1'd1; - b.in = 2'd1; - B[done] = b.done; - } - - } - - control { - seq { - B; - B; - } - } -} \ No newline at end of file diff --git a/tests/passes/cell-share/continuous-assignment.expect b/tests/passes/cell-share/continuous-assignment.expect index a214bf2ef..08c100ec5 100644 --- a/tests/passes/cell-share/continuous-assignment.expect +++ b/tests/passes/cell-share/continuous-assignment.expect @@ -6,12 +6,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done don y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = 32'd1; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = 32'd2; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/passes/cell-share/continuous-assignment.futil b/tests/passes/cell-share/continuous-assignment.futil index 3ad5dadea..9055ddf40 100644 --- a/tests/passes/cell-share/continuous-assignment.futil +++ b/tests/passes/cell-share/continuous-assignment.futil @@ -7,12 +7,12 @@ component main() -> (x_out: 32) { y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = 32'd1; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = 32'd2; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/passes/cell-share/empty-invoke.expect b/tests/passes/cell-share/empty-invoke.expect index 1b1ddbe98..ac766911b 100644 --- a/tests/passes/cell-share/empty-invoke.expect +++ b/tests/passes/cell-share/empty-invoke.expect @@ -5,7 +5,7 @@ component write_one<"state_share"=1>(@go go: 1, @clk clk: 1, @reset reset: 1) -> @data x = std_reg(32); } wires { - group invoke0<"promote_static"=1> { + group invoke0<"promotable"=1> { x.write_en = 1'd1; invoke0[done] = x.done; x.in = 32'd1; @@ -30,7 +30,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x.go = 1'd1; invoke1[done] = x.done; } - group invoke2<"promote_static"=1> { + group invoke2<"promotable"=1> { mem.write_en = 1'd1; invoke2[done] = mem.done; mem.addr0 = 1'd0; @@ -40,7 +40,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x.go = 1'd1; invoke3[done] = x.done; } - group invoke4<"promote_static"=1> { + group invoke4<"promotable"=1> { mem.write_en = 1'd1; invoke4[done] = mem.done; mem.addr0 = 1'd1; diff --git a/tests/passes/cell-share/escape-boundary.expect b/tests/passes/cell-share/escape-boundary.expect index 2e1c991eb..75b095445 100644 --- a/tests/passes/cell-share/escape-boundary.expect +++ b/tests/passes/cell-share/escape-boundary.expect @@ -6,12 +6,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (x_out: 32, @done don y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = 32'd1; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = 32'd2; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/passes/cell-share/escape-boundary.futil b/tests/passes/cell-share/escape-boundary.futil index c4d7a96b5..4260ea118 100644 --- a/tests/passes/cell-share/escape-boundary.futil +++ b/tests/passes/cell-share/escape-boundary.futil @@ -7,12 +7,12 @@ component main() -> (x_out: 32) { y_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { x_0.in = 32'd1; x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { y_0.in = 32'd2; y_0.write_en = 1'd1; let1[done] = y_0.done; diff --git a/tests/passes/cell-share/inline.expect b/tests/passes/cell-share/inline.expect index df8211ba2..3f6745079 100644 --- a/tests/passes/cell-share/inline.expect +++ b/tests/passes/cell-share/inline.expect @@ -5,7 +5,7 @@ component my_reg<"state_share"=1>(@data in: 32, @go go: 1, @clk clk: 1, @reset r @data r = std_reg(32); } wires { - group invoke0<"promote_static"=1> { + group invoke0<"promotable"=1> { r.write_en = 1'd1; invoke0[done] = r.done; r.in = in; diff --git a/tests/passes/cell-share/live-register-analysis.expect b/tests/passes/cell-share/live-register-analysis.expect index 083051529..1f1d82b53 100644 --- a/tests/passes/cell-share/live-register-analysis.expect +++ b/tests/passes/cell-share/live-register-analysis.expect @@ -13,60 +13,60 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated comb_reg = std_reg(1); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = 6'd0; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { i0.in = 6'd0; i0.write_en = 1'd1; let1[done] = i0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = i0.out; A_read0_0.in = A0.read_data; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { C0.addr0 = i0.out; C0.write_en = 1'd1; C0.write_data = A_read0_0.out; upd1[done] = C0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = i0.out; B_read0_0.in = B0.read_data; upd2[done] = B_read0_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { A0.addr0 = i0.out; A0.write_en = 1'd1; A0.write_data = B_read0_0.out; upd3[done] = A0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = 6'd1; i0.in = add0.out; upd4[done] = i0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { A_read0_0.write_en = 1'd1; C0.addr0 = i0.out; A_read0_0.in = C0.read_data; upd5[done] = A_read0_0.done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { B0.addr0 = i0.out; B0.write_en = 1'd1; B0.write_data = A_read0_0.out; upd6[done] = B0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = 6'd1; diff --git a/tests/passes/cell-share/live-register-analysis.futil b/tests/passes/cell-share/live-register-analysis.futil index 2b00c1ca0..bffa5edae 100644 --- a/tests/passes/cell-share/live-register-analysis.futil +++ b/tests/passes/cell-share/live-register-analysis.futil @@ -25,60 +25,60 @@ component main() -> () { le1.left = i1.out; le1.right = 6'd31; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = 6'd0; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { i1.in = 6'd0; i1.write_en = 1'd1; let1[done] = i1.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = i0.out; A_read0_0.in = A0.read_data; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { C0.addr0 = i0.out; C0.write_en = 1'd1; C0.write_data = A_read0_0.out; upd1[done] = C0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = i0.out; B_read0_0.in = B0.read_data; upd2[done] = B_read0_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { A0.addr0 = i0.out; A0.write_en = 1'd1; A0.write_data = B_read0_0.out; upd3[done] = A0.done; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = 6'd1; i0.in = add0.out; upd4[done] = i0.done; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { C_read0_0.write_en = 1'd1; C0.addr0 = i1.out; C_read0_0.in = C0.read_data; upd5[done] = C_read0_0.done; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { B0.addr0 = i1.out; B0.write_en = 1'd1; B0.write_data = C_read0_0.out; upd6[done] = B0.done; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { i1.write_en = 1'd1; add1.left = i1.out; add1.right = 6'd1; diff --git a/tests/passes/cell-share/multiple-adders.expect b/tests/passes/cell-share/multiple-adders.expect index 877d540e0..f5506e86c 100644 --- a/tests/passes/cell-share/multiple-adders.expect +++ b/tests/passes/cell-share/multiple-adders.expect @@ -9,7 +9,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { add0.left = 32'd1; add0.right = 32'd2; add1.right = 32'd3; @@ -18,7 +18,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { add0.left = 32'd1; add0.right = 32'd2; add1.right = 32'd3; diff --git a/tests/passes/cell-share/multiple-adders.futil b/tests/passes/cell-share/multiple-adders.futil index 898896e7d..71e34c192 100644 --- a/tests/passes/cell-share/multiple-adders.futil +++ b/tests/passes/cell-share/multiple-adders.futil @@ -10,7 +10,7 @@ component main() -> () { x_0 = std_reg(32); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { add0.left = 32'd1; add0.right = 32'd2; add1.right = 32'd3; @@ -19,7 +19,7 @@ component main() -> () { x_0.write_en = 1'd1; let0[done] = x_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { add2.left = 32'd1; add2.right = 32'd2; add3.right = 32'd3; diff --git a/tests/passes/cell-share/nested-par.expect b/tests/passes/cell-share/nested-par.expect index b5a99ac05..5dab63260 100644 --- a/tests/passes/cell-share/nested-par.expect +++ b/tests/passes/cell-share/nested-par.expect @@ -10,17 +10,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @external read_x1 = std_add(4); } wires { - group wr_before0<"static"=1> { + group wr_before0<"promotable"=1> { before0.in = 4'd1; before0.write_en = 1'd1; wr_before0[done] = before0.done; } - group wr_x0<"static"=1> { + group wr_x0<"promotable"=1> { before0.in = 4'd1; before0.write_en = 1'd1; wr_x0[done] = before0.done; } - group wr_b0<"static"=1> { + group wr_b0<"promotable"=1> { b0.in = 32'd1; b0.write_en = 1'd1; wr_b0[done] = b0.done; @@ -30,17 +30,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { read_x0.left = before0.out; rd_x0[done] = before0.done; } - group wr_before1<"static"=1> { + group wr_before1<"promotable"=1> { before1.in = 4'd1; before1.write_en = 1'd1; wr_before1[done] = before1.done; } - group wr_x1<"static"=1> { + group wr_x1<"promotable"=1> { before1.in = 4'd1; before1.write_en = 1'd1; wr_x1[done] = before1.done; } - group wr_b1<"static"=1> { + group wr_b1<"promotable"=1> { b1.in = 32'd1; b1.write_en = 1'd1; wr_b1[done] = b1.done; diff --git a/tests/passes/cell-share/nested-par.futil b/tests/passes/cell-share/nested-par.futil index 6077ffba3..6cffc593e 100644 --- a/tests/passes/cell-share/nested-par.futil +++ b/tests/passes/cell-share/nested-par.futil @@ -14,17 +14,17 @@ component main() -> () { @external read_x1 = std_add(4); } wires { - group wr_before0<"static"=1> { + group wr_before0<"promotable"=1> { before0.in = 4'd1; before0.write_en = 1'd1; wr_before0[done] = before0.done; } - group wr_x0<"static"=1> { + group wr_x0<"promotable"=1> { x0.in = 4'd1; x0.write_en = 1'd1; wr_x0[done] = x0.done; } - group wr_b0<"static"=1> { + group wr_b0<"promotable"=1> { b0.in = 32'd1; b0.write_en = 1'd1; wr_b0[done] = b0.done; @@ -35,17 +35,17 @@ component main() -> () { rd_x0[done] = x0.done; // XXX: This is functionally wrong } - group wr_before1<"static"=1> { + group wr_before1<"promotable"=1> { before1.in = 4'd1; before1.write_en = 1'd1; wr_before1[done] = before1.done; } - group wr_x1<"static"=1> { + group wr_x1<"promotable"=1> { x1.in = 4'd1; x1.write_en = 1'd1; wr_x1[done] = x1.done; } - group wr_b1<"static"=1> { + group wr_b1<"promotable"=1> { b1.in = 32'd1; b1.write_en = 1'd1; wr_b1[done] = b1.done; diff --git a/tests/passes/cell-share/par-while-liveness.expect b/tests/passes/cell-share/par-while-liveness.expect index 092a2364c..92930a444 100644 --- a/tests/passes/cell-share/par-while-liveness.expect +++ b/tests/passes/cell-share/par-while-liveness.expect @@ -26,72 +26,72 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @generated comb_reg0 = std_reg(1); } wires { - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { i1.in = const3.out; i1.write_en = 1'd1; let1[done] = i1.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let2[done] = i0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { a_src_read0_0.write_en = 1'd1; a_src0.addr0 = i0.out; a_src_read0_0.in = a_src0.read_data; upd0[done] = a_src_read0_0.done ? 1'd1; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { a_tar0.addr0 = i0.out; a_tar0.write_en = 1'd1; a_tar0.write_data = a_src_read0_0.out; upd1[done] = a_tar0.done ? 1'd1; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = const2.out; i0.in = add0.out; upd2[done] = i0.done ? 1'd1; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { b_src_read0_0.write_en = 1'd1; b_src0.addr0 = i1.out; b_src_read0_0.in = b_src0.read_data; upd3[done] = b_src_read0_0.done ? 1'd1; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { b_tar0.addr0 = i1.out; b_tar0.write_en = 1'd1; b_tar0.write_data = b_src_read0_0.out; upd4[done] = b_tar0.done ? 1'd1; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { i1.write_en = 1'd1; add1.left = i1.out; add1.right = const5.out; i1.in = add1.out; upd5[done] = i1.done ? 1'd1; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { a_src_read0_0.write_en = 1'd1; c_tar0.addr0 = i0.out; a_src_read0_0.in = c_tar0.read_data; upd6[done] = a_src_read0_0.done ? 1'd1; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { c_src0.addr0 = i0.out; c_src0.write_en = 1'd1; c_src0.write_data = a_src_read0_0.out; upd7[done] = c_src0.done ? 1'd1; } - group upd8<"static"=1> { + group upd8<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = const2.out; diff --git a/tests/passes/cell-share/par-while-liveness.futil b/tests/passes/cell-share/par-while-liveness.futil index 3c8091be8..b7d4c922c 100644 --- a/tests/passes/cell-share/par-while-liveness.futil +++ b/tests/passes/cell-share/par-while-liveness.futil @@ -44,72 +44,72 @@ component main() -> () { le2.left = i2.out; le2.right = const7.out; } - group let0<"static"=1> { + group let0<"promotable"=1> { i0.in = const0.out; i0.write_en = 1'd1; let0[done] = i0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { i1.in = const3.out; i1.write_en = 1'd1; let1[done] = i1.done; } - group let2<"static"=1> { + group let2<"promotable"=1> { i2.in = const6.out; i2.write_en = 1'd1; let2[done] = i2.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { a_src_read0_0.write_en = 1'd1; a_src0.addr0 = i0.out; a_src_read0_0.in = 1'd1 ? a_src0.read_data; upd0[done] = a_src_read0_0.done ? 1'd1; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { a_tar0.addr0 = i0.out; a_tar0.write_en = 1'd1; a_tar0.write_data = 1'd1 ? a_src_read0_0.out; upd1[done] = a_tar0.done ? 1'd1; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { i0.write_en = 1'd1; add0.left = i0.out; add0.right = const2.out; i0.in = 1'd1 ? add0.out; upd2[done] = i0.done ? 1'd1; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { b_src_read0_0.write_en = 1'd1; b_src0.addr0 = i1.out; b_src_read0_0.in = 1'd1 ? b_src0.read_data; upd3[done] = b_src_read0_0.done ? 1'd1; } - group upd4<"static"=1> { + group upd4<"promotable"=1> { b_tar0.addr0 = i1.out; b_tar0.write_en = 1'd1; b_tar0.write_data = 1'd1 ? b_src_read0_0.out; upd4[done] = b_tar0.done ? 1'd1; } - group upd5<"static"=1> { + group upd5<"promotable"=1> { i1.write_en = 1'd1; add1.left = i1.out; add1.right = const5.out; i1.in = 1'd1 ? add1.out; upd5[done] = i1.done ? 1'd1; } - group upd6<"static"=1> { + group upd6<"promotable"=1> { c_tar_read0_0.write_en = 1'd1; c_tar0.addr0 = i2.out; c_tar_read0_0.in = 1'd1 ? c_tar0.read_data; upd6[done] = c_tar_read0_0.done ? 1'd1; } - group upd7<"static"=1> { + group upd7<"promotable"=1> { c_src0.addr0 = i2.out; c_src0.write_en = 1'd1; c_src0.write_data = 1'd1 ? c_tar_read0_0.out; upd7[done] = c_src0.done ? 1'd1; } - group upd8<"static"=1> { + group upd8<"promotable"=1> { i2.write_en = 1'd1; add2.left = i2.out; add2.right = const8.out; diff --git a/tests/passes/cell-share/share-mult.expect b/tests/passes/cell-share/share-mult.expect index b22aca167..a824a5e70 100644 --- a/tests/passes/cell-share/share-mult.expect +++ b/tests/passes/cell-share/share-mult.expect @@ -32,7 +32,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { A_read0_0.write_en = 1'd1; let0[done] = A_read0_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { B_read0_0.in = A_read0_0.out; B_read0_0.write_en = 1'd1; let1[done] = B_read0_0.done; @@ -48,30 +48,30 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { A_read0_0.write_en = 1'd1; let2[done] = A_read0_0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { B_read0_0.in = A_read0_0.out; B_read0_0.write_en = 1'd1; let3[done] = B_read0_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = const0.out; A_read0_0.in = A0.read_data; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = const1.out; B_read0_0.in = B0.read_data; upd1[done] = B_read0_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = const0.out; A_read0_0.in = A0.read_data; upd2[done] = A_read0_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = const1.out; B_read0_0.in = B0.read_data; diff --git a/tests/passes/cell-share/share-mult.futil b/tests/passes/cell-share/share-mult.futil index 9ff15b0f6..b779c31f6 100644 --- a/tests/passes/cell-share/share-mult.futil +++ b/tests/passes/cell-share/share-mult.futil @@ -35,7 +35,7 @@ component main() -> () { bin_read0_0.write_en = 1'd1; let0[done] = bin_read0_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { x_0.in = bin_read0_0.out; x_0.write_en = 1'd1; let1[done] = x_0.done; @@ -51,30 +51,30 @@ component main() -> () { bin_read1_0.write_en = 1'd1; let2[done] = bin_read1_0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { y_0.in = bin_read1_0.out; y_0.write_en = 1'd1; let3[done] = y_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = const0.out; A_read0_0.in = A0.read_data; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = const1.out; B_read0_0.in = B0.read_data; upd1[done] = B_read0_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { A_read1_0.write_en = 1'd1; A0.addr0 = const2.out; A_read1_0.in = A0.read_data; upd2[done] = A_read1_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { B_read1_0.write_en = 1'd1; B0.addr0 = const3.out; B_read1_0.in = B0.read_data; diff --git a/tests/passes/cell-share/simple-liveness.expect b/tests/passes/cell-share/simple-liveness.expect index 161633f02..7cf839773 100644 --- a/tests/passes/cell-share/simple-liveness.expect +++ b/tests/passes/cell-share/simple-liveness.expect @@ -7,22 +7,22 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { @external read_x = std_add(4); } wires { - group wr_before<"static"=1> { + group wr_before<"promotable"=1> { before.in = 4'd1; before.write_en = 1'd1; wr_before[done] = before.done; } - group wr_x<"static"=1> { + group wr_x<"promotable"=1> { before.in = 4'd1; before.write_en = 1'd1; wr_x[done] = before.done; } - group wr_b<"static"=1> { + group wr_b<"promotable"=1> { b.in = 32'd1; b.write_en = 1'd1; wr_b[done] = b.done; } - group rd_x<"static"=1> { + group rd_x<"promotable"=1> { read_x.right = before.out; read_x.left = before.out; rd_x[done] = before.done; diff --git a/tests/passes/cell-share/simple-liveness.futil b/tests/passes/cell-share/simple-liveness.futil index 7c7862127..511e727d8 100644 --- a/tests/passes/cell-share/simple-liveness.futil +++ b/tests/passes/cell-share/simple-liveness.futil @@ -9,22 +9,22 @@ component main() -> () { @external read_x = std_add(4); } wires { - group wr_before<"static"=1> { + group wr_before<"promotable"=1> { before.in = 4'd1; before.write_en = 1'd1; wr_before[done] = before.done; } - group wr_x<"static"=1> { + group wr_x<"promotable"=1> { x.in = 4'd1; x.write_en = 1'd1; wr_x[done] = x.done; } - group wr_b<"static"=1> { + group wr_b<"promotable"=1> { b.in = 32'd1; b.write_en = 1'd1; wr_b[done] = b.done; } - group rd_x<"static"=1> { + group rd_x<"promotable"=1> { read_x.right = x.out; read_x.left = x.out; rd_x[done] = x.done; // XXX: This is functionally incorrect diff --git a/tests/passes/compile-empty.expect b/tests/passes/compile-empty.expect deleted file mode 100644 index 1591cf539..000000000 --- a/tests/passes/compile-empty.expect +++ /dev/null @@ -1,29 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; -component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { - cells { - r = std_reg(1); - @generated empty_reg = std_reg(1); - } - wires { - group do_incr { - r.in = 1'd1; - r.write_en = 1'd1; - do_incr[done] = r.done; - } - group _empty<"static"=1> { - empty_reg.write_en = 1'd1; - empty_reg.in = 1'd1; - _empty[done] = empty_reg.done; - } - comb group cond { - } - } - control { - if r.out with cond { - do_incr; - } else { - _empty; - } - } -} diff --git a/tests/passes/compile-empty.futil b/tests/passes/compile-empty.futil deleted file mode 100644 index 81acd3d70..000000000 --- a/tests/passes/compile-empty.futil +++ /dev/null @@ -1,22 +0,0 @@ -// -p compile-empty -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; - -component main() -> () { - cells { - r = std_reg(1); - } - wires { - comb group cond {} - group do_incr { - r.in = 1'd1; - r.write_en = 1'd1; - do_incr[done] = r.done; - } - } - control { - if r.out with cond { - do_incr; - } - } -} diff --git a/tests/passes/compile-invoke/compile-invoke.expect b/tests/passes/compile-invoke/compile-invoke.expect index 0d521e273..4e57e4166 100644 --- a/tests/passes/compile-invoke/compile-invoke.expect +++ b/tests/passes/compile-invoke/compile-invoke.expect @@ -21,13 +21,13 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { w = std_wire(32); } wires { - group invoke0<"static"=4> { + group invoke0<"promotable"=4> { exp0.go = 1'd1; invoke0[done] = exp0.done; exp0.base = r.out; exp0.exp = 4'd3; } - group invoke1<"static"=4> { + group invoke1<"promotable"=4> { exp0.go = 1'd1; invoke1[done] = exp0.done; exp0.base = w.out; @@ -37,8 +37,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { seq { - @static(4) invoke0; - @static(4) invoke1; + @promotable(4) invoke0; + @promotable(4) invoke1; } } } diff --git a/tests/passes/compile-invoke/compile-invoke.futil b/tests/passes/compile-invoke/compile-invoke.futil index d7ac4ca2d..ea67cd4ec 100644 --- a/tests/passes/compile-invoke/compile-invoke.futil +++ b/tests/passes/compile-invoke/compile-invoke.futil @@ -25,7 +25,7 @@ component main() -> () { } } control { - @static(4) invoke exp0(base = r.out, exp = 4'd3)(); - @static(4) invoke exp0(base = w.out, exp = 4'd3)() with foo; + @promotable(4) invoke exp0(base = r.out, exp = 4'd3)(); + @promotable(4) invoke exp0(base = w.out, exp = 4'd3)() with foo; } } diff --git a/tests/passes/compile-invoke/static-invoke-reg.expect b/tests/passes/compile-invoke/static-invoke-reg.expect new file mode 100644 index 000000000..286b9c782 --- /dev/null +++ b/tests/passes/compile-invoke/static-invoke-reg.expect @@ -0,0 +1,15 @@ +import "primitives/core.futil"; +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(32); + } + wires { + static<1> group static_invoke { + r.write_en = 1'd1; + r.in = 32'd2; + } + } + control { + static_invoke; + } +} diff --git a/tests/passes/compile-invoke/static-invoke-reg.futil b/tests/passes/compile-invoke/static-invoke-reg.futil new file mode 100644 index 000000000..fb10b50b7 --- /dev/null +++ b/tests/passes/compile-invoke/static-invoke-reg.futil @@ -0,0 +1,13 @@ +// -p validate -p compile-invoke -p dead-group-removal +import "primitives/core.futil"; + +component main() -> () { + cells { + r = std_reg(32); + } + wires { + } + control { + static invoke r(in = 32'd2)(); + } +} diff --git a/tests/passes/compile-repeat/nested.expect b/tests/passes/compile-repeat/nested.expect index 6ccc5309a..096dd4a74 100644 --- a/tests/passes/compile-repeat/nested.expect +++ b/tests/passes/compile-repeat/nested.expect @@ -18,14 +18,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r1.write_en = 1'd1; write_r1[done] = r1.done; } - group init_repeat<"promote_static"=1> { + group init_repeat<"promotable"=1> { idx.write_en = 1'd1; idx.in = 2'd0; cond_reg.write_en = 1'd1; cond_reg.in = 1'd1; init_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group incr_repeat<"promote_static"=1> { + group incr_repeat<"promotable"=1> { adder.left = idx.out; adder.right = 2'd1; lt.left = adder.out; @@ -36,14 +36,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { idx.in = adder.out; incr_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group init_repeat0<"promote_static"=1> { + group init_repeat0<"promotable"=1> { idx0.write_en = 1'd1; idx0.in = 3'd0; cond_reg0.write_en = 1'd1; cond_reg0.in = 1'd1; init_repeat0[done] = cond_reg0.done & idx0.done ? 1'd1; } - group incr_repeat0<"promote_static"=1> { + group incr_repeat0<"promotable"=1> { adder0.left = idx0.out; adder0.right = 3'd1; lt0.left = adder0.out; diff --git a/tests/passes/compile-repeat/simple.expect b/tests/passes/compile-repeat/simple.expect index c34f92c71..aa1413ee7 100644 --- a/tests/passes/compile-repeat/simple.expect +++ b/tests/passes/compile-repeat/simple.expect @@ -20,14 +20,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r2.write_en = 1'd1; write_r2[done] = r2.done; } - group init_repeat<"promote_static"=1> { + group init_repeat<"promotable"=1> { idx.write_en = 1'd1; idx.in = 3'd0; cond_reg.write_en = 1'd1; cond_reg.in = 1'd1; init_repeat[done] = cond_reg.done & idx.done ? 1'd1; } - group incr_repeat<"promote_static"=1> { + group incr_repeat<"promotable"=1> { adder.left = idx.out; adder.right = 3'd1; lt.left = adder.out; diff --git a/tests/passes/compile-static-interface-one-cycle.expect b/tests/passes/compile-static-interface/compile-static-interface-one-cycle.expect similarity index 100% rename from tests/passes/compile-static-interface-one-cycle.expect rename to tests/passes/compile-static-interface/compile-static-interface-one-cycle.expect diff --git a/tests/passes/compile-static-interface-one-cycle.futil b/tests/passes/compile-static-interface/compile-static-interface-one-cycle.futil similarity index 100% rename from tests/passes/compile-static-interface-one-cycle.futil rename to tests/passes/compile-static-interface/compile-static-interface-one-cycle.futil diff --git a/tests/passes/compile-static-interface-repeat.expect b/tests/passes/compile-static-interface/compile-static-interface-repeat.expect similarity index 100% rename from tests/passes/compile-static-interface-repeat.expect rename to tests/passes/compile-static-interface/compile-static-interface-repeat.expect diff --git a/tests/passes/compile-static-interface-repeat.futil b/tests/passes/compile-static-interface/compile-static-interface-repeat.futil similarity index 100% rename from tests/passes/compile-static-interface-repeat.futil rename to tests/passes/compile-static-interface/compile-static-interface-repeat.futil diff --git a/tests/passes/compile-static-interface.expect b/tests/passes/compile-static-interface/compile-static-interface.expect similarity index 100% rename from tests/passes/compile-static-interface.expect rename to tests/passes/compile-static-interface/compile-static-interface.expect diff --git a/tests/passes/compile-static-interface.futil b/tests/passes/compile-static-interface/compile-static-interface.futil similarity index 100% rename from tests/passes/compile-static-interface.futil rename to tests/passes/compile-static-interface/compile-static-interface.futil diff --git a/tests/passes/group2invoke/multi-go-done-component.expect b/tests/passes/group2invoke/multi-go-done-component.expect index c8640237c..5a216072a 100644 --- a/tests/passes/group2invoke/multi-go-done-component.expect +++ b/tests/passes/group2invoke/multi-go-done-component.expect @@ -2,7 +2,7 @@ import "primitives/core.futil"; import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; extern "/calyx/tests/passes/group2invoke/multi-go-done-component.futil" { - primitive real_mem(@static @go read_en: 1, @static(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); + primitive real_mem(@interval @go read_en: 1, @interval(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); } component real_mem_comp(@go port0_read_en: 1, @go(2) port1_write_en: 1, @clk clk: 1, @reset reset: 1) -> (@done port0_read_done: 1, @done(2) port1_write_done: 1) { cells { diff --git a/tests/passes/group2invoke/multi-go-done-component.futil b/tests/passes/group2invoke/multi-go-done-component.futil index cbc5edcfc..319cce9b3 100644 --- a/tests/passes/group2invoke/multi-go-done-component.futil +++ b/tests/passes/group2invoke/multi-go-done-component.futil @@ -5,8 +5,8 @@ import "primitives/memories/comb.futil"; import "primitives/binary_operators.futil"; extern "./multi-go-done-component.futil" { primitive real_mem( - @static(1) @go read_en: 1, - @static(2) @go(2) write_en: 1 + @interval(1) @go read_en: 1, + @interval(2) @go(2) write_en: 1 ) -> ( @done read_done: 1, @done(2) write_done: 1 diff --git a/tests/passes/group2invoke/multi-go-done.expect b/tests/passes/group2invoke/multi-go-done.expect index d19c857f0..2ffbdf007 100644 --- a/tests/passes/group2invoke/multi-go-done.expect +++ b/tests/passes/group2invoke/multi-go-done.expect @@ -1,7 +1,7 @@ import "primitives/core.futil"; import "primitives/memories/comb.futil"; extern "/calyx/tests/passes/group2invoke/multi-go-done.futil" { - primitive real_mem(@static @go read_en: 1, @static(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); + primitive real_mem(@interval @go read_en: 1, @interval(2) @go(2) write_en: 1) -> (@done read_done: 1, @done(2) write_done: 1); } component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cells { diff --git a/tests/passes/group2invoke/multi-go-done.futil b/tests/passes/group2invoke/multi-go-done.futil index 27903f1d1..ee6293680 100644 --- a/tests/passes/group2invoke/multi-go-done.futil +++ b/tests/passes/group2invoke/multi-go-done.futil @@ -4,8 +4,8 @@ import "primitives/memories/comb.futil"; extern "./multi-go-done.futil" { primitive real_mem( - @static(1) @go(1) read_en: 1, - @static(2) @go(2) write_en: 1 + @interval(1) @go(1) read_en: 1, + @interval(2) @go(2) write_en: 1 ) -> ( @done(1) read_done: 1, @done(2) write_done: 1 diff --git a/tests/passes/group_to_seq/dahlia_mult.expect b/tests/passes/group_to_seq/dahlia_mult.expect index c42887b24..bcbd2b2a5 100644 --- a/tests/passes/group_to_seq/dahlia_mult.expect +++ b/tests/passes/group_to_seq/dahlia_mult.expect @@ -43,35 +43,35 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { bin_read1_0.write_en = 1'd1; end_spl_let2[done] = bin_read1_0.done; } - group let1<"static"=1> { + group let1<"promotable"=1> { x_0.write_en = 1'd1; x_0.in = bin_read0_0.out; let1[done] = x_0.done; } - group let3<"static"=1> { + group let3<"promotable"=1> { y_0.write_en = 1'd1; y_0.in = bin_read1_0.out; let3[done] = y_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A0.addr0 = const0.out; A_read0_0.in = A0.read_data; A_read0_0.write_en = 1'd1; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B0.addr0 = const1.out; B_read0_0.in = B0.read_data; B_read0_0.write_en = 1'd1; upd1[done] = B_read0_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { A0.addr0 = const2.out; A_read1_0.in = A0.read_data; A_read1_0.write_en = 1'd1; upd2[done] = A_read1_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { B0.addr0 = const3.out; B_read1_0.in = B0.read_data; B_read1_0.write_en = 1'd1; diff --git a/tests/passes/group_to_seq/dahlia_mult.futil b/tests/passes/group_to_seq/dahlia_mult.futil index 180393e6a..2e6901251 100644 --- a/tests/passes/group_to_seq/dahlia_mult.futil +++ b/tests/passes/group_to_seq/dahlia_mult.futil @@ -23,7 +23,7 @@ component main() -> () { y_0 = std_reg(32); } wires { - group let0<"static"=4> { + group let0<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; bin_read0_0.write_en = mult_pipe0.done; let0[done] = bin_read0_0.done; @@ -31,12 +31,12 @@ component main() -> () { mult_pipe0.right = B_read0_0.out; mult_pipe0.go = !mult_pipe0.done ? 1'd1; } - group let1<"static"=1> { + group let1<"promotable"=1> { x_0.in = bin_read0_0.out; x_0.write_en = 1'd1; let1[done] = x_0.done; } - group let2<"static"=4> { + group let2<"promotable"=4> { bin_read1_0.in = mult_pipe1.out; bin_read1_0.write_en = mult_pipe1.done; let2[done] = bin_read1_0.done; @@ -44,30 +44,30 @@ component main() -> () { mult_pipe1.right = B_read1_0.out; mult_pipe1.go = !mult_pipe1.done ? 1'd1; } - group let3<"static"=1> { + group let3<"promotable"=1> { y_0.in = bin_read1_0.out; y_0.write_en = 1'd1; let3[done] = y_0.done; } - group upd0<"static"=1> { + group upd0<"promotable"=1> { A_read0_0.write_en = 1'd1; A0.addr0 = const0.out; A_read0_0.in = A0.read_data; upd0[done] = A_read0_0.done; } - group upd1<"static"=1> { + group upd1<"promotable"=1> { B_read0_0.write_en = 1'd1; B0.addr0 = const1.out; B_read0_0.in = B0.read_data; upd1[done] = B_read0_0.done; } - group upd2<"static"=1> { + group upd2<"promotable"=1> { A_read1_0.write_en = 1'd1; A0.addr0 = const2.out; A_read1_0.in = A0.read_data; upd2[done] = A_read1_0.done; } - group upd3<"static"=1> { + group upd3<"promotable"=1> { B_read1_0.write_en = 1'd1; B0.addr0 = const3.out; B_read1_0.in = B0.read_data; diff --git a/tests/passes/inliner/always.expect b/tests/passes/inliner/always.expect index 198ea80a3..85d92b084 100644 --- a/tests/passes/inliner/always.expect +++ b/tests/passes/inliner/always.expect @@ -34,7 +34,7 @@ component counter(start: 4, end: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> @generated comp_done = std_wire(1); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.write_en = 1'd1; count.in = start; init[done] = count.done; @@ -88,12 +88,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 4, @done done: @generated c_done = std_wire(1); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.write_en = 1'd1; count.in = 4'd0; init[done] = count.done; } - group init0<"static"=1> { + group init0<"promotable"=1> { count0.write_en = 1'd1; count0.in = c_start.out; init0[done] = count0.done; diff --git a/tests/passes/inliner/always.futil b/tests/passes/inliner/always.futil index e6740d5ea..4fbb8979d 100644 --- a/tests/passes/inliner/always.futil +++ b/tests/passes/inliner/always.futil @@ -30,7 +30,7 @@ component counter(start: 4, end: 4) -> (out: 4) { comp = check(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.in = start; count.write_en = 1'd1; init[done] = count.done; @@ -60,7 +60,7 @@ component main() -> (out: 4) { lt = std_lt(4); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.in = 4'd0; count.write_en = 1'd1; init[done] = count.done; diff --git a/tests/passes/inliner/simple.expect b/tests/passes/inliner/simple.expect index 198ea80a3..85d92b084 100644 --- a/tests/passes/inliner/simple.expect +++ b/tests/passes/inliner/simple.expect @@ -34,7 +34,7 @@ component counter(start: 4, end: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> @generated comp_done = std_wire(1); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.write_en = 1'd1; count.in = start; init[done] = count.done; @@ -88,12 +88,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 4, @done done: @generated c_done = std_wire(1); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.write_en = 1'd1; count.in = 4'd0; init[done] = count.done; } - group init0<"static"=1> { + group init0<"promotable"=1> { count0.write_en = 1'd1; count0.in = c_start.out; init0[done] = count0.done; diff --git a/tests/passes/inliner/simple.futil b/tests/passes/inliner/simple.futil index 18f56860e..3dd87ce00 100644 --- a/tests/passes/inliner/simple.futil +++ b/tests/passes/inliner/simple.futil @@ -30,7 +30,7 @@ component counter(start: 4, end: 4) -> (out: 4) { @inline comp = check(); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.in = start; count.write_en = 1'd1; init[done] = count.done; @@ -60,7 +60,7 @@ component main() -> (out: 4) { lt = std_lt(4); } wires { - group init<"static"=1> { + group init<"promotable"=1> { count.in = 4'd0; count.write_en = 1'd1; init[done] = count.done; diff --git a/tests/passes/schedule-compaction/continuous-compaction.expect b/tests/passes/schedule-compaction/continuous-compaction.expect index ed17ad912..ab9b64b5b 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-compaction.expect @@ -30,7 +30,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: add.left = r0.out; } control { - @promote_static(2) @promoted static<2> par { + @promotable(2) @promoted static<2> par { static<2> seq { write_r00; write_r10; diff --git a/tests/passes/schedule-compaction/continuous-compaction.futil b/tests/passes/schedule-compaction/continuous-compaction.futil index 0f59d3826..f39bd31e8 100644 --- a/tests/passes/schedule-compaction/continuous-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-compaction.futil @@ -12,22 +12,22 @@ component main() -> (out: 8) { add = std_add(8); } wires { - group write_r0<"promote_static"=1> { + group write_r0<"promotable"=1> { r0.write_en = 1'd1; r0.in = 8'd1; write_r0[done] = r0.done; } - group write_r1<"promote_static"=1> { + group write_r1<"promotable"=1> { r1.write_en = 1'd1; r1.in = add.out; write_r1[done] = r1.done; } - group write_r2<"promote_static"=1> { + group write_r2<"promotable"=1> { r2.write_en = 1'd1; r2.in = 8'd3; write_r2[done] = r2.done; } - group write_r3<"promote_static"=1> { + group write_r3<"promotable"=1> { r3.write_en = 1'd1; r3.in = 8'd3; write_r3[done] = r3.done; @@ -37,12 +37,12 @@ component main() -> (out: 8) { out = r1.out; } control { - @promote_static(4) seq { - @promote_static write_r0; + @promotable(4) seq { + @promotable write_r0; // Continuous assignments to add.left and add.right prevent compation. - @promote_static write_r1; - @promote_static write_r2; - @promote_static write_r3; + @promotable write_r1; + @promotable write_r2; + @promotable write_r3; } } } \ No newline at end of file diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.expect b/tests/passes/schedule-compaction/continuous-no-compaction.expect index 842386793..ad7b41f28 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.expect +++ b/tests/passes/schedule-compaction/continuous-no-compaction.expect @@ -10,17 +10,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: ud = undef(1); } wires { - group write_r0<"promote_static"=1> { + group write_r0<"promotable"=1> { r0.in = 8'd1; r0.write_en = 1'd1; write_r0[done] = r0.done; } - group write_r1<"promote_static"=1> { + group write_r1<"promotable"=1> { r1.in = add.out; r1.write_en = 1'd1; write_r1[done] = r1.done; } - group write_add1<"promote_static"=1> { + group write_add1<"promotable"=1> { add1.right = 8'd4; add1.left = 8'd1; write_add1[done] = ud.out; @@ -31,14 +31,14 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: r2.in = add1.out; } control { - @promote_static(4) seq { - @promote_static(2) seq { - @promote_static write_r0; - @promote_static write_r1; + @promotable(4) seq { + @promotable(2) seq { + @promotable write_r0; + @promotable write_r1; } - @promote_static(2) seq { - @promote_static write_r0; - @promote_static write_add1; + @promotable(2) seq { + @promotable write_r0; + @promotable write_add1; } } } diff --git a/tests/passes/schedule-compaction/continuous-no-compaction.futil b/tests/passes/schedule-compaction/continuous-no-compaction.futil index af10d44b0..77c435e99 100644 --- a/tests/passes/schedule-compaction/continuous-no-compaction.futil +++ b/tests/passes/schedule-compaction/continuous-no-compaction.futil @@ -13,17 +13,17 @@ component main() -> (out: 8) { ud = undef(1); } wires { - group write_r0<"promote_static"=1> { + group write_r0<"promotable"=1> { r0.write_en = 1'd1; r0.in = 8'd1; write_r0[done] = r0.done; } - group write_r1<"promote_static"=1> { + group write_r1<"promotable"=1> { r1.write_en = 1'd1; r1.in = add.out; write_r1[done] = r1.done; } - group write_add1<"promote_static"=1> { + group write_add1<"promotable"=1> { add1.left = 8'd1; add1.right = 8'd4; write_add1[done] = ud.out; @@ -34,17 +34,17 @@ component main() -> (out: 8) { out = r1.out; } control { - @promote_static(4) seq { - @promote_static(2) seq { - @promote_static write_r0; + @promotable(4) seq { + @promotable(2) seq { + @promotable write_r0; // Continuous assignments to add.left and add.right prevent compation. - @promote_static write_r1; + @promotable write_r1; } - @promote_static(2) seq { - @promote_static write_r0; + @promotable(2) seq { + @promotable write_r0; // Continuous assignment r2.in = add1.out prevents compaction. // This is overly conservative. - @promote_static write_add1; + @promotable write_add1; } } } diff --git a/tests/passes/schedule-compaction/fixup-necessary.expect b/tests/passes/schedule-compaction/fixup-necessary.expect index 6aa7c76a4..c3f9fa30f 100644 --- a/tests/passes/schedule-compaction/fixup-necessary.expect +++ b/tests/passes/schedule-compaction/fixup-necessary.expect @@ -1,6 +1,6 @@ import "primitives/core.futil"; import "primitives/memories/comb.futil"; -component example(@go @static go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { +component example(@go @promotable go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @done done: 1) { cells { r0 = std_reg(8); r1 = std_reg(8); @@ -9,7 +9,7 @@ component example(@go @static go: 1, @clk clk: 1, @reset reset: 1) -> (out: 8, @ out = r1.out; } control { - @promote_static @promoted static<1> par { + @promotable @promoted static<1> par { static<1> invoke r0( in = 8'd1 )(); @@ -26,9 +26,9 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } wires {} control { - @promote_static(2) seq { - @promote_static invoke ex()(); - @promote_static invoke mem( + @promotable(2) seq { + @promotable invoke ex()(); + @promotable invoke mem( addr0 = 1'd0, write_data = ex.out )(); diff --git a/tests/passes/schedule-compaction/no-compact.expect b/tests/passes/schedule-compaction/no-compact.expect index c4630e85e..7b5282c94 100644 --- a/tests/passes/schedule-compaction/no-compact.expect +++ b/tests/passes/schedule-compaction/no-compact.expect @@ -7,27 +7,27 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { d_reg = std_reg(32); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a_reg.write_en = 1'd1; a_reg.in = 32'd5; A[done] = a_reg.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b_reg.write_en = 1'd1; b_reg.in = a_reg.out; B[done] = b_reg.done; } - group D<"promote_static"=1> { + group D<"promotable"=1> { d_reg.write_en = 1'd1; d_reg.in = b_reg.out; D[done] = d_reg.done; } } control { - @promote_static(3) seq { - @promote_static A; - @promote_static B; - @promote_static D; + @promotable(3) seq { + @promotable A; + @promotable B; + @promotable D; } } } diff --git a/tests/passes/schedule-compaction/no-compact.futil b/tests/passes/schedule-compaction/no-compact.futil index 4f1887e8c..cc70a6b3e 100644 --- a/tests/passes/schedule-compaction/no-compact.futil +++ b/tests/passes/schedule-compaction/no-compact.futil @@ -10,19 +10,19 @@ component main() -> () { d_reg = std_reg(32); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a_reg.in = 32'd5; a_reg.write_en = 1'd1; A[done] = a_reg.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b_reg.in = a_reg.out; b_reg.write_en = 1'd1; B[done] = b_reg.done; } - group D<"promote_static"=1> { + group D<"promotable"=1> { d_reg.in = b_reg.out; d_reg.write_en = 1'd1; D[done] = d_reg.done; diff --git a/tests/passes/schedule-compaction/partial-compaction.expect b/tests/passes/schedule-compaction/partial-compaction.expect index 648214a17..8ed953a6b 100644 --- a/tests/passes/schedule-compaction/partial-compaction.expect +++ b/tests/passes/schedule-compaction/partial-compaction.expect @@ -12,7 +12,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { ud = undef(1); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a_reg.write_en = 1'd1; a_reg.in = 32'd5; A[done] = a_reg.done; @@ -22,7 +22,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c_reg.in = 32'd10; C[done] = ud.out; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b_reg.write_en = 1'd1; a.right = c_reg.out; a.left = a_reg.out; @@ -44,12 +44,12 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { seq { - @promote_static(2) seq { - @promote_static A; - @promote_static B; + @promotable(2) seq { + @promotable A; + @promotable B; } C; - @promote_static @promoted static<1> par { + @promotable @promoted static<1> par { D0; E0; F0; diff --git a/tests/passes/schedule-compaction/partial-compaction.futil b/tests/passes/schedule-compaction/partial-compaction.futil index 32add36bf..eda318e31 100644 --- a/tests/passes/schedule-compaction/partial-compaction.futil +++ b/tests/passes/schedule-compaction/partial-compaction.futil @@ -32,7 +32,7 @@ component main () -> () { } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a_reg.in = 32'd5; a_reg.write_en = 1'd1; A[done] = a_reg.done; @@ -44,7 +44,7 @@ component main () -> () { C[done] = ud.out; } - group B<"promote_static"=1> { + group B<"promotable"=1> { a.left = a_reg.out; a.right = c_reg.out; b_reg.in = a.out; @@ -52,19 +52,19 @@ component main () -> () { B[done] = b_reg.done; } - group D<"promote_static"=1> { + group D<"promotable"=1> { d_reg.in = a_reg.out; d_reg.write_en = 1'd1; D[done] = ud.out; } - group E<"promote_static"=1> { + group E<"promotable"=1> { e_reg.in = 32'd4; e_reg.write_en = 1'd1; E[done] = e_reg.done; } - group F<"promote_static"=1> { + group F<"promotable"=1> { f_reg.in = 32'd4; f_reg.write_en = 1'd1; F[done] = f_reg.done; @@ -73,12 +73,12 @@ component main () -> () { control { seq { - @promote_static A; - @promote_static B; + @promotable A; + @promotable B; C; - @promote_static D; - @promote_static E; - @promote_static F; + @promotable D; + @promotable E; + @promotable F; } } } \ No newline at end of file diff --git a/tests/passes/schedule-compaction/schedule-compaction.expect b/tests/passes/schedule-compaction/schedule-compaction.expect index 2cff214a6..5503b55d1 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.expect +++ b/tests/passes/schedule-compaction/schedule-compaction.expect @@ -30,7 +30,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } control { - @promote_static(11) @promoted static<11> par { + @promotable(11) @promoted static<11> par { static<11> seq { A0; D0; diff --git a/tests/passes/schedule-compaction/schedule-compaction.futil b/tests/passes/schedule-compaction/schedule-compaction.futil index 719d587ea..44e709619 100644 --- a/tests/passes/schedule-compaction/schedule-compaction.futil +++ b/tests/passes/schedule-compaction/schedule-compaction.futil @@ -30,19 +30,19 @@ component main () -> () { } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a_reg.in = 32'd5; a_reg.write_en = 1'd1; A[done] = a_reg.done; } - group C<"promote_static"=10> { + group C<"promotable"=10> { c_reg.in = 32'd10; c_reg.write_en = 1'd1; C[done] = ud.out; } - group B<"promote_static"=1> { + group B<"promotable"=1> { a.left = a_reg.out; a.right = c_reg.out; b_reg.in = a.out; @@ -50,7 +50,7 @@ component main () -> () { B[done] = b_reg.done; } - group D<"promote_static"=10> { + group D<"promotable"=10> { d_reg.in = a_reg.out; d_reg.write_en = 1'd1; D[done] = ud.out; @@ -58,11 +58,11 @@ component main () -> () { } control { - @promote_static(22) seq { - @promote_static A; - @promote_static(10) C; - @promote_static B; - @promote_static(10) D; + @promotable(22) seq { + @promotable A; + @promotable(10) C; + @promotable B; + @promotable(10) D; } } } \ No newline at end of file diff --git a/tests/passes/static-inference-promotion/groups.expect b/tests/passes/static-inference-promotion/groups.expect index 9c524c842..4d88a0ed1 100644 --- a/tests/passes/static-inference-promotion/groups.expect +++ b/tests/passes/static-inference-promotion/groups.expect @@ -7,11 +7,11 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don m0 = comb_mem_d1(32, 1, 1); } wires { - group one_cycle<"promote_static"=1> { + group one_cycle<"promotable"=1> { r0.write_en = 1'd1; one_cycle[done] = r0.done; } - group two_cycles<"promote_static"=2> { + group two_cycles<"promotable"=2> { r0.write_en = 1'd1; r1.write_en = r0.done; two_cycles[done] = r1.done; diff --git a/tests/passes/static-inference-promotion/if-diff.expect b/tests/passes/static-inference-promotion/if-diff.expect index aed5e1c4a..3dfedc0de 100644 --- a/tests/passes/static-inference-promotion/if-diff.expect +++ b/tests/passes/static-inference-promotion/if-diff.expect @@ -6,7 +6,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cond = std_reg(1); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; diff --git a/tests/passes/static-inference-promotion/invoke.expect b/tests/passes/static-inference-promotion/invoke.expect index 71203c3e5..6d7f8ea30 100644 --- a/tests/passes/static-inference-promotion/invoke.expect +++ b/tests/passes/static-inference-promotion/invoke.expect @@ -21,7 +21,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } -static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 32, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-inference-promotion/multi-static.expect b/tests/passes/static-inference-promotion/multi-static.expect index cd0020aef..b6822888d 100644 --- a/tests/passes/static-inference-promotion/multi-static.expect +++ b/tests/passes/static-inference-promotion/multi-static.expect @@ -21,7 +21,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } } } -static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +static<2> component exponent<"promoted"=1>(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); diff --git a/tests/passes/static-inference-promotion/threshold.expect b/tests/passes/static-inference-promotion/threshold.expect index ee2863035..5e8934cd1 100644 --- a/tests/passes/static-inference-promotion/threshold.expect +++ b/tests/passes/static-inference-promotion/threshold.expect @@ -7,17 +7,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c = std_reg(2); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group C<"promote_static"=1> { + group C<"promotable"=1> { c.in = 2'd2; c.write_en = 1'd1; C[done] = c.done; diff --git a/tests/passes/static-inference/component.expect b/tests/passes/static-inference/component.expect index ea7df95b7..fff3ffbc6 100644 --- a/tests/passes/static-inference/component.expect +++ b/tests/passes/static-inference/component.expect @@ -7,27 +7,27 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c = std_reg(2); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group C<"promote_static"=1> { + group C<"promotable"=1> { c.in = 2'd2; c.write_en = 1'd1; C[done] = c.done; } } control { - @promote_static(3) seq { - @promote_static A; - @promote_static B; - @promote_static C; + @promotable(3) seq { + @promotable A; + @promotable B; + @promotable C; } } } diff --git a/tests/passes/static-inference/groups.expect b/tests/passes/static-inference/groups.expect index 82a468db4..7c9348bae 100644 --- a/tests/passes/static-inference/groups.expect +++ b/tests/passes/static-inference/groups.expect @@ -7,16 +7,16 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don m0 = comb_mem_d1(32, 1, 1); } wires { - group one_cycle<"promote_static"=1> { + group one_cycle<"promotable"=1> { r0.write_en = 1'd1; one_cycle[done] = r0.done; } - group two_cycles<"promote_static"=2> { + group two_cycles<"promotable"=2> { r0.write_en = 1'd1; r1.write_en = r0.done; two_cycles[done] = r1.done; } - group mem_wrt_to_done<"promote_static"=1> { + group mem_wrt_to_done<"promotable"=1> { m0.addr0 = 1'd0; m0.write_data = 32'd5; m0.write_en = 1'd1; @@ -29,13 +29,13 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don } control { seq { - @promote_static one_cycle; - @promote_static(2) two_cycles; - @promote_static mem_wrt_to_done; + @promotable one_cycle; + @promotable(2) two_cycles; + @promotable mem_wrt_to_done; mult_wrts_to_done; - @promote_static one_cycle; + @promotable one_cycle; mult_wrts_to_done; - @promote_static(2) two_cycles; + @promotable(2) two_cycles; } } } diff --git a/tests/passes/static-inference/if-no-else.expect b/tests/passes/static-inference/if-no-else.expect index 710fa1138..a4242e0da 100644 --- a/tests/passes/static-inference/if-no-else.expect +++ b/tests/passes/static-inference/if-no-else.expect @@ -6,15 +6,15 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { cond = std_reg(1); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } } control { - @promote_static if cond.out { - @promote_static A; + @promotable if cond.out { + @promotable A; } } } diff --git a/tests/passes/static-inference/invoke.expect b/tests/passes/static-inference/invoke.expect index bc14f1aaf..c400fd9f5 100644 --- a/tests/passes/static-inference/invoke.expect +++ b/tests/passes/static-inference/invoke.expect @@ -6,43 +6,43 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { exp0 = exponent(); } wires { - group upd0<"promote_static"=1> { + group upd0<"promotable"=1> { r.in = 32'd1; r.write_en = 1'd1; upd0[done] = r.done; } } control { - @promote_static(3) seq { - @promote_static upd0; - @promote_static(2) invoke exp0( + @promotable(3) seq { + @promotable upd0; + @promotable(2) invoke exp0( base = r.out, exp = r.out )(); } } } -component exponent(base: 32, exp: 32, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +component exponent(base: 32, exp: 32, @go @promotable(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); } wires { - group upd2<"promote_static"=1> { + group upd2<"promotable"=1> { r2.in = 32'd1; r2.write_en = 1'd1; upd2[done] = r2.done; } - group upd1<"promote_static"=1> { + group upd1<"promotable"=1> { r1.in = 32'd1; r1.write_en = 1'd1; upd1[done] = r1.done; } } control { - @promote_static(2) seq { - @promote_static upd1; - @promote_static upd2; + @promotable(2) seq { + @promotable upd1; + @promotable upd2; } } } diff --git a/tests/passes/static-inference/par.expect b/tests/passes/static-inference/par.expect index 9bcbe955d..061e578f4 100644 --- a/tests/passes/static-inference/par.expect +++ b/tests/passes/static-inference/par.expect @@ -7,16 +7,16 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don m0 = comb_mem_d1(32, 1, 1); } wires { - group one_cycle<"promote_static"=1> { + group one_cycle<"promotable"=1> { r0.write_en = 1'd1; one_cycle[done] = r0.done; } - group two_cycles<"promote_static"=2> { + group two_cycles<"promotable"=2> { r0.write_en = 1'd1; r1.write_en = r0.done; two_cycles[done] = r1.done; } - group mem_wrt_to_done<"promote_static"=1> { + group mem_wrt_to_done<"promotable"=1> { m0.addr0 = 1'd0; m0.write_data = 32'd5; m0.write_en = 1'd1; @@ -29,10 +29,10 @@ component main(go: 1, clk: 1, @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (don } control { par { - @promote_static one_cycle; - @promote_static(2) two_cycles; + @promotable one_cycle; + @promotable(2) two_cycles; mult_wrts_to_done; - @promote_static mem_wrt_to_done; + @promotable mem_wrt_to_done; } } } diff --git a/tests/passes/static-inference/promote-nested.expect b/tests/passes/static-inference/promote-nested.expect index 2a16eb259..e41ff4d3e 100644 --- a/tests/passes/static-inference/promote-nested.expect +++ b/tests/passes/static-inference/promote-nested.expect @@ -9,17 +9,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { r0 = std_reg(2); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group C<"promote_static"=1> { + group C<"promotable"=1> { c.in = 2'd2; c.write_en = 1'd1; C[done] = c.done; @@ -31,26 +31,26 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { seq { - @promote_static(4) seq { - @promote_static par { - @promote_static A; - @promote_static B; + @promotable(4) seq { + @promotable par { + @promotable A; + @promotable B; } - @promote_static(2) seq { - @promote_static C; - @promote_static C; + @promotable(2) seq { + @promotable C; + @promotable C; } - @promote_static par { - @promote_static A; - @promote_static B; + @promotable par { + @promotable A; + @promotable B; } } no_upgrade; - @bound(2) @promote_static(6) while cond_reg.out { - @promote_static(3) seq { - @promote_static A; - @promote_static B; - @promote_static C; + @bound(2) @promotable(6) while cond_reg.out { + @promotable(3) seq { + @promotable A; + @promotable B; + @promotable C; } } } diff --git a/tests/passes/static-inference/promote-repeat.expect b/tests/passes/static-inference/promote-repeat.expect index afa151804..72c01bacf 100644 --- a/tests/passes/static-inference/promote-repeat.expect +++ b/tests/passes/static-inference/promote-repeat.expect @@ -7,41 +7,41 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c = std_reg(2); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group C<"promote_static"=1> { + group C<"promotable"=1> { c.in = 2'd2; c.write_en = 1'd1; C[done] = c.done; } } control { - @promote_static(43) seq { - @promote_static(40) repeat 10 { - @promote_static(4) seq { - @promote_static A; - @promote_static B; - @promote_static C; - @promote_static C; + @promotable(43) seq { + @promotable(40) repeat 10 { + @promotable(4) seq { + @promotable A; + @promotable B; + @promotable C; + @promotable C; } } - @promote_static(3) par { - @promote_static(2) seq { - @promote_static A; - @promote_static B; + @promotable(3) par { + @promotable(2) seq { + @promotable A; + @promotable B; } - @promote_static(3) seq { - @promote_static C; - @promote_static C; - @promote_static C; + @promotable(3) seq { + @promotable C; + @promotable C; + @promotable C; } } } diff --git a/tests/passes/static-passes/both-passes-promote.expect b/tests/passes/static-passes/both-passes-promote.expect index 6601ce520..19613ac19 100644 --- a/tests/passes/static-passes/both-passes-promote.expect +++ b/tests/passes/static-passes/both-passes-promote.expect @@ -7,17 +7,17 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { c = std_reg(2); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group C<"promote_static"=1> { + group C<"promotable"=1> { c.in = 2'd2; c.write_en = 1'd1; C[done] = c.done; @@ -37,7 +37,7 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { } control { static repeat 10 { - @promote_static @promoted static<1> par { + @promotable @promoted static<1> par { A0; B0; C0; diff --git a/tests/passes/static-promotion/fixup-invoke.expect b/tests/passes/static-promotion/fixup-invoke.expect new file mode 100644 index 000000000..7a653141f --- /dev/null +++ b/tests/passes/static-promotion/fixup-invoke.expect @@ -0,0 +1,57 @@ +import "primitives/core.futil"; +component foo(@go go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2<"promotable"=1> { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1<"promotable"=1> { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + seq { + upd1; + upd2; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + foo_inst = foo(); + } + wires { + static<1> group A0 { + a.in = 2'd0; + a.write_en = 1'd1; + } + static<1> group B0 { + b.in = 2'd1; + b.write_en = 1'd1; + } + } + control { + seq { + static<8> seq { + A0; + A0; + A0; + A0; + B0; + B0; + B0; + B0; + } + invoke foo_inst()(); + } + } +} diff --git a/tests/passes/static-promotion/fixup-invoke.futil b/tests/passes/static-promotion/fixup-invoke.futil new file mode 100644 index 000000000..a4c72d6bf --- /dev/null +++ b/tests/passes/static-promotion/fixup-invoke.futil @@ -0,0 +1,60 @@ +// -p well-formed -p static-promotion -x static-promotion:threshold=5 -p dead-group-removal + +import "primitives/core.futil"; + +component foo(@go @promotable(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { + cells { + r1 = std_reg(32); + r2 = std_reg(32); + } + wires { + group upd2<"promotable"=1> { + r2.in = 32'd1; + r2.write_en = 1'd1; + upd2[done] = r2.done; + } + group upd1<"promotable"=1> { + r1.in = 32'd1; + r1.write_en = 1'd1; + upd1[done] = r1.done; + } + } + control { + @promotable(2) seq { + @promotable upd1; + @promotable upd2; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + a = std_reg(2); + b = std_reg(2); + foo_inst = foo(); + } + wires { + group A<"promotable"=1> { + a.in = 2'd0; + a.write_en = 1'd1; + A[done] = a.done; + } + group B<"promotable"=1> { + b.in = 2'd1; + b.write_en = 1'd1; + B[done] = b.done; + } + } + control { + @promotable(10) seq { + @promotable A; + @promotable A; + @promotable A; + @promotable A; + @promotable B; + @promotable B; + @promotable B; + @promotable B; + @promotable(2) invoke foo_inst()(); + } + } +} \ No newline at end of file diff --git a/tests/passes/static-promotion/fixup-necessary.expect b/tests/passes/static-promotion/fixup-necessary.expect index 4e6976dbd..0c10d329b 100644 --- a/tests/passes/static-promotion/fixup-necessary.expect +++ b/tests/passes/static-promotion/fixup-necessary.expect @@ -6,12 +6,12 @@ component foo(base: 32, exp: 4, @go go: 1, @clk clk: 1, @reset reset: 1) -> (out r2 = std_reg(32); } wires { - group upd2<"promote_static"=1> { + group upd2<"promotable"=1> { r2.in = 32'd1; r2.write_en = 1'd1; upd2[done] = r2.done; } - group upd1<"promote_static"=1> { + group upd1<"promotable"=1> { r1.in = 32'd1; r1.write_en = 1'd1; upd1[done] = r1.done; diff --git a/tests/passes/static-promotion/fixup-necessary.futil b/tests/passes/static-promotion/fixup-necessary.futil index 24c8e406e..25a304b82 100644 --- a/tests/passes/static-promotion/fixup-necessary.futil +++ b/tests/passes/static-promotion/fixup-necessary.futil @@ -3,27 +3,27 @@ import "primitives/core.futil"; import "primitives/memories/comb.futil"; -component foo(base: 32, exp: 4, @go @static(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { +component foo(base: 32, exp: 4, @go @promotable(2) go: 1, @clk clk: 1, @reset reset: 1) -> (out: 32, @done done: 1) { cells { r1 = std_reg(32); r2 = std_reg(32); } wires { - group upd2<"promote_static"=1> { + group upd2<"promotable"=1> { r2.in = 32'd1; r2.write_en = 1'd1; upd2[done] = r2.done; } - group upd1<"promote_static"=1> { + group upd1<"promotable"=1> { r1.in = 32'd1; r1.write_en = 1'd1; upd1[done] = r1.done; } } control { - @promote_static(2) seq { - @promote_static upd1; - @promote_static upd2; + @promotable(2) seq { + @promotable upd1; + @promotable upd2; } } } @@ -34,32 +34,32 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { foo_inst = foo(); } wires { - group A<"promote_static"=1> { + group A<"promotable"=1> { a.in = 2'd0; a.write_en = 1'd1; A[done] = a.done; } - group B<"promote_static"=1> { + group B<"promotable"=1> { b.in = 2'd1; b.write_en = 1'd1; B[done] = b.done; } - group F<"promote_static"=2> { + group F<"promotable"=2> { foo_inst.go = 1'd1; F[done] = foo_inst.done; } } control { - @promote_static(10) seq { - @promote_static A; - @promote_static A; - @promote_static A; - @promote_static A; - @promote_static B; - @promote_static B; - @promote_static B; - @promote_static B; - @promote_static(2) F; + @promotable(10) seq { + @promotable A; + @promotable A; + @promotable A; + @promotable A; + @promotable B; + @promotable B; + @promotable B; + @promotable B; + @promotable(2) F; } } } \ No newline at end of file diff --git a/tests/passes/tdcc/branch-at-start.futil b/tests/passes/tdcc/branch-at-start.futil index 811523c40..e7301300a 100644 --- a/tests/passes/tdcc/branch-at-start.futil +++ b/tests/passes/tdcc/branch-at-start.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d static-promotion -d attr-promotion -d post-opt -d lower -d group2invoke -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d lower -d group2invoke -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; component main(is_valid: 1) -> () { diff --git a/tests/passes/tdcc/empty-exit.futil b/tests/passes/tdcc/empty-exit.futil index e614447e9..f1f53e83f 100644 --- a/tests/passes/tdcc/empty-exit.futil +++ b/tests/passes/tdcc/empty-exit.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d post-opt -d static-promotion -d attr-promotion -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d post-opt -d static-promotion -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/if.futil b/tests/passes/tdcc/if.futil index 2915ad4f8..b00a0605c 100644 --- a/tests/passes/tdcc/if.futil +++ b/tests/passes/tdcc/if.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/nested-while.futil b/tests/passes/tdcc/nested-while.futil index 4514a376a..cd7f9b355 100644 --- a/tests/passes/tdcc/nested-while.futil +++ b/tests/passes/tdcc/nested-while.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; @@ -8,7 +8,7 @@ component main() -> () { r1 = std_reg(1); } wires { - group init<"static"=1> { + group init<"promotable"=1> { init[done] = r0.out; } group exit { diff --git a/tests/passes/tdcc/new-fsm-nested.futil b/tests/passes/tdcc/new-fsm-nested.futil index 167594a44..785fa2606 100644 --- a/tests/passes/tdcc/new-fsm-nested.futil +++ b/tests/passes/tdcc/new-fsm-nested.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/new-fsm-seq.futil b/tests/passes/tdcc/new-fsm-seq.futil index 5750df841..200994f81 100644 --- a/tests/passes/tdcc/new-fsm-seq.futil +++ b/tests/passes/tdcc/new-fsm-seq.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/par.futil b/tests/passes/tdcc/par.futil index 4f7b1a782..124ac1153 100644 --- a/tests/passes/tdcc/par.futil +++ b/tests/passes/tdcc/par.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/seq-with-same-done.futil b/tests/passes/tdcc/seq-with-same-done.futil index bf68799db..2b84acaca 100644 --- a/tests/passes/tdcc/seq-with-same-done.futil +++ b/tests/passes/tdcc/seq-with-same-done.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/seq.futil b/tests/passes/tdcc/seq.futil index cbeda6d2b..40f0224f3 100644 --- a/tests/passes/tdcc/seq.futil +++ b/tests/passes/tdcc/seq.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/tdcc/while-if.futil b/tests/passes/tdcc/while-if.futil index 034d995ed..04884a3ab 100644 --- a/tests/passes/tdcc/while-if.futil +++ b/tests/passes/tdcc/while-if.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; component main() -> () { diff --git a/tests/passes/tdcc/while.futil b/tests/passes/tdcc/while.futil index c2cf39b59..fc1460df2 100644 --- a/tests/passes/tdcc/while.futil +++ b/tests/passes/tdcc/while.futil @@ -1,4 +1,4 @@ -// -x tdcc:dump-fsm -d attr-promotion -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none +// -x tdcc:dump-fsm -d schedule-compaction -d static-promotion -d post-opt -d group2invoke -d lower -b none import "primitives/core.futil"; import "primitives/memories/comb.futil"; diff --git a/tests/passes/well-formed/interval-attr.expect b/tests/passes/well-formed/interval-attr.expect new file mode 100644 index 000000000..76a8cdc7f --- /dev/null +++ b/tests/passes/well-formed/interval-attr.expect @@ -0,0 +1,4 @@ +---STDERR--- +Error: tests/passes/well-formed/interval-attr.futil +4 |component foo(@interval @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: component foo expected @interval 1, got @interval 2 diff --git a/tests/passes/well-formed/interval-attr.futil b/tests/passes/well-formed/interval-attr.futil new file mode 100644 index 000000000..d4f412de0 --- /dev/null +++ b/tests/passes/well-formed/interval-attr.futil @@ -0,0 +1,34 @@ +// -p well-formed +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component foo(@interval @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(32); + } + wires { + static<1> group upd_r { + r.in = 32'd10; + r.write_en = 1'd1; + } + + } + control { + static seq { + upd_r; + upd_r; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = foo(); + } + wires { + } + + control { + seq { + invoke f()(); + } + } +} diff --git a/tests/passes/well-formed/interval-attr2.expect b/tests/passes/well-formed/interval-attr2.expect new file mode 100644 index 000000000..e56bda80c --- /dev/null +++ b/tests/passes/well-formed/interval-attr2.expect @@ -0,0 +1,4 @@ +---STDERR--- +Error: tests/passes/well-formed/interval-attr2.futil +4 |component foo(@interval @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: component foo has dynamic control but has @interval annotations diff --git a/tests/passes/well-formed/interval-attr2.futil b/tests/passes/well-formed/interval-attr2.futil new file mode 100644 index 000000000..9bcbc26ff --- /dev/null +++ b/tests/passes/well-formed/interval-attr2.futil @@ -0,0 +1,34 @@ +// -p well-formed +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component foo(@interval @go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + r = std_reg(32); + } + wires { + group upd_r <"promotable"=1> { + r.in = 32'd10; + r.write_en = 1'd1; + upd_r[done] = r.done; + } + + } + control { + @promotable seq { + @promotable upd_r; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = foo(); + } + wires { + } + + control { + seq { + invoke f()(); + } + } +} diff --git a/tests/passes/well-formed/interval-attr3.expect b/tests/passes/well-formed/interval-attr3.expect new file mode 100644 index 000000000..d8ed5e911 --- /dev/null +++ b/tests/passes/well-formed/interval-attr3.expect @@ -0,0 +1,4 @@ +---STDERR--- +Error: tests/passes/well-formed/interval-attr3.futil +4 |component foo(@interval @go go: 1, @go(2) go2: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1, @done(2) done2: 1) { + |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Malformed Structure: @go port expected @interval(1) attribute on all ports since the component has static control diff --git a/tests/passes/well-formed/interval-attr3.futil b/tests/passes/well-formed/interval-attr3.futil new file mode 100644 index 000000000..9665fead5 --- /dev/null +++ b/tests/passes/well-formed/interval-attr3.futil @@ -0,0 +1,33 @@ +// -p well-formed +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +component foo(@interval @go go: 1, @go(2) go2: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1, @done(2) done2: 1) { + cells { + r = std_reg(32); + } + wires { + static<1> group upd_r { + r.in = 32'd10; + r.write_en = 1'd1; + } + + } + control { + static seq { + upd_r; + } + } +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = foo(); + } + wires { + } + + control { + seq { + invoke f()(); + } + } +} diff --git a/tests/passes/well-formed/interval-cont.expect b/tests/passes/well-formed/interval-cont.expect new file mode 100644 index 000000000..d81469b6d --- /dev/null +++ b/tests/passes/well-formed/interval-cont.expect @@ -0,0 +1,68 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +comb component layout_hw0(reform_port_addr0: 4, reform_port_addr1: 4) -> (flat_port_addr0: 8) { + cells { + add_0 = std_add(8); + d1_times_16 = std_lsh(8); + pad_reform_port_addr1 = std_pad(4, 8); + pad_reform_port_addr0 = std_pad(4, 8); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = pad_reform_port_addr0.out; + add_0.right = d1_times_16.out; + d1_times_16.left = pad_reform_port_addr1.out; + d1_times_16.right = 8'd4; + pad_reform_port_addr1.in = reform_port_addr1; + pad_reform_port_addr0.in = reform_port_addr0; + } +} +comb component layout_hw1(reform_port_addr0: 4, reform_port_addr1: 4) -> (flat_port_addr0: 8) { + cells { + add_0 = std_add(8); + d1_times_16 = std_lsh(8); + pad_reform_port_addr1 = std_pad(4, 8); + pad_reform_port_addr0 = std_pad(4, 8); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = pad_reform_port_addr0.out; + add_0.right = d1_times_16.out; + d1_times_16.left = pad_reform_port_addr1.out; + d1_times_16.right = 8'd4; + pad_reform_port_addr1.in = reform_port_addr1; + pad_reform_port_addr0.in = reform_port_addr0; + } +} +component amcMemory0(@clk clk: 1, port0_addr0: 4, port0_addr1: 4, port0_write_data: 32, @go @interval port0_write_en: 1, port1_addr0: 4, port1_addr1: 4, @go(3) @interval port1_read_en: 1, port1_write_data: 32, @go(2) @interval port1_write_en: 1, @reset reset: 1) -> (@done port0_write_done: 1, @stable port1_read_data: 32, @done(3) port1_read_done: 1, @done(2) port1_write_done: 1) { + cells { + layout_hw_inst1 = layout_hw1(); + layout_hw_inst0 = layout_hw0(); + my_reg = std_reg(32); + } + wires { + my_reg.clk = clk; + layout_hw_inst1.reform_port_addr0 = port1_addr0; + layout_hw_inst1.reform_port_addr1 = port1_addr1; + layout_hw_inst0.reform_port_addr0 = port0_addr0; + layout_hw_inst0.reform_port_addr1 = port0_addr1; + my_reg.in = port0_write_data; + my_reg.write_en = port0_write_en; + port0_write_done = my_reg.done; + port1_write_done = my_reg.done; + port1_read_data = my_reg.out; + port1_read_done = my_reg.done; + } + control {} +} +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = amcMemory0(); + } + wires {} + control { + seq { + invoke f()(); + } + } +} diff --git a/tests/passes/well-formed/interval-cont.futil b/tests/passes/well-formed/interval-cont.futil new file mode 100644 index 000000000..475bf9a86 --- /dev/null +++ b/tests/passes/well-formed/interval-cont.futil @@ -0,0 +1,76 @@ +// -p well-formed + +// You can use @interval to specify timing of primitive-like Calyx components. +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; + +comb component layout_hw0(reform_port_addr0: 4, reform_port_addr1: 4) -> (flat_port_addr0: 8) { + cells { + add_0 = std_add(8); + d1_times_16 = std_lsh(8); + pad_reform_port_addr1 = std_pad(4, 8); + pad_reform_port_addr0 = std_pad(4, 8); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = pad_reform_port_addr0.out; + add_0.right = d1_times_16.out; + d1_times_16.left = pad_reform_port_addr1.out; + d1_times_16.right = 8'd4; + pad_reform_port_addr1.in = reform_port_addr1; + pad_reform_port_addr0.in = reform_port_addr0; + } +} +comb component layout_hw1(reform_port_addr0: 4, reform_port_addr1: 4) -> (flat_port_addr0: 8) { + cells { + add_0 = std_add(8); + d1_times_16 = std_lsh(8); + pad_reform_port_addr1 = std_pad(4, 8); + pad_reform_port_addr0 = std_pad(4, 8); + } + wires { + flat_port_addr0 = add_0.out; + add_0.left = pad_reform_port_addr0.out; + add_0.right = d1_times_16.out; + d1_times_16.left = pad_reform_port_addr1.out; + d1_times_16.right = 8'd4; + pad_reform_port_addr1.in = reform_port_addr1; + pad_reform_port_addr0.in = reform_port_addr0; + } +} +component amcMemory0(@clk clk: 1, port0_addr0: 4, port0_addr1: 4, port0_write_data: 32, @go @interval(1) port0_write_en: 1, port1_addr0: 4, port1_addr1: 4, @go(3) @interval(1) port1_read_en: 1, port1_write_data: 32, @go(2) @interval(1) port1_write_en: 1, @reset reset: 1) -> (@done port0_write_done: 1, @stable port1_read_data: 32, @done(3) port1_read_done: 1, @done(2) port1_write_done: 1) { + cells { + layout_hw_inst1 = layout_hw1(); + layout_hw_inst0 = layout_hw0(); + my_reg = std_reg(32); + } + wires { + my_reg.clk = clk; + layout_hw_inst1.reform_port_addr0 = port1_addr0; + layout_hw_inst1.reform_port_addr1 = port1_addr1; + layout_hw_inst0.reform_port_addr0 = port0_addr0; + layout_hw_inst0.reform_port_addr1 = port0_addr1; + my_reg.in = port0_write_data; + my_reg.write_en = port0_write_en; + port0_write_done = my_reg.done; + port1_write_done = my_reg.done; + port1_read_data = my_reg.out; + port1_read_done = my_reg.done; + } + control { + } +} + +component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { + cells { + f = amcMemory0(); + } + wires { + } + + control { + seq { + invoke f()(); + } + } +} \ No newline at end of file From fbcf573d33a9fd0025dbec0a9d81e7d19ca0d025 Mon Sep 17 00:00:00 2001 From: calebmkim <55243755+calebmkim@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:24:17 -0500 Subject: [PATCH 171/189] Remove `@static` from docs (#1911) * language reference * clarification * tell static is deprecated --- docs/lang/attributes.md | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/lang/attributes.md b/docs/lang/attributes.md index 6c39f7ee4..f7a1abce3 100644 --- a/docs/lang/attributes.md +++ b/docs/lang/attributes.md @@ -29,7 +29,7 @@ cells { #### **Group Attributes** ``` -group cond<"static"=1> { +group cond<"promotable"=1> { ... } ``` @@ -37,9 +37,9 @@ group cond<"static"=1> { #### **Control Attributes** ``` control { - @static(3) seq { - @static(1) A; - @static(2) B; + @promotable(3) seq { + @promotable(1) A; + @promotable(2) B; } } ``` @@ -70,14 +70,26 @@ It has two meanings: 2. If the cell is a memory and has an `external` attribute on it, the Verilog backend (`-b verilog`) generates code to read `.dat` to initialize the memory state and dumps out its final value after execution. ### `static(n)` -Can be attached to components, groups, and control statements. They indicate how -many cycles a component, group, or control statement will take to run and are used -by `-p static-timing` to generate more efficient control FSMs. - -The `go` and `done` attributes are, in particular, used by the `infer-static-timing` pass to configure which ports are used like -`go` and `done` signals. -Along with the `static(n)` attribute, this allows the pass to calculate when -a particular done signal of a primitive will be high. +This is now deprecated. See the [promotable][promotable] and [interval][interval] +attributes. + +### `promotable(n)` +Can be attached to groups, control, and `@go` ports of components. +This tells the compiler how long the group/control would take if it were promoted +to static. +This is just a hint, and is free to be ignored by the compiler. +However, the compiler may use it in the `static-promotion` pass to upgrade dynamic +constructs to `static` ones. + +### `interval(n)` +This can be attached to the `@go` ports of dynamic components (both primitives or +Calyx-defined components). +This tells the compiler that if you assert the `@go` port for cycles `[0,n)`, then +the done signal will be asserted on cycle `n`. +This is different from `@promotable` since it provides a guarantee rather than a hint. +Attach `@interval` to `@go` ports essentially means that the component can serve +"double duty": it can be used in both static and dynamic contexts. +This is common for things like registers. ### `inline` Used by the `inline` pass on cell definitions. Instructs the pass to completely @@ -202,4 +214,6 @@ Since the value `'x` can be replaced with anything. [datapath-components]: https://github.com/calyxir/calyx/issues/1169 [builder]: https://docs.rs/calyx-ir/latest/calyx_ir/struct.Builder.html -[externalize]: https://docs.rs/calyx-opt/latest/calyx_opt/passes/struct.Externalize.html \ No newline at end of file +[externalize]: https://docs.rs/calyx-opt/latest/calyx_opt/passes/struct.Externalize.html +[promotable]: #promotable(n) +[interval]: #interval(n) From 6802fbd4417cc37d3b548837fa31777fed50d962 Mon Sep 17 00:00:00 2001 From: Griffin Berlstein Date: Mon, 12 Feb 2024 14:28:47 -0500 Subject: [PATCH 172/189] [Cider 2.0] Basic Simulation flow (#1912) * clippy lint * debug printing * misc nonsense * checkpoint * add run program * rename the stdmem impls * move the get_next for control points into two separate non-internal functions * some light documentation and renaming * add an assert * add some dinky placeholder printing for internal state * fix some issues with the memories and move serialization * set the go ports appropriately * clean up warnings --- interp/src/debugger/cidr.rs | 2 +- interp/src/flatten/flat_ir/base.rs | 25 +- interp/src/flatten/primitives/builder.rs | 8 +- .../src/flatten/primitives/combinational.rs | 8 - interp/src/flatten/primitives/macros.rs | 4 - interp/src/flatten/primitives/prim_trait.rs | 15 +- .../flatten/primitives/stateful/memories.rs | 186 ++++++++---- .../src/flatten/structures/environment/env.rs | 230 +++++++++----- .../structures/environment/program_counter.rs | 70 ++++- interp/src/flatten/structures/indexed_map.rs | 25 +- interp/src/flatten/structures/printer.rs | 13 +- .../src/interpreter/component_interpreter.rs | 4 +- interp/src/lib.rs | 1 + interp/src/primitives/combinational.rs | 12 +- interp/src/primitives/mod.rs | 3 +- interp/src/primitives/primitive_traits.rs | 287 +----------------- interp/src/primitives/stateful/math.rs | 3 +- interp/src/primitives/stateful/mem_utils.rs | 6 +- interp/src/primitives/stateful/memories.rs | 3 +- interp/src/serialization.rs | 282 +++++++++++++++++ interp/src/structures/state_views.rs | 3 +- 21 files changed, 715 insertions(+), 475 deletions(-) create mode 100644 interp/src/serialization.rs diff --git a/interp/src/debugger/cidr.rs b/interp/src/debugger/cidr.rs index 64f99e5a2..c6619cba5 100644 --- a/interp/src/debugger/cidr.rs +++ b/interp/src/debugger/cidr.rs @@ -11,7 +11,7 @@ use crate::interpreter::{ComponentInterpreter, ConstCell, Interpreter}; use crate::structures::names::{CompGroupName, ComponentQualifiedInstanceName}; use crate::structures::state_views::StateView; use crate::utils::AsRaw; -use crate::{interpreter_ir as iir, primitives::Serializable}; +use crate::{interpreter_ir as iir, serialization::Serializable}; use calyx_ir::{self as ir, Id, RRC}; diff --git a/interp/src/flatten/flat_ir/base.rs b/interp/src/flatten/flat_ir/base.rs index e91cd16fa..a1a9bcc58 100644 --- a/interp/src/flatten/flat_ir/base.rs +++ b/interp/src/flatten/flat_ir/base.rs @@ -274,12 +274,21 @@ impl From for AssignmentWinner { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Clone, PartialEq)] pub struct AssignedValue { val: Value, winner: AssignmentWinner, } +impl std::fmt::Debug for AssignedValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AssignedValue") + .field("val", &format!("{}", &self.val)) + .field("winner", &self.winner) + .finish() + } +} + impl std::fmt::Display for AssignedValue { // TODO: replace with something more reasonable fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -342,7 +351,7 @@ impl AssignedValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] /// A wrapper struct around an option of an [AssignedValue] pub struct PortValue(Option); @@ -398,6 +407,12 @@ impl PortValue { pub fn new_implicit(val: Value) -> Self { Self(Some(AssignedValue::implicit_value(val))) } + + /// Sets the value to undefined and returns the former value if present. + /// This is equivalent to [Option::take] + pub fn set_undef(&mut self) -> Option { + self.0.take() + } } impl From> for PortValue { @@ -412,6 +427,12 @@ impl From for PortValue { } } +impl From for Option { + fn from(value: PortValue) -> Self { + value.0 + } +} + /// A global index for standard groups in the IR #[derive(Debug, Eq, Copy, Clone, PartialEq, Hash, PartialOrd, Ord)] pub struct GroupIdx(u32); diff --git a/interp/src/flatten/primitives/builder.rs b/interp/src/flatten/primitives/builder.rs index f2bbb8e9d..037a3cc86 100644 --- a/interp/src/flatten/primitives/builder.rs +++ b/interp/src/flatten/primitives/builder.rs @@ -106,7 +106,7 @@ pub fn build_primitive( idx_size: _, } => match mem_type { MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), - MemType::Std => Box::new(StdMemD1::new(base_port, *width, false, *size as usize)) + MemType::Std => Box::new(CombMemD1::new(base_port, *width, false, *size as usize)) }, CellPrototype::MemD2 { mem_type, @@ -117,7 +117,7 @@ pub fn build_primitive( d1_idx_size: _, } => match mem_type { MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), - MemType::Std => Box::new(StdMemD2::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize))), + MemType::Std => Box::new(CombMemD2::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize))), }, CellPrototype::MemD3 { mem_type, @@ -130,7 +130,7 @@ pub fn build_primitive( d2_idx_size: _, } => match mem_type { MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), - MemType::Std => Box::new(StdMemD3::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize))), + MemType::Std => Box::new(CombMemD3::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize))), }, CellPrototype::MemD4 { mem_type, @@ -145,7 +145,7 @@ pub fn build_primitive( d3_idx_size: _, }=> match mem_type { MemType::Seq => todo!("SeqMem primitives are not currently defined in the flat interpreter"), - MemType::Std => Box::new(StdMemD4::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize, *d3_size as usize))), + MemType::Std => Box::new(CombMemD4::new(base_port, *width, false, (*d0_size as usize, *d1_size as usize, *d2_size as usize, *d3_size as usize))), }, CellPrototype::Unknown(_, _) => todo!(), } diff --git a/interp/src/flatten/primitives/combinational.rs b/interp/src/flatten/primitives/combinational.rs index a1b389949..7d1dfee6c 100644 --- a/interp/src/flatten/primitives/combinational.rs +++ b/interp/src/flatten/primitives/combinational.rs @@ -3,7 +3,6 @@ use std::ops::Not; use bitvec::vec::BitVec; use crate::{ - errors::InterpreterResult, flatten::{ flat_ir::prelude::{AssignedValue, GlobalPortIdx, PortValue}, primitives::{ @@ -84,13 +83,6 @@ impl Primitive for StdMux { } } - fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { - ports![&self.base; out: Self::OUT]; - port_map.write_undef_unchecked(out); - - Ok(()) - } - fn has_stateful(&self) -> bool { false } diff --git a/interp/src/flatten/primitives/macros.rs b/interp/src/flatten/primitives/macros.rs index 79162465f..9571e656f 100644 --- a/interp/src/flatten/primitives/macros.rs +++ b/interp/src/flatten/primitives/macros.rs @@ -102,10 +102,6 @@ macro_rules! comb_primitive { false } - fn reset(&mut self, map:&mut $crate::flatten::structures::environment::PortMap) -> $crate::errors::InterpreterResult<()> { - self.exec_comb(map)?; - Ok(()) - } } }; diff --git a/interp/src/flatten/primitives/prim_trait.rs b/interp/src/flatten/primitives/prim_trait.rs index d5d22b5bc..c6f712a6a 100644 --- a/interp/src/flatten/primitives/prim_trait.rs +++ b/interp/src/flatten/primitives/prim_trait.rs @@ -2,7 +2,7 @@ use crate::{ debugger::PrintCode, errors::InterpreterResult, flatten::{flat_ir::base::GlobalPortIdx, structures::environment::PortMap}, - primitives::Serializable, + serialization::Serializable, values::Value, }; @@ -30,6 +30,7 @@ impl From<(Value, GlobalPortIdx)> for AssignResult { } /// An enum used to denote whether or not committed updates changed the state +#[derive(Debug)] pub enum UpdateStatus { Unchanged, Changed, @@ -50,7 +51,7 @@ impl UpdateStatus { /// If the status is unchanged and other is changed, updates the status of /// self to changed, otherwise does nothing pub fn update(&mut self, other: Self) { - if !self.is_changed() && other.is_changed() { + if !self.as_bool() && other.as_bool() { *self = UpdateStatus::Changed; } } @@ -60,7 +61,7 @@ impl UpdateStatus { /// /// [`Changed`]: UpdateStatus::Changed #[must_use] - pub fn is_changed(&self) -> bool { + pub fn as_bool(&self) -> bool { matches!(self, Self::Changed) } } @@ -69,7 +70,7 @@ impl std::ops::BitOr for UpdateStatus { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { - if self.is_changed() || rhs.is_changed() { + if self.as_bool() || rhs.as_bool() { UpdateStatus::Changed } else { UpdateStatus::Unchanged @@ -81,7 +82,7 @@ impl std::ops::BitOr for &UpdateStatus { type Output = UpdateStatus; fn bitor(self, rhs: Self) -> Self::Output { - if self.is_changed() || rhs.is_changed() { + if self.as_bool() || rhs.as_bool() { UpdateStatus::Changed } else { UpdateStatus::Unchanged @@ -106,10 +107,6 @@ pub trait Primitive { Ok(UpdateStatus::Unchanged) } - fn reset(&mut self, _port_map: &mut PortMap) -> InterpreterResult<()> { - Ok(()) - } - fn has_comb(&self) -> bool { true } diff --git a/interp/src/flatten/primitives/stateful/memories.rs b/interp/src/flatten/primitives/stateful/memories.rs index 9c5c9a98b..ddf86cc37 100644 --- a/interp/src/flatten/primitives/stateful/memories.rs +++ b/interp/src/flatten/primitives/stateful/memories.rs @@ -1,7 +1,7 @@ use crate::{ - errors::{InterpreterError, InterpreterResult}, + errors::InterpreterError, flatten::{ - flat_ir::prelude::{AssignedValue, GlobalPortIdx, PortValue}, + flat_ir::prelude::{AssignedValue, GlobalPortIdx}, primitives::{ declare_ports, make_getters, ports, prim_trait::{UpdateResult, UpdateStatus}, @@ -9,13 +9,14 @@ use crate::{ }, structures::environment::PortMap, }, - primitives::{Entry, Serializable}, + serialization::{Entry, Serializable, Shape}, values::Value, }; pub struct StdReg { base_port: GlobalPortIdx, internal_state: Value, + done_is_high: bool, } impl StdReg { @@ -26,6 +27,7 @@ impl StdReg { Self { base_port, internal_state, + done_is_high: false, } } } @@ -43,7 +45,7 @@ impl Primitive for StdReg { let done_port = if port_map[reset].as_bool().unwrap_or_default() { self.internal_state = Value::zeroes(self.internal_state.width()); port_map - .insert_val(done, AssignedValue::cell_value(Value::bit_low())) + .insert_val(done, AssignedValue::cell_value(Value::bit_low()))? } else if port_map[write_en].as_bool().unwrap_or_default() { self.internal_state = port_map[input] .as_option() @@ -51,12 +53,20 @@ impl Primitive for StdReg { .val() .clone(); - port_map - .insert_val(done, AssignedValue::cell_value(Value::bit_high())) + self.done_is_high = true; + + port_map.insert_val( + done, + AssignedValue::cell_value(Value::bit_high()), + )? | port_map.insert_val( + out_idx, + AssignedValue::cell_value(self.internal_state.clone()), + )? } else { + self.done_is_high = false; port_map - .insert_val(done, AssignedValue::cell_value(Value::bit_low())) - }?; + .insert_val(done, AssignedValue::cell_value(Value::bit_low()))? + }; Ok(done_port | port_map.insert_val( @@ -65,18 +75,24 @@ impl Primitive for StdReg { )?) } - fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { - ports![&self.base_port; done: Self::DONE]; - port_map[done] = PortValue::new_cell(Value::bit_low()); - Ok(()) - } - fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { - ports![&self.base_port; out_idx: Self::OUT]; - port_map.insert_val( + ports![&self.base_port; + done: Self::DONE, + out_idx: Self::OUT]; + let out_signal = port_map.insert_val( out_idx, AssignedValue::cell_value(self.internal_state.clone()), - ) + )?; + let done_signal = port_map.insert_val( + done, + AssignedValue::cell_value(if self.done_is_high { + Value::bit_high() + } else { + Value::bit_low() + }), + )?; + + Ok(out_signal | done_signal) } fn serialize( @@ -102,9 +118,13 @@ pub trait MemAddresser { port_map: &PortMap, base_port: GlobalPortIdx, ) -> Option; + + fn get_dimensions(&self) -> Shape; } -pub struct MemD1; +pub struct MemD1 { + d0_size: usize, +} impl MemAddresser for MemD1 { fn calculate_addr( @@ -128,6 +148,10 @@ impl MemAddresser for MemD1 { } else { Self::COMB_ADDR0 + 1 }; + + fn get_dimensions(&self) -> Shape { + Shape::D1((self.d0_size,)) + } } impl MemD1 { @@ -135,6 +159,7 @@ impl MemD1 { } pub struct MemD2 { + d0_size: usize, d1_size: usize, } @@ -171,9 +196,14 @@ impl MemAddresser for MemD2 { } else { Self::COMB_ADDR1 + 1 }; + + fn get_dimensions(&self) -> Shape { + Shape::D2((self.d0_size, self.d1_size)) + } } pub struct MemD3 { + d0_size: usize, d1_size: usize, d2_size: usize, } @@ -219,9 +249,14 @@ impl MemAddresser for MemD3 { } else { Self::COMB_ADDR2 + 1 }; + + fn get_dimensions(&self) -> Shape { + Shape::D3((self.d0_size, self.d1_size, self.d2_size)) + } } pub struct MemD4 { + d0_size: usize, d1_size: usize, d2_size: usize, d3_size: usize, @@ -279,24 +314,29 @@ impl MemAddresser for MemD4 { } else { Self::COMB_ADDR3 + 1 }; + + fn get_dimensions(&self) -> Shape { + Shape::D4((self.d0_size, self.d1_size, self.d2_size, self.d3_size)) + } } -pub struct StdMem { +pub struct CombMem { base_port: GlobalPortIdx, internal_state: Vec, allow_invalid_access: bool, width: u32, addresser: M, + done_is_high: bool, } -impl StdMem { +impl CombMem { declare_ports![ - WRITE_DATA: M::NON_ADDRESS_BASE + 1, - WRITE_EN: M::NON_ADDRESS_BASE + 2, - CLK: M::NON_ADDRESS_BASE + 3, - RESET: M::NON_ADDRESS_BASE + 4, - READ_DATA: M::NON_ADDRESS_BASE + 5, - DONE: M::NON_ADDRESS_BASE + 6 + WRITE_DATA: M::NON_ADDRESS_BASE, + WRITE_EN: M::NON_ADDRESS_BASE + 1, + CLK: M::NON_ADDRESS_BASE + 2, + RESET: M::NON_ADDRESS_BASE + 3, + READ_DATA: M::NON_ADDRESS_BASE + 4, + DONE: M::NON_ADDRESS_BASE + 5 ]; make_getters![base_port; @@ -308,25 +348,36 @@ impl StdMem { ]; } -impl Primitive for StdMem { +impl Primitive for CombMem { fn exec_comb(&self, port_map: &mut PortMap) -> UpdateResult { let addr = self.addresser.calculate_addr(port_map, self.base_port); let read_data = self.read_data(); - if addr.is_some() && addr.unwrap() < self.internal_state.len() { - Ok(port_map.insert_val( - read_data, - AssignedValue::cell_value( - self.internal_state[addr.unwrap()].clone(), - ), - )?) - } - // either the address is undefined or it is outside the range of valid addresses - else { - // throw error on cycle boundary rather than here - port_map.write_undef(read_data)?; - Ok(UpdateStatus::Unchanged) - } + let read = + if addr.is_some() && addr.unwrap() < self.internal_state.len() { + port_map.insert_val( + read_data, + AssignedValue::cell_value( + self.internal_state[addr.unwrap()].clone(), + ), + )? + } + // either the address is undefined or it is outside the range of valid addresses + else { + // throw error on cycle boundary rather than here + port_map.write_undef(read_data)?; + UpdateStatus::Unchanged + }; + + let done_signal = port_map.insert_val( + self.done(), + AssignedValue::cell_value(if self.done_is_high { + Value::bit_high() + } else { + Value::bit_low() + }), + )?; + Ok(done_signal | read) } fn exec_cycle(&mut self, port_map: &mut PortMap) -> UpdateResult { @@ -344,8 +395,10 @@ impl Primitive for StdMem { .as_option() .ok_or(InterpreterError::UndefinedWrite)?; self.internal_state[addr] = write_data.val().clone(); + self.done_is_high = true; port_map.insert_val(done, AssignedValue::cell_b_high())? } else { + self.done_is_high = false; port_map.insert_val(done, AssignedValue::cell_b_low())? }; @@ -355,24 +408,24 @@ impl Primitive for StdMem { AssignedValue::cell_value(self.internal_state[addr].clone()), )? | done) } else { + port_map.write_undef(read_data)?; Ok(done) } } - fn reset(&mut self, port_map: &mut PortMap) -> InterpreterResult<()> { - let (read_data, done) = (self.read_data(), self.done()); - - port_map.write_undef_unchecked(read_data); - port_map[done] = PortValue::new_cell(Value::bit_low()); - - Ok(()) - } - fn serialize( &self, - _code: Option, + code: Option, ) -> Serializable { - todo!("StdMemD1::serialize") + let code = code.unwrap_or_default(); + + Serializable::Array( + self.internal_state + .iter() + .map(|x| Entry::from_val_code(x, &code)) + .collect(), + self.addresser.get_dimensions(), + ) } fn has_serializable_state(&self) -> bool { @@ -381,12 +434,12 @@ impl Primitive for StdMem { } // type aliases -pub type StdMemD1 = StdMem>; -pub type StdMemD2 = StdMem>; -pub type StdMemD3 = StdMem>; -pub type StdMemD4 = StdMem>; +pub type CombMemD1 = CombMem>; +pub type CombMemD2 = CombMem>; +pub type CombMemD3 = CombMem>; +pub type CombMemD4 = CombMem>; -impl StdMemD1 { +impl CombMemD1 { pub fn new( base: GlobalPortIdx, width: u32, @@ -400,12 +453,13 @@ impl StdMemD1 { internal_state, allow_invalid_access: allow_invalid, width, - addresser: MemD1::, + addresser: MemD1:: { d0_size: size }, + done_is_high: false, } } } -impl StdMemD2 { +impl CombMemD2 { pub fn new( base: GlobalPortIdx, width: u32, @@ -419,12 +473,16 @@ impl StdMemD2 { internal_state, allow_invalid_access: allow_invalid, width, - addresser: MemD2:: { d1_size: size.1 }, + addresser: MemD2:: { + d0_size: size.0, + d1_size: size.1, + }, + done_is_high: false, } } } -impl StdMemD3 { +impl CombMemD3 { pub fn new( base: GlobalPortIdx, width: u32, @@ -440,14 +498,16 @@ impl StdMemD3 { allow_invalid_access: allow_invalid, width, addresser: MemD3:: { + d0_size: size.0, d1_size: size.1, d2_size: size.2, }, + done_is_high: false, } } } -impl StdMemD4 { +impl CombMemD4 { pub fn new( base: GlobalPortIdx, width: u32, @@ -463,10 +523,12 @@ impl StdMemD4 { allow_invalid_access: allow_invalid, width, addresser: MemD4:: { + d0_size: size.0, d1_size: size.1, d2_size: size.2, d3_size: size.3, }, + done_is_high: false, } } } diff --git a/interp/src/flatten/structures/environment/env.rs b/interp/src/flatten/structures/environment/env.rs index 78ae6132e..5b1776140 100644 --- a/interp/src/flatten/structures/environment/env.rs +++ b/interp/src/flatten/structures/environment/env.rs @@ -1,4 +1,3 @@ -use ahash::HashSet; use itertools::Itertools; use super::{assignments::AssignmentBundle, program_counter::ProgramCounter}; @@ -20,10 +19,10 @@ use crate::{ }, primitives::{self, prim_trait::UpdateStatus, Primitive}, structures::{ - environment::program_counter::{ControlPoint, SearchPath}, - index_trait::IndexRef, + environment::program_counter::ControlPoint, index_trait::IndexRef, }, }, + values::Value, }; use std::{collections::VecDeque, fmt::Debug}; @@ -134,6 +133,15 @@ impl CellLedger { self.as_comp() .expect("Unwrapped cell ledger as component but received primitive") } + + #[must_use] + pub(crate) fn as_primitive(&self) -> Option<&dyn Primitive> { + if let Self::Primitive { cell_dyn } = self { + Some(&**cell_dyn) + } else { + None + } + } } impl Debug for CellLedger { @@ -348,15 +356,32 @@ impl<'a> Environment<'a> { let definition = &self.ctx.secondary[comp.port_offset_map[port]]; println!( - " {}: {}", + " {}: {} ({:?})", self.ctx.secondary[definition.name], - self.ports[&info.index_bases + port] + self.ports[&info.index_bases + port], + &info.index_bases + port ); } + let cell_idx = &info.index_bases + cell_off; + if definition.prototype.is_component() { - let child_target = &info.index_bases + cell_off; - self.print_component(child_target, hierarchy); + self.print_component(cell_idx, hierarchy); + } else if self.cells[cell_idx] + .as_primitive() + .unwrap() + .has_serializable_state() + { + println!( + " INTERNAL_DATA: {}", + serde_json::to_string_pretty( + &self.cells[cell_idx] + .as_primitive() + .unwrap() + .serialize(None) + ) + .unwrap() + ) } } @@ -377,7 +402,8 @@ impl<'a> Environment<'a> { } /// A wrapper struct for the environment that provides the functions used to -/// simulate the actual program +/// simulate the actual program. This is just to keep the simulation logic under +/// a different namespace than the environment to avoid confusion pub struct Simulator<'a> { env: Environment<'a>, } @@ -482,7 +508,7 @@ impl<'a> Simulator<'a> { control_points .iter() .map(|node| { - match &self.ctx().primary[node.control_node] { + match &self.ctx().primary[node.control_node_idx] { ControlNode::Enable(e) => { (node.comp, self.ctx().primary[e.group()].assignments) } @@ -511,36 +537,25 @@ impl<'a> Simulator<'a> { } pub fn step(&mut self) -> InterpreterResult<()> { - /// attempts to get the next node for the given control point, if found - /// it replaces the given node. Returns true if the node was found and - /// replaced, returns false otherwise - fn get_next(node: &mut ControlPoint, ctx: &Context) -> bool { - let path = SearchPath::find_path_from_root(node.control_node, ctx); - let next = path.next_node(&ctx.primary.control); - if let Some(next) = next { - *node = node.new_w_comp(next); - true - } else { - //need to remove the node from the list now - false - } - } - // place to keep track of what groups we need to conclude at the end of // this step. These are indices into the program counter + // In the future it may be worthwhile to preallocate some space to these + // buffers. Can pick anything from zero to the number of nodes in the + // program counter as the size let mut leaf_nodes = vec![]; + let mut done_groups = vec![]; self.env.pc.vec_mut().retain_mut(|node| { // just considering a single node case for the moment - match &self.env.ctx.primary[node.control_node] { + match &self.env.ctx.primary[node.control_node_idx] { ControlNode::Seq(seq) => { if !seq.is_empty() { let next = seq.stms()[0]; - *node = node.new_w_comp(next); + *node = node.new_retain_comp(next); true } else { - get_next(node, self.env.ctx) + node.mutate_into_next(self.env.ctx) } } ControlNode::Par(_par) => todo!("not ready for par yet"), @@ -567,7 +582,7 @@ impl<'a> Simulator<'a> { }; let target = if result { i.tbranch() } else { i.fbranch() }; - *node = node.new_w_comp(target); + *node = node.new_retain_comp(target); true } ControlNode::While(w) => { @@ -594,50 +609,127 @@ impl<'a> Simulator<'a> { if result { // enter the body - *node = node.new_w_comp(w.body()); + *node = node.new_retain_comp(w.body()); true } else { // ascend the tree - get_next(node, self.env.ctx) + node.mutate_into_next(self.env.ctx) } } // ===== leaf nodes ===== - ControlNode::Empty(_) => get_next(node, self.env.ctx), - ControlNode::Enable(_) => { - leaf_nodes.push(node.clone()); - true + ControlNode::Empty(_) => node.mutate_into_next(self.env.ctx), + ControlNode::Enable(e) => { + let done_local = self.env.ctx.primary[e.group()].done; + let done_idx = &self.env.cells[node.comp] + .as_comp() + .unwrap() + .index_bases + + done_local; + + if !self.env.ports[done_idx].as_bool().unwrap_or_default() { + leaf_nodes.push(node.clone()); + true + } else { + done_groups.push(( + node.clone(), + self.env.ports[done_idx].clone(), + )); + // remove from the list now + false + } } ControlNode::Invoke(_) => todo!("invokes not implemented yet"), } }); - self.simulate_combinational(&leaf_nodes)?; + self.undef_all_ports(); + for (node, val) in &done_groups { + match &self.env.ctx.primary[node.control_node_idx] { + ControlNode::Enable(e) => { + let go_local = self.env.ctx.primary[e.group()].go; + let done_local = self.env.ctx.primary[e.group()].done; + let index_bases = &self.env.cells[node.comp] + .as_comp() + .unwrap() + .index_bases; + let done_idx = index_bases + done_local; + let go_idx = index_bases + go_local; + + // retain done condition from before + self.env.ports[done_idx] = val.clone(); + self.env.ports[go_idx] = + PortValue::new_implicit(Value::bit_high()); + } + ControlNode::Invoke(_) => todo!(), + _ => { + unreachable!("non-leaf node included in list of done nodes. This should never happen, please report it.") + } + } + } - let parent_cells: HashSet = self - .get_assignments(&leaf_nodes) - .iter() - .flat_map(|(cell, assigns)| { - assigns.iter().map(|x| { - let assign = &self.env.ctx.primary[x]; - self.get_parent_cell(assign.dst, *cell) - }) - }) - .flatten() - .collect(); + for node in &leaf_nodes { + match &self.env.ctx.primary[node.control_node_idx] { + ControlNode::Enable(e) => { + let go_local = self.env.ctx.primary[e.group()].go; + let index_bases = &self.env.cells[node.comp] + .as_comp() + .unwrap() + .index_bases; + + // set go high + let go_idx = index_bases + go_local; + self.env.ports[go_idx] = + PortValue::new_implicit(Value::bit_high()); + } + ControlNode::Invoke(_) => todo!(), + non_leaf => { + unreachable!("non-leaf node {:?} included in list of leaf nodes. This should never happen, please report it.", non_leaf) + } + } + } + + self.simulate_combinational(&leaf_nodes)?; - for cell in parent_cells { - match &mut self.env.cells[cell] { + for cell in self.env.cells.values_mut() { + match cell { CellLedger::Primitive { cell_dyn } => { cell_dyn.exec_cycle(&mut self.env.ports)?; } - CellLedger::Component(_) => todo!(), + CellLedger::Component(_) => {} + } + } + + // need to cleanup the finished groups + for (node, _) in done_groups { + if let Some(next) = ControlPoint::get_next(&node, self.env.ctx) { + self.env.pc.insert_node(next) } } Ok(()) } + fn is_done(&self) -> bool { + assert!( + self.ctx().primary[self.ctx().entry_point].control.is_some(), + "flat interpreter doesn't handle a fully structural entrypoint program yet" + ); + // TODO griffin: need to handle structural components + self.env.pc.is_done() + } + + /// Evaluate the entire program + pub fn run_program(&mut self) -> InterpreterResult<()> { + while !self.is_done() { + dbg!("calling step"); + // self.env.print_pc(); + self.print_env(); + self.step()? + } + Ok(()) + } + fn evaluate_guard( &self, guard: GuardIdx, @@ -684,6 +776,12 @@ impl<'a> Simulator<'a> { } } + fn undef_all_ports(&mut self) { + for (_idx, port_val) in self.env.ports.iter_mut() { + port_val.set_undef(); + } + } + fn simulate_combinational( &mut self, control_points: &[ControlPoint], @@ -691,17 +789,6 @@ impl<'a> Simulator<'a> { let assigns_bundle = self.get_assignments(control_points); let mut has_changed = true; - let parent_cells: HashSet = assigns_bundle - .iter() - .flat_map(|(cell, assigns)| { - assigns.iter().map(|x| { - let assign = &self.env.ctx.primary[x]; - self.get_parent_cell(assign.dst, *cell) - }) - }) - .flatten() - .collect(); - while has_changed { has_changed = false; @@ -730,17 +817,21 @@ impl<'a> Simulator<'a> { } // Run all the primitives - let changed: bool = parent_cells + let changed: bool = self + .env + .cells + .range() .iter() - .map(|x| match &mut self.env.cells[*x] { + .filter_map(|x| match &mut self.env.cells[x] { CellLedger::Primitive { cell_dyn } => { - cell_dyn.exec_comb(&mut self.env.ports) + Some(cell_dyn.exec_comb(&mut self.env.ports)) } - CellLedger::Component(_) => todo!(), + CellLedger::Component(_) => None, }) - .fold_ok(false, |has_changed, update| { - has_changed | update.is_changed() - })?; + .fold_ok(UpdateStatus::Unchanged, |has_changed, update| { + has_changed | update + })? + .as_bool(); has_changed |= changed; } @@ -750,11 +841,8 @@ impl<'a> Simulator<'a> { pub fn _main_test(&mut self) { self.env.print_pc(); - for _x in self.env.pc.iter() { - // println!("{:?} next {:?}", x, self.find_next_control_point(x)) - } + let _ = self.run_program(); self.env.print_pc(); self.print_env(); - // println!("{:?}", self.get_assignments()) } } diff --git a/interp/src/flatten/structures/environment/program_counter.rs b/interp/src/flatten/structures/environment/program_counter.rs index 90ed42195..d40446f69 100644 --- a/interp/src/flatten/structures/environment/program_counter.rs +++ b/interp/src/flatten/structures/environment/program_counter.rs @@ -11,27 +11,46 @@ use crate::flatten::{ use itertools::{FoldWhile, Itertools}; /// Simple struct containing both the component instance and the active leaf -/// node in the component +/// node in the component. This is used to represent an active execution of some +/// portion of the control tree #[derive(Debug, Hash, Eq, PartialEq, Clone)] pub struct ControlPoint { pub comp: GlobalCellIdx, - pub control_node: ControlIdx, + pub control_node_idx: ControlIdx, } impl ControlPoint { pub fn new(comp: GlobalCellIdx, control_leaf: ControlIdx) -> Self { Self { comp, - control_node: control_leaf, + control_node_idx: control_leaf, } } /// Constructs a new [ControlPoint] from an existing one by copying over the /// component identifier but changing the leaf node - pub fn new_w_comp(&self, target: ControlIdx) -> Self { + pub fn new_retain_comp(&self, target: ControlIdx) -> Self { Self { comp: self.comp, - control_node: target, + control_node_idx: target, + } + } + + pub fn get_next(node: &Self, ctx: &Context) -> Option { + let path = SearchPath::find_path_from_root(node.control_node_idx, ctx); + let next = path.next_node(&ctx.primary.control); + next.map(|x| node.new_retain_comp(x)) + } + + /// Attempts to get the next node for the given control point, if found + /// it replaces the given node. Returns true if the node was found and + /// replaced, returns false otherwise + pub fn mutate_into_next(&mut self, ctx: &Context) -> bool { + if let Some(next) = Self::get_next(self, ctx) { + *self = next; + true + } else { + false } } } @@ -79,7 +98,7 @@ impl SearchPath { } pub fn source_node(&self) -> Option<&SearchNode> { - self.path.get(0) + self.path.first() } pub fn len(&self) -> usize { @@ -232,8 +251,37 @@ impl SearchPath { search_index: None, }) } - ControlNode::If(_) => todo!(), - ControlNode::While(_) => todo!(), + ControlNode::If(i) => { + if let Some(idx) = &mut node.search_index { + if idx.is_true_branch() { + *idx = SearchIndex::new(SearchIndex::FALSE_BRANCH); + current_path.path.push(SearchNode { + node: i.fbranch(), + search_index: None, + }) + } else { + current_path.path.pop(); + } + } else { + node.search_index = + Some(SearchIndex::new(SearchIndex::TRUE_BRANCH)); + current_path.path.push(SearchNode { + node: i.tbranch(), + search_index: None, + }) + } + } + ControlNode::While(w) => { + if node.search_index.is_some() { + current_path.path.pop(); + } else { + node.search_index = Some(SearchIndex::new(0)); + current_path.path.push(SearchNode { + node: w.body(), + search_index: None, + }) + } + } } } @@ -294,7 +342,7 @@ impl ProgramCounter { if let Some(current) = ctx.primary[root].control { vec.push(ControlPoint { comp: root_cell, - control_node: current, + control_node_idx: current, }) } else { todo!( @@ -323,6 +371,10 @@ impl ProgramCounter { pub(crate) fn vec_mut(&mut self) -> &mut Vec { &mut self.vec } + + pub(crate) fn insert_node(&mut self, node: ControlPoint) { + self.vec.push(node) + } } impl<'a> IntoIterator for &'a ProgramCounter { diff --git a/interp/src/flatten/structures/indexed_map.rs b/interp/src/flatten/structures/indexed_map.rs index 5b201d969..78abde87a 100644 --- a/interp/src/flatten/structures/indexed_map.rs +++ b/interp/src/flatten/structures/indexed_map.rs @@ -1,4 +1,4 @@ -use super::index_trait::{IndexRangeIterator, IndexRef}; +use super::index_trait::{IndexRange, IndexRangeIterator, IndexRef}; use std::{ marker::PhantomData, ops::{self, Index}, @@ -13,6 +13,18 @@ where phantom: PhantomData, } +impl IndexedMap +where + K: IndexRef + PartialOrd, +{ + /// Produces a range containing all the keys in the input map. This is + /// similar to [IndexedMap::keys] but has an independent lifetime from the + /// map + pub fn range(&self) -> IndexRange { + IndexRange::new(K::new(0), K::new(self.len())) + } +} + impl IndexedMap where K: IndexRef, @@ -98,6 +110,17 @@ where self.data.iter().enumerate().map(|(i, v)| (K::new(i), v)) } + pub fn iter_mut(&mut self) -> impl Iterator { + self.data + .iter_mut() + .enumerate() + .map(|(i, v)| (K::new(i), v)) + } + + pub fn values_mut(&mut self) -> impl Iterator { + self.data.iter_mut() + } + pub fn keys(&self) -> impl Iterator + '_ { // TODO (griffin): Make this an actual struct instead self.data.iter().enumerate().map(|(i, _)| K::new(i)) diff --git a/interp/src/flatten/structures/printer.rs b/interp/src/flatten/structures/printer.rs index 2aa7a1d52..8a3f5ba5c 100644 --- a/interp/src/flatten/structures/printer.rs +++ b/interp/src/flatten/structures/printer.rs @@ -173,14 +173,21 @@ impl<'a> Printer<'a> { match &self.ctx.primary[control] { ControlNode::Empty(_) => String::new(), ControlNode::Enable(e) => text_utils::indent( - self.ctx.secondary[self.ctx.primary[e.group()].name()].clone() - + ";", + format!( + "{}; ({:?})", + self.ctx.secondary[self.ctx.primary[e.group()].name()] + .clone(), + control + ), indent, ), // TODO Griffin: refactor into shared function rather than copy-paste? ControlNode::Seq(s) => { - let mut seq = text_utils::indent("seq {\n", indent); + let mut seq = text_utils::indent( + format!("seq {{ ({:?})\n", control), + indent, + ); for stmt in s.stms() { let child = self.format_control(parent, *stmt, indent + 1); seq += &child; diff --git a/interp/src/interpreter/component_interpreter.rs b/interp/src/interpreter/component_interpreter.rs index 778500df5..737b941ff 100644 --- a/interp/src/interpreter/component_interpreter.rs +++ b/interp/src/interpreter/component_interpreter.rs @@ -471,8 +471,8 @@ impl Primitive for ComponentInterpreter { fn serialize( &self, _signed: Option, - ) -> crate::primitives::Serializable { - crate::primitives::Serializable::Full( + ) -> crate::serialization::Serializable { + crate::serialization::Serializable::Full( self.get_env() .gen_serializer(matches!(_signed, Some(PrintCode::Binary))), ) diff --git a/interp/src/lib.rs b/interp/src/lib.rs index 414d2f896..10739d587 100644 --- a/interp/src/lib.rs +++ b/interp/src/lib.rs @@ -1,5 +1,6 @@ pub mod interpreter; pub mod primitives; +mod serialization; pub use utils::MemoryMap; pub mod configuration; pub mod debugger; diff --git a/interp/src/primitives/combinational.rs b/interp/src/primitives/combinational.rs index fbe998691..ce246fef0 100644 --- a/interp/src/primitives/combinational.rs +++ b/interp/src/primitives/combinational.rs @@ -5,9 +5,12 @@ use super::{ primitive_traits::Named, Primitive, }; -use crate::logging::warn; use crate::values::Value; use crate::{comb_primitive, errors::InterpreterError}; +use crate::{ + logging::warn, + serialization::{Entry, Serializable}, +}; use bitvec::vec::BitVec; use calyx_ir as ir; use std::ops::Not; @@ -77,12 +80,9 @@ impl Primitive for StdConst { fn serialize( &self, code: Option, - ) -> super::Serializable { + ) -> Serializable { let code = code.unwrap_or(crate::debugger::PrintCode::Unsigned); - super::Serializable::Val(super::Entry::from_val_code( - &self.value, - &code, - )) + Serializable::Val(Entry::from_val_code(&self.value, &code)) } } diff --git a/interp/src/primitives/mod.rs b/interp/src/primitives/mod.rs index 6523d7ffa..0d95116e9 100644 --- a/interp/src/primitives/mod.rs +++ b/interp/src/primitives/mod.rs @@ -1,8 +1,7 @@ mod primitive_traits; -pub use primitive_traits::Entry; + pub use primitive_traits::Named; pub use primitive_traits::Primitive; -pub use primitive_traits::Serializable; pub mod combinational; pub(super) mod prim_utils; diff --git a/interp/src/primitives/primitive_traits.rs b/interp/src/primitives/primitive_traits.rs index 276012d2d..df888bf1c 100644 --- a/interp/src/primitives/primitive_traits.rs +++ b/interp/src/primitives/primitive_traits.rs @@ -1,18 +1,10 @@ use crate::{ - errors::InterpreterResult, - interpreter::ComponentInterpreter, - structures::state_views::{FullySerialize, StateView}, - utils::PrintCode, - values::Value, + errors::InterpreterResult, interpreter::ComponentInterpreter, + serialization::Serializable, structures::state_views::StateView, + utils::PrintCode, values::Value, }; use calyx_ir as ir; -use fraction::Fraction; - -use itertools::Itertools; -use serde::Serialize; -use std::fmt::Debug; -use std::fmt::Display; /// A trait indicating that the thing has a name pub trait Named { @@ -71,276 +63,3 @@ pub trait Primitive: Named { None } } - -/// An enum wrapping over a tuple representing the shape of a multi-dimensional -/// array -#[derive(Clone)] -pub enum Shape { - D1((usize,)), - D2((usize, usize)), - D3((usize, usize, usize)), - D4((usize, usize, usize, usize)), -} - -impl Shape { - fn is_1d(&self) -> bool { - matches!(self, Shape::D1(_)) - } - - pub(crate) fn dim_str(&self) -> String { - match self { - Shape::D1(_) => String::from("1D"), - Shape::D2(_) => String::from("2D"), - Shape::D3(_) => String::from("3D"), - Shape::D4(_) => String::from("4D"), - } - } -} -impl From for Shape { - fn from(u: usize) -> Self { - Shape::D1((u,)) - } -} -impl From<(usize,)> for Shape { - fn from(u: (usize,)) -> Self { - Shape::D1(u) - } -} -impl From<(usize, usize)> for Shape { - fn from(u: (usize, usize)) -> Self { - Shape::D2(u) - } -} - -impl From<(usize, usize, usize)> for Shape { - fn from(u: (usize, usize, usize)) -> Self { - Shape::D3(u) - } -} - -impl From<(usize, usize, usize, usize)> for Shape { - fn from(u: (usize, usize, usize, usize)) -> Self { - Shape::D4(u) - } -} - -/// A wrapper enum used during serialization. It represents either an unsigned integer, -/// or a signed integer and is serialized as the underlying integer. This also allows -/// mixed serialization of signed and unsigned values -#[derive(Serialize, Clone)] -#[serde(untagged)] -pub enum Entry { - U(u64), - I(i64), - Frac(Fraction), - Value(Value), -} - -impl From for Entry { - fn from(u: u64) -> Self { - Self::U(u) - } -} - -impl From for Entry { - fn from(i: i64) -> Self { - Self::I(i) - } -} - -impl From for Entry { - fn from(f: Fraction) -> Self { - Self::Frac(f) - } -} - -impl Entry { - pub fn from_val_code(val: &Value, code: &PrintCode) -> Self { - match code { - PrintCode::Unsigned => val.as_u64().into(), - PrintCode::Signed => val.as_i64().into(), - PrintCode::UFixed(f) => val.as_ufp(*f).into(), - PrintCode::SFixed(f) => val.as_sfp(*f).into(), - PrintCode::Binary => Entry::Value(val.clone()), - } - } -} - -impl Display for Entry { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Entry::U(v) => write!(f, "{}", v), - Entry::I(v) => write!(f, "{}", v), - Entry::Frac(v) => write!(f, "{}", v), - Entry::Value(v) => write!(f, "{}", v), - } - } -} - -impl Debug for Entry { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self) - } -} - -#[derive(Clone)] -pub enum Serializable { - Empty, - Val(Entry), - Array(Vec, Shape), - Full(FullySerialize), -} - -impl Serializable { - pub fn has_state(&self) -> bool { - !matches!(self, Serializable::Empty) - } -} - -impl Display for Serializable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Serializable::Empty => write!(f, ""), - Serializable::Val(v) => write!(f, "{}", v), - Serializable::Array(arr, shape) => { - write!(f, "{}", format_array(arr, shape)) - } - full @ Serializable::Full(_) => { - write!(f, "{}", serde_json::to_string(full).unwrap()) - } - } - } -} - -impl Serialize for Serializable { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - Serializable::Empty => serializer.serialize_unit(), - Serializable::Val(u) => u.serialize(serializer), - Serializable::Array(arr, shape) => { - let arr: Vec<&Entry> = arr.iter().collect(); - if shape.is_1d() { - return arr.serialize(serializer); - } - // there's probably a better way to write this - match shape { - Shape::D2(shape) => { - let mem = arr - .iter() - .chunks(shape.1) - .into_iter() - .map(|x| x.into_iter().collect::>()) - .collect::>(); - mem.serialize(serializer) - } - Shape::D3(shape) => { - let mem = arr - .iter() - .chunks(shape.1 * shape.2) - .into_iter() - .map(|x| { - x.into_iter() - .chunks(shape.2) - .into_iter() - .map(|y| y.into_iter().collect::>()) - .collect::>() - }) - .collect::>(); - mem.serialize(serializer) - } - Shape::D4(shape) => { - let mem = arr - .iter() - .chunks(shape.2 * shape.1 * shape.3) - .into_iter() - .map(|x| { - x.into_iter() - .chunks(shape.2 * shape.3) - .into_iter() - .map(|y| { - y.into_iter() - .chunks(shape.3) - .into_iter() - .map(|z| { - z.into_iter() - .collect::>() - }) - .collect::>() - }) - .collect::>() - }) - .collect::>(); - mem.serialize(serializer) - } - Shape::D1(_) => unreachable!(), - } - } - Serializable::Full(s) => s.serialize(serializer), - } - } -} - -impl Serialize for dyn Primitive { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.serialize(None).serialize(serializer) - } -} - -fn format_array(arr: &[Entry], shape: &Shape) -> String { - match shape { - Shape::D2(shape) => { - let mem = arr - .iter() - .chunks(shape.1) - .into_iter() - .map(|x| x.into_iter().collect::>()) - .collect::>(); - format!("{:?}", mem) - } - Shape::D3(shape) => { - let mem = arr - .iter() - .chunks(shape.1 * shape.0) - .into_iter() - .map(|x| { - x.into_iter() - .chunks(shape.2) - .into_iter() - .map(|y| y.into_iter().collect::>()) - .collect::>() - }) - .collect::>(); - format!("{:?}", mem) - } - Shape::D4(shape) => { - let mem = arr - .iter() - .chunks(shape.2 * shape.1 * shape.3) - .into_iter() - .map(|x| { - x.into_iter() - .chunks(shape.2 * shape.3) - .into_iter() - .map(|y| { - y.into_iter() - .chunks(shape.3) - .into_iter() - .map(|z| z.into_iter().collect::>()) - .collect::>() - }) - .collect::>() - }) - .collect::>(); - format!("{:?}", mem) - } - Shape::D1(_) => { - format!("{:?}", arr) - } - } -} diff --git a/interp/src/primitives/stateful/math.rs b/interp/src/primitives/stateful/math.rs index c9bf0bc13..02563bf7d 100644 --- a/interp/src/primitives/stateful/math.rs +++ b/interp/src/primitives/stateful/math.rs @@ -1,8 +1,9 @@ use super::super::prim_utils::{get_inputs, get_param, ShiftBuffer}; use super::super::primitive_traits::Named; -use super::super::{Entry, Primitive, Serializable}; +use super::super::Primitive; use crate::errors::{InterpreterError, InterpreterResult}; use crate::logging::{self, warn}; +use crate::serialization::{Entry, Serializable}; use crate::utils::PrintCode; use crate::validate; use crate::values::Value; diff --git a/interp/src/primitives/stateful/mem_utils.rs b/interp/src/primitives/stateful/mem_utils.rs index 7ec5093c5..1803e7d4c 100644 --- a/interp/src/primitives/stateful/mem_utils.rs +++ b/interp/src/primitives/stateful/mem_utils.rs @@ -2,10 +2,8 @@ use calyx_ir as ir; use crate::{ errors::{InterpreterError, InterpreterResult}, - primitives::{ - prim_utils::{get_inputs, get_params}, - primitive_traits::Shape, - }, + primitives::prim_utils::{get_inputs, get_params}, + serialization::Shape, validate_friendly, values::Value, }; diff --git a/interp/src/primitives/stateful/memories.rs b/interp/src/primitives/stateful/memories.rs index 797e3c7f3..a2a3b1486 100644 --- a/interp/src/primitives/stateful/memories.rs +++ b/interp/src/primitives/stateful/memories.rs @@ -4,8 +4,9 @@ use crate::{ errors::{InterpreterError, InterpreterResult}, primitives::{ prim_utils::{get_inputs, get_param, output}, - Entry, Named, Primitive, Serializable, + Named, Primitive, }, + serialization::{Entry, Serializable}, utils::construct_bindings, validate, validate_friendly, values::Value, diff --git a/interp/src/serialization.rs b/interp/src/serialization.rs new file mode 100644 index 000000000..2d23042a9 --- /dev/null +++ b/interp/src/serialization.rs @@ -0,0 +1,282 @@ +use fraction::Fraction; +use itertools::Itertools; +use serde::Serialize; +use std::fmt::{Debug, Display}; + +use crate::{ + primitives::Primitive, structures::state_views::FullySerialize, + utils::PrintCode, values::Value, +}; + +/// An enum wrapping over a tuple representing the shape of a multi-dimensional +/// array +#[derive(Clone)] +pub enum Shape { + D1((usize,)), + D2((usize, usize)), + D3((usize, usize, usize)), + D4((usize, usize, usize, usize)), +} + +impl Shape { + fn is_1d(&self) -> bool { + matches!(self, Shape::D1(_)) + } + + pub(crate) fn dim_str(&self) -> String { + match self { + Shape::D1(_) => String::from("1D"), + Shape::D2(_) => String::from("2D"), + Shape::D3(_) => String::from("3D"), + Shape::D4(_) => String::from("4D"), + } + } +} +impl From for Shape { + fn from(u: usize) -> Self { + Shape::D1((u,)) + } +} +impl From<(usize,)> for Shape { + fn from(u: (usize,)) -> Self { + Shape::D1(u) + } +} +impl From<(usize, usize)> for Shape { + fn from(u: (usize, usize)) -> Self { + Shape::D2(u) + } +} + +impl From<(usize, usize, usize)> for Shape { + fn from(u: (usize, usize, usize)) -> Self { + Shape::D3(u) + } +} + +impl From<(usize, usize, usize, usize)> for Shape { + fn from(u: (usize, usize, usize, usize)) -> Self { + Shape::D4(u) + } +} + +/// A wrapper enum used during serialization. It represents either an unsigned integer, +/// or a signed integer and is serialized as the underlying integer. This also allows +/// mixed serialization of signed and unsigned values +#[derive(Serialize, Clone)] +#[serde(untagged)] +pub enum Entry { + U(u64), + I(i64), + Frac(Fraction), + Value(Value), +} + +impl From for Entry { + fn from(u: u64) -> Self { + Self::U(u) + } +} + +impl From for Entry { + fn from(i: i64) -> Self { + Self::I(i) + } +} + +impl From for Entry { + fn from(f: Fraction) -> Self { + Self::Frac(f) + } +} + +impl Entry { + pub fn from_val_code(val: &Value, code: &PrintCode) -> Self { + match code { + PrintCode::Unsigned => val.as_u64().into(), + PrintCode::Signed => val.as_i64().into(), + PrintCode::UFixed(f) => val.as_ufp(*f).into(), + PrintCode::SFixed(f) => val.as_sfp(*f).into(), + PrintCode::Binary => Entry::Value(val.clone()), + } + } +} + +impl Display for Entry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Entry::U(v) => write!(f, "{}", v), + Entry::I(v) => write!(f, "{}", v), + Entry::Frac(v) => write!(f, "{}", v), + Entry::Value(v) => write!(f, "{}", v), + } + } +} + +impl Debug for Entry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self) + } +} + +#[derive(Clone)] +pub enum Serializable { + Empty, + Val(Entry), + Array(Vec, Shape), + Full(FullySerialize), +} + +impl Serializable { + pub fn has_state(&self) -> bool { + !matches!(self, Serializable::Empty) + } +} + +impl Display for Serializable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Serializable::Empty => write!(f, ""), + Serializable::Val(v) => write!(f, "{}", v), + Serializable::Array(arr, shape) => { + write!(f, "{}", format_array(arr, shape)) + } + full @ Serializable::Full(_) => { + write!(f, "{}", serde_json::to_string(full).unwrap()) + } + } + } +} + +impl Serialize for Serializable { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Serializable::Empty => serializer.serialize_unit(), + Serializable::Val(u) => u.serialize(serializer), + Serializable::Array(arr, shape) => { + let arr: Vec<&Entry> = arr.iter().collect(); + if shape.is_1d() { + return arr.serialize(serializer); + } + // there's probably a better way to write this + match shape { + Shape::D2(shape) => { + let mem = arr + .iter() + .chunks(shape.1) + .into_iter() + .map(|x| x.into_iter().collect::>()) + .collect::>(); + mem.serialize(serializer) + } + Shape::D3(shape) => { + let mem = arr + .iter() + .chunks(shape.1 * shape.2) + .into_iter() + .map(|x| { + x.into_iter() + .chunks(shape.2) + .into_iter() + .map(|y| y.into_iter().collect::>()) + .collect::>() + }) + .collect::>(); + mem.serialize(serializer) + } + Shape::D4(shape) => { + let mem = arr + .iter() + .chunks(shape.2 * shape.1 * shape.3) + .into_iter() + .map(|x| { + x.into_iter() + .chunks(shape.2 * shape.3) + .into_iter() + .map(|y| { + y.into_iter() + .chunks(shape.3) + .into_iter() + .map(|z| { + z.into_iter() + .collect::>() + }) + .collect::>() + }) + .collect::>() + }) + .collect::>(); + mem.serialize(serializer) + } + Shape::D1(_) => unreachable!(), + } + } + Serializable::Full(s) => s.serialize(serializer), + } + } +} + +impl Serialize for dyn Primitive { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.serialize(None).serialize(serializer) + } +} + +fn format_array(arr: &[Entry], shape: &Shape) -> String { + match shape { + Shape::D2(shape) => { + let mem = arr + .iter() + .chunks(shape.1) + .into_iter() + .map(|x| x.into_iter().collect::>()) + .collect::>(); + format!("{:?}", mem) + } + Shape::D3(shape) => { + let mem = arr + .iter() + .chunks(shape.1 * shape.0) + .into_iter() + .map(|x| { + x.into_iter() + .chunks(shape.2) + .into_iter() + .map(|y| y.into_iter().collect::>()) + .collect::>() + }) + .collect::>(); + format!("{:?}", mem) + } + Shape::D4(shape) => { + let mem = arr + .iter() + .chunks(shape.2 * shape.1 * shape.3) + .into_iter() + .map(|x| { + x.into_iter() + .chunks(shape.2 * shape.3) + .into_iter() + .map(|y| { + y.into_iter() + .chunks(shape.3) + .into_iter() + .map(|z| z.into_iter().collect::>()) + .collect::>() + }) + .collect::>() + }) + .collect::>(); + format!("{:?}", mem) + } + Shape::D1(_) => { + format!("{:?}", arr) + } + } +} diff --git a/interp/src/structures/state_views.rs b/interp/src/structures/state_views.rs index f44adcfb6..8f09a7bb7 100644 --- a/interp/src/structures/state_views.rs +++ b/interp/src/structures/state_views.rs @@ -13,7 +13,8 @@ use crate::{ environment::{InterpreterState, PrimitiveMap}, interpreter::ConstCell, interpreter_ir as iir, - primitives::{Entry, Primitive, Serializable}, + primitives::Primitive, + serialization::{Entry, Serializable}, utils::AsRaw, values::Value, }; From 3773b058a60a8ebfbe58c71e536772cd5403d0a0 Mon Sep 17 00:00:00 2001 From: Anthony Abeo Date: Thu, 15 Feb 2024 13:57:50 +0000 Subject: [PATCH 173/189] std-bit-slice implementation (#1906) * add docs entry for std_bit_slice module * add implementation of std_bit_slice module * add test case for std_bit_slice module * add test data for testing std_bit_slice module * fix backward ordering of range extract parameters * add 'std_bit_slice' implementation to interpreter * change the Value.slice method to accept &self * Update std-bit-slice test to use the new 'comb_mem_d1' * Fix failing test * Add 'std_bit_slice' definition to 'tests/import/a.expect' * update std-bit-slice test --- docs/libraries/core.md | 12 ++++++++ interp/src/primitives/combinational.rs | 4 +++ interp/src/structures/environment.rs | 3 ++ interp/src/structures/values.rs | 2 +- primitives/core.futil | 2 ++ primitives/core.sv | 25 ++++++++++++++++- .../memory-with-external-attribute.expect | 25 ++++++++++++++++- tests/correctness/std-bit-slice.expect | 5 ++++ tests/correctness/std-bit-slice.futil | 28 +++++++++++++++++++ tests/correctness/std-bit-slice.futil.data | 10 +++++++ tests/import/a.expect | 1 + 11 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 tests/correctness/std-bit-slice.expect create mode 100644 tests/correctness/std-bit-slice.futil create mode 100644 tests/correctness/std-bit-slice.futil.data diff --git a/docs/libraries/core.md b/docs/libraries/core.md index 235492f23..7f6ef9494 100644 --- a/docs/libraries/core.md +++ b/docs/libraries/core.md @@ -119,7 +119,19 @@ Slice out the lower OUT_WIDTH bits of an IN_WIDTH-bit value. Computes - `out: OUT_WIDTH` - The lower OUT_WIDTH bits of `in` --- +### `std_bit_slice` +Extract the bit-string starting at `START_IDX` and ending at `END_IDX - 1` from `in`. +This is computed as `in[END_IDX:START_IDX]`.`OUT_WIDTH` must be specified to +be `END_WIDTH - START_WITH` wide when instantiating the module. + +**Inputs:** +- `in: IN_WIDTH` - An IN_WIDTH-bit value + +**Outputs:** + +- `out: OUT_WIDTH` - The value of the bit-string `in[START_IDX:END_IDX]` +--- ### `std_pad` Given an IN_WIDTH-bit input, zero pad from the left to an output of diff --git a/interp/src/primitives/combinational.rs b/interp/src/primitives/combinational.rs index ce246fef0..ecc907d88 100644 --- a/interp/src/primitives/combinational.rs +++ b/interp/src/primitives/combinational.rs @@ -538,6 +538,10 @@ comb_primitive!(StdPad[IN_WIDTH, OUT_WIDTH](r#in: IN_WIDTH) -> (out: OUT_WIDTH) Ok(r#in.ext(OUT_WIDTH as usize)) }); +comb_primitive!(StdBitSlice[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](r#in: IN_WIDTH) -> (out: OUT_WIDTH) { + Ok(r#in.slice(END_IDX as usize, START_IDX as usize)) +}); + // ===================== Unsynthesizeable Operations ====================== comb_primitive!(StdUnsynMult[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH) { Ok(Value::from(left.as_unsigned() * right.as_unsigned(), WIDTH)) diff --git a/interp/src/structures/environment.rs b/interp/src/structures/environment.rs index c3526566b..85d6ee217 100644 --- a/interp/src/structures/environment.rs +++ b/interp/src/structures/environment.rs @@ -251,6 +251,9 @@ impl InterpreterState { Box::new(combinational::StdFpSlt::new(params, cell_qin)) } // Resizing ops + "std_bit_slice" => { + Box::new(combinational::StdBitSlice::new(params, cell_qin)) + } "std_slice" => { Box::new(combinational::StdSlice::new(params, cell_qin)) } diff --git a/interp/src/structures/values.rs b/interp/src/structures/values.rs index a66e552c1..eddfb463c 100644 --- a/interp/src/structures/values.rs +++ b/interp/src/structures/values.rs @@ -639,7 +639,7 @@ impl Value { } /// Returns a value containing the sliced region \[lower,upper\] - pub fn slice(self, upper_idx: usize, lower_idx: usize) -> Self { + pub fn slice(&self, upper_idx: usize, lower_idx: usize) -> Self { assert!(upper_idx >= lower_idx); assert!(upper_idx < self.vec.len()); diff --git a/primitives/core.futil b/primitives/core.futil index 7965cc5e9..2f48fca68 100644 --- a/primitives/core.futil +++ b/primitives/core.futil @@ -5,6 +5,8 @@ extern "core.sv" { comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_cat<"share"=1>[LEFT_WIDTH, RIGHT_WIDTH, OUT_WIDTH](@data left: LEFT_WIDTH, @data right: RIGHT_WIDTH) -> (out: OUT_WIDTH); + comb primitive std_bit_slice<"share"=1>[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); + /// Logical operators comb primitive std_not<"share"=1>[WIDTH](@data in: WIDTH) -> (out: WIDTH); diff --git a/primitives/core.sv b/primitives/core.sv index 208057491..261571622 100644 --- a/primitives/core.sv +++ b/primitives/core.sv @@ -217,4 +217,27 @@ module std_mux #( assign out = cond ? tru : fal; endmodule -`default_nettype wire +module std_bit_slice #( + parameter IN_WIDTH = 32, + parameter START_IDX = 0, + parameter END_IDX = 31, + parameter OUT_WIDTH = 32 +)( + input wire logic [IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + assign out = in[END_IDX:START_IDX]; + + `ifdef VERILATOR + always_comb begin + if (START_IDX < 0 || END_IDX > IN_WIDTH-1) + $error( + "std_bit_slice: Slice range out of bounds\n", + "IN_WIDTH: %0d", IN_WIDTH, + "START_IDX: %0d", START_IDX, + "END_IDX: %0d", END_IDX, + ); + end + `endif + +endmodule diff --git a/tests/backend/verilog/memory-with-external-attribute.expect b/tests/backend/verilog/memory-with-external-attribute.expect index b428e9e23..4c08fe3ba 100644 --- a/tests/backend/verilog/memory-with-external-attribute.expect +++ b/tests/backend/verilog/memory-with-external-attribute.expect @@ -455,7 +455,30 @@ module std_mux #( assign out = cond ? tru : fal; endmodule -`default_nettype wire +module std_bit_slice #( + parameter IN_WIDTH = 32, + parameter START_IDX = 0, + parameter END_IDX = 31, + parameter OUT_WIDTH = 32 +)( + input wire logic [IN_WIDTH-1:0] in, + output logic [OUT_WIDTH-1:0] out +); + assign out = in[END_IDX:START_IDX]; + + `ifdef VERILATOR + always_comb begin + if (START_IDX < 0 || END_IDX > IN_WIDTH-1) + $error( + "std_bit_slice: Slice range out of bounds\n", + "IN_WIDTH: %0d", IN_WIDTH, + "START_IDX: %0d", START_IDX, + "END_IDX: %0d", END_IDX, + ); + end + `endif + +endmodule module undef #( parameter WIDTH = 32 diff --git a/tests/correctness/std-bit-slice.expect b/tests/correctness/std-bit-slice.expect new file mode 100644 index 000000000..5e2718b09 --- /dev/null +++ b/tests/correctness/std-bit-slice.expect @@ -0,0 +1,5 @@ +{ + "mem": [ + 9 + ] +} diff --git a/tests/correctness/std-bit-slice.futil b/tests/correctness/std-bit-slice.futil new file mode 100644 index 000000000..3c78cb6e9 --- /dev/null +++ b/tests/correctness/std-bit-slice.futil @@ -0,0 +1,28 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main(@go go: 1) -> (@done done: 1) { + cells { + @external mem = comb_mem_d1(32, 1, 1); + slice = std_bit_slice(32, 10, 14, 4); + pad = std_pad(4, 32); + } + + wires { + group bit_slice { + slice.in = 32'b00000000000000110010010110110000; + + pad.in = slice.out; + + mem.addr0 = 1'b0; + mem.write_data = pad.out; + mem.write_en = 1'b1; + + bit_slice[done] = mem.done; + } + } + + control { + bit_slice; + } +} \ No newline at end of file diff --git a/tests/correctness/std-bit-slice.futil.data b/tests/correctness/std-bit-slice.futil.data new file mode 100644 index 000000000..012ed5a3f --- /dev/null +++ b/tests/correctness/std-bit-slice.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [0], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/import/a.expect b/tests/import/a.expect index ea7847939..93e1abff6 100644 --- a/tests/import/a.expect +++ b/tests/import/a.expect @@ -14,6 +14,7 @@ extern "/calyx/primitives/core.sv" { comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_cat<"share"=1>[LEFT_WIDTH, RIGHT_WIDTH, OUT_WIDTH](@data left: LEFT_WIDTH, @data right: RIGHT_WIDTH) -> (out: OUT_WIDTH); + comb primitive std_bit_slice<"share"=1>[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH); comb primitive std_not<"share"=1>[WIDTH](@data in: WIDTH) -> (out: WIDTH); comb primitive std_and<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); comb primitive std_or<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH); From 0a8630e2d6ac8982f0f79eb835f0c789d2a40530 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:01:27 +0530 Subject: [PATCH 174/189] merge and fix --- calyx-opt/src/passes/papercut.rs | 65 ++++++++++++++----- primitives/memories/seq.futil | 44 ++++++------- tests/backend/yxi/seq-mem-d4-add.futil | 11 ++-- .../correctness/ref-cells/higher-order.futil | 4 +- tests/correctness/seq-mem-d4-add.futil | 8 +-- tests/correctness/seq-mem-dot-product.futil | 6 +- .../static-islands/seq-mem-dot-product.futil | 11 ++-- tests/errors/papercut/multi-done.futil | 2 +- tests/passes/papercut-multi-done.expect | 7 +- tests/passes/papercut-multi-done.futil | 7 +- yxi/axi-calyx/axi-combined-calyx.futil | 16 ++--- yxi/axi-calyx/axi-reads-calyx.futil | 4 +- yxi/axi-calyx/axi-writes-calyx.futil | 6 +- 13 files changed, 107 insertions(+), 84 deletions(-) diff --git a/calyx-opt/src/passes/papercut.rs b/calyx-opt/src/passes/papercut.rs index 895e0faee..b43ef6de6 100644 --- a/calyx-opt/src/passes/papercut.rs +++ b/calyx-opt/src/passes/papercut.rs @@ -28,6 +28,30 @@ pub struct Papercut { cont_cells: HashSet, } +impl Papercut { + #[allow(unused)] + /// String representation of the write together and read together specifications. + /// Used for debugging. Should not be relied upon by external users. + fn fmt_write_together_spec(&self) -> String { + self.write_together + .iter() + .map(|(prim, writes)| { + let writes = writes + .iter() + .map(|write| { + write + .iter() + .sorted() + .map(|port| format!("{port}")) + .join(", ") + }) + .join("; "); + format!("{}: [{}]", prim, writes) + }) + .join("\n") + } +} + impl ConstructVisitor for Papercut { fn from(ctx: &ir::Context) -> CalyxResult { let write_together = @@ -224,7 +248,7 @@ impl Papercut { .join(", "); let msg = format!("Required signal not driven inside the group.\ - \nWhen read the port `{}.{}', the ports [{}] must be written to.\ + \nWhen reading the port `{}.{}', the ports [{}] must be written to.\ \nThe primitive type `{}' requires this invariant.", inst, read, @@ -237,30 +261,35 @@ impl Papercut { } for ((inst, comp_type), writes) in all_writes { if let Some(spec) = self.write_together.get(&comp_type) { + // For each write together spec. for required in spec { // It should either be the case that: // 1. `writes` contains no writes that overlap with `required` // In which case `required - writes` == `required`. // 2. `writes` contains writes that overlap with `required` // In which case `required - writes == {}` - let mut diff = required - &writes; - if !diff.is_empty() && diff != *required { - let first = writes.iter().sorted().next().unwrap(); - let missing = diff - .drain() - .sorted() - .map(|port| format!("{}.{}", inst, port)) - .join(", "); - let msg = - format!("Required signal not driven inside the group.\ - \nWhen writing to the port `{}.{}', the ports [{}] must also be written to.\ - \nThe primitive type `{}' requires this invariant.", - inst, - first, - missing, - comp_type); - return Err(Error::papercut(msg)); + let mut diff: HashSet<_> = + required.difference(&writes).copied().collect(); + if diff.is_empty() || diff == *required { + continue; } + + let first = + writes.intersection(required).sorted().next().unwrap(); + let missing = diff + .drain() + .sorted() + .map(|port| format!("{}.{}", inst, port)) + .join(", "); + let msg = + format!("Required signal not driven inside the group. \ + When writing to the port `{}.{}', the ports [{}] must also be written to. \ + The primitive type `{}' specifies this using a @write_together spec.", + inst, + first, + missing, + comp_type); + return Err(Error::papercut(msg)); } } } diff --git a/primitives/memories/seq.futil b/primitives/memories/seq.futil index 4f0c26ad0..57517f882 100644 --- a/primitives/memories/seq.futil +++ b/primitives/memories/seq.futil @@ -3,11 +3,11 @@ extern "seq.sv" { primitive seq_mem_d1[WIDTH, SIZE, IDX_SIZE]( @clk clk: 1, @reset reset: 1, - @data addr0: IDX_SIZE, - @static(1) @go(1) content_en: 1, + @write_together(1) @data addr0: IDX_SIZE, + @write_together(1) @interval(1) @go(1) content_en: 1, // Write ports - @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH + @write_together(2) write_en: 1, + @write_together(2) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, @done(1) done: 1 @@ -16,12 +16,12 @@ extern "seq.sv" { primitive seq_mem_d2[WIDTH, D0_SIZE, D1_SIZE, D0_IDX_SIZE, D1_IDX_SIZE]( @clk clk: 1, @reset reset: 1, - @data addr0: D0_IDX_SIZE, - @data addr1: D1_IDX_SIZE, - @static(1) @go(1) content_en: 1, + @write_together(1) @data addr0: D0_IDX_SIZE, + @write_together(1) @data addr1: D1_IDX_SIZE, + @write_together(1) @interval(1) @go(1) content_en: 1, // Write ports - @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH + @write_together(2) write_en: 1, + @write_together(2) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, @done(1) done: 1 @@ -30,13 +30,13 @@ extern "seq.sv" { primitive seq_mem_d3[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE]( @clk clk: 1, @reset reset: 1, - @data addr0: D0_IDX_SIZE, - @data addr1: D1_IDX_SIZE, - @data addr2: D2_IDX_SIZE, - @static(1) @go(1) content_en: 1, + @write_together(1) @data addr0: D0_IDX_SIZE, + @write_together(1) @data addr1: D1_IDX_SIZE, + @write_together(1) @data addr2: D2_IDX_SIZE, + @write_together(1) @interval(1) @go(1) content_en: 1, // Write ports - @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH + @write_together(2) write_en: 1, + @write_together(2) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, @done(1) done: 1 @@ -45,14 +45,14 @@ extern "seq.sv" { primitive seq_mem_d4[WIDTH, D0_SIZE, D1_SIZE, D2_SIZE, D3_SIZE, D0_IDX_SIZE, D1_IDX_SIZE, D2_IDX_SIZE, D3_IDX_SIZE]( @clk clk: 1, @reset reset: 1, - @data addr0: D0_IDX_SIZE, - @data addr1: D1_IDX_SIZE, - @data addr2: D2_IDX_SIZE, - @data addr3: D3_IDX_SIZE, - @static(1) @go(1) content_en: 1, + @write_together(1) @data addr0: D0_IDX_SIZE, + @write_together(1) @data addr1: D1_IDX_SIZE, + @write_together(1) @data addr2: D2_IDX_SIZE, + @write_together(1) @data addr3: D3_IDX_SIZE, + @write_together(1) @interval(1) @go(1) content_en: 1, // Write ports - @write_together(1) write_en: 1, - @write_together(1) @data write_data: WIDTH + @write_together(2) write_en: 1, + @write_together(2) @data write_data: WIDTH ) -> ( @stable read_data: WIDTH, @done(1) done: 1 diff --git a/tests/backend/yxi/seq-mem-d4-add.futil b/tests/backend/yxi/seq-mem-d4-add.futil index 5e09f5f06..59dfdbb46 100644 --- a/tests/backend/yxi/seq-mem-d4-add.futil +++ b/tests/backend/yxi/seq-mem-d4-add.futil @@ -76,8 +76,8 @@ component main() -> () { in1.addr1 = j.out; in1.addr2 = k.out; in1.addr3 = l.out; - in1.read_en = 1'd1; - in1_reg.write_en = in1.read_done; + in1.content_en = 1'd1; + in1_reg.write_en = in1.done; in1_reg.in = in1.read_data; read_in1[done] = in1_reg.done; } @@ -86,8 +86,8 @@ component main() -> () { in2.addr1 = j.out; in2.addr2 = k.out; in2.addr3 = l.out; - in2.read_en = 1'd1; - in2_reg.write_en = in2.read_done; + in2.content_en = 1'd1; + in2_reg.write_en = in2.done; in2_reg.in = in2.read_data; read_in2[done] = in2_reg.done; } @@ -98,9 +98,10 @@ component main() -> () { out.addr1 = j.out; out.addr2 = k.out; out.addr3 = l.out; + out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = add.out; - update_val[done] = out.write_done; + update_val[done] = out.done; } group incr_i { add_i.left = i.out; diff --git a/tests/correctness/ref-cells/higher-order.futil b/tests/correctness/ref-cells/higher-order.futil index a3038600b..29fd761de 100644 --- a/tests/correctness/ref-cells/higher-order.futil +++ b/tests/correctness/ref-cells/higher-order.futil @@ -69,9 +69,9 @@ component map_f() -> () { incr[done] = idx.done; } group read_in { - in.read_en = 1'd1; + in.content_en = 1'd1; in.addr0 = idx.out; - read_in[done] = in.read_done; + read_in[done] = in.done; } group write_r { r.write_en = 1'd1; diff --git a/tests/correctness/seq-mem-d4-add.futil b/tests/correctness/seq-mem-d4-add.futil index bff939899..1a8a4c6f3 100644 --- a/tests/correctness/seq-mem-d4-add.futil +++ b/tests/correctness/seq-mem-d4-add.futil @@ -70,24 +70,22 @@ component main() -> () { lt4.left = l.out; lt4.right = 3'd4; } - group read_in1{ + group read_in1 { in1.addr0 = i.out; in1.addr1 = j.out; in1.addr2 = k.out; in1.addr3 = l.out; in1.content_en = 1'd1; - in1.write_en = 1'd0; in1_reg.write_en = in1.done; in1_reg.in = in1.read_data; read_in1[done] = in1_reg.done; } - group read_in2{ + group read_in2 { in2.addr0 = i.out; in2.addr1 = j.out; in2.addr2 = k.out; in2.addr3 = l.out; in2.content_en = 1'd1; - in2.write_en = 1'd0; in2_reg.write_en = in2.done; in2_reg.in = in2.read_data; read_in2[done] = in2_reg.done; @@ -102,7 +100,7 @@ component main() -> () { out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = add.out; - update_val[done] = out.write_done; + update_val[done] = out.done; } group incr_i { add_i.left = i.out; diff --git a/tests/correctness/seq-mem-dot-product.futil b/tests/correctness/seq-mem-dot-product.futil index 91d96df71..856353f67 100644 --- a/tests/correctness/seq-mem-dot-product.futil +++ b/tests/correctness/seq-mem-dot-product.futil @@ -40,13 +40,11 @@ component main() -> () { // Prime memories for reading group prime_in1 { in1.content_en = 1'd1; - in1.write_en = 1'd0; in1.addr0 = idx.out; prime_in1[done] = in1.done; } group prime_in2 { in2.content_en = 1'd1; - in2.write_en = 1'd0; in2.addr0 = idx.out; prime_in2[done] = in2.done; } @@ -54,7 +52,6 @@ component main() -> () { // Computation group init_tmp { tmp.in = 32'd0; - tmp.content_en = 1'd1; tmp.write_en = 1'd1; init_tmp[done] = tmp.done; } @@ -62,7 +59,6 @@ component main() -> () { add.left = tmp.out; add.right = mult.out; tmp.in = add.out; - tmp.content_en = 1'd1; tmp.write_en = 1'd1; do_add[done] = tmp.done; } @@ -73,7 +69,7 @@ component main() -> () { out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = tmp.out; - write[done] = out.write_done; + write[done] = out.done; } } control { diff --git a/tests/correctness/static-islands/seq-mem-dot-product.futil b/tests/correctness/static-islands/seq-mem-dot-product.futil index 0d0dac3aa..2bd501ded 100644 --- a/tests/correctness/static-islands/seq-mem-dot-product.futil +++ b/tests/correctness/static-islands/seq-mem-dot-product.futil @@ -34,14 +34,14 @@ component main() -> () { // Prime memories for reading group prime_in1 { - in1.read_en = 1'd1; + in1.content_en = 1'd1; in1.addr0 = idx.out; - prime_in1[done] = in1.read_done; + prime_in1[done] = in1.done; } group prime_in2 { - in2.read_en = 1'd1; + in2.content_en = 1'd1; in2.addr0 = idx.out; - prime_in2[done] = in2.read_done; + prime_in2[done] = in2.done; } // Computation @@ -61,9 +61,10 @@ component main() -> () { // Write to output group write { out.addr0 = 1'd0; + out.content_en = 1'd1; out.write_en = 1'd1; out.write_data = tmp.out; - write[done] = out.write_done; + write[done] = out.done; } } control { diff --git a/tests/errors/papercut/multi-done.futil b/tests/errors/papercut/multi-done.futil index 6cf6aecf0..de825346f 100644 --- a/tests/errors/papercut/multi-done.futil +++ b/tests/errors/papercut/multi-done.futil @@ -6,7 +6,7 @@ component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go wires { mem_0.clk = clk; read_data = mem_0.read_data; - mem_0.read_en = read_en; + mem_0.content_en = read_en; read_done = mem_0.read_done; mem_0.addr0 = addr0; mem_0.write_data = write_data; diff --git a/tests/passes/papercut-multi-done.expect b/tests/passes/papercut-multi-done.expect index 5e37f8477..9b5c7a848 100644 --- a/tests/passes/papercut-multi-done.expect +++ b/tests/passes/papercut-multi-done.expect @@ -1,17 +1,16 @@ import "primitives/memories/seq.futil"; -component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done read_done: 1, @done(2) write_done: 1) { +component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done done: 1) { cells { mem_0 = seq_mem_d1(32, 6, 3); } wires { mem_0.clk = clk; read_data = mem_0.read_data; - mem_0.read_en = read_en; - read_done = mem_0.read_done; + mem_0.content_en = read_en; + done = mem_0.done; mem_0.addr0 = addr0; mem_0.write_data = write_data; mem_0.write_en = write_en; - write_done = mem_0.write_done; } control {} } diff --git a/tests/passes/papercut-multi-done.futil b/tests/passes/papercut-multi-done.futil index 7084ea516..0943af98f 100644 --- a/tests/passes/papercut-multi-done.futil +++ b/tests/passes/papercut-multi-done.futil @@ -2,19 +2,18 @@ import "primitives/memories/seq.futil"; -component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done read_done: 1, @done(2) write_done: 1) { +component mem_0_comp<"toplevel"=1>(addr0: 3, @go read_en: 1, write_data: 32, @go(2) write_en: 1, @clk clk: 1, @reset reset: 1) -> (read_data: 32, @done done: 1) { cells { mem_0 = seq_mem_d1(32, 6, 3); } wires { mem_0.clk = clk; read_data = mem_0.read_data; - mem_0.read_en = read_en; - read_done = mem_0.read_done; + mem_0.content_en = read_en; + done = mem_0.done; mem_0.addr0 = addr0; mem_0.write_data = write_data; mem_0.write_en = write_en; - write_done = mem_0.write_done; } control { } diff --git a/yxi/axi-calyx/axi-combined-calyx.futil b/yxi/axi-calyx/axi-combined-calyx.futil index 6e5b1db55..d116a9b24 100644 --- a/yxi/axi-calyx/axi-combined-calyx.futil +++ b/yxi/axi-calyx/axi-combined-calyx.futil @@ -196,7 +196,7 @@ component m_read_channel( wires{ RREADY = is_rdy.out; - data_received.read_en = 1'b0; + data_received.content_en = 1'b0; // NOTE: xVALID signals must be high until xREADY is high as well, so this works // because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip @@ -247,7 +247,7 @@ component m_read_channel( data_received.addr0 = curr_addr_internal_mem.out; data_received.write_en = 1'b1; data_received.write_data = read_data_reg.out; - receive_r_transfer[done] = data_received.write_done; + receive_r_transfer[done] = data_received.done; } @@ -324,17 +324,17 @@ component vec_add() -> () { } //modified upd0 and upd1 to use seq_mem correctly group upd0<"static"=2> { - A_read0_0.write_en = A0.read_done; + A_read0_0.write_en = A0.done; A0.addr0 = i0.out; - A0.read_en = 1'b1; + A0.content_en = 1'b1; A_read0_0.in = 1'd1 ? A0.read_data; upd0[done] = A_read0_0.done ? 1'd1; } //see comment for upd0 group upd1<"static"=2> { - B_read0_0.write_en = B0.read_done; + B_read0_0.write_en = B0.done; B0.addr0 = i0.out; - B0.read_en = 1'b1; + B0.content_en = 1'b1; B_read0_0.in = 1'd1 ? B0.read_data; upd1[done] = B_read0_0.done ? 1'd1; } @@ -344,7 +344,7 @@ component vec_add() -> () { add0.left = A_read0_0.out; add0.right = B_read0_0.out; Sum0.write_data = 1'd1 ? add0.out; - upd2[done] = Sum0.write_done ? 1'd1; + upd2[done] = Sum0.done ? 1'd1; } group upd3<"static"=1> { i0.write_en = 1'd1; @@ -590,7 +590,7 @@ component m_write_channel( // set data output based on curr_addr_internal_mem register internal_mem.addr0 = curr_addr_internal_mem.out; - internal_mem.read_en = 1'b1; + internal_mem.content_en = 1'b1; WDATA = internal_mem.read_data; //set wlast diff --git a/yxi/axi-calyx/axi-reads-calyx.futil b/yxi/axi-calyx/axi-reads-calyx.futil index b566cbe5c..8bd5d6f34 100644 --- a/yxi/axi-calyx/axi-reads-calyx.futil +++ b/yxi/axi-calyx/axi-reads-calyx.futil @@ -209,7 +209,7 @@ component m_read_channel( wires{ RREADY = is_rdy.out; - data_received.read_en = 1'b0; + data_received.content_en = 1'b0; group init_n_RLAST { n_RLAST.in = 1'b1; @@ -269,7 +269,7 @@ component m_read_channel( data_received.addr0 = curr_addr.out; data_received.write_en = 1'b1; data_received.write_data = read_data_reg.out; - receive_r_transfer[done] = data_received.write_done; + receive_r_transfer[done] = data_received.done; } diff --git a/yxi/axi-calyx/axi-writes-calyx.futil b/yxi/axi-calyx/axi-writes-calyx.futil index 402d9f8a4..150cc9be9 100644 --- a/yxi/axi-calyx/axi-writes-calyx.futil +++ b/yxi/axi-calyx/axi-writes-calyx.futil @@ -243,13 +243,13 @@ component m_write_channel( } group write_to_internal{ - internal_mem.read_en = 1'b0; + internal_mem.content_en = 1'b0; internal_mem.write_en = 1'b1; internal_mem.addr0 = curr_addr.out; curr_addr_slice.in = curr_addr.out; internal_mem.write_data = curr_addr_slice.out; - write_to_internal[done] = internal_mem.write_done; + write_to_internal[done] = internal_mem.done; } group check_if_writes_done{ @@ -303,7 +303,7 @@ component m_write_channel( // set data output based on curr_addr register internal_mem.addr0 = curr_addr.out; - internal_mem.read_en = 1'b1; + internal_mem.content_en = 1'b1; WDATA = internal_mem.read_data; //set wlast From f5304a87e9792390a10ef18db7533be274094bd6 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:12:46 +0530 Subject: [PATCH 175/189] fix test --- tests/correctness/ref-cells/higher-order.futil | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/correctness/ref-cells/higher-order.futil b/tests/correctness/ref-cells/higher-order.futil index 29fd761de..1ba433f0f 100644 --- a/tests/correctness/ref-cells/higher-order.futil +++ b/tests/correctness/ref-cells/higher-order.futil @@ -82,7 +82,7 @@ component map_f() -> () { out.write_en = 1'd1; out.addr0 = idx.out; out.write_data = r.out; - write_out[done] = out.write_done; + write_out[done] = out.done; } } control { @@ -113,13 +113,13 @@ component main() -> () { stats.addr0 = 2'd0; stats.write_data = f1.processed; stats.write_en = 1'd1; - f1_stats[done] = stats.write_done; + f1_stats[done] = stats.done; } group f2_stats { stats.addr0 = 2'd1; stats.write_data = f2.processed; stats.write_en = 1'd1; - f2_stats[done] = stats.write_done; + f2_stats[done] = stats.done; } } control { From 6c65f5729b3e30ca3c867428a39580bf1ea20555 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:13:34 +0530 Subject: [PATCH 176/189] Update dahlia version --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f5cbbfcd4..8290c8634 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ WORKDIR /home RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia ## Checkout specific version -RUN git checkout 51954e7 +RUN git checkout 22f4e87 RUN sbt "; getHeaders; assembly" # Add the Calyx source code from the build context From 634e1d8ab907b6af55a2e57faf4430dd6bdefc19 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:14:40 +0530 Subject: [PATCH 177/189] update error tests --- tests/errors/no-drive.expect | 4 +--- tests/errors/papercut/multi-done.expect | 4 +++- tests/errors/papercut/read-missing-write-comb.expect | 2 +- tests/errors/papercut/read-missing-write.expect | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/errors/no-drive.expect b/tests/errors/no-drive.expect index a68436f9a..6c4a4a7e7 100644 --- a/tests/errors/no-drive.expect +++ b/tests/errors/no-drive.expect @@ -3,6 +3,4 @@ ---STDERR--- Error: tests/errors/no-drive.futil 9 | group no_drive { - | ^^^^^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. -When writing to the port `r.in', the ports [r.write_en] must also be written to. -The primitive type `std_reg' requires this invariant. + | ^^^^^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. When writing to the port `r.in', the ports [r.write_en] must also be written to. The primitive type `std_reg' specifies this using a @write_together spec. diff --git a/tests/errors/papercut/multi-done.expect b/tests/errors/papercut/multi-done.expect index 220508184..ec53a5bb7 100644 --- a/tests/errors/papercut/multi-done.expect +++ b/tests/errors/papercut/multi-done.expect @@ -1,4 +1,6 @@ ---CODE--- 1 ---STDERR--- -Error: [Papercut] Component `mem_0_comp` has an empty control program and does not assign to the done port `write_done`. Without an assignment to the done port, the component cannot return control flow. +Error: tests/errors/papercut/multi-done.futil +10 | read_done = mem_0.read_done; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined port name: read_done diff --git a/tests/errors/papercut/read-missing-write-comb.expect b/tests/errors/papercut/read-missing-write-comb.expect index e7c11b899..762173ca2 100644 --- a/tests/errors/papercut/read-missing-write-comb.expect +++ b/tests/errors/papercut/read-missing-write-comb.expect @@ -4,5 +4,5 @@ Error: tests/errors/papercut/read-missing-write-comb.futil 11 | comb group check { | ^^^^^^^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. -When read the port `mem.read_data', the ports [mem.addr0] must be written to. +When reading the port `mem.read_data', the ports [mem.addr0] must be written to. The primitive type `comb_mem_d1' requires this invariant. diff --git a/tests/errors/papercut/read-missing-write.expect b/tests/errors/papercut/read-missing-write.expect index 228667fd5..d544c1a27 100644 --- a/tests/errors/papercut/read-missing-write.expect +++ b/tests/errors/papercut/read-missing-write.expect @@ -4,5 +4,5 @@ Error: tests/errors/papercut/read-missing-write.futil 11 | group incr { | ^^^^^^^^^^^^ [Papercut] Required signal not driven inside the group. -When read the port `mem.read_data', the ports [mem.addr0] must be written to. +When reading the port `mem.read_data', the ports [mem.addr0] must be written to. The primitive type `comb_mem_d1' requires this invariant. From b92d1758a9060cb48654cb0fb2bd58d28fb64f8c Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:17:01 +0530 Subject: [PATCH 178/189] fetch required because of caching --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8290c8634..c2b0db97f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,8 +49,8 @@ RUN python3 setup.py bdist_wheel && python3 -m pip install --user dist/tvm-*.whl WORKDIR /home RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia -## Checkout specific version -RUN git checkout 22f4e87 +## Checkout specific version. Fetch before checkout because clone might be cached. +RUN git fetch --all && git checkout 22f4e87 RUN sbt "; getHeaders; assembly" # Add the Calyx source code from the build context From 6bd4a70f946e9873a41c090d19f7046c9a24ba6e Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:27:54 +0530 Subject: [PATCH 179/189] content en --- tests/correctness/ref-cells/higher-order.futil | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/correctness/ref-cells/higher-order.futil b/tests/correctness/ref-cells/higher-order.futil index 1ba433f0f..77d517a2b 100644 --- a/tests/correctness/ref-cells/higher-order.futil +++ b/tests/correctness/ref-cells/higher-order.futil @@ -79,6 +79,7 @@ component map_f() -> () { write_r[done] = r.done; } group write_out { + out.content_en = 1'd1; out.write_en = 1'd1; out.addr0 = idx.out; out.write_data = r.out; @@ -111,12 +112,14 @@ component main() -> () { wires { group f1_stats { stats.addr0 = 2'd0; + stats.content_en = 1'd1; stats.write_data = f1.processed; stats.write_en = 1'd1; f1_stats[done] = stats.done; } group f2_stats { stats.addr0 = 2'd1; + stats.content_en = 1'd1; stats.write_data = f2.processed; stats.write_en = 1'd1; f2_stats[done] = stats.done; From bb49fe6da0a5337c7df454ddbb3590f206d43e5f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 12:38:34 +0530 Subject: [PATCH 180/189] update Dahlia --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c2b0db97f..32226f1d1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,7 @@ WORKDIR /home RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia ## Checkout specific version. Fetch before checkout because clone might be cached. -RUN git fetch --all && git checkout 22f4e87 +RUN git fetch --all && git checkout 88e05e5 RUN sbt "; getHeaders; assembly" # Add the Calyx source code from the build context From 1b60407536beb4bf1961f35d9bf6acd1dc0d040f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 17:26:02 +0530 Subject: [PATCH 181/189] Add names to fields in `ir::Canonical` --- calyx-backend/src/verilog.rs | 2 +- calyx-ir/src/from_ast.rs | 14 ++++++-------- calyx-ir/src/structure.rs | 18 +++++++++++++++--- calyx-opt/src/analysis/dataflow_order.rs | 4 ++-- calyx-opt/src/passes/comb_prop.rs | 2 +- calyx-opt/src/passes/compile_invoke.rs | 4 ++-- calyx-opt/src/passes/compile_static.rs | 2 +- calyx-opt/src/passes/component_iniliner.rs | 10 +++++++--- calyx-opt/src/passes/dump_ports.rs | 2 +- calyx-opt/src/passes/simplify_with_control.rs | 5 ++--- 10 files changed, 38 insertions(+), 25 deletions(-) diff --git a/calyx-backend/src/verilog.rs b/calyx-backend/src/verilog.rs index 9da5f2ebf..742a8b9e2 100644 --- a/calyx-backend/src/verilog.rs +++ b/calyx-backend/src/verilog.rs @@ -478,7 +478,7 @@ fn emit_guard_disjoint_check( let mut check = v::SequentialIfElse::new(not_onehot0); // Generated error message - let ir::Canonical(cell, port) = dst.borrow().canonical(); + let ir::Canonical { cell, port } = dst.borrow().canonical(); let msg = format!("Multiple assignment to port `{}.{}'.", cell, port); let err = v::Sequential::new_seqexpr(v::Expr::new_call( "$fatal", diff --git a/calyx-ir/src/from_ast.rs b/calyx-ir/src/from_ast.rs index 9930d0d1d..446f41706 100644 --- a/calyx-ir/src/from_ast.rs +++ b/calyx-ir/src/from_ast.rs @@ -1,6 +1,6 @@ use super::{ - Assignment, Attributes, BackendConf, Builder, Canonical, Cell, CellType, - Component, Context, Control, Direction, GetAttributes, Guard, Id, Invoke, + Assignment, Attributes, BackendConf, Builder, Cell, CellType, Component, + Context, Control, Direction, GetAttributes, Guard, Id, Invoke, LibrarySignatures, Port, PortDef, StaticControl, StaticInvoke, RESERVED_NAMES, RRC, }; @@ -490,17 +490,15 @@ fn ensure_direction(pr: RRC, dir: Direction) -> CalyxResult> { let port_dir = pr.borrow().direction.clone(); match (dir, port_dir) { (Direction::Input, Direction::Output) => { - let Canonical(c, p) = pr.borrow().canonical(); + let name = pr.borrow().canonical(); Err(Error::malformed_structure(format!( - "Port `{}.{}` occurs in write position but is an output port", - c, p + "Port `{name}` occurs in write position but is an output port", ))) } (Direction::Output, Direction::Input) => { - let Canonical(c, p) = pr.borrow().canonical(); + let name = pr.borrow().canonical(); Err(Error::malformed_structure(format!( - "Port `{}.{}` occurs in write position but is an output port", - c, p + "Port `{name}` occurs in write position but is an output port", ))) } _ => Ok(pr), diff --git a/calyx-ir/src/structure.rs b/calyx-ir/src/structure.rs index 8d40bd8f8..3a6f3444a 100644 --- a/calyx-ir/src/structure.rs +++ b/calyx-ir/src/structure.rs @@ -39,11 +39,20 @@ pub struct Port { /// Canonical name of a Port #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Canonical(pub Id, pub Id); +pub struct Canonical { + pub cell: Id, + pub port: Id, +} + +impl Canonical { + pub const fn new(cell: Id, port: Id) -> Self { + Self { cell, port } + } +} impl std::fmt::Display for Canonical { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}.{}", self.0, self.1) + write!(f, "{}.{}", self.cell, self.port) } } @@ -96,7 +105,10 @@ impl Port { /// Get the canonical representation for this Port. pub fn canonical(&self) -> Canonical { - Canonical(self.get_parent_name(), self.name) + Canonical { + cell: self.get_parent_name(), + port: self.name, + } } /// Returns the value of an attribute if present diff --git a/calyx-opt/src/analysis/dataflow_order.rs b/calyx-opt/src/analysis/dataflow_order.rs index 1b6e0e415..1e0f604ac 100644 --- a/calyx-opt/src/analysis/dataflow_order.rs +++ b/calyx-opt/src/analysis/dataflow_order.rs @@ -140,7 +140,7 @@ impl DataflowOrder { // XXX(rachit): This probably adds a bunch of duplicate edges and in the // worst case makes this pass much slower than it needs to be. for (r_idx, (comp, canonical_port)) in reads { - let ir::Canonical(inst, port) = canonical_port; + let ir::Canonical { cell: inst, port } = canonical_port; let dep_ports = self .write_map .get(&comp) @@ -159,7 +159,7 @@ impl DataflowOrder { dep_ports .iter() .cloned() - .flat_map(|port| writes.get(&ir::Canonical(inst, port))) + .flat_map(|port| writes.get(&ir::Canonical::new(inst, port))) .flatten() .try_for_each(|w_idx| { if *w_idx == r_idx { diff --git a/calyx-opt/src/passes/comb_prop.rs b/calyx-opt/src/passes/comb_prop.rs index 566e2f6d4..739485d7f 100644 --- a/calyx-opt/src/passes/comb_prop.rs +++ b/calyx-opt/src/passes/comb_prop.rs @@ -131,7 +131,7 @@ impl From for ir::rewriter::PortRewriteMap { impl std::fmt::Debug for WireRewriter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (ir::Canonical(cell, port), port_ref) in &self.rewrites { + for (ir::Canonical { cell, port }, port_ref) in &self.rewrites { writeln!( f, "{}.{} -> {}", diff --git a/calyx-opt/src/passes/compile_invoke.rs b/calyx-opt/src/passes/compile_invoke.rs index 3bc81493d..c40d60e21 100644 --- a/calyx-opt/src/passes/compile_invoke.rs +++ b/calyx-opt/src/passes/compile_invoke.rs @@ -158,12 +158,12 @@ impl CompileInvoke { continue; } - let canon = ir::Canonical(ref_cell_name, port.name); + let canon = ir::Canonical::new(ref_cell_name, port.name); let Some(comp_port) = comp_ports.get(&canon) else { unreachable!("port `{}` not found in the signature of {}. Known ports are: {}", canon, inv_comp, - comp_ports.keys().map(|c| c.1.as_ref()).collect_vec().join(", ") + comp_ports.keys().map(|c| c.port.as_ref()).collect_vec().join(", ") ) }; // Get the port on the new cell with the same name as ref_port diff --git a/calyx-opt/src/passes/compile_static.rs b/calyx-opt/src/passes/compile_static.rs index 3f91527e3..beaf6acca 100644 --- a/calyx-opt/src/passes/compile_static.rs +++ b/calyx-opt/src/passes/compile_static.rs @@ -731,7 +731,7 @@ impl Visitor for CompileStatic { // technically could do this w/ early_reset_map but is easier w/ // group_rewrite, which is explicitly of type `PortRewriterMap` self.group_rewrite.insert( - ir::Canonical(sgroup_name, ir::Id::from("go")), + ir::Canonical::new(sgroup_name, ir::Id::from("go")), g.borrow().find("go").unwrap_or_else(|| { unreachable!("group {} has no go port", g.borrow().name()) }), diff --git a/calyx-opt/src/passes/component_iniliner.rs b/calyx-opt/src/passes/component_iniliner.rs index 8699513d3..43fc3e7f9 100644 --- a/calyx-opt/src/passes/component_iniliner.rs +++ b/calyx-opt/src/passes/component_iniliner.rs @@ -341,14 +341,17 @@ impl ComponentInliner { // Return as an iterator because it's immediately merged into the global rewrite map. let rev_interface_map = rewrite.port_map.into_iter().map(move |(cp, pr)| { - let ir::Canonical(_, p) = cp; + let ir::Canonical { port: p, .. } = cp; let port = pr.borrow(); let np = match port.name.id.as_str() { "in" => "out", "out" => "in", _ => unreachable!(), }; - (ir::Canonical(name, p), port.cell_parent().borrow().get(np)) + ( + ir::Canonical::new(name, p), + port.cell_parent().borrow().get(np), + ) }); (con, rev_interface_map) @@ -528,7 +531,8 @@ impl Visitor for ComponentInliner { }) .map(|(name, param)| { let port = Rc::clone( - &interface_rewrites[&ir::Canonical(instance, name)], + &interface_rewrites + [&ir::Canonical::new(instance, name)], ); // The parameter can refer to port on a cell that has been // inlined. diff --git a/calyx-opt/src/passes/dump_ports.rs b/calyx-opt/src/passes/dump_ports.rs index ce3eeb340..ae2b4b301 100644 --- a/calyx-opt/src/passes/dump_ports.rs +++ b/calyx-opt/src/passes/dump_ports.rs @@ -15,7 +15,7 @@ pub struct DumpResults { /// Formats name of a port given the id of the cell and the port pub(super) fn format_port_name(canon: &ir::Canonical) -> ir::Id { - format!("{}_{}", canon.0, canon.1).into() + format!("{}_{}", canon.cell, canon.port).into() } /// Remove all the cells matching the given criterion (f evaluates to true) from diff --git a/calyx-opt/src/passes/simplify_with_control.rs b/calyx-opt/src/passes/simplify_with_control.rs index eddfa273e..55a37aef8 100644 --- a/calyx-opt/src/passes/simplify_with_control.rs +++ b/calyx-opt/src/passes/simplify_with_control.rs @@ -224,10 +224,9 @@ impl Visitor for SimplifyWithControl { let (port_ref, cond_ref) = self.port_rewrite.get(&key).unwrap_or_else(|| { panic!( - "{}: Port `{}.{}` in group `{}` doesn't have a rewrite", + "{}: Port `{}` in group `{}` doesn't have a rewrite", Self::name(), - key.1 .0, - key.1 .1, + key.1, key.0 ) }); From fd372968a290f27bb6e795107ef29525c212da22 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 17:56:14 +0530 Subject: [PATCH 182/189] Define `ReadWriteSet::PortIterator` and provide methods for nicer chaining --- .../domination_analysis/node_analysis.rs | 10 +- calyx-opt/src/analysis/inference_analysis.rs | 18 +-- calyx-opt/src/analysis/live_range_analysis.rs | 36 +++--- calyx-opt/src/analysis/read_write_set.rs | 108 +++++++++++------- calyx-opt/src/analysis/variable_detection.rs | 3 +- calyx-opt/src/passes/group_to_invoke.rs | 3 +- calyx-opt/src/passes/group_to_seq.rs | 7 +- calyx-opt/src/passes/papercut.rs | 3 +- 8 files changed, 117 insertions(+), 71 deletions(-) diff --git a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs index 48e816468..2ab33b4ef 100644 --- a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs +++ b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs @@ -77,11 +77,11 @@ fn add_assignment_reads( share: &ShareSet, assignments: &[ir::Assignment], ) { - for cell in ReadWriteSet::read_set( - assignments - .iter() - .filter(|assign| !reads_only_dones(assign)), - ) { + let assigns = assignments + .iter() + .filter(|assign| !reads_only_dones(assign)); + + for cell in ReadWriteSet::port_read_set(assigns).cells() { if share.is_shareable_component(&cell) && !cell.borrow().is_reference() { reads.insert(cell.borrow().name()); diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs index 0b425649a..16ea01e19 100644 --- a/calyx-opt/src/analysis/inference_analysis.rs +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -518,14 +518,16 @@ impl InferenceAnalysis { // This checks any group that writes to the component: // We can probably switch this to any group that writes to the component's // `go` port to be more precise analysis. - if ReadWriteSet::write_set(group.borrow_mut().assignments.iter()) - .any(|cell| match cell.borrow().prototype { - CellType::Component { name } => { - self.updated_components.contains(&name) - } - _ => false, - }) - { + if ReadWriteSet::port_write_set( + group.borrow_mut().assignments.iter(), + ) + .cells() + .any(|cell| match cell.borrow().prototype { + CellType::Component { name } => { + self.updated_components.contains(&name) + } + _ => false, + }) { // Remove attribute from group. group .borrow_mut() diff --git a/calyx-opt/src/analysis/live_range_analysis.rs b/calyx-opt/src/analysis/live_range_analysis.rs index 76b4f2c95..799104b88 100644 --- a/calyx-opt/src/analysis/live_range_analysis.rs +++ b/calyx-opt/src/analysis/live_range_analysis.rs @@ -736,7 +736,8 @@ impl LiveRangeAnalysis { }); // calculate reads, but ignore `variable`. we've already dealt with that - let reads: HashSet<_> = ReadWriteSet::read_set(assignments) + let reads: HashSet<_> = ReadWriteSet::port_read_set(assignments) + .cells() .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) .collect(); @@ -761,7 +762,8 @@ impl LiveRangeAnalysis { .collect::>(); let writes: HashSet<_> = - ReadWriteSet::write_set(assignments.iter()) + ReadWriteSet::port_write_set(assignments.iter()) + .cells() .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) .collect(); @@ -792,10 +794,12 @@ impl LiveRangeAnalysis { .cloned() .collect::>(); - let writes: HashSet<_> = ReadWriteSet::write_set(assignments.iter()) - .filter(|c| sc_clone.is_shareable_component(c)) - .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) - .collect(); + let writes: HashSet<_> = + ReadWriteSet::port_write_set(assignments.iter()) + .cells() + .filter(|c| sc_clone.is_shareable_component(c)) + .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) + .collect(); (reads, writes) } @@ -822,7 +826,8 @@ impl LiveRangeAnalysis { .filter(|cell| shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>(); - let state_reads = ReadWriteSet::read_set(group.assignments.iter()) + let state_reads = ReadWriteSet::port_read_set(group.assignments.iter()) + .cells() .filter(|cell| state_shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>(); @@ -887,13 +892,16 @@ impl LiveRangeAnalysis { if let Some(comb_group) = comb_group_info { read_set.extend( - ReadWriteSet::read_set(comb_group.borrow().assignments.iter()) - .filter(|cell| { - shareable_components.is_shareable_component(cell) - }) - .map(|cell| { - (cell.borrow().prototype.clone(), cell.borrow().name()) - }), + ReadWriteSet::port_read_set( + comb_group.borrow().assignments.iter(), + ) + .cells() + .filter(|cell| { + shareable_components.is_shareable_component(cell) + }) + .map(|cell| { + (cell.borrow().prototype.clone(), cell.borrow().name()) + }), ); } diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index 43d14927b..0e16123f4 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -1,57 +1,83 @@ use calyx_ir::{self as ir, RRC}; use itertools::Itertools; -use std::{iter, rc::Rc}; +use std::{collections::HashMap, iter, rc::Rc}; /// Calcuate the reads-from and writes-to set for a given set of assignments. pub struct ReadWriteSet; +/// An iterator over ports +pub struct PortIterator +where + I: Iterator>, +{ + iter: I, +} + +impl Iterator for PortIterator +where + I: Iterator>, +{ + type Item = RRC; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl PortIterator +where + I: Iterator>, +{ + pub const fn new(iter: I) -> Self { + Self { iter } + } + + /// Return the unique cells that the ports are a part of + pub fn cells(self) -> impl Iterator> { + self.iter + .map(|port| Rc::clone(&port.borrow().cell_parent())) + .unique_by(|cell| cell.borrow().name()) + } + + /// Group the ports by cells that they are a part of + pub fn group_by_cell(self) -> HashMap>> { + self.iter.into_group_map_by(|port| { + port.borrow().cell_parent().borrow().name() + }) + } +} + impl ReadWriteSet { /// Returns [ir::Port] that are read from in the given Assignment. pub fn port_reads( assign: &ir::Assignment, - ) -> impl Iterator> + '_ { - assign - .guard - .all_ports() - .into_iter() - .chain(iter::once(Rc::clone(&assign.src))) - .filter(|port| !port.borrow().is_hole()) + ) -> PortIterator>> { + PortIterator::new( + assign + .guard + .all_ports() + .into_iter() + .chain(iter::once(Rc::clone(&assign.src))) + .filter(|port| !port.borrow().is_hole()), + ) } /// Returns [ir::Port] which are read from in the assignments. pub fn port_read_set<'a, T: 'a>( assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - assigns.flat_map(Self::port_reads) + ) -> PortIterator>> { + PortIterator::new(assigns.flat_map(Self::port_reads)) } /// Returns [ir::Port] which are written to in the assignments. pub fn port_write_set<'a, T: 'a>( assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - assigns - .map(|assign| Rc::clone(&assign.dst)) - .filter(|port| !port.borrow().is_hole()) - } - - /// Returns [ir::Cell] which are read from in the assignments. - /// **Ignores** reads from group holes. - pub fn read_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - Self::port_read_set(assigns) - .map(|port| Rc::clone(&port.borrow().cell_parent())) - .unique_by(|cell| cell.borrow().name()) - } - - /// Returns [ir::Cell] which are written to by the assignments. - /// **Ignores** reads from group holes. - pub fn write_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> impl Iterator> + 'a { - Self::port_write_set(assigns) - .map(|port| Rc::clone(&port.borrow().cell_parent())) - .unique_by(|cell| cell.borrow().name()) + ) -> PortIterator> + 'a> { + PortIterator::new( + assigns + .map(|assign| Rc::clone(&assign.dst)) + .filter(|port| !port.borrow().is_hole()), + ) } /// Returns the register cells whose out port is read anywhere in the given @@ -96,7 +122,7 @@ impl ReadWriteSet { ) -> impl Iterator> + 'a { assigns .filter_map(|assignment| { - if let ir::Guard::True = *assignment.guard { + if assignment.guard.is_true() { let dst_ref = assignment.dst.borrow(); if let ir::PortParent::Cell(cell_wref) = &dst_ref.parent { return Some(Rc::clone(&cell_wref.upgrade())); @@ -112,9 +138,9 @@ impl ReadWriteSet { pub fn uses<'a, T: 'a>( assigns: impl Iterator> + Clone + 'a, ) -> impl Iterator> + 'a { - let reads = Self::read_set(assigns.clone()); + let reads = Self::port_read_set(assigns.clone()).cells(); reads - .chain(Self::write_set(assigns)) + .chain(Self::port_write_set(assigns).cells()) .unique_by(|cell| cell.borrow().name()) } } @@ -404,8 +430,12 @@ impl ReadWriteSet { comp: &mut calyx_ir::Component, ) -> (Vec>, Vec>) { ( - Self::read_set(comp.continuous_assignments.iter()).collect(), - Self::write_set(comp.continuous_assignments.iter()).collect(), + Self::port_read_set(comp.continuous_assignments.iter()) + .cells() + .collect(), + Self::port_write_set(comp.continuous_assignments.iter()) + .cells() + .collect(), ) } } diff --git a/calyx-opt/src/analysis/variable_detection.rs b/calyx-opt/src/analysis/variable_detection.rs index 46535f5a3..6080a058d 100644 --- a/calyx-opt/src/analysis/variable_detection.rs +++ b/calyx-opt/src/analysis/variable_detection.rs @@ -18,7 +18,8 @@ impl VariableDetection { ) -> Option<(ir::CellType, ir::Id)> { let group = group_ref.borrow(); - let writes = ReadWriteSet::write_set(group.assignments.iter()) + let writes = ReadWriteSet::port_write_set(group.assignments.iter()) + .cells() .filter(|cell| state_share.is_shareable_component(cell)) .collect::>(); diff --git a/calyx-opt/src/passes/group_to_invoke.rs b/calyx-opt/src/passes/group_to_invoke.rs index 3764ad0ab..ffd85672a 100644 --- a/calyx-opt/src/passes/group_to_invoke.rs +++ b/calyx-opt/src/passes/group_to_invoke.rs @@ -237,7 +237,8 @@ impl GroupToInvoke { assigns: &[ir::Assignment], group_done_port: &ir::RRC, ) { - let mut writes = ReadWriteSet::write_set(assigns.iter()) + let mut writes = ReadWriteSet::port_write_set(assigns.iter()) + .cells() .filter(|cell| match cell.borrow().prototype { ir::CellType::Primitive { is_comb, .. } => !is_comb, _ => true, diff --git a/calyx-opt/src/passes/group_to_seq.rs b/calyx-opt/src/passes/group_to_seq.rs index e58983f48..13018d07a 100644 --- a/calyx-opt/src/passes/group_to_seq.rs +++ b/calyx-opt/src/passes/group_to_seq.rs @@ -150,7 +150,9 @@ fn comp_or_non_comb(cell: &ir::RRC) -> bool { //If asmt is a write to a cell named name returns Some(name). //If asmt is a write to a group port, returns None. fn writes_to_cell(asmt: &ir::Assignment) -> Option> { - ReadWriteSet::write_set(std::iter::once(asmt)).next() + ReadWriteSet::port_write_set(std::iter::once(asmt)) + .cells() + .next() } ///Primarily used to help determine the order cells are executed within @@ -307,7 +309,8 @@ where asmts: &[ir::Assignment], ) -> Option<(ir::Id, ir::Id)> { let stateful_writes: Vec = - ReadWriteSet::write_set(asmts.iter()) + ReadWriteSet::port_write_set(asmts.iter()) + .cells() .filter_map(|cell| { if cell.borrow().is_comb_cell() { None diff --git a/calyx-opt/src/passes/papercut.rs b/calyx-opt/src/passes/papercut.rs index b43ef6de6..f67fd915e 100644 --- a/calyx-opt/src/passes/papercut.rs +++ b/calyx-opt/src/passes/papercut.rs @@ -148,9 +148,10 @@ impl Visitor for Papercut { } // Compute all cells that are driven in by the continuous assignments0 - self.cont_cells = analysis::ReadWriteSet::write_set( + self.cont_cells = analysis::ReadWriteSet::port_write_set( comp.continuous_assignments.iter(), ) + .cells() .map(|cr| cr.borrow().name()) .collect(); From 08737c5023021f6820226a41179586a7410a01a5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 18:55:03 +0530 Subject: [PATCH 183/189] More changes to the ReadWriteSet interface --- calyx-opt/src/analysis/control_ports.rs | 14 +- .../domination_analysis/node_analysis.rs | 6 +- calyx-opt/src/analysis/inference_analysis.rs | 30 +-- calyx-opt/src/analysis/live_range_analysis.rs | 93 ++++--- calyx-opt/src/analysis/mod.rs | 2 +- calyx-opt/src/analysis/reaching_defns.rs | 25 +- calyx-opt/src/analysis/read_write_set.rs | 229 +++++++++++------- calyx-opt/src/analysis/variable_detection.rs | 9 +- calyx-opt/src/passes/cell_share.rs | 14 +- calyx-opt/src/passes/group_to_invoke.rs | 8 +- calyx-opt/src/passes/group_to_seq.rs | 29 ++- calyx-opt/src/passes/papercut.rs | 25 +- calyx-opt/src/passes/schedule_compaction.rs | 12 +- 13 files changed, 303 insertions(+), 193 deletions(-) diff --git a/calyx-opt/src/analysis/control_ports.rs b/calyx-opt/src/analysis/control_ports.rs index 2ca1c46d7..2fb9238b4 100644 --- a/calyx-opt/src/analysis/control_ports.rs +++ b/calyx-opt/src/analysis/control_ports.rs @@ -1,3 +1,4 @@ +use super::AssignmentAnalysis; use calyx_ir::{self as ir, RRC}; use itertools::Itertools; use std::{ @@ -66,10 +67,15 @@ impl ControlPorts { comb_group: &Option>, ) { if let Some(c) = comb_group { - let cells = - super::ReadWriteSet::uses(c.borrow().assignments.iter()) - .map(|cell| cell.borrow().name()) - .collect::>(); + let cells = c + .borrow() + .assignments + .iter() + .analysis() + .cell_uses() + .map(|cell| cell.borrow().name()) + .collect::>(); + // Only add ports that come from cells used in this comb group. let ports = inputs diff --git a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs index 2ab33b4ef..32dc61d6b 100644 --- a/calyx-opt/src/analysis/domination_analysis/node_analysis.rs +++ b/calyx-opt/src/analysis/domination_analysis/node_analysis.rs @@ -1,4 +1,6 @@ -use crate::analysis::{DominatorMap, ReadWriteSet, ShareSet}; +use crate::analysis::{ + AssignmentAnalysis, DominatorMap, ReadWriteSet, ShareSet, +}; use calyx_ir as ir; use std::collections::HashSet; @@ -81,7 +83,7 @@ fn add_assignment_reads( .iter() .filter(|assign| !reads_only_dones(assign)); - for cell in ReadWriteSet::port_read_set(assigns).cells() { + for cell in assigns.analysis().cell_reads() { if share.is_shareable_component(&cell) && !cell.borrow().is_reference() { reads.insert(cell.borrow().name()); diff --git a/calyx-opt/src/analysis/inference_analysis.rs b/calyx-opt/src/analysis/inference_analysis.rs index 16ea01e19..48ae55fa3 100644 --- a/calyx-opt/src/analysis/inference_analysis.rs +++ b/calyx-opt/src/analysis/inference_analysis.rs @@ -1,6 +1,5 @@ -use crate::analysis::{ - compute_static::WithStatic, GraphAnalysis, ReadWriteSet, -}; +use super::AssignmentAnalysis; +use crate::analysis::{compute_static::WithStatic, GraphAnalysis}; use calyx_ir::{self as ir, GetAttributes, RRC}; use ir::CellType; use itertools::Itertools; @@ -281,7 +280,7 @@ impl InferenceAnalysis { &self, group: &ir::Group, ) -> Vec<(RRC, RRC)> { - let rw_set = ReadWriteSet::uses(group.assignments.iter()); + let rw_set = group.assignments.iter().analysis().cell_uses(); let mut go_done_edges: Vec<(RRC, RRC)> = Vec::new(); for cell_ref in rw_set { @@ -518,16 +517,19 @@ impl InferenceAnalysis { // This checks any group that writes to the component: // We can probably switch this to any group that writes to the component's // `go` port to be more precise analysis. - if ReadWriteSet::port_write_set( - group.borrow_mut().assignments.iter(), - ) - .cells() - .any(|cell| match cell.borrow().prototype { - CellType::Component { name } => { - self.updated_components.contains(&name) - } - _ => false, - }) { + if group + .borrow_mut() + .assignments + .iter() + .analysis() + .cell_writes() + .any(|cell| match cell.borrow().prototype { + CellType::Component { name } => { + self.updated_components.contains(&name) + } + _ => false, + }) + { // Remove attribute from group. group .borrow_mut() diff --git a/calyx-opt/src/analysis/live_range_analysis.rs b/calyx-opt/src/analysis/live_range_analysis.rs index 799104b88..c2416ba99 100644 --- a/calyx-opt/src/analysis/live_range_analysis.rs +++ b/calyx-opt/src/analysis/live_range_analysis.rs @@ -1,4 +1,6 @@ -use crate::analysis::{ControlId, ReadWriteSet, ShareSet, VariableDetection}; +use crate::analysis::{ + AssignmentAnalysis, ControlId, ReadWriteSet, ShareSet, VariableDetection, +}; use calyx_ir::{self as ir, Id, RRC}; use itertools::Itertools; use std::{ @@ -40,11 +42,12 @@ pub fn meaningful_port_read_set<'a, T: 'a>( assigns: impl Iterator> + Clone + 'a, ) -> impl Iterator> + 'a { // go_writes = all cells which are guaranteed to have their go port written to in assigns - let go_writes: Vec> = - ReadWriteSet::port_write_set(assigns.clone().filter(|asgn| { + let go_writes: Vec> = assigns + .clone() + .filter(|asgn| { // to be included in go_writes, one of the following must hold: // a) guard is true - // b) cell.go = !cell.done ? 1'd1 + // b cell.go = !cell.done ? 1'd1 if asgn.guard.is_true() { return true; } @@ -55,7 +58,9 @@ pub fn meaningful_port_read_set<'a, T: 'a>( &asgn.dst.borrow().cell_parent().borrow().name(), ) && asgn.src.borrow().is_constant(1, 1) - })) + }) + .analysis() + .writes() .filter(|port| port.borrow().attributes.has(ir::NumAttr::Go)) .map(|port| Rc::clone(&port.borrow().cell_parent())) .collect(); @@ -736,8 +741,9 @@ impl LiveRangeAnalysis { }); // calculate reads, but ignore `variable`. we've already dealt with that - let reads: HashSet<_> = ReadWriteSet::port_read_set(assignments) - .cells() + let reads: HashSet<_> = assignments + .analysis() + .cell_reads() .filter(|c| sc_clone.is_shareable_component(c)) .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) .collect(); @@ -761,12 +767,13 @@ impl LiveRangeAnalysis { .cloned() .collect::>(); - let writes: HashSet<_> = - ReadWriteSet::port_write_set(assignments.iter()) - .cells() - .filter(|c| sc_clone.is_shareable_component(c)) - .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) - .collect(); + let writes: HashSet<_> = assignments + .iter() + .analysis() + .cell_writes() + .filter(|c| sc_clone.is_shareable_component(c)) + .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) + .collect(); (reads, writes) } @@ -794,12 +801,13 @@ impl LiveRangeAnalysis { .cloned() .collect::>(); - let writes: HashSet<_> = - ReadWriteSet::port_write_set(assignments.iter()) - .cells() - .filter(|c| sc_clone.is_shareable_component(c)) - .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) - .collect(); + let writes: HashSet<_> = assignments + .iter() + .analysis() + .cell_writes() + .filter(|c| sc_clone.is_shareable_component(c)) + .map(|c| (c.borrow().prototype.clone(), c.borrow().name())) + .collect(); (reads, writes) } @@ -808,7 +816,10 @@ impl LiveRangeAnalysis { assigns: &[ir::Assignment], shareable_components: &ShareSet, ) -> TypeNameSet { - ReadWriteSet::uses(assigns.iter()) + assigns + .iter() + .analysis() + .cell_uses() .filter(|cell| shareable_components.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>() @@ -822,11 +833,19 @@ impl LiveRangeAnalysis { state_shareable: &ShareSet, ) -> (TypeNameSet, TypeNameSet) { let group = group_ref.borrow(); - let share_uses = ReadWriteSet::uses(group.assignments.iter()) + let share_uses = group + .assignments + .iter() + .analysis() + .cell_uses() .filter(|cell| shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) .collect::>(); - let state_reads = ReadWriteSet::port_read_set(group.assignments.iter()) + let state_reads = group + .assignments + .iter() + .analysis() + .reads() .cells() .filter(|cell| state_shareable.is_shareable_component(cell)) .map(|cell| (cell.borrow().prototype.clone(), cell.borrow().name())) @@ -892,16 +911,19 @@ impl LiveRangeAnalysis { if let Some(comb_group) = comb_group_info { read_set.extend( - ReadWriteSet::port_read_set( - comb_group.borrow().assignments.iter(), - ) - .cells() - .filter(|cell| { - shareable_components.is_shareable_component(cell) - }) - .map(|cell| { - (cell.borrow().prototype.clone(), cell.borrow().name()) - }), + comb_group + .borrow() + .assignments + .iter() + .analysis() + .reads() + .cells() + .filter(|cell| { + shareable_components.is_shareable_component(cell) + }) + .map(|cell| { + (cell.borrow().prototype.clone(), cell.borrow().name()) + }), ); } @@ -928,7 +950,12 @@ impl LiveRangeAnalysis { // uses of shareable components in the comb group (if it exists) if let Some(comb_group) = &comb_group_info { uses.extend( - ReadWriteSet::uses(comb_group.borrow().assignments.iter()) + comb_group + .borrow() + .assignments + .iter() + .analysis() + .cell_uses() .filter(|cell| { shareable_components.is_shareable_component(cell) }) diff --git a/calyx-opt/src/analysis/mod.rs b/calyx-opt/src/analysis/mod.rs index 6be29f0d2..cb00684f8 100644 --- a/calyx-opt/src/analysis/mod.rs +++ b/calyx-opt/src/analysis/mod.rs @@ -36,7 +36,7 @@ pub use inference_analysis::InferenceAnalysis; pub use live_range_analysis::LiveRangeAnalysis; pub use port_interface::PortInterface; pub use promotion_analysis::PromotionAnalysis; -pub use read_write_set::ReadWriteSet; +pub use read_write_set::{AssignmentAnalysis, ReadWriteSet}; pub use schedule_conflicts::ScheduleConflicts; pub use share_set::ShareSet; pub use static_par_timing::StaticParTiming; diff --git a/calyx-opt/src/analysis/reaching_defns.rs b/calyx-opt/src/analysis/reaching_defns.rs index 384cfda85..618ee07fe 100644 --- a/calyx-opt/src/analysis/reaching_defns.rs +++ b/calyx-opt/src/analysis/reaching_defns.rs @@ -8,6 +8,8 @@ use std::{ ops::BitOr, }; +use super::read_write_set::AssignmentAnalysis; + const INVOKE_PREFIX: &str = "__invoke_"; type GroupName = ir::Id; @@ -219,18 +221,19 @@ impl ReachingDefinitionAnalysis { where I: Iterator> + Clone + 'a, { - let continuous_regs: Vec = - ReadWriteSet::uses(continuous_assignments) - .filter_map(|cell| { - let cell_ref = cell.borrow(); - if let Some(name) = cell_ref.type_name() { - if name == "std_reg" { - return Some(cell_ref.name()); - } + let continuous_regs: Vec = continuous_assignments + .analysis() + .cell_uses() + .filter_map(|cell| { + let cell_ref = cell.borrow(); + if let Some(name) = cell_ref.type_name() { + if name == "std_reg" { + return Some(cell_ref.name()); } - None - }) - .collect(); + } + None + }) + .collect(); let mut overlap_map: BTreeMap< ir::Id, diff --git a/calyx-opt/src/analysis/read_write_set.rs b/calyx-opt/src/analysis/read_write_set.rs index 0e16123f4..c5208ea59 100644 --- a/calyx-opt/src/analysis/read_write_set.rs +++ b/calyx-opt/src/analysis/read_write_set.rs @@ -2,6 +2,106 @@ use calyx_ir::{self as ir, RRC}; use itertools::Itertools; use std::{collections::HashMap, iter, rc::Rc}; +#[derive(Clone)] +pub struct AssignmentIterator<'a, T: 'a, I> +where + I: Iterator>, +{ + iter: I, +} + +impl<'a, T: 'a, I> Iterator for AssignmentIterator<'a, T, I> +where + I: Iterator>, +{ + type Item = &'a ir::Assignment; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I> +where + I: Iterator>, +{ + /// Returns [ir::Port] which are read from in the assignments. + pub fn reads( + self, + ) -> PortIterator> + 'a> { + PortIterator::new(self.flat_map(ReadWriteSet::port_reads)) + } + + /// Returns [ir::Port] which are written to in the assignments. + pub fn writes( + self, + ) -> PortIterator> + 'a> { + PortIterator::new( + self.map(|assign| Rc::clone(&assign.dst)) + .filter(|port| !port.borrow().is_hole()), + ) + } + + /// Returns the ports mentioned in this set of assignments. + pub fn uses( + self, + ) -> PortIterator> + 'a> { + PortIterator::new(self.flat_map(|assign| { + iter::once(Rc::clone(&assign.src)).chain(assign.guard.all_ports()) + })) + } + + // Convinience Methods + + /// Returns the cells read from in this set of assignments + pub fn cell_reads(self) -> impl Iterator> + 'a { + self.reads().cells() + } + + /// Returns the cells written to in this set of assignments + pub fn cell_writes(self) -> impl Iterator> + 'a { + self.writes().cells() + } + + /// Returns the cells used in this set of assignments + pub fn cell_uses(self) -> impl Iterator> + 'a { + self.uses().cells() + } +} + +impl<'a, T: 'a, I: 'a> AssignmentIterator<'a, T, I> +where + I: Iterator>, + I: Clone, + T: Clone, +{ + /// Separately returns the read and write sets for the given assignments. + pub fn reads_and_writes( + self, + ) -> ( + PortIterator> + 'a>, + PortIterator> + 'a>, + ) { + (self.clone().reads(), self.writes()) + } +} + +/// Analyzes that can be performed on a set of assignments. +pub trait AssignmentAnalysis<'a, T: 'a>: + Iterator> +where + Self: Sized, +{ + fn analysis(self) -> AssignmentIterator<'a, T, Self> { + AssignmentIterator { iter: self } + } +} + +impl<'a, T: 'a, I: 'a> AssignmentAnalysis<'a, T> for I where + I: Iterator> +{ +} + /// Calcuate the reads-from and writes-to set for a given set of assignments. pub struct ReadWriteSet; @@ -62,24 +162,6 @@ impl ReadWriteSet { ) } - /// Returns [ir::Port] which are read from in the assignments. - pub fn port_read_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> PortIterator>> { - PortIterator::new(assigns.flat_map(Self::port_reads)) - } - - /// Returns [ir::Port] which are written to in the assignments. - pub fn port_write_set<'a, T: 'a>( - assigns: impl Iterator> + 'a, - ) -> PortIterator> + 'a> { - PortIterator::new( - assigns - .map(|assign| Rc::clone(&assign.dst)) - .filter(|port| !port.borrow().is_hole()), - ) - } - /// Returns the register cells whose out port is read anywhere in the given /// assignments pub fn register_reads<'a, T: 'a>( @@ -132,17 +214,6 @@ impl ReadWriteSet { }) .unique_by(|cell| cell.borrow().name()) } - - /// Returns all uses of cells in this group. Uses constitute both reads and - /// writes to cells. - pub fn uses<'a, T: 'a>( - assigns: impl Iterator> + Clone + 'a, - ) -> impl Iterator> + 'a { - let reads = Self::port_read_set(assigns.clone()).cells(); - reads - .chain(Self::port_write_set(assigns).cells()) - .unique_by(|cell| cell.borrow().name()) - } } impl ReadWriteSet { @@ -153,12 +224,11 @@ impl ReadWriteSet { ) -> (Vec>, Vec>) { match scon { ir::StaticControl::Empty(_) => (vec![], vec![]), - ir::StaticControl::Enable(ir::StaticEnable { group, .. }) => ( - Self::port_read_set(group.borrow().assignments.iter()) - .collect(), - Self::port_write_set(group.borrow().assignments.iter()) - .collect(), - ), + ir::StaticControl::Enable(ir::StaticEnable { group, .. }) => { + let g = group.borrow(); + let (r, w) = g.assignments.iter().analysis().reads_and_writes(); + (r.collect(), w.collect()) + } ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => { Self::control_port_read_write_set_static(body) } @@ -262,20 +332,23 @@ impl ReadWriteSet { ) -> (Vec>, Vec>) { match con { ir::Control::Empty(_) => (vec![], vec![]), - ir::Control::Enable(ir::Enable { group, .. }) => ( - Self::port_read_set(group.borrow().assignments.iter().filter( - |assign| { - INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() - }, - )) - .collect(), - Self::port_write_set(group.borrow().assignments.iter().filter( - |assign| { - INCLUDE_HOLE_ASSIGNS || !assign.dst.borrow().is_hole() - }, - )) - .collect(), - ), + ir::Control::Enable(ir::Enable { group, .. }) => { + let group = group.borrow(); + let (reads, writes) = + group.assignments.iter().analysis().reads_and_writes(); + ( + reads + .filter(|p| { + INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole() + }) + .collect(), + writes + .filter(|p| { + INCLUDE_HOLE_ASSIGNS || !p.borrow().is_hole() + }) + .collect(), + ) + } ir::Control::Invoke(ir::Invoke { inputs, outputs, @@ -321,10 +394,12 @@ impl ReadWriteSet { match comb_group { Some(cgr) => { let cg = cgr.borrow(); - let assigns = cg.assignments.iter(); - let reads = Self::port_read_set(assigns.clone()); - let writes = Self::port_write_set(assigns); - (reads.chain(r).collect(), writes.chain(w).collect()) + let (reads, writes) = + cg.assignments.iter().analysis().reads_and_writes(); + ( + reads.into_iter().chain(r).collect(), + writes.into_iter().chain(w).collect(), + ) } None => (r, w), } @@ -356,12 +431,11 @@ impl ReadWriteSet { twrites.append(&mut fwrites); if let Some(cg) = cond { - treads.extend(Self::port_read_set( - cg.borrow().assignments.iter(), - )); - twrites.extend(Self::port_write_set( - cg.borrow().assignments.iter(), - )); + let cg = cg.borrow(); + let (reads, writes) = + cg.assignments.iter().analysis().reads_and_writes(); + treads.extend(reads); + twrites.extend(writes); } (treads, twrites) } @@ -373,12 +447,11 @@ impl ReadWriteSet { reads.push(Rc::clone(port)); if let Some(cg) = cond { - reads.extend(Self::port_read_set( - cg.borrow().assignments.iter(), - )); - writes.extend(Self::port_write_set( - cg.borrow().assignments.iter(), - )); + let cg = cg.borrow(); + let (r, w) = + cg.assignments.iter().analysis().reads_and_writes(); + reads.extend(r); + writes.extend(w); } (reads, writes) } @@ -412,30 +485,4 @@ impl ReadWriteSet { .collect(), ) } - - /// Returns the ports that are read and written, respectively, - /// in the continuous assignments of the given component. - pub fn cont_ports_read_write_set( - comp: &mut calyx_ir::Component, - ) -> (Vec>, Vec>) { - ( - Self::port_read_set(comp.continuous_assignments.iter()).collect(), - Self::port_write_set(comp.continuous_assignments.iter()).collect(), - ) - } - - /// Returns the cells that are read and written, respectively, - /// in the continuous assignments of the given component. - pub fn cont_read_write_set( - comp: &mut calyx_ir::Component, - ) -> (Vec>, Vec>) { - ( - Self::port_read_set(comp.continuous_assignments.iter()) - .cells() - .collect(), - Self::port_write_set(comp.continuous_assignments.iter()) - .cells() - .collect(), - ) - } } diff --git a/calyx-opt/src/analysis/variable_detection.rs b/calyx-opt/src/analysis/variable_detection.rs index 6080a058d..3cc112b6f 100644 --- a/calyx-opt/src/analysis/variable_detection.rs +++ b/calyx-opt/src/analysis/variable_detection.rs @@ -1,4 +1,4 @@ -use super::{GraphAnalysis, ReadWriteSet}; +use super::{read_write_set::AssignmentAnalysis, GraphAnalysis}; use crate::analysis::ShareSet; use calyx_ir::{self as ir, RRC}; @@ -18,8 +18,11 @@ impl VariableDetection { ) -> Option<(ir::CellType, ir::Id)> { let group = group_ref.borrow(); - let writes = ReadWriteSet::port_write_set(group.assignments.iter()) - .cells() + let writes = group + .assignments + .iter() + .analysis() + .cell_writes() .filter(|cell| state_share.is_shareable_component(cell)) .collect::>(); diff --git a/calyx-opt/src/passes/cell_share.rs b/calyx-opt/src/passes/cell_share.rs index 9ec5f5c5a..860abd2de 100644 --- a/calyx-opt/src/passes/cell_share.rs +++ b/calyx-opt/src/passes/cell_share.rs @@ -1,5 +1,6 @@ use crate::analysis::{ - GraphColoring, LiveRangeAnalysis, ReadWriteSet, ShareSet, StaticParTiming, + AssignmentAnalysis, GraphColoring, LiveRangeAnalysis, ShareSet, + StaticParTiming, }; use crate::traversal::{ Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor, @@ -191,10 +192,13 @@ impl CellShare { _sigs: &ir::LibrarySignatures, ) { //add cont cells - self.cont_ref_cells = - ReadWriteSet::uses(comp.continuous_assignments.iter()) - .map(|cr| cr.borrow().name()) - .collect(); + self.cont_ref_cells = comp + .continuous_assignments + .iter() + .analysis() + .cell_uses() + .map(|cr| cr.borrow().name()) + .collect(); //add ref cells self.cont_ref_cells.extend( comp.cells diff --git a/calyx-opt/src/passes/group_to_invoke.rs b/calyx-opt/src/passes/group_to_invoke.rs index ffd85672a..4acdb5002 100644 --- a/calyx-opt/src/passes/group_to_invoke.rs +++ b/calyx-opt/src/passes/group_to_invoke.rs @@ -1,4 +1,4 @@ -use crate::analysis::ReadWriteSet; +use crate::analysis::AssignmentAnalysis; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir}; use calyx_ir::{GetAttributes, RRC}; @@ -237,8 +237,10 @@ impl GroupToInvoke { assigns: &[ir::Assignment], group_done_port: &ir::RRC, ) { - let mut writes = ReadWriteSet::port_write_set(assigns.iter()) - .cells() + let mut writes = assigns + .iter() + .analysis() + .cell_writes() .filter(|cell| match cell.borrow().prototype { ir::CellType::Primitive { is_comb, .. } => !is_comb, _ => true, diff --git a/calyx-opt/src/passes/group_to_seq.rs b/calyx-opt/src/passes/group_to_seq.rs index 13018d07a..4b39c960d 100644 --- a/calyx-opt/src/passes/group_to_seq.rs +++ b/calyx-opt/src/passes/group_to_seq.rs @@ -1,4 +1,4 @@ -use crate::analysis::ReadWriteSet; +use crate::analysis::{AssignmentAnalysis, ReadWriteSet}; use crate::traversal::{Action, Named, VisResult, Visitor}; use calyx_ir as ir; use ir::Nothing; @@ -150,9 +150,7 @@ fn comp_or_non_comb(cell: &ir::RRC) -> bool { //If asmt is a write to a cell named name returns Some(name). //If asmt is a write to a group port, returns None. fn writes_to_cell(asmt: &ir::Assignment) -> Option> { - ReadWriteSet::port_write_set(std::iter::once(asmt)) - .cells() - .next() + std::iter::once(asmt).analysis().cell_writes().next() } ///Primarily used to help determine the order cells are executed within @@ -308,17 +306,18 @@ where pub fn possible_split( asmts: &[ir::Assignment], ) -> Option<(ir::Id, ir::Id)> { - let stateful_writes: Vec = - ReadWriteSet::port_write_set(asmts.iter()) - .cells() - .filter_map(|cell| { - if cell.borrow().is_comb_cell() { - None - } else { - Some(cell.borrow().name()) - } - }) - .collect(); + let stateful_writes: Vec = asmts + .iter() + .analysis() + .cell_writes() + .filter_map(|cell| { + if cell.borrow().is_comb_cell() { + None + } else { + Some(cell.borrow().name()) + } + }) + .collect(); if stateful_writes.len() == 2 { let (maybe_first, maybe_last, last) = diff --git a/calyx-opt/src/passes/papercut.rs b/calyx-opt/src/passes/papercut.rs index f67fd915e..72b26dd94 100644 --- a/calyx-opt/src/passes/papercut.rs +++ b/calyx-opt/src/passes/papercut.rs @@ -1,4 +1,4 @@ -use crate::analysis; +use crate::analysis::{self, AssignmentAnalysis}; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; @@ -148,12 +148,13 @@ impl Visitor for Papercut { } // Compute all cells that are driven in by the continuous assignments0 - self.cont_cells = analysis::ReadWriteSet::port_write_set( - comp.continuous_assignments.iter(), - ) - .cells() - .map(|cr| cr.borrow().name()) - .collect(); + self.cont_cells = comp + .continuous_assignments + .iter() + .analysis() + .cell_writes() + .map(|cr| cr.borrow().name()) + .collect(); Ok(Action::Continue) } @@ -225,11 +226,17 @@ impl Visitor for Papercut { impl Papercut { fn check_specs(&mut self, assigns: &[ir::Assignment]) -> VisResult { - let all_writes = analysis::ReadWriteSet::port_write_set(assigns.iter()) + let all_writes = assigns + .iter() + .analysis() + .writes() .filter_map(port_information) .into_grouping_map() .collect::>(); - let all_reads = analysis::ReadWriteSet::port_read_set(assigns.iter()) + let all_reads = assigns + .iter() + .analysis() + .reads() .filter_map(port_information) .into_grouping_map() .collect::>(); diff --git a/calyx-opt/src/passes/schedule_compaction.rs b/calyx-opt/src/passes/schedule_compaction.rs index 69f051bea..23f868313 100644 --- a/calyx-opt/src/passes/schedule_compaction.rs +++ b/calyx-opt/src/passes/schedule_compaction.rs @@ -1,4 +1,6 @@ -use crate::analysis::{InferenceAnalysis, PromotionAnalysis, ReadWriteSet}; +use crate::analysis::{ + AssignmentAnalysis, InferenceAnalysis, PromotionAnalysis, +}; use crate::traversal::{Action, ConstructVisitor}; use crate::{ analysis, @@ -261,7 +263,13 @@ impl Visitor for ScheduleCompaction { sigs: &calyx_ir::LibrarySignatures, _comps: &[calyx_ir::Component], ) -> crate::traversal::VisResult { - let (cont_reads, cont_writes) = ReadWriteSet::cont_read_write_set(comp); + let (cont_reads, cont_writes) = comp + .continuous_assignments + .iter() + .analysis() + .reads_and_writes(); + let (cont_reads, cont_writes) = + (cont_reads.cells().collect(), cont_writes.cells().collect()); InferenceAnalysis::remove_promotable_from_seq(s); self.inference_analysis.fixup_seq(s); From 4e12766ac1fcab99de775df3bf398a68ed3a1081 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Fri, 16 Feb 2024 18:55:20 +0530 Subject: [PATCH 184/189] work on default assigns pass --- calyx-ir/src/common.rs | 4 +- calyx-ir/src/component.rs | 8 +++ calyx-opt/src/passes/default_assigns.rs | 70 +++++++++++++++++++++++++ calyx-opt/src/passes/mod.rs | 1 + 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 calyx-opt/src/passes/default_assigns.rs diff --git a/calyx-ir/src/common.rs b/calyx-ir/src/common.rs index 139c16e70..4e5a7a25b 100644 --- a/calyx-ir/src/common.rs +++ b/calyx-ir/src/common.rs @@ -32,9 +32,9 @@ impl WRC { pub fn upgrade(&self) -> RRC { let Some(r) = self.internal.upgrade() else { #[cfg(debug_assertions)] - unreachable!("weak reference points to a dropped. Original object's name: `{}'", self.debug_name); + unreachable!("weak reference points to a dropped value. Original object's name: `{}'", self.debug_name); #[cfg(not(debug_assertions))] - unreachable!("weak reference points to a dropped."); + unreachable!("weak reference points to a dropped value."); }; r } diff --git a/calyx-ir/src/component.rs b/calyx-ir/src/component.rs index b0923f5fc..368866a5b 100644 --- a/calyx-ir/src/component.rs +++ b/calyx-ir/src/component.rs @@ -231,6 +231,14 @@ impl Component { self.namegen.gen_name(prefix) } + /// Check whether this component is purely structural, i.e. has no groups or control + pub fn is_structural(&self) -> bool { + self.groups.is_empty() + && self.comb_groups.is_empty() + && self.static_groups.is_empty() + && self.control.borrow().is_empty() + } + /// Check whether this is a static component. /// A static component is a component which has a latency field. pub fn is_static(&self) -> bool { diff --git a/calyx-opt/src/passes/default_assigns.rs b/calyx-opt/src/passes/default_assigns.rs new file mode 100644 index 000000000..b7f8a5396 --- /dev/null +++ b/calyx-opt/src/passes/default_assigns.rs @@ -0,0 +1,70 @@ +use crate::analysis::AssignmentAnalysis; +use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; +use calyx_ir::{self as ir, LibrarySignatures}; +use calyx_utils::{CalyxResult, Error}; +use std::collections::HashMap; + +/// Adds default assignments to all non-`@data` ports of an instance. +pub struct DefaultAssigns { + /// Mapping from component to data ports + data_ports: HashMap>, +} + +impl Named for DefaultAssigns { + fn name() -> &'static str { + "default-assigns" + } + + fn description() -> &'static str { + "adds default assignments to all non-`@data` ports of an instance." + } +} + +impl ConstructVisitor for DefaultAssigns { + fn from(ctx: &ir::Context) -> CalyxResult + where + Self: Sized, + { + let data_ports = ctx + .lib + .signatures() + .map(|sig| { + let ports = sig.signature.iter().filter_map(|p| { + if p.attributes.has(ir::BoolAttr::Data) { + Some(p.name()) + } else { + None + } + }); + (sig.name, ports.collect()) + }) + .collect(); + Ok(Self { data_ports }) + } + + fn clear_data(&mut self) { + /* shared across components */ + } +} + +impl Visitor for DefaultAssigns { + fn start( + &mut self, + comp: &mut ir::Component, + _sigs: &LibrarySignatures, + _comps: &[ir::Component], + ) -> VisResult { + if !comp.is_structural() { + return Err(Error::pass_assumption( + Self::name(), + format!("component {} is not purely structural", comp.name), + )); + } + + // We only need to consider write set of the continuous assignments + let writes = comp.continuous_assignments.iter().analysis().writes(); + + // Purely structural pass + Ok(Action::Stop) + } +} diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index b9aa04c15..0a4b91f09 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -36,6 +36,7 @@ mod sync; mod add_guard; mod compile_static_interface; mod data_path_infer; +mod default_assigns; mod discover_external; mod simplify_with_control; mod synthesis_papercut; From ff9d32dec262ba3a2a9819e9bed70da851b93fb5 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 17 Feb 2024 22:45:12 +0530 Subject: [PATCH 185/189] default assign pass works --- calyx-ir/src/component.rs | 2 +- calyx-opt/src/default_passes.rs | 8 +-- calyx-opt/src/passes/default_assigns.rs | 65 +++++++++++++++++++++++-- calyx-opt/src/passes/mod.rs | 1 + 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/calyx-ir/src/component.rs b/calyx-ir/src/component.rs index 368866a5b..f9752afd1 100644 --- a/calyx-ir/src/component.rs +++ b/calyx-ir/src/component.rs @@ -324,7 +324,7 @@ impl Component { #[derive(Debug)] pub struct IdList(LinkedHashMap>); -/// Simple into-iter impl delegating to the [`Values`](linked_hash_map::Values). +/// Simple iter impl delegating to the [`Values`](linked_hash_map::Values). impl<'a, T: GetName> IntoIterator for &'a IdList { type Item = &'a RRC; diff --git a/calyx-opt/src/default_passes.rs b/calyx-opt/src/default_passes.rs index 74782acb5..2d5c2bd2c 100644 --- a/calyx-opt/src/default_passes.rs +++ b/calyx-opt/src/default_passes.rs @@ -3,9 +3,9 @@ use crate::passes::{ AddGuard, Canonicalize, CellShare, ClkInsertion, CollapseControl, CombProp, CompileInvoke, CompileRepeat, CompileStatic, CompileStaticInterface, CompileSync, CompileSyncWithoutSyncReg, ComponentInliner, DataPathInfer, - DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DiscoverExternal, - Externalize, GoInsertion, GroupToInvoke, GroupToSeq, HoleInliner, - InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, + DeadAssignmentRemoval, DeadCellRemoval, DeadGroupRemoval, DefaultAssigns, + DiscoverExternal, Externalize, GoInsertion, GroupToInvoke, GroupToSeq, + HoleInliner, InferShare, LowerGuards, MergeAssign, Papercut, ParToSeq, RegisterUnsharing, RemoveIds, ResetInsertion, SimplifyStaticGuards, SimplifyWithControl, StaticInference, StaticInliner, StaticPromotion, SynthesisPapercut, TopDownCompileControl, UnrollBounded, WellFormed, @@ -59,6 +59,7 @@ impl PassManager { pm.register_pass::()?; pm.register_pass::()?; pm.register_pass::()?; + pm.register_pass::()?; // Enabled in the synthesis compilation flow pm.register_pass::()?; @@ -134,6 +135,7 @@ impl PassManager { ClkInsertion, ResetInsertion, MergeAssign, + DefaultAssigns, ] ); diff --git a/calyx-opt/src/passes/default_assigns.rs b/calyx-opt/src/passes/default_assigns.rs index b7f8a5396..7f1e3cb53 100644 --- a/calyx-opt/src/passes/default_assigns.rs +++ b/calyx-opt/src/passes/default_assigns.rs @@ -2,6 +2,7 @@ use crate::analysis::AssignmentAnalysis; use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor}; use calyx_ir::{self as ir, LibrarySignatures}; use calyx_utils::{CalyxResult, Error}; +use itertools::Itertools; use std::collections::HashMap; /// Adds default assignments to all non-`@data` ports of an instance. @@ -30,7 +31,11 @@ impl ConstructVisitor for DefaultAssigns { .signatures() .map(|sig| { let ports = sig.signature.iter().filter_map(|p| { - if p.attributes.has(ir::BoolAttr::Data) { + if p.direction == ir::Direction::Input + && !p.attributes.has(ir::BoolAttr::Data) + && !p.attributes.has(ir::BoolAttr::Clk) + && !p.attributes.has(ir::BoolAttr::Reset) + { Some(p.name()) } else { None @@ -51,7 +56,7 @@ impl Visitor for DefaultAssigns { fn start( &mut self, comp: &mut ir::Component, - _sigs: &LibrarySignatures, + sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { if !comp.is_structural() { @@ -62,7 +67,61 @@ impl Visitor for DefaultAssigns { } // We only need to consider write set of the continuous assignments - let writes = comp.continuous_assignments.iter().analysis().writes(); + let writes = comp + .continuous_assignments + .iter() + .analysis() + .writes() + .group_by_cell(); + + let mut assigns = Vec::new(); + + let mt = vec![]; + let cells = comp.cells.iter().cloned().collect_vec(); + let mut builder = ir::Builder::new(comp, sigs); + + for cr in &cells { + let cell = cr.borrow(); + let Some(typ) = cell.type_name() else { + continue; + }; + let Some(required) = self.data_ports.get(&typ) else { + continue; + }; + + // For all the assignments not in the write set, add a default assignment + let cell_writes = writes + .get(&cell.name()) + .unwrap_or(&mt) + .iter() + .map(|p| { + let p = p.borrow(); + p.name + }) + .collect_vec(); + + assigns.extend( + required.iter().filter(|p| !cell_writes.contains(p)).map( + |name| { + let port = cell.get(name); + let zero = builder.add_constant(0, port.borrow().width); + let assign: ir::Assignment = builder + .build_assignment( + cell.get(name), + zero.borrow().get("out"), + ir::Guard::True, + ); + log::info!( + "Adding {}", + ir::Printer::assignment_to_str(&assign) + ); + assign + }, + ), + ); + } + + comp.continuous_assignments.extend(assigns); // Purely structural pass Ok(Action::Stop) diff --git a/calyx-opt/src/passes/mod.rs b/calyx-opt/src/passes/mod.rs index 36dabe37a..6cb73f2c7 100644 --- a/calyx-opt/src/passes/mod.rs +++ b/calyx-opt/src/passes/mod.rs @@ -82,6 +82,7 @@ pub use sync::CompileSyncWithoutSyncReg; // pub use simplify_guards::SimplifyGuards; pub use add_guard::AddGuard; pub use compile_static_interface::CompileStaticInterface; +pub use default_assigns::DefaultAssigns; pub use synthesis_papercut::SynthesisPapercut; pub use top_down_compile_control::TopDownCompileControl; pub use unroll_bound::UnrollBounded; From cc8b5023f24cc8c44ae262aa3c33ecbafd21baf1 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sat, 17 Feb 2024 22:45:31 +0530 Subject: [PATCH 186/189] update test --- examples/futil/dot-product.expect | 2 ++ examples/futil/vectorized-add.expect | 2 ++ tests/backend/verilog/memory-with-external-attribute.expect | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/examples/futil/dot-product.expect b/examples/futil/dot-product.expect index 892882468..dd5edecb8 100644 --- a/examples/futil/dot-product.expect +++ b/examples/futil/dot-product.expect @@ -115,6 +115,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { A_read0_0.reset = reset; A_read0_0.in = fsm.out == 4'd0 & early_reset_static_seq_go.out ? A0.read_data; A_read0_0.in = fsm.out == 4'd4 & early_reset_static_seq_go.out ? mult_pipe0.out; + A0.write_en = 1'd0; + B0.write_en = 1'd0; } control {} } diff --git a/examples/futil/vectorized-add.expect b/examples/futil/vectorized-add.expect index 45a34acfd..52171e14b 100644 --- a/examples/futil/vectorized-add.expect +++ b/examples/futil/vectorized-add.expect @@ -105,6 +105,8 @@ component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) { A_read0_0.clk = clk; A_read0_0.reset = reset; A_read0_0.in = fsm.out == 3'd0 & early_reset_static_seq_go.out ? A0.read_data; + A0.write_en = 1'd0; + B0.write_en = 1'd0; } control {} } diff --git a/tests/backend/verilog/memory-with-external-attribute.expect b/tests/backend/verilog/memory-with-external-attribute.expect index 4c08fe3ba..e6e7ee163 100644 --- a/tests/backend/verilog/memory-with-external-attribute.expect +++ b/tests/backend/verilog/memory-with-external-attribute.expect @@ -595,10 +595,14 @@ comb_mem_d1 # ( .write_en(m1_write_en) ); wire _guard0 = 1; +assign m1_write_en = 1'd0; assign m1_clk = clk; +assign m1_addr0 = 4'd0; assign m1_reset = reset; assign done = m1_done; +assign m0_write_en = 1'd0; assign m0_clk = clk; +assign m0_addr0 = 4'd0; assign m0_reset = reset; // COMPONENT END: main endmodule From 242adacc7f08a05d69f1ba3bd3eb3e828935e18f Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Sun, 18 Feb 2024 11:28:08 +0530 Subject: [PATCH 187/189] update test --- tests/frontend/dahlia/combine.expect | 4 ++-- tests/frontend/dahlia/dot-func.expect | 11 ++++++----- tests/frontend/dahlia/invoke-memory.expect | 7 ++++--- tests/frontend/dahlia/matadd-fixed-point.expect | 11 ++++++----- tests/frontend/dahlia/memory.expect | 9 ++++++--- tests/frontend/dahlia/signed_dotproduct.expect | 8 ++++---- tests/frontend/dahlia/unroll.expect | 16 ++++++++-------- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/tests/frontend/dahlia/combine.expect b/tests/frontend/dahlia/combine.expect index d4d9e5cce..35d968ef8 100644 --- a/tests/frontend/dahlia/combine.expect +++ b/tests/frontend/dahlia/combine.expect @@ -26,10 +26,10 @@ component main() -> () { } group let1<"promotable"=2> { acc_0.in = A.read_data; - acc_0.write_en = A.read_done; + acc_0.write_en = A.done; let1[done] = acc_0.done; + A.content_en = 1'd1; A.addr0 = i0.out; - A.read_en = 1'd1; } group upd0<"promotable"=1> { res_0.write_en = 1'd1; diff --git a/tests/frontend/dahlia/dot-func.expect b/tests/frontend/dahlia/dot-func.expect index 9363646fa..a52d267ef 100644 --- a/tests/frontend/dahlia/dot-func.expect +++ b/tests/frontend/dahlia/dot-func.expect @@ -29,17 +29,17 @@ component dot() -> () { } group let1<"promotable"=2> { A_read0_0.in = A.read_data; - A_read0_0.write_en = A.read_done; + A_read0_0.write_en = A.done; let1[done] = A_read0_0.done; + A.content_en = 1'd1; A.addr0 = i0.out; - A.read_en = 1'd1; } group let2<"promotable"=2> { B_read0_0.in = B.read_data; - B_read0_0.write_en = B.read_done; + B_read0_0.write_en = B.done; let2[done] = B_read0_0.done; + B.content_en = 1'd1; B.addr0 = i0.out; - B.read_en = 1'd1; } group let3<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; @@ -50,10 +50,11 @@ component dot() -> () { mult_pipe0.go = !mult_pipe0.done ? 1'd1; } group upd0<"promotable"=1> { + out.content_en = 1'd1; out.addr0 = i0.out; out.write_en = 1'd1; out.write_data = bin_read0_0.out; - upd0[done] = out.write_done; + upd0[done] = out.done; } group upd1<"promotable"=1> { i0.write_en = 1'd1; diff --git a/tests/frontend/dahlia/invoke-memory.expect b/tests/frontend/dahlia/invoke-memory.expect index 2c868faba..89e8ae49e 100644 --- a/tests/frontend/dahlia/invoke-memory.expect +++ b/tests/frontend/dahlia/invoke-memory.expect @@ -22,16 +22,17 @@ component mem_copy(length: 3) -> () { } group let1<"promotable"=2> { src_read0_0.in = src.read_data; - src_read0_0.write_en = src.read_done; + src_read0_0.write_en = src.done; let1[done] = src_read0_0.done; + src.content_en = 1'd1; src.addr0 = i_0.out; - src.read_en = 1'd1; } group upd0<"promotable"=1> { + dest.content_en = 1'd1; dest.addr0 = i_0.out; dest.write_en = 1'd1; dest.write_data = src_read0_0.out; - upd0[done] = dest.write_done; + upd0[done] = dest.done; } } control { diff --git a/tests/frontend/dahlia/matadd-fixed-point.expect b/tests/frontend/dahlia/matadd-fixed-point.expect index c631be0b1..2c489e005 100644 --- a/tests/frontend/dahlia/matadd-fixed-point.expect +++ b/tests/frontend/dahlia/matadd-fixed-point.expect @@ -43,28 +43,29 @@ component main() -> () { } group let2<"promotable"=2> { a0_0_read0_0.in = a0_0.read_data; - a0_0_read0_0.write_en = a0_0.read_done; + a0_0_read0_0.write_en = a0_0.done; let2[done] = a0_0_read0_0.done; + a0_0.content_en = 1'd1; a0_0.addr1 = j0.out; a0_0.addr0 = i0.out; - a0_0.read_en = 1'd1; } group let3<"promotable"=2> { b0_0_read0_0.in = b0_0.read_data; - b0_0_read0_0.write_en = b0_0.read_done; + b0_0_read0_0.write_en = b0_0.done; let3[done] = b0_0_read0_0.done; + b0_0.content_en = 1'd1; b0_0.addr1 = j0.out; b0_0.addr0 = i0.out; - b0_0.read_en = 1'd1; } group upd0<"promotable"=1> { + result0_0.content_en = 1'd1; result0_0.addr1 = j0.out; result0_0.addr0 = i0.out; result0_0.write_en = 1'd1; add0.left = a0_0_read0_0.out; add0.right = b0_0_read0_0.out; result0_0.write_data = add0.out; - upd0[done] = result0_0.write_done; + upd0[done] = result0_0.done; } group upd1<"promotable"=1> { j0.write_en = 1'd1; diff --git a/tests/frontend/dahlia/memory.expect b/tests/frontend/dahlia/memory.expect index 0e9773a1a..ba9ecce9f 100644 --- a/tests/frontend/dahlia/memory.expect +++ b/tests/frontend/dahlia/memory.expect @@ -18,25 +18,28 @@ component main() -> () { } wires { group upd0<"promotable"=1> { + A.content_en = 1'd1; A.addr0 = const1.out; A.write_en = 1'd1; A.write_data = const0.out; - upd0[done] = A.write_done; + upd0[done] = A.done; } group upd1<"promotable"=1> { + B.content_en = 1'd1; B.addr1 = const4.out; B.addr0 = const3.out; B.write_en = 1'd1; B.write_data = const2.out; - upd1[done] = B.write_done; + upd1[done] = B.done; } group upd2<"promotable"=1> { + C.content_en = 1'd1; C.addr2 = const8.out; C.addr1 = const7.out; C.addr0 = const6.out; C.write_en = 1'd1; C.write_data = const5.out; - upd2[done] = C.write_done; + upd2[done] = C.done; } } control { diff --git a/tests/frontend/dahlia/signed_dotproduct.expect b/tests/frontend/dahlia/signed_dotproduct.expect index d73788461..1fec16e24 100644 --- a/tests/frontend/dahlia/signed_dotproduct.expect +++ b/tests/frontend/dahlia/signed_dotproduct.expect @@ -40,19 +40,19 @@ component main() -> () { } group let2<"promotable"=2> { a0_read0_0.in = a0.read_data; - a0_read0_0.write_en = a0.read_done; + a0_read0_0.write_en = a0.done; let2[done] = a0_read0_0.done; + a0.content_en = 1'd1; a0.addr0 = slice0.out; slice0.in = i0.out; - a0.read_en = 1'd1; } group let3<"promotable"=2> { b0_read0_0.in = b0.read_data; - b0_read0_0.write_en = b0.read_done; + b0_read0_0.write_en = b0.done; let3[done] = b0_read0_0.done; + b0.content_en = 1'd1; b0.addr0 = slice1.out; slice1.in = i0.out; - b0.read_en = 1'd1; } group let4<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; diff --git a/tests/frontend/dahlia/unroll.expect b/tests/frontend/dahlia/unroll.expect index 367e11f3f..b461a2295 100644 --- a/tests/frontend/dahlia/unroll.expect +++ b/tests/frontend/dahlia/unroll.expect @@ -38,34 +38,34 @@ component main() -> () { let0[done] = i0.done; } group upd0<"promotable"=2> { - acc_00.write_en = A0.read_done; + acc_00.write_en = A0.done; + A0.content_en = 1'd1; A0.addr0 = slice0.out; slice0.in = i0.out; - A0.read_en = 1'd1; acc_00.in = A0.read_data; upd0[done] = acc_00.done; } group upd1<"promotable"=2> { - acc_10.write_en = A1.read_done; + acc_10.write_en = A1.done; + A1.content_en = 1'd1; A1.addr0 = slice1.out; slice1.in = i0.out; - A1.read_en = 1'd1; acc_10.in = A1.read_data; upd1[done] = acc_10.done; } group upd2<"promotable"=2> { - acc_20.write_en = A2.read_done; + acc_20.write_en = A2.done; + A2.content_en = 1'd1; A2.addr0 = slice2.out; slice2.in = i0.out; - A2.read_en = 1'd1; acc_20.in = A2.read_data; upd2[done] = acc_20.done; } group upd3<"promotable"=2> { - acc_30.write_en = A3.read_done; + acc_30.write_en = A3.done; + A3.content_en = 1'd1; A3.addr0 = slice3.out; slice3.in = i0.out; - A3.read_en = 1'd1; acc_30.in = A3.read_data; upd3[done] = acc_30.done; } From 7444365c4aeb29ebc6f9d027d58509fd4e69d8e1 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 19 Feb 2024 08:19:57 -0500 Subject: [PATCH 188/189] redo tests --- .../batch_flatten-same-dimensions.expect | 7 +++--- tests/frontend/relay/batch_flatten.expect | 7 +++--- tests/frontend/relay/batch_matmul.expect | 22 ++++++++++-------- tests/frontend/relay/bias_add.expect | 11 +++++---- tests/frontend/relay/broadcast.expect | 11 +++++---- tests/frontend/relay/constant-multiply.expect | 7 +++--- tests/frontend/relay/conv2d.expect | 11 +++++---- tests/frontend/relay/dense.expect | 15 ++++++------ .../relay/duplicate-relay-call.expect | 7 +++--- tests/frontend/relay/max_pool2d.expect | 11 +++++---- tests/frontend/relay/negative.expect | 7 +++--- tests/frontend/relay/relu.expect | 14 ++++++----- tests/frontend/relay/reshape.expect | 7 +++--- tests/frontend/relay/softmax.expect | 23 ++++++++++--------- tests/frontend/relay/sqrt.expect | 7 +++--- tests/frontend/relay/tensor_add.expect | 11 +++++---- 16 files changed, 98 insertions(+), 80 deletions(-) diff --git a/tests/frontend/relay/batch_flatten-same-dimensions.expect b/tests/frontend/relay/batch_flatten-same-dimensions.expect index 3babccb72..e9d262895 100644 --- a/tests/frontend/relay/batch_flatten-same-dimensions.expect +++ b/tests/frontend/relay/batch_flatten-same-dimensions.expect @@ -50,18 +50,19 @@ component batch_flatten_2x4096() -> () { } group let3<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let3[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __k_0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __k_0.write_en = 1'd1; diff --git a/tests/frontend/relay/batch_flatten.expect b/tests/frontend/relay/batch_flatten.expect index 8b4a51f52..a59a05d96 100644 --- a/tests/frontend/relay/batch_flatten.expect +++ b/tests/frontend/relay/batch_flatten.expect @@ -65,19 +65,20 @@ component batch_flatten_1x4() -> () { } group let4<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let4[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr2 = __k0.out; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __l_0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __l_0.write_en = 1'd1; diff --git a/tests/frontend/relay/batch_matmul.expect b/tests/frontend/relay/batch_matmul.expect index fead34bc0..4a29bba8c 100644 --- a/tests/frontend/relay/batch_matmul.expect +++ b/tests/frontend/relay/batch_matmul.expect @@ -105,12 +105,12 @@ component batch_matmul_4x7x7() -> () { } group let11<"promotable"=2> { red_read00.in = x.read_data; - red_read00.write_en = x.read_done; + red_read00.write_en = x.done; let11[done] = red_read00.done; + x.content_en = 1'd1; x.addr2 = __j1.out; x.addr1 = __i1.out; x.addr0 = __batch1.out; - x.read_en = 1'd1; } group let2<"promotable"=1> { __j0.in = const4.out; @@ -119,12 +119,12 @@ component batch_matmul_4x7x7() -> () { } group let3<"promotable"=2> { b_read0_0.in = b.read_data; - b_read0_0.write_en = b.read_done; + b_read0_0.write_en = b.done; let3[done] = b_read0_0.done; + b.content_en = 1'd1; b.addr2 = __j0.out; b.addr1 = __i0.out; b.addr0 = __batch0.out; - b.read_en = 1'd1; } group let4<"promotable"=1> { __batch1.in = const9.out; @@ -148,12 +148,12 @@ component batch_matmul_4x7x7() -> () { } group let8<"promotable"=2> { a_read0_0.in = a.read_data; - a_read0_0.write_en = a.read_done; + a_read0_0.write_en = a.done; let8[done] = a_read0_0.done; + a.content_en = 1'd1; a.addr2 = __k0.out; a.addr1 = __i1.out; a.addr0 = __batch1.out; - a.read_en = 1'd1; } group let9<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; @@ -164,12 +164,13 @@ component batch_matmul_4x7x7() -> () { mult_pipe0.go = !mult_pipe0.done ? 1'd1; } group upd0<"promotable"=1> { + __transpose_b0_0_0.content_en = 1'd1; __transpose_b0_0_0.addr2 = __i0.out; __transpose_b0_0_0.addr1 = __j0.out; __transpose_b0_0_0.addr0 = __batch0.out; __transpose_b0_0_0.write_en = 1'd1; __transpose_b0_0_0.write_data = b_read0_0.out; - upd0[done] = __transpose_b0_0_0.write_done; + upd0[done] = __transpose_b0_0_0.done; } group upd1<"promotable"=1> { __j0.write_en = 1'd1; @@ -193,15 +194,16 @@ component batch_matmul_4x7x7() -> () { upd3[done] = __batch0.done; } group upd4<"promotable"=2> { - __transpose_b_read0_0.write_en = __transpose_b0_0_0.read_done; + __transpose_b_read0_0.write_en = __transpose_b0_0_0.done; + __transpose_b0_0_0.content_en = 1'd1; __transpose_b0_0_0.addr2 = __j1.out; __transpose_b0_0_0.addr1 = __k0.out; __transpose_b0_0_0.addr0 = __batch1.out; - __transpose_b0_0_0.read_en = 1'd1; __transpose_b_read0_0.in = __transpose_b0_0_0.read_data; upd4[done] = __transpose_b_read0_0.done; } group upd5<"promotable"=1> { + x.content_en = 1'd1; x.addr2 = __j1.out; x.addr1 = __i1.out; x.addr0 = __batch1.out; @@ -209,7 +211,7 @@ component batch_matmul_4x7x7() -> () { add3.left = red_read00.out; add3.right = __product_0.out; x.write_data = add3.out; - upd5[done] = x.write_done; + upd5[done] = x.done; } group upd6<"promotable"=1> { __k0.write_en = 1'd1; diff --git a/tests/frontend/relay/bias_add.expect b/tests/frontend/relay/bias_add.expect index afd34c5ab..3be156f32 100644 --- a/tests/frontend/relay/bias_add.expect +++ b/tests/frontend/relay/bias_add.expect @@ -74,22 +74,23 @@ component bias_add_1x64x512x256() -> () { } group let4<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let4[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr3 = __l0.out; x.addr2 = __k0.out; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let5<"promotable"=2> { bias_read0_0.in = bias.read_data; - bias_read0_0.write_en = bias.read_done; + bias_read0_0.write_en = bias.done; let5[done] = bias_read0_0.done; + bias.content_en = 1'd1; bias.addr0 = __j0.out; - bias.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; @@ -98,7 +99,7 @@ component bias_add_1x64x512x256() -> () { add0.left = x_read0_0.out; add0.right = bias_read0_0.out; x1.write_data = add0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __l0.write_en = 1'd1; diff --git a/tests/frontend/relay/broadcast.expect b/tests/frontend/relay/broadcast.expect index 93b0f564f..c3546dc72 100644 --- a/tests/frontend/relay/broadcast.expect +++ b/tests/frontend/relay/broadcast.expect @@ -45,28 +45,29 @@ component add_2x4() -> () { } group let2<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let2[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let3<"promotable"=2> { y_read0_0.in = y.read_data; - y_read0_0.write_en = y.read_done; + y_read0_0.write_en = y.done; let3[done] = y_read0_0.done; + y.content_en = 1'd1; y.addr1 = const4.out; y.addr0 = __i0.out; - y.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; add0.left = x_read0_0.out; add0.right = y_read0_0.out; x1.write_data = add0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __j0.write_en = 1'd1; diff --git a/tests/frontend/relay/constant-multiply.expect b/tests/frontend/relay/constant-multiply.expect index e843c9127..83930a3ea 100644 --- a/tests/frontend/relay/constant-multiply.expect +++ b/tests/frontend/relay/constant-multiply.expect @@ -28,10 +28,10 @@ component multiply_1(x1: 32) -> () { } group let1<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let1[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let2<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; @@ -42,10 +42,11 @@ component multiply_1(x1: 32) -> () { mult_pipe0.go = !mult_pipe0.done ? 1'd1; } group upd0<"promotable"=1> { + x2.content_en = 1'd1; x2.addr0 = __i0.out; x2.write_en = 1'd1; x2.write_data = bin_read0_0.out; - upd0[done] = x2.write_done; + upd0[done] = x2.done; } group upd1<"promotable"=1> { __i0.write_en = 1'd1; diff --git a/tests/frontend/relay/conv2d.expect b/tests/frontend/relay/conv2d.expect index b755a86ce..049a320f9 100644 --- a/tests/frontend/relay/conv2d.expect +++ b/tests/frontend/relay/conv2d.expect @@ -173,8 +173,9 @@ component conv2d_5x512x14x14() -> () { } group let13<"promotable"=2> { data_read0_0.in = data.read_data; - data_read0_0.write_en = data.read_done; + data_read0_0.write_en = data.done; let13[done] = data_read0_0.done; + data.content_en = 1'd1; data.addr3 = slice3.out; slice3.in = sub1.out; sub1.left = __kernel_x_0.out; @@ -187,12 +188,12 @@ component conv2d_5x512x14x14() -> () { slice1.in = __k0.out; data.addr0 = slice0.out; slice0.in = __b0.out; - data.read_en = 1'd1; } group let14<"promotable"=2> { weight_read0_0.in = weight.read_data; - weight_read0_0.write_en = weight.read_done; + weight_read0_0.write_en = weight.done; let14[done] = weight_read0_0.done; + weight.content_en = 1'd1; weight.addr3 = slice7.out; slice7.in = __dx0.out; weight.addr2 = slice6.out; @@ -201,7 +202,6 @@ component conv2d_5x512x14x14() -> () { slice5.in = __k0.out; weight.addr0 = slice4.out; slice4.in = __c0.out; - weight.read_en = 1'd1; } group let15<"promotable"=4> { bin_read2_0.in = mult_pipe2.out; @@ -290,6 +290,7 @@ component conv2d_5x512x14x14() -> () { upd4[done] = __k0.done; } group upd5<"promotable"=1> { + x.content_en = 1'd1; x.addr3 = slice11.out; slice11.in = __x0.out; x.addr2 = slice10.out; @@ -300,7 +301,7 @@ component conv2d_5x512x14x14() -> () { slice8.in = __b0.out; x.write_en = 1'd1; x.write_data = __sum_0.out; - upd5[done] = x.write_done; + upd5[done] = x.done; } group upd6<"promotable"=1> { __x0.write_en = 1'd1; diff --git a/tests/frontend/relay/dense.expect b/tests/frontend/relay/dense.expect index 39d9f12c7..5fbd43f9a 100644 --- a/tests/frontend/relay/dense.expect +++ b/tests/frontend/relay/dense.expect @@ -63,19 +63,19 @@ component dense_1x10() -> () { } group let3<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let3[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __k0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let4<"promotable"=2> { y_read0_0.in = y.read_data; - y_read0_0.write_en = y.read_done; + y_read0_0.write_en = y.done; let4[done] = y_read0_0.done; + y.content_en = 1'd1; y.addr1 = __k0.out; y.addr0 = __j0.out; - y.read_en = 1'd1; } group let5<"promotable"=4> { bin_read0_0.in = mult_pipe0.out; @@ -92,20 +92,21 @@ component dense_1x10() -> () { } group let7<"promotable"=2> { red_read00.in = x1.read_data; - red_read00.write_en = x1.read_done; + red_read00.write_en = x1.done; let7[done] = red_read00.done; + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; - x1.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; add0.left = red_read00.out; add0.right = __product_0.out; x1.write_data = add0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __k0.write_en = 1'd1; diff --git a/tests/frontend/relay/duplicate-relay-call.expect b/tests/frontend/relay/duplicate-relay-call.expect index 13b64c01d..3fc72d25b 100644 --- a/tests/frontend/relay/duplicate-relay-call.expect +++ b/tests/frontend/relay/duplicate-relay-call.expect @@ -43,20 +43,21 @@ component negative_2x2() -> () { } group let2<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let2[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; sub0.left = const4.out; sub0.right = x_read0_0.out; x1.write_data = sub0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __j0.write_en = 1'd1; diff --git a/tests/frontend/relay/max_pool2d.expect b/tests/frontend/relay/max_pool2d.expect index 0df1a3990..2b546206e 100644 --- a/tests/frontend/relay/max_pool2d.expect +++ b/tests/frontend/relay/max_pool2d.expect @@ -130,8 +130,9 @@ component max_pool2d_2x2x2x2() -> () { } group let13<"promotable"=2> { __current_0.in = data.read_data; - __current_0.write_en = data.read_done; + __current_0.write_en = data.done; let13[done] = __current_0.done; + data.content_en = 1'd1; data.addr3 = slice7.out; slice7.in = __pool_x_0.out; data.addr2 = slice6.out; @@ -140,7 +141,6 @@ component max_pool2d_2x2x2x2() -> () { slice5.in = __c0.out; data.addr0 = slice4.out; slice4.in = __b0.out; - data.read_en = 1'd1; } group let2<"promotable"=1> { __y0.in = const4.out; @@ -180,8 +180,9 @@ component max_pool2d_2x2x2x2() -> () { } group let8<"promotable"=2> { __max_0.in = data.read_data; - __max_0.write_en = data.read_done; + __max_0.write_en = data.done; let8[done] = __max_0.done; + data.content_en = 1'd1; data.addr3 = slice3.out; slice3.in = __stride_x_0.out; data.addr2 = slice2.out; @@ -190,7 +191,6 @@ component max_pool2d_2x2x2x2() -> () { slice1.in = __c0.out; data.addr0 = slice0.out; slice0.in = __b0.out; - data.read_en = 1'd1; } group let9<"promotable"=1> { __m0.in = const10.out; @@ -217,6 +217,7 @@ component max_pool2d_2x2x2x2() -> () { upd2[done] = __m0.done; } group upd3<"promotable"=1> { + result.content_en = 1'd1; result.addr3 = slice11.out; slice11.in = __x0.out; result.addr2 = slice10.out; @@ -227,7 +228,7 @@ component max_pool2d_2x2x2x2() -> () { slice8.in = __b0.out; result.write_en = 1'd1; result.write_data = __max_0.out; - upd3[done] = result.write_done; + upd3[done] = result.done; } group upd4<"promotable"=1> { __x0.write_en = 1'd1; diff --git a/tests/frontend/relay/negative.expect b/tests/frontend/relay/negative.expect index 5770fa359..105bdf318 100644 --- a/tests/frontend/relay/negative.expect +++ b/tests/frontend/relay/negative.expect @@ -28,18 +28,19 @@ component negative_4() -> () { } group let1<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let1[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr0 = __i0.out; x1.write_en = 1'd1; sub0.left = const2.out; sub0.right = x_read0_0.out; x1.write_data = sub0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __i0.write_en = 1'd1; diff --git a/tests/frontend/relay/relu.expect b/tests/frontend/relay/relu.expect index 3031812ea..c687b4eaa 100644 --- a/tests/frontend/relay/relu.expect +++ b/tests/frontend/relay/relu.expect @@ -79,41 +79,43 @@ component relu_2x4x8x32() -> () { } group let4<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let4[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr3 = __l0.out; x.addr2 = __k0.out; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let5<"promotable"=2> { x_read1_0.in = x.read_data; - x_read1_0.write_en = x.read_done; + x_read1_0.write_en = x.done; let5[done] = x_read1_0.done; + x.content_en = 1'd1; x.addr3 = __l0.out; x.addr2 = __k0.out; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = x_read1_0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { + x1.content_en = 1'd1; x1.addr3 = __l0.out; x1.addr2 = __k0.out; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = fp_const1.out; - upd1[done] = x1.write_done; + upd1[done] = x1.done; } group upd2<"promotable"=1> { __l0.write_en = 1'd1; diff --git a/tests/frontend/relay/reshape.expect b/tests/frontend/relay/reshape.expect index 51e398d78..85acd332c 100644 --- a/tests/frontend/relay/reshape.expect +++ b/tests/frontend/relay/reshape.expect @@ -81,20 +81,21 @@ component reshape_1x8() -> () { } group let5<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let5[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr3 = __l0.out; x.addr2 = __k0.out; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __m_0.out; x1.addr0 = const9.out; x1.write_en = 1'd1; x1.write_data = x_read0_0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __m_0.write_en = 1'd1; diff --git a/tests/frontend/relay/softmax.expect b/tests/frontend/relay/softmax.expect index b66310665..37c9b6872 100644 --- a/tests/frontend/relay/softmax.expect +++ b/tests/frontend/relay/softmax.expect @@ -85,11 +85,11 @@ component softmax_1x10() -> () { } group let0<"promotable"=2> { __max_0.in = x.read_data; - __max_0.write_en = x.read_done; + __max_0.write_en = x.done; let0[done] = __max_0.done; + x.content_en = 1'd1; x.addr1 = const1.out; x.addr0 = const0.out; - x.read_en = 1'd1; } group let1<"promotable"=1> { __i0.in = const2.out; @@ -108,11 +108,11 @@ component softmax_1x10() -> () { } group let12<"promotable"=2> { x_read3_0.in = x.read_data; - x_read3_0.write_en = x.read_done; + x_read3_0.write_en = x.done; let12[done] = x_read3_0.done; + x.content_en = 1'd1; x.addr1 = __k0.out; x.addr0 = __i1.out; - x.read_en = 1'd1; } group let13<"promotable"=1> { __t2_0.in = sub1.out; @@ -141,19 +141,19 @@ component softmax_1x10() -> () { } group let3<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let3[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let4<"promotable"=2> { x_read1_0.in = x.read_data; - x_read1_0.write_en = x.read_done; + x_read1_0.write_en = x.done; let4[done] = x_read1_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let5<"promotable"=1> { __i1.in = const8.out; @@ -172,11 +172,11 @@ component softmax_1x10() -> () { } group let8<"promotable"=2> { x_read2_0.in = x.read_data; - x_read2_0.write_en = x.read_done; + x_read2_0.write_en = x.done; let8[done] = x_read2_0.done; + x.content_en = 1'd1; x.addr1 = __j1.out; x.addr0 = __i1.out; - x.read_en = 1'd1; } group let9<"promotable"=1> { __t0_0.in = sub0.out; @@ -219,11 +219,12 @@ component softmax_1x10() -> () { upd4[done] = __j1.done; } group upd5<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __k0.out; x1.addr0 = __i1.out; x1.write_en = 1'd1; x1.write_data = bin_read0_0.out; - upd5[done] = x1.write_done; + upd5[done] = x1.done; } group upd6<"promotable"=1> { __k0.write_en = 1'd1; diff --git a/tests/frontend/relay/sqrt.expect b/tests/frontend/relay/sqrt.expect index c6b20dcb3..ed5d9a528 100644 --- a/tests/frontend/relay/sqrt.expect +++ b/tests/frontend/relay/sqrt.expect @@ -43,11 +43,11 @@ component sqrt_1x4() -> () { } group let2<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let2[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let3 { __tmp_0.in = sqrt0.out; @@ -55,11 +55,12 @@ component sqrt_1x4() -> () { let3[done] = __tmp_0.done; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; x1.write_data = __tmp_0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __j0.write_en = 1'd1; diff --git a/tests/frontend/relay/tensor_add.expect b/tests/frontend/relay/tensor_add.expect index 6900f3583..f195de4c6 100644 --- a/tests/frontend/relay/tensor_add.expect +++ b/tests/frontend/relay/tensor_add.expect @@ -44,28 +44,29 @@ component add_2x4() -> () { } group let2<"promotable"=2> { x_read0_0.in = x.read_data; - x_read0_0.write_en = x.read_done; + x_read0_0.write_en = x.done; let2[done] = x_read0_0.done; + x.content_en = 1'd1; x.addr1 = __j0.out; x.addr0 = __i0.out; - x.read_en = 1'd1; } group let3<"promotable"=2> { y_read0_0.in = y.read_data; - y_read0_0.write_en = y.read_done; + y_read0_0.write_en = y.done; let3[done] = y_read0_0.done; + y.content_en = 1'd1; y.addr1 = __j0.out; y.addr0 = __i0.out; - y.read_en = 1'd1; } group upd0<"promotable"=1> { + x1.content_en = 1'd1; x1.addr1 = __j0.out; x1.addr0 = __i0.out; x1.write_en = 1'd1; add0.left = x_read0_0.out; add0.right = y_read0_0.out; x1.write_data = add0.out; - upd0[done] = x1.write_done; + upd0[done] = x1.done; } group upd1<"promotable"=1> { __j0.write_en = 1'd1; From 0c0b56d5d5284a603a95652841cb34cbc0b0b992 Mon Sep 17 00:00:00 2001 From: Rachit Nigam Date: Tue, 20 Feb 2024 14:07:22 +0530 Subject: [PATCH 189/189] update ports for SeqMem in calyx-py --- calyx-py/calyx/builder.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/calyx-py/calyx/builder.py b/calyx-py/calyx/builder.py index bbfea8ac7..b716ab6fc 100644 --- a/calyx-py/calyx/builder.py +++ b/calyx-py/calyx/builder.py @@ -599,8 +599,8 @@ def mem_read_seq_d1(self, mem, i, groupname=None): groupname = groupname or f"read_from_{mem.name()}" with self.group(groupname) as read_grp: mem.addr0 = i - mem.read_en = 1 - read_grp.done = mem.read_done + mem.content_en = 1 + read_grp.done = mem.done return read_grp def mem_write_seq_d1_to_reg(self, mem, reg, groupname=None): @@ -625,7 +625,8 @@ def mem_store_seq_d1(self, mem, i, val, groupname=None): mem.addr0 = i mem.write_en = 1 mem.write_data = val - store_grp.done = mem.write_done + mem.content_en = 1 + store_grp.done = mem.done return store_grp def mem_load_to_mem(self, mem, i, ans, j, groupname=None): @@ -1093,7 +1094,7 @@ def infer_width(self, port_name) -> int: return inst.args[2] if port_name == "in": return inst.args[0] - if prim == "seq_mem_d1" and port_name == "read_en": + if prim == "seq_mem_d1" and port_name == "content_en": return 1 if prim in ( "std_mult_pipe",