Last updated: 2017-12-10

Code version: 32d98f0

See more puzzles

Advent of Code

Session information

sessionInfo()
R version 3.4.2 (2017-09-28)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Sierra 10.12.6

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] rlist_0.4.6.1   jsonlite_1.5    bindrcpp_0.2    aocodeR_0.1.1   testthat_1.0.2 
 [6] forcats_0.2.0   stringr_1.2.0   dplyr_0.7.4     purrr_0.2.4     readr_1.1.1    
[11] tidyr_0.7.2     tibble_1.3.4    ggplot2_2.2.1   tidyverse_1.2.1

loaded via a namespace (and not attached):
 [1] reshape2_1.4.2      haven_1.1.0         lattice_0.20-35     colorspace_1.3-2   
 [5] htmltools_0.3.6     base64enc_0.1-3     yaml_2.1.15         rlang_0.1.4        
 [9] foreign_0.8-69      glue_1.2.0          modelr_0.1.1        readxl_1.0.0       
[13] bindr_0.1           plyr_1.8.4          munsell_0.4.3       gtable_0.2.0       
[17] cellranger_1.1.0    rvest_0.3.2         evaluate_0.10.1     psych_1.7.8        
[21] knitr_1.17          curl_3.0            parallel_3.4.2      broom_0.4.2        
[25] Rcpp_0.12.14        scales_0.5.0        backports_1.1.1     mnormt_1.5-5       
[29] digest_0.6.12       hms_0.4.0           stringi_1.1.6       grid_3.4.2         
[33] rprojroot_1.2       cli_1.0.0           tools_3.4.2         magrittr_1.5       
[37] lazyeval_0.2.1      crayon_1.3.4        pkgconfig_2.0.1     data.table_1.10.4-3
[41] rsconnect_0.8.5     xml2_1.1.1          lubridate_1.7.1     assertthat_0.2.0   
[45] rmarkdown_1.8       httr_1.3.1          rstudioapi_0.7      R6_2.2.2           
[49] nlme_3.1-131        compiler_3.4.2      git2r_0.19.0       

Brief

A large stream blocks your path. According to the locals, it’s not safe to cross the stream at the moment because it’s full of garbage. You look down at the stream; rather than water, you discover that it’s a stream of characters.

You sit for a while and record part of the stream (your puzzle input). The characters represent groups - sequences that begin with { and end with }. Within a group, there are zero or more other things, separated by commas: either another group or garbage. Since groups can contain other groups, a } only closes the most-recently-opened unclosed group - that is, they are nestable. Your puzzle input represents a single, large group which itself contains many smaller ones.

Sometimes, instead of a group, you will find garbage. Garbage begins with < and ends with >. Between those angle brackets, almost any character can appear, including { and }. Within garbage, < has no special meaning.

In a futile attempt to clean up the garbage, some program has canceled some of the characters within it using !: inside garbage, any character that comes after ! should be ignored, including <, >, and even another !.

You don’t see any characters that deviate from these rules. Outside garbage, you only find well-formed groups, and garbage always terminates according to the rules above.

Let’s go

Today there was quite a bit of REGEX

Packages & functions

library(tidyverse)
library(testthat)
library(aocodeR)

Input

input <- aoc_get_input(day = 9, cookie_path = paste0(rprojroot::find_rstudio_root_file(),
                                                 "/secrets/session_cookie.txt")) 

Functions

grp_chr_sets <- function (input){
    input %>% gsub("!.", "", .)  %>% gsub("(<[^>]*>,?)", "", .)
}
score_sets <- function(input) {
    chr_sets <-  input %>% grp_chr_sets
    sets <- chr_sets %>% gregexpr("\\}", .)
    score <- function(i, chr_sets){
        substr(chr_sets,1, i -1) %>% str_count("\\{") - 
            substr(chr_sets,1, i -1) %>% str_count("\\}")
    }
    sets %>% unlist %>% map_int(~score(.x, chr_sets)) %>% sum
}
count_junk <- function(input){
    stream <- input %>% gsub("!.", "", .) %>% strsplit(.,split ="") %>% unlist
    score <- 0
    record <- F
    for(i in 1:length(stream)){
        c <- stream[i]
        if(c == "<"){if(record){
            score <- score + 1
            next
        }else{
            record <- TRUE}
            next}
        
        if(record){
            if(stream[i] != ">"){
                score <- score + 1}else{
                    record <- F
                }}
    }
    score
} 

Test

# test ! removing gsub
expect_equal("<!!e!!>>" %>% gsub("(!.)", "", .) , "<e>>")
expect_equal("<!!!!>>" %>% gsub("!.", "", .) , "<>>")
expect_equal("<!!!>>" %>% gsub("!.", "", .) , "<>")
expect_equal("<!!!>>" %>% gsub("!.", "", .) , "<>")
# test garbage cleaning gsub
expect_equal("{{<a>},{<a>},{<a>},{<a>}}" %>% gsub("(<[^>]*>)", "", .) , "{{},{},{},{}}")
expect_equal("{<{},{},{{}}>}" %>% gsub("(<[^>]*>)", "", .) , "{}")
# test group 
expect_equal("<{o'i!a,<{i<a>" %>% grp_chr_sets, "")
expect_equal("{<{},{},{{}}>}" %>% grp_chr_sets , "{}")
expect_equal("{{<!>},{<!>},{<!>},{<a>}}" %>% grp_chr_sets , "{{}}")
expect_equal("{<a>,<a>,<a>,<a>}" %>% grp_chr_sets , "{}")
expect_equal("{{{},{},{{}}}}"  %>% score_sets, 16)
expect_equal("{{<ab>},{<ab>},{<ab>},{<ab>}}"  %>% score_sets, 9)
expect_equal("{{<!!>},{<!!>},{<!!>},{<!!>}}"  %>% score_sets, 9)
expect_equal("{{<a!>},{<a!>},{<a!>},{<ab>}}"  %>% score_sets, 3)
expect_equal("<{o'i!a,<{i<a>" %>% count_junk, 10)
expect_equal("<!!>" %>% count_junk, 0)
expect_equal("<random characters>" %>% count_junk, 17)
expect_equal("<!!!>>" %>% count_junk, 0)
expect_equal("<{!>}>" %>% count_junk, 2)
expect_equal("<{!><}>" %>% count_junk, 3)
expect_equal("{<{o'i!a,<{i<a>, <{!><}>}" %>% count_junk, 13)

deploy

input %>% score_sets
[1] 14204

Success!



—- Part 2 —-

Brief

Now, you’re ready to remove the garbage.

To prove you’ve removed it, you need to count all of the characters within the garbage. The leading and trailing < and > don’t count, nor do any canceled characters or the ! doing the canceling.

<>, 0 characters. <random characters>, 17 characters. <<<<>, 3 characters. <{!>}>, 2 characters. <!!>, 0 characters. <!!!>>, 0 characters. <{o"i!a,<{i<a>, 10 characters.

How many non-canceled characters are within the garbage in your puzzle input?

Let’s go

This one really stumped me in parts because I think I was continuously trying to use the wrong tool.

I also managed to develop many solutions that would pass the tests but the result was wrong. I finally gave in an wrote an element by element recording algorithm is 20 mins…and it worked. I don’t why I kept thinking there’s some better way than building this sort of algorithm. Alas in the end, the simplest approach worked just fine!

Anyroad, I did learn a lot more about regex, the different flavours and thinking about how to extract set nestedness information from a series of curly braces

Test

expect_equal("<{o'i!a,<{i<a>" %>% count_junk, 10)
expect_equal("<!!>" %>% count_junk, 0)
expect_equal("<random characters>" %>% count_junk, 17)
expect_equal("<!!!>>" %>% count_junk, 0)
expect_equal("<{!>}>" %>% count_junk, 2)
expect_equal("<{!><}>" %>% count_junk, 3)
expect_equal("{<{o'i!a,<{i<a>, <{!><}>}" %>% count_junk, 13)

deploy

input %>% count_junk
[1] 6622

Success!



template based on the workflowr standalone template

LS0tCnRpdGxlOiAiLS0tIERheSA5OiBTdHJlYW0gUHJvY2Vzc2luZyAtLS0iCmF1dGhvcjogImFubmFrcnlzdGFsbGkiCmRhdGU6IDIwMTctMTItMDgKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Iga25pdHItb3B0cy1jaHVuaywgaW5jbHVkZT1GQUxTRX0KIyBVcGRhdGUga25pdHIgY2h1bmsgb3B0aW9ucwojIGh0dHBzOi8veWlodWkubmFtZS9rbml0ci9vcHRpb25zLyNjaHVuay1vcHRpb25zCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb21tZW50ID0gTkEsCiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgdGlkeSA9IEZBTFNFLAogIGZpZy5wYXRoID0gcGFzdGUwKCJmaWd1cmUvIiwga25pdHI6OmN1cnJlbnRfaW5wdXQoKSwgIi8iKQopCmBgYAoKYGBge3IgbGFzdC11cGRhdGVkLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KIyBJbnNlcnQgdGhlIGRhdGUgdGhlIGZpbGUgd2FzIGxhc3QgdXBkYXRlZApjYXQoc3ByaW50ZigiKipMYXN0IHVwZGF0ZWQ6KiogJXMiLCBTeXMuRGF0ZSgpKSkKYGBgCgpgYGB7ciBjb2RlLXZlcnNpb24sIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQojIEluc2VydCB0aGUgY29kZSB2ZXJzaW9uIChHaXQgY29tbWl0IFNIQTEpIGlmIEdpdCByZXBvc2l0b3J5IGV4aXN0cyBhbmQgUgojIHBhY2thZ2UgZ2l0MnIgaXMgaW5zdGFsbGVkCmlmKHJlcXVpcmVOYW1lc3BhY2UoImdpdDJyIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgaWYoZ2l0MnI6OmluX3JlcG9zaXRvcnkoKSkgewogICAgY29kZV92ZXJzaW9uIDwtIHN1YnN0cihnaXQycjo6Y29tbWl0cygpW1sxXV1Ac2hhLCAxLCA3KQogIH0gZWxzZSB7CiAgICBjb2RlX3ZlcnNpb24gPC0gIlVuYXZhaWxhYmxlLiBJbml0aWFsaXplIEdpdCByZXBvc2l0b3J5IHRvIGVuYWJsZS4iCiAgfQp9IGVsc2UgewogIGNvZGVfdmVyc2lvbiA8LSAiVW5hdmFpbGFibGUuIEluc3RhbGwgZ2l0MnIgcGFja2FnZSB0byBlbmFibGUuIgp9CmNhdChzcHJpbnRmKCIqKkNvZGUgdmVyc2lvbjoqKiAlcyIsIGNvZGVfdmVyc2lvbikpCnJtKGNvZGVfdmVyc2lvbikKYGBgCgoKPiBbKioqU2VlIG1vcmUgcHV6emxlcyoqKl0oaHR0cDovL2FubmFrcnlzdGFsbGkubWUvYWR2ZW50X29mX2NvZGUvKQoKWyoqQWR2ZW50IG9mIENvZGUqKl0oaHR0cHM6Ly9hZHZlbnRvZmNvZGUuY29tLzIwMTcvKQoKCiMjIFNlc3Npb24gaW5mb3JtYXRpb24KCjwhLS0gSW5zZXJ0IHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGludG8gdGhlIGRvY3VtZW50IC0tPgpgYGB7ciBzZXNzaW9uLWluZm99CnNlc3Npb25JbmZvKCkKYGBgCgoKIyMgQnJpZWYKCjwhLS0gSW5zZXJ0IFBhcnQgMSBvZiB0aGUgcHV6emxlIGJyaWVmIGhlcmUgLS0+CgpBIGxhcmdlIHN0cmVhbSBibG9ja3MgeW91ciBwYXRoLiBBY2NvcmRpbmcgdG8gdGhlIGxvY2FscywgaXQncyBub3Qgc2FmZSB0byBjcm9zcyB0aGUgc3RyZWFtIGF0IHRoZSBtb21lbnQgYmVjYXVzZSBpdCdzIGZ1bGwgb2YgZ2FyYmFnZS4gWW91IGxvb2sgZG93biBhdCB0aGUgc3RyZWFtOyByYXRoZXIgdGhhbiB3YXRlciwgeW91IGRpc2NvdmVyIHRoYXQgaXQncyBhIHN0cmVhbSBvZiBjaGFyYWN0ZXJzLgoKWW91IHNpdCBmb3IgYSB3aGlsZSBhbmQgcmVjb3JkIHBhcnQgb2YgdGhlIHN0cmVhbSAoeW91ciBwdXp6bGUgaW5wdXQpLiBUaGUgY2hhcmFjdGVycyByZXByZXNlbnQgZ3JvdXBzIC0gc2VxdWVuY2VzIHRoYXQgYmVnaW4gd2l0aCBge2AgYW5kIGVuZCB3aXRoIGB9YC4gKipXaXRoaW4gYSBncm91cCwgdGhlcmUgYXJlIHplcm8gb3IgbW9yZSBvdGhlciB0aGluZ3MsIHNlcGFyYXRlZCBieSBjb21tYXM6KiogZWl0aGVyIGFub3RoZXIgZ3JvdXAgb3IgZ2FyYmFnZS4gU2luY2UgZ3JvdXBzIGNhbiBjb250YWluIG90aGVyIGdyb3VwcywgYSAqKmB9YCBvbmx5IGNsb3NlcyB0aGUgbW9zdC1yZWNlbnRseS1vcGVuZWQgdW5jbG9zZWQgZ3JvdXAqKiAtIHRoYXQgaXMsIHRoZXkgYXJlICoqbmVzdGFibGUqKi4gWW91ciBwdXp6bGUgaW5wdXQgcmVwcmVzZW50cyBhIHNpbmdsZSwgbGFyZ2UgZ3JvdXAgd2hpY2ggaXRzZWxmIGNvbnRhaW5zIG1hbnkgc21hbGxlciBvbmVzLgoKU29tZXRpbWVzLCBpbnN0ZWFkIG9mIGEgZ3JvdXAsIHlvdSB3aWxsIGZpbmQgZ2FyYmFnZS4gKipHYXJiYWdlIGJlZ2lucyB3aXRoIGA8YCBhbmQgZW5kcyB3aXRoIGA+YCoqLiBCZXR3ZWVuIHRob3NlIGFuZ2xlIGJyYWNrZXRzLCBhbG1vc3QgYW55IGNoYXJhY3RlciBjYW4gYXBwZWFyLCBpbmNsdWRpbmcgYHtgIGFuZCBgfWAuICpXaXRoaW4gZ2FyYmFnZSwgPCBoYXMgbm8gc3BlY2lhbCBtZWFuaW5nLioKCkluIGEgZnV0aWxlIGF0dGVtcHQgdG8gY2xlYW4gdXAgdGhlIGdhcmJhZ2UsIHNvbWUgcHJvZ3JhbSBoYXMgY2FuY2VsZWQgc29tZSBvZiB0aGUgY2hhcmFjdGVycyB3aXRoaW4gaXQgdXNpbmcgITogaW5zaWRlIGdhcmJhZ2UsICoqYW55IGNoYXJhY3RlciB0aGF0IGNvbWVzIGFmdGVyICEqKiBzaG91bGQgYmUgaWdub3JlZCwgaW5jbHVkaW5nIDwsID4sIGFuZCBldmVuIGFub3RoZXIgIS4KCllvdSBkb24ndCBzZWUgYW55IGNoYXJhY3RlcnMgdGhhdCBkZXZpYXRlIGZyb20gdGhlc2UgcnVsZXMuIE91dHNpZGUgZ2FyYmFnZSwgeW91IG9ubHkgZmluZCB3ZWxsLWZvcm1lZCBncm91cHMsIGFuZCBnYXJiYWdlIGFsd2F5cyB0ZXJtaW5hdGVzIGFjY29yZGluZyB0byB0aGUgcnVsZXMgYWJvdmUuCgoKIyBMZXQncyBnbwoKVG9kYXkgdGhlcmUgd2FzIHF1aXRlIGEgYml0IG9mICoqYFJFR0VYYCoqCgohW10oaHR0cDovL21lZGlhLnB5d2Vlay5vcmcvZGwvNy9SZWdFeEV4cHJlc3MvdHJhaW5fYW5pbTIuZ2lmKQoKIyMjIFBhY2thZ2VzICYgZnVuY3Rpb25zCmBgYHtyLCBtZXNzYWdlID0gRn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGVzdHRoYXQpCmxpYnJhcnkoYW9jb2RlUikKYGBgCgoKIyMgSW5wdXQKCjwhLS0gU3VwcGx5IGRheS4gY29va2llX3BhdGggZGVmYXVsdHMgdG8gcGF0aCBpbiBteSBwcm9qZWN0IC0tPgpgYGB7cn0KaW5wdXQgPC0gYW9jX2dldF9pbnB1dChkYXkgPSA5LCBjb29raWVfcGF0aCA9IHBhc3RlMChycHJvanJvb3Q6OmZpbmRfcnN0dWRpb19yb290X2ZpbGUoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIvc2VjcmV0cy9zZXNzaW9uX2Nvb2tpZS50eHQiKSkgCgpgYGAKCiMjIEZ1bmN0aW9ucwpgYGB7cn0KZ3JwX2Nocl9zZXRzIDwtIGZ1bmN0aW9uIChpbnB1dCl7CiAgICBpbnB1dCAlPiUgZ3N1YigiIS4iLCAiIiwgLikgICU+JSBnc3ViKCIoPFtePl0qPiw/KSIsICIiLCAuKQp9CgpzY29yZV9zZXRzIDwtIGZ1bmN0aW9uKGlucHV0KSB7CiAgICBjaHJfc2V0cyA8LSAgaW5wdXQgJT4lIGdycF9jaHJfc2V0cwogICAgc2V0cyA8LSBjaHJfc2V0cyAlPiUgZ3JlZ2V4cHIoIlxcfSIsIC4pCiAgICBzY29yZSA8LSBmdW5jdGlvbihpLCBjaHJfc2V0cyl7CiAgICAgICAgc3Vic3RyKGNocl9zZXRzLDEsIGkgLTEpICU+JSBzdHJfY291bnQoIlxceyIpIC0gCiAgICAgICAgICAgIHN1YnN0cihjaHJfc2V0cywxLCBpIC0xKSAlPiUgc3RyX2NvdW50KCJcXH0iKQogICAgfQogICAgc2V0cyAlPiUgdW5saXN0ICU+JSBtYXBfaW50KH5zY29yZSgueCwgY2hyX3NldHMpKSAlPiUgc3VtCn0KYGBgCgoKCgoKYGBge3J9CmNvdW50X2p1bmsgPC0gZnVuY3Rpb24oaW5wdXQpewogICAgc3RyZWFtIDwtIGlucHV0ICU+JSBnc3ViKCIhLiIsICIiLCAuKSAlPiUgc3Ryc3BsaXQoLixzcGxpdCA9IiIpICU+JSB1bmxpc3QKICAgIHNjb3JlIDwtIDAKICAgIHJlY29yZCA8LSBGCiAgICBmb3IoaSBpbiAxOmxlbmd0aChzdHJlYW0pKXsKICAgICAgICBjIDwtIHN0cmVhbVtpXQogICAgICAgIGlmKGMgPT0gIjwiKXtpZihyZWNvcmQpewogICAgICAgICAgICBzY29yZSA8LSBzY29yZSArIDEKICAgICAgICAgICAgbmV4dAogICAgICAgIH1lbHNlewogICAgICAgICAgICByZWNvcmQgPC0gVFJVRX0KICAgICAgICAgICAgbmV4dH0KICAgICAgICAKICAgICAgICBpZihyZWNvcmQpewogICAgICAgICAgICBpZihzdHJlYW1baV0gIT0gIj4iKXsKICAgICAgICAgICAgICAgIHNjb3JlIDwtIHNjb3JlICsgMX1lbHNlewogICAgICAgICAgICAgICAgICAgIHJlY29yZCA8LSBGCiAgICAgICAgICAgICAgICB9fQogICAgfQogICAgc2NvcmUKfSAKYGBgCgoKIyMgVGVzdApgYGB7cn0KIyB0ZXN0ICEgcmVtb3ZpbmcgZ3N1YgpleHBlY3RfZXF1YWwoIjwhIWUhIT4+IiAlPiUgZ3N1YigiKCEuKSIsICIiLCAuKSAsICI8ZT4+IikKZXhwZWN0X2VxdWFsKCI8ISEhIT4+IiAlPiUgZ3N1YigiIS4iLCAiIiwgLikgLCAiPD4+IikKZXhwZWN0X2VxdWFsKCI8ISEhPj4iICU+JSBnc3ViKCIhLiIsICIiLCAuKSAsICI8PiIpCmV4cGVjdF9lcXVhbCgiPCEhIT4+IiAlPiUgZ3N1YigiIS4iLCAiIiwgLikgLCAiPD4iKQoKIyB0ZXN0IGdhcmJhZ2UgY2xlYW5pbmcgZ3N1YgpleHBlY3RfZXF1YWwoInt7PGE+fSx7PGE+fSx7PGE+fSx7PGE+fX0iICU+JSBnc3ViKCIoPFtePl0qPikiLCAiIiwgLikgLCAie3t9LHt9LHt9LHt9fSIpCmV4cGVjdF9lcXVhbCgiezx7fSx7fSx7e319Pn0iICU+JSBnc3ViKCIoPFtePl0qPikiLCAiIiwgLikgLCAie30iKQoKIyB0ZXN0IGdyb3VwIApleHBlY3RfZXF1YWwoIjx7bydpIWEsPHtpPGE+IiAlPiUgZ3JwX2Nocl9zZXRzLCAiIikKZXhwZWN0X2VxdWFsKCJ7PHt9LHt9LHt7fX0+fSIgJT4lIGdycF9jaHJfc2V0cyAsICJ7fSIpCmV4cGVjdF9lcXVhbCgie3s8IT59LHs8IT59LHs8IT59LHs8YT59fSIgJT4lIGdycF9jaHJfc2V0cyAsICJ7e319IikKZXhwZWN0X2VxdWFsKCJ7PGE+LDxhPiw8YT4sPGE+fSIgJT4lIGdycF9jaHJfc2V0cyAsICJ7fSIpCgpleHBlY3RfZXF1YWwoInt7e30se30se3t9fX19IiAgJT4lIHNjb3JlX3NldHMsIDE2KQpleHBlY3RfZXF1YWwoInt7PGFiPn0sezxhYj59LHs8YWI+fSx7PGFiPn19IiAgJT4lIHNjb3JlX3NldHMsIDkpCmV4cGVjdF9lcXVhbCgie3s8ISE+fSx7PCEhPn0sezwhIT59LHs8ISE+fX0iICAlPiUgc2NvcmVfc2V0cywgOSkKZXhwZWN0X2VxdWFsKCJ7ezxhIT59LHs8YSE+fSx7PGEhPn0sezxhYj59fSIgICU+JSBzY29yZV9zZXRzLCAzKQoKYGBgCgojIyBkZXBsb3kKCmBgYHtyfQppbnB1dCAlPiUgc2NvcmVfc2V0cwpgYGAKCgojIyBTdWNjZXNzIQoKIVtdKC4uL3NjcmVlbnNob3RzL0RheTFfMS5wbmcpCgo8YnI+CgoqKioKCiMgLS0tLSBQYXJ0IDIgLS0tLQoKCiMjIEJyaWVmCjwhLS0gSW5zZXJ0IFBhcnQgMiBvZiB0aGUgcHV6emxlIGJyaWVmIGhlcmUgLS0+CgoKTm93LCB5b3UncmUgcmVhZHkgdG8gcmVtb3ZlIHRoZSBnYXJiYWdlLgoKVG8gcHJvdmUgeW91J3ZlIHJlbW92ZWQgaXQsIHlvdSBuZWVkIHRvIGNvdW50IGFsbCBvZiB0aGUgY2hhcmFjdGVycyB3aXRoaW4gdGhlIGdhcmJhZ2UuIFRoZSBsZWFkaW5nIGFuZCB0cmFpbGluZyA8IGFuZCA+IGRvbid0IGNvdW50LCBub3IgZG8gYW55IGNhbmNlbGVkIGNoYXJhY3RlcnMgb3IgdGhlICEgZG9pbmcgdGhlIGNhbmNlbGluZy4KCmA8PmAsIDAgY2hhcmFjdGVycy4KYDxyYW5kb20gY2hhcmFjdGVycz5gLCAxNyBjaGFyYWN0ZXJzLgpgPDw8PD5gLCAzIGNoYXJhY3RlcnMuCmA8eyE+fT5gLCAyIGNoYXJhY3RlcnMuCmA8ISE+YCwgMCBjaGFyYWN0ZXJzLgpgPCEhIT4+YCwgMCBjaGFyYWN0ZXJzLgpgPHtvImkhYSw8e2k8YT5gLCAxMCBjaGFyYWN0ZXJzLgoKSG93IG1hbnkgbm9uLWNhbmNlbGVkIGNoYXJhY3RlcnMgYXJlIHdpdGhpbiB0aGUgZ2FyYmFnZSBpbiB5b3VyIHB1enpsZSBpbnB1dD8KCiMgTGV0J3MgZ28KCgpUaGlzIG9uZSByZWFsbHkgc3R1bXBlZCBtZSBpbiBwYXJ0cyBiZWNhdXNlIEkgdGhpbmsgSSB3YXMgY29udGludW91c2x5IHRyeWluZyB0byB1c2UgdGhlIHdyb25nIHRvb2wuIAoKLSBJIHRyaWVkIHJlZ2V4Ci0gdHJ5aW5nIHRvIHdvcmsgd2l0aCBhIG5lc3RlZCBsaXN0Ci0gdHVybiBpdCBpbnRvIGpzb24gYW5kIHRyeWluZyB0byBleHRyYWN0IGluZm9ybWF0aW9uIGFib3V0IHRoZSBzdWJzdHJ1Y3R1cmUuIAoKSSBhbHNvIG1hbmFnZWQgdG8gZGV2ZWxvcCBtYW55IHNvbHV0aW9ucyB0aGF0IHdvdWxkIHBhc3MgdGhlIHRlc3RzIGJ1dCB0aGUgcmVzdWx0IHdhcyB3cm9uZy4gSSBmaW5hbGx5IGdhdmUgaW4gYW4gd3JvdGUgYW4gZWxlbWVudCBieSBlbGVtZW50IHJlY29yZGluZyBhbGdvcml0aG0gaXMgMjAgbWlucy4uLmFuZCBpdCB3b3JrZWQuIEkgZG9uJ3Qgd2h5IEkga2VwdCB0aGlua2luZyB0aGVyZSdzIHNvbWUgYmV0dGVyIHdheSB0aGFuIGJ1aWxkaW5nIHRoaXMgc29ydCBvZiBhbGdvcml0aG0uIEFsYXMgaW4gdGhlIGVuZCwgdGhlIHNpbXBsZXN0IGFwcHJvYWNoIHdvcmtlZCBqdXN0IGZpbmUhCgpBbnlyb2FkLCBJIGRpZCBsZWFybiBhIGxvdCBtb3JlIGFib3V0IHJlZ2V4LCB0aGUgZGlmZmVyZW50IGZsYXZvdXJzIGFuZCB0aGlua2luZyBhYm91dCBob3cgdG8gZXh0cmFjdCBzZXQgbmVzdGVkbmVzcyBpbmZvcm1hdGlvbiBmcm9tIGEgc2VyaWVzIG9mIGN1cmx5IGJyYWNlcwoKCiMjIFRlc3QKYGBge3J9CmV4cGVjdF9lcXVhbCgiPHtvJ2khYSw8e2k8YT4iICU+JSBjb3VudF9qdW5rLCAxMCkKZXhwZWN0X2VxdWFsKCI8ISE+IiAlPiUgY291bnRfanVuaywgMCkKZXhwZWN0X2VxdWFsKCI8cmFuZG9tIGNoYXJhY3RlcnM+IiAlPiUgY291bnRfanVuaywgMTcpCmV4cGVjdF9lcXVhbCgiPCEhIT4+IiAlPiUgY291bnRfanVuaywgMCkKZXhwZWN0X2VxdWFsKCI8eyE+fT4iICU+JSBjb3VudF9qdW5rLCAyKQpleHBlY3RfZXF1YWwoIjx7IT48fT4iICU+JSBjb3VudF9qdW5rLCAzKQpleHBlY3RfZXF1YWwoIns8e28naSFhLDx7aTxhPiwgPHshPjx9Pn0iICU+JSBjb3VudF9qdW5rLCAxMykKYGBgCgojIyBkZXBsb3kKCmBgYHtyfQppbnB1dCAlPiUgY291bnRfanVuawpgYGAKCiMjIFN1Y2Nlc3MhCgohW10oLi4vc2NyZWVuc2hvdHMvRGF5MV8yLnBuZykKCjxicj4KCioqKgoKdGVtcGxhdGUgYmFzZWQgb24gdGhlIFt3b3JrZmxvd3JdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZGJsaXNjaGFrL3dvcmtmbG93cikgc3RhbmRhbG9uZSB0ZW1wbGF0ZQo=