use std::collections::VecDeque;
use std::collections::HashMap;
enum Token {
Inc,
Dec,
IncPtr,
DecPtr,
StartLoop,
EndLoop,
Input,
Output,
}
impl Token{
fn tokenize(c:char) -> Option<Token>{
match c{
'+' => Some(Token::Inc),
'-' => Some(Token::Dec),
'>' => Some(Token::IncPtr),
'<' => Some(Token::DecPtr),
'[' => Some(Token::StartLoop),
']' => Some(Token::EndLoop),
',' => Some(Token::Input),
'.' => Some(Token::Output),
_ => None,
}
}
fn tokenize_from_array(char_array: Vec<char>)->Vec<Token>{
let mut token_array: Vec<Token> = Vec::new();
for c in char_array{
if let Some(token) = Token::tokenize(c){
token_array.push(token);
}
}
return token_array;
}
fn get_loop_token_ptr(token_array:&Vec<Token>)->
(HashMap<u32,u32>,HashMap<u32,u32>){
let mut start_end_map : HashMap<u32,u32> = HashMap::new();
let mut end_start_map : HashMap<u32,u32> = HashMap::new();
let mut start_ptr_stack : Vec<u32> = Vec::new();
let mut ptr : u32 = 0;
for token in token_array{
match *token{
Token::StartLoop => {
start_ptr_stack.push(ptr);
},
Token::EndLoop => {
if let Some(start_ptr) = start_ptr_stack.pop(){
start_end_map.insert(start_ptr, ptr);
end_start_map.insert(ptr, start_ptr);
}else{
panic!("Too many ']' tokens detected!");
}
},
_ => {}
}
ptr+=1;
}
if ! start_ptr_stack.is_empty(){
panic!("Too many '[' tokens detected!");
}
return (start_end_map, end_start_map);
}
//fn for token '+'.
fn inc_mem_val(memory :&mut Vec<u32>, memory_ptr:u16){
if let Some(val) = memory.get_mut(memory_ptr as usize) {
*val += 1;
}
}
//fn for token '-'.
fn dec_mem_val(memory :&mut Vec<u32>, memory_ptr:u16){
if let Some(val) = memory.get_mut(memory_ptr as usize) {
*val -= 1;
}
}
//fn for token '>'.
fn inc_mem_ptr(memory_ptr:&mut u16){
*memory_ptr +=1;
}
//fn for token '<'.
fn dec_mem_ptr(memory_ptr:&mut u16){
*memory_ptr -=1;
}
//fn for token '['.
fn jump_loop_end_token_if_mem_0(mem_val:Option<&u32>,
loop_start_end_token_ptr_map:&HashMap<u32,u32>,
token_ptr : &mut u32){
if let Some(val) = mem_val{
if *val != 0{return;}
}else{return;}
if let Some(end_ptr) = loop_start_end_token_ptr_map.get(token_ptr){
*token_ptr = *end_ptr;
}else{
panic!("no pair ']' token found.");
}
}
//fn for token ']'.
fn jump_loop_start_token_if_mem_not_0(mem_val:Option<&u32>,
loop_end_start_token_ptr_map:&HashMap<u32,u32>,
token_ptr : &mut u32){
if let Some(val) = mem_val{
if *val == 0{return;}
}else{return;}
if let Some(start_ptr) = loop_end_start_token_ptr_map.get(token_ptr){
*token_ptr = *start_ptr;
}else{
panic!("no pair '[' token found.");
}
}
//fn for token ','.
fn put_char_from_input_to_mem(input_char_array:&mut VecDeque<char>,
memory :&mut Vec<u32>, memory_ptr:u16){
if let Some(val) = memory.get_mut(memory_ptr as usize){
if let Some(c) = input_char_array.pop_front() {
*val = u32::from(c);
}
}
}
//fn for token '.'.
fn join_output_char_to_str(output_char:Option<char>, output_str:&mut String){
if let Some(c) = output_char{
output_str.push(c);
}
}
}
struct BfInterpreter{
token_array : Vec<Token>,
token_ptr : u32,
memory : Vec<u32>,
memory_ptr: u16,
input : VecDeque<char>,
output : String,
loop_start_end_token_ptr_map : HashMap<u32,u32>,
loop_end_start_token_ptr_map : HashMap<u32,u32>,
}
impl BfInterpreter{
fn init(src: &str, input: &str) -> BfInterpreter {
let ta = Token::tokenize_from_array(src.chars().collect::<Vec<char>>());
let (lsetpm,lestpm) = Token::get_loop_token_ptr(&ta);
BfInterpreter{
token_array : ta,
token_ptr : 0,
//Brainf*ck's number of memory cell is defined to be larger than 30,000.
//So this program should reserve size of u16::max_value(),
//which is expected to be 2^16 = 65,536.
memory : vec![0 ; u16::max_value() as usize],
memory_ptr : 0,
input : input.chars().collect(),
output : String::from(""),
loop_start_end_token_ptr_map : lsetpm,
loop_end_start_token_ptr_map : lestpm,
}
}
fn exec(&mut self){
let token_array = &self.token_array;
while let Some(token) = token_array.get(self.token_ptr as usize){
match *token{
Token::Inc => {
Token::inc_mem_val(&mut self.memory, self.memory_ptr);
}
Token::Dec => {
Token::dec_mem_val(&mut self.memory, self.memory_ptr);
}
Token::IncPtr => {
Token::inc_mem_ptr(&mut self.memory_ptr);
}
Token::DecPtr => {
Token::dec_mem_ptr(&mut self.memory_ptr);
}
Token::StartLoop => {
Token::jump_loop_end_token_if_mem_0(
self.memory.get(self.memory_ptr as usize),
&self.loop_start_end_token_ptr_map,
&mut self.token_ptr
);
}
Token::EndLoop => {
Token::jump_loop_start_token_if_mem_not_0(
self.memory.get(self.memory_ptr as usize),
&self.loop_end_start_token_ptr_map,
&mut self.token_ptr
);
}
Token::Input => {
Token::put_char_from_input_to_mem(
&mut self.input,
&mut self.memory, self.memory_ptr
);
}
Token::Output => {
Token::join_output_char_to_str(
self.memory.get(self.memory_ptr as usize)
.and_then(|i| std::char::from_u32(*i)),
&mut self.output);
}
}
self.token_ptr += 1;
}
}
fn output(&self)->&str{
return &self.output;
}
}
fn main (){
let src: &str =
"+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.
------------.<++++++++.--------.+++.------.--------.>+.";
let input : &str = "";
let mut bf = BfInterpreter::init(src, input);
bf.exec();
println!("{}",bf.output());
}
dXNlIHN0ZDo6Y29sbGVjdGlvbnM6OlZlY0RlcXVlOwp1c2Ugc3RkOjpjb2xsZWN0aW9uczo6SGFzaE1hcDsKZW51bSBUb2tlbiB7CiAgICBJbmMsCiAgICBEZWMsCiAgICBJbmNQdHIsCiAgICBEZWNQdHIsCiAgICBTdGFydExvb3AsCiAgICBFbmRMb29wLAogICAgSW5wdXQsCiAgICBPdXRwdXQsCn0KaW1wbCBUb2tlbnsKICAgIGZuIHRva2VuaXplKGM6Y2hhcikgLT4gT3B0aW9uPFRva2VuPnsKICAgICAgICBtYXRjaCBjewogICAgICAgICAgICAnKycgPT4gU29tZShUb2tlbjo6SW5jKSwKICAgICAgICAgICAgJy0nID0+IFNvbWUoVG9rZW46OkRlYyksCiAgICAgICAgICAgICc+JyA9PiBTb21lKFRva2VuOjpJbmNQdHIpLAogICAgICAgICAgICAnPCcgPT4gU29tZShUb2tlbjo6RGVjUHRyKSwKICAgICAgICAgICAgJ1snID0+IFNvbWUoVG9rZW46OlN0YXJ0TG9vcCksCiAgICAgICAgICAgICddJyA9PiBTb21lKFRva2VuOjpFbmRMb29wKSwKICAgICAgICAgICAgJywnID0+IFNvbWUoVG9rZW46OklucHV0KSwKICAgICAgICAgICAgJy4nID0+IFNvbWUoVG9rZW46Ok91dHB1dCksCiAgICAgICAgICAgICBfICA9PiBOb25lLAogICAgICAgIH0KICAgIH0KICAgIGZuIHRva2VuaXplX2Zyb21fYXJyYXkoY2hhcl9hcnJheTogVmVjPGNoYXI+KS0+VmVjPFRva2VuPnsKICAgICAgICBsZXQgbXV0IHRva2VuX2FycmF5OiBWZWM8VG9rZW4+ID0gVmVjOjpuZXcoKTsKICAgICAgICBmb3IgYyBpbiBjaGFyX2FycmF5ewogICAgICAgICAgICBpZiBsZXQgU29tZSh0b2tlbikgPSBUb2tlbjo6dG9rZW5pemUoYyl7CiAgICAgICAgICAgICAgICB0b2tlbl9hcnJheS5wdXNoKHRva2VuKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gdG9rZW5fYXJyYXk7CiAgICB9CiAgICBmbiBnZXRfbG9vcF90b2tlbl9wdHIodG9rZW5fYXJyYXk6JlZlYzxUb2tlbj4pLT4KICAgICAgICAgICAgICAgICAgICAgICAgIChIYXNoTWFwPHUzMix1MzI+LEhhc2hNYXA8dTMyLHUzMj4pewogICAgICAgIGxldCBtdXQgc3RhcnRfZW5kX21hcCA6IEhhc2hNYXA8dTMyLHUzMj4gPSBIYXNoTWFwOjpuZXcoKTsKICAgICAgICBsZXQgbXV0IGVuZF9zdGFydF9tYXAgOiBIYXNoTWFwPHUzMix1MzI+ID0gSGFzaE1hcDo6bmV3KCk7CiAgICAgICAgbGV0IG11dCBzdGFydF9wdHJfc3RhY2sgOiBWZWM8dTMyPiA9IFZlYzo6bmV3KCk7CiAgICAgICAgbGV0IG11dCBwdHIgOiB1MzIgPSAwOwogICAgICAgIGZvciB0b2tlbiBpbiB0b2tlbl9hcnJheXsKICAgICAgICAgICAgbWF0Y2ggKnRva2VuewogICAgICAgICAgICAgICAgVG9rZW46OlN0YXJ0TG9vcCA9PiB7CiAgICAgICAgICAgICAgICAgICAgc3RhcnRfcHRyX3N0YWNrLnB1c2gocHRyKTsKICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICBUb2tlbjo6RW5kTG9vcCA9PiB7CiAgICAgICAgICAgICAgICAgICAgaWYgbGV0IFNvbWUoc3RhcnRfcHRyKSA9IHN0YXJ0X3B0cl9zdGFjay5wb3AoKXsKICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfZW5kX21hcC5pbnNlcnQoc3RhcnRfcHRyLCBwdHIpOwogICAgICAgICAgICAgICAgICAgICAgICBlbmRfc3RhcnRfbWFwLmluc2VydChwdHIsIHN0YXJ0X3B0cik7CiAgICAgICAgICAgICAgICAgICAgfWVsc2V7CiAgICAgICAgICAgICAgICAgICAgICAgIHBhbmljISgiVG9vIG1hbnkgJ10nIHRva2VucyBkZXRlY3RlZCEiKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgXyA9PiB7fQogICAgICAgICAgICB9CiAgICAgICAgICAgIHB0cis9MTsKICAgICAgICB9CiAgICAgICAgaWYgISBzdGFydF9wdHJfc3RhY2suaXNfZW1wdHkoKXsKICAgICAgICAgICAgcGFuaWMhKCJUb28gbWFueSAnWycgdG9rZW5zIGRldGVjdGVkISIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gKHN0YXJ0X2VuZF9tYXAsIGVuZF9zdGFydF9tYXApOwogICAgfQogICAgLy9mbiBmb3IgdG9rZW4gJysnLgogICAgZm4gaW5jX21lbV92YWwobWVtb3J5IDombXV0IFZlYzx1MzI+LCBtZW1vcnlfcHRyOnUxNil7CiAgICAgICAgaWYgbGV0IFNvbWUodmFsKSA9IG1lbW9yeS5nZXRfbXV0KG1lbW9yeV9wdHIgYXMgdXNpemUpIHsKICAgICAgICAgICAgKnZhbCArPSAxOwogICAgICAgIH0KICAgIH0KICAgIC8vZm4gZm9yIHRva2VuICctJy4KICAgIGZuIGRlY19tZW1fdmFsKG1lbW9yeSA6Jm11dCBWZWM8dTMyPiwgbWVtb3J5X3B0cjp1MTYpewogICAgICAgIGlmIGxldCBTb21lKHZhbCkgPSBtZW1vcnkuZ2V0X211dChtZW1vcnlfcHRyIGFzIHVzaXplKSB7CiAgICAgICAgICAgICp2YWwgLT0gMTsKICAgICAgICB9CiAgICB9CiAgICAvL2ZuIGZvciB0b2tlbiAnPicuCiAgICBmbiBpbmNfbWVtX3B0cihtZW1vcnlfcHRyOiZtdXQgdTE2KXsKICAgICAgICAqbWVtb3J5X3B0ciArPTE7CiAgICB9CiAgICAvL2ZuIGZvciB0b2tlbiAnPCcuCiAgICBmbiBkZWNfbWVtX3B0cihtZW1vcnlfcHRyOiZtdXQgdTE2KXsKICAgICAgICAqbWVtb3J5X3B0ciAtPTE7CiAgICB9CiAgICAvL2ZuIGZvciB0b2tlbiAnWycuCiAgICBmbiBqdW1wX2xvb3BfZW5kX3Rva2VuX2lmX21lbV8wKG1lbV92YWw6T3B0aW9uPCZ1MzI+LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF9zdGFydF9lbmRfdG9rZW5fcHRyX21hcDomSGFzaE1hcDx1MzIsdTMyPiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuX3B0ciA6ICZtdXQgdTMyKXsKICAgICAgICBpZiBsZXQgU29tZSh2YWwpID0gbWVtX3ZhbHsKICAgICAgICAgICAgaWYgKnZhbCAhPSAwe3JldHVybjt9CiAgICAgICAgfWVsc2V7cmV0dXJuO30KICAgICAgICBpZiBsZXQgU29tZShlbmRfcHRyKSA9IGxvb3Bfc3RhcnRfZW5kX3Rva2VuX3B0cl9tYXAuZ2V0KHRva2VuX3B0cil7CiAgICAgICAgICAgICp0b2tlbl9wdHIgPSAqZW5kX3B0cjsKICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgcGFuaWMhKCJubyBwYWlyICddJyB0b2tlbiBmb3VuZC4iKTsKICAgICAgICB9CiAgICB9CiAgICAvL2ZuIGZvciB0b2tlbiAnXScuCiAgICBmbiBqdW1wX2xvb3Bfc3RhcnRfdG9rZW5faWZfbWVtX25vdF8wKG1lbV92YWw6T3B0aW9uPCZ1MzI+LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9vcF9lbmRfc3RhcnRfdG9rZW5fcHRyX21hcDomSGFzaE1hcDx1MzIsdTMyPiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuX3B0ciA6ICZtdXQgdTMyKXsKICAgICAgICBpZiBsZXQgU29tZSh2YWwpID0gbWVtX3ZhbHsKICAgICAgICAgICAgaWYgKnZhbCA9PSAwe3JldHVybjt9CiAgICAgICAgfWVsc2V7cmV0dXJuO30KICAgICAgICBpZiBsZXQgU29tZShzdGFydF9wdHIpID0gbG9vcF9lbmRfc3RhcnRfdG9rZW5fcHRyX21hcC5nZXQodG9rZW5fcHRyKXsKICAgICAgICAgICAgKnRva2VuX3B0ciA9ICpzdGFydF9wdHI7CiAgICAgICAgfWVsc2V7CiAgICAgICAgICAgIHBhbmljISgibm8gcGFpciAnWycgdG9rZW4gZm91bmQuIik7CiAgICAgICAgfQogICAgfQogICAgLy9mbiBmb3IgdG9rZW4gJywnLgogICAgZm4gcHV0X2NoYXJfZnJvbV9pbnB1dF90b19tZW0oaW5wdXRfY2hhcl9hcnJheTombXV0IFZlY0RlcXVlPGNoYXI+LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVtb3J5IDombXV0IFZlYzx1MzI+LCBtZW1vcnlfcHRyOnUxNil7CiAgICAgICAgaWYgbGV0IFNvbWUodmFsKSA9IG1lbW9yeS5nZXRfbXV0KG1lbW9yeV9wdHIgYXMgdXNpemUpewogICAgICAgICAgICBpZiBsZXQgU29tZShjKSA9IGlucHV0X2NoYXJfYXJyYXkucG9wX2Zyb250KCkgewogICAgICAgICAgICAgICAgKnZhbCA9IHUzMjo6ZnJvbShjKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIC8vZm4gZm9yIHRva2VuICcuJy4KICAgIGZuIGpvaW5fb3V0cHV0X2NoYXJfdG9fc3RyKG91dHB1dF9jaGFyOk9wdGlvbjxjaGFyPiwgb3V0cHV0X3N0cjombXV0IFN0cmluZyl7CiAgICAgICAgaWYgbGV0IFNvbWUoYykgPSBvdXRwdXRfY2hhcnsKICAgICAgICAgICAgb3V0cHV0X3N0ci5wdXNoKGMpOwogICAgICAgIH0KICAgIH0KfQpzdHJ1Y3QgQmZJbnRlcnByZXRlcnsKICAgIHRva2VuX2FycmF5IDogVmVjPFRva2VuPiwKICAgIHRva2VuX3B0ciA6IHUzMiwKICAgIG1lbW9yeSA6IFZlYzx1MzI+LAogICAgbWVtb3J5X3B0cjogdTE2LAogICAgaW5wdXQgOiBWZWNEZXF1ZTxjaGFyPiwKICAgIG91dHB1dCA6IFN0cmluZywKICAgIGxvb3Bfc3RhcnRfZW5kX3Rva2VuX3B0cl9tYXAgOiBIYXNoTWFwPHUzMix1MzI+LAogICAgbG9vcF9lbmRfc3RhcnRfdG9rZW5fcHRyX21hcCA6IEhhc2hNYXA8dTMyLHUzMj4sCn0KaW1wbCBCZkludGVycHJldGVyewogICAgZm4gaW5pdChzcmM6ICZzdHIsIGlucHV0OiAmc3RyKSAtPiBCZkludGVycHJldGVyIHsKICAgICAgICBsZXQgdGEgPSBUb2tlbjo6dG9rZW5pemVfZnJvbV9hcnJheShzcmMuY2hhcnMoKS5jb2xsZWN0Ojo8VmVjPGNoYXI+PigpKTsKICAgICAgICBsZXQgKGxzZXRwbSxsZXN0cG0pID0gVG9rZW46OmdldF9sb29wX3Rva2VuX3B0cigmdGEpOwogICAgICAgIEJmSW50ZXJwcmV0ZXJ7CiAgICAgICAgICAgIHRva2VuX2FycmF5IDogdGEsCiAgICAgICAgICAgIHRva2VuX3B0ciA6IDAsCiAgICAgICAgICAgIC8vQnJhaW5mKmNrJ3MgbnVtYmVyIG9mIG1lbW9yeSBjZWxsIGlzIGRlZmluZWQgdG8gYmUgbGFyZ2VyIHRoYW4gMzAsMDAwLgogICAgICAgICAgICAvL1NvIHRoaXMgcHJvZ3JhbSBzaG91bGQgcmVzZXJ2ZSBzaXplIG9mIHUxNjo6bWF4X3ZhbHVlKCksIAogICAgICAgICAgICAvL3doaWNoIGlzIGV4cGVjdGVkIHRvIGJlIDJeMTYgPSA2NSw1MzYuCiAgICAgICAgICAgIG1lbW9yeSA6IHZlYyFbMCA7IHUxNjo6bWF4X3ZhbHVlKCkgYXMgdXNpemVdLAogICAgICAgICAgICBtZW1vcnlfcHRyIDogMCwKICAgICAgICAgICAgaW5wdXQgOiBpbnB1dC5jaGFycygpLmNvbGxlY3QoKSwKICAgICAgICAgICAgb3V0cHV0IDogU3RyaW5nOjpmcm9tKCIiKSwKICAgICAgICAgICAgbG9vcF9zdGFydF9lbmRfdG9rZW5fcHRyX21hcCA6IGxzZXRwbSwKICAgICAgICAgICAgbG9vcF9lbmRfc3RhcnRfdG9rZW5fcHRyX21hcCA6IGxlc3RwbSwKICAgICAgICB9CiAgICB9CiAgICBmbiBleGVjKCZtdXQgc2VsZil7CiAgICAgICAgbGV0IHRva2VuX2FycmF5ID0gJnNlbGYudG9rZW5fYXJyYXk7CiAgICAgICAgd2hpbGUgbGV0IFNvbWUodG9rZW4pID0gdG9rZW5fYXJyYXkuZ2V0KHNlbGYudG9rZW5fcHRyIGFzIHVzaXplKXsKICAgICAgICAgICAgbWF0Y2ggKnRva2VuewogICAgICAgICAgICAgICAgVG9rZW46OkluYyA9PiB7CiAgICAgICAgICAgICAgICAgICAgVG9rZW46OmluY19tZW1fdmFsKCZtdXQgc2VsZi5tZW1vcnksIHNlbGYubWVtb3J5X3B0cik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBUb2tlbjo6RGVjID0+IHsKICAgICAgICAgICAgICAgICAgICBUb2tlbjo6ZGVjX21lbV92YWwoJm11dCBzZWxmLm1lbW9yeSwgc2VsZi5tZW1vcnlfcHRyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIFRva2VuOjpJbmNQdHIgPT4gewogICAgICAgICAgICAgICAgICAgIFRva2VuOjppbmNfbWVtX3B0cigmbXV0IHNlbGYubWVtb3J5X3B0cik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBUb2tlbjo6RGVjUHRyID0+IHsKICAgICAgICAgICAgICAgICAgICBUb2tlbjo6ZGVjX21lbV9wdHIoJm11dCBzZWxmLm1lbW9yeV9wdHIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgVG9rZW46OlN0YXJ0TG9vcCA9PiB7CiAgICAgICAgICAgICAgICAgICAgVG9rZW46Omp1bXBfbG9vcF9lbmRfdG9rZW5faWZfbWVtXzAoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYubWVtb3J5LmdldChzZWxmLm1lbW9yeV9wdHIgYXMgdXNpemUpLAogICAgICAgICAgICAgICAgICAgICAgICAmc2VsZi5sb29wX3N0YXJ0X2VuZF90b2tlbl9wdHJfbWFwLAogICAgICAgICAgICAgICAgICAgICAgICAmbXV0IHNlbGYudG9rZW5fcHRyCiAgICAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBUb2tlbjo6RW5kTG9vcCA9PiB7CiAgICAgICAgICAgICAgICAgICAgVG9rZW46Omp1bXBfbG9vcF9zdGFydF90b2tlbl9pZl9tZW1fbm90XzAoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYubWVtb3J5LmdldChzZWxmLm1lbW9yeV9wdHIgYXMgdXNpemUpLAogICAgICAgICAgICAgICAgICAgICAgICAmc2VsZi5sb29wX2VuZF9zdGFydF90b2tlbl9wdHJfbWFwLAogICAgICAgICAgICAgICAgICAgICAgICAmbXV0IHNlbGYudG9rZW5fcHRyCiAgICAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBUb2tlbjo6SW5wdXQgPT4gewogICAgICAgICAgICAgICAgICAgIFRva2VuOjpwdXRfY2hhcl9mcm9tX2lucHV0X3RvX21lbSgKICAgICAgICAgICAgICAgICAgICAgICAgJm11dCBzZWxmLmlucHV0LCAKICAgICAgICAgICAgICAgICAgICAgICAgJm11dCBzZWxmLm1lbW9yeSwgc2VsZi5tZW1vcnlfcHRyCiAgICAgICAgICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBUb2tlbjo6T3V0cHV0ID0+IHsKICAgICAgICAgICAgICAgICAgICBUb2tlbjo6am9pbl9vdXRwdXRfY2hhcl90b19zdHIoCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYubWVtb3J5LmdldChzZWxmLm1lbW9yeV9wdHIgYXMgdXNpemUpCiAgICAgICAgICAgICAgICAgICAgICAgIC5hbmRfdGhlbih8aXwgc3RkOjpjaGFyOjpmcm9tX3UzMigqaSkpLAogICAgICAgICAgICAgICAgICAgICAgICAmbXV0IHNlbGYub3V0cHV0KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBzZWxmLnRva2VuX3B0ciArPSAxOwogICAgICAgIH0KICAgIH0KICAgIGZuIG91dHB1dCgmc2VsZiktPiZzdHJ7CiAgICAgICAgcmV0dXJuICZzZWxmLm91dHB1dDsKICAgIH0KfQpmbiBtYWluICgpewogICAgbGV0IHNyYzogJnN0ciA9IAogICAgICAgICIrKysrKysrKytbPisrKysrKysrPisrKysrKysrKysrPisrKysrPDw8LV0+Lj4rKy4rKysrKysrLi4rKysuPi0uCiAgICAgICAgLS0tLS0tLS0tLS0tLjwrKysrKysrKy4tLS0tLS0tLS4rKysuLS0tLS0tLi0tLS0tLS0tLj4rLiI7CiAgICBsZXQgaW5wdXQgOiAmc3RyID0gIiI7CiAgICBsZXQgbXV0ICBiZiA9IEJmSW50ZXJwcmV0ZXI6OmluaXQoc3JjLCBpbnB1dCk7CiAgICBiZi5leGVjKCk7CiAgICBwcmludGxuISgie30iLGJmLm91dHB1dCgpKTsKfQ==