Introduction
Slot machines are a popular form of gambling in casinos, offering
players a chance to win prizes by matching symbols on a spinning reel.
These machines are known for their low payout rates, which contribute
significantly to casino profits. In this project, you will create a
virtual slot machine based on real-life Video Lottery Terminals (VLTs)
from Manitoba, Canada, which were involved in a scandal in the 1990s.
The goal is to understand the payout rates of these machines through
programming and simulations.
Slot Machine Basics:
A slot machine consists of a spinning reel with various
symbols.
Players insert a small fee and pull a lever to spin the
reel.
The machine generates a random combination of symbols.
If the symbols match a winning pattern, the player wins a
prize.
Low Payout Rates:
Slot machines are designed to have low payout rates, typically
around 90-95 cents for every dollar spent.
This means casinos keep a significant portion of the money
wagered on these machines.
Despite this, slot machines remain extremely popular among
gamblers.
Manitoba VLT Scandal:
In the 1990s, VLTs in Manitoba were at the center of a scandal
due to their low payout rates.
These VLTs were found to have even lower payout rates than
typical slot machines, leading to increased profits for the casino and
reduced winnings for players.
Your task is to recreate these VLTs in a virtual environment to
investigate their payout rates.
Project Objectives:
Build a Virtual Slot Machine: Create a program
that simulates the behavior of the Manitoba VLTs, including spinning the
reel and determining winning combinations.
Investigate Payout Rates: Calculate and analyze
the payout rates of these VLTs by running simulations and comparing them
to the advertised rates.
Understand the Scandal: Through your
simulations, uncover the reasons behind the scandal and the impact of
low payout rates on players.
Steps to Recreate the VLTs:
Data Collection: Gather information about the
symbols on the VLT reels and their probabilities of appearing.
Random Number Generation: Implement a random
number generator to simulate the spinning of the reels.
Symbol Selection: Use the generated random
numbers to select symbols for each reel position.
Winning Combinations: Define the winning
patterns and calculate the probability of hitting each
combination.
Payout Calculation: Determine the payout for
each winning combination and the overall payout rate.
Simulations: Run multiple simulations to
validate the calculated payout rates and analyze the results.
Expected Outcomes:
A fully functional virtual slot machine that mimics the behavior
of the Manitoba VLTs.
Insights into the low payout rates of these machines and their
impact on players’ winnings.
A deeper understanding of the Manitoba VLT scandal and the
importance of payout rates in gambling.
In this chapter, you will build a real, working slot machine that you
can play by running an R function. When you’re finished, you’ll be able
to play it like this:
play()
## 0 0 DD
## $0
play()
## 7 7 7
## $80
The play
function will need to do two things. First, it
will need to randomly generate three symbols; and, second, it will need
to calculate a prize based on those symbols.
The first step is easy to simulate. You can randomly generate three
symbols with the sample
function—just like you randomly
“rolled” two dice in [Project 1: Weighted Dice]. The following function
generates three symbols from a group of common slot machine symbols:
diamonds (DD
), sevens (7
), triple bars
(BBB
), double bars (BB
), single bars
(B
), cherries (C
), and zeroes
(0
). The symbols are selected randomly, and each symbol
appears with a different probability:
get_symbols <- function() {
wheel <- c("DD", "7", "BBB", "BB", "B", "C", "0")
sample(wheel, size = 3, replace = TRUE,
prob = c(0.03, 0.03, 0.06, 0.1, 0.25, 0.01, 0.52))
}
You can use get_symbols
to generate the symbols used in
your slot machine:
get_symbols()
## "BBB" "0" "C"
get_symbols()
## "0" "0" "0"
get_symbols()
## "7" "0" "B"
get_symbols
uses the probabilities observed in a group
of video lottery terminals from Manitoba, Canada. These slot machines
became briefly controversial in the 1990s, when a reporter decided to
test their payout rate. The machines appeared to pay out only 40 cents
on the dollar, even though the manufacturer claimed they would pay out
92 cents on the dollar. The original data collected on the machines and
a description of the controversy is available online in a journal article by W. John Braun.
The controversy died down when additional testing showed that the
manufacturer was correct.
The Manitoba slot machines use the complicated payout scheme shown in
Table @ref(tab:prizes). A player will win a prize if he gets:
- Three of the same type of symbol (except for three zeroes)
- Three bars (of mixed variety)
- One or more cherries
Otherwise, the player receives no prize.
The monetary value of the prize is determined by the exact
combination of symbols and is further modified by the presence of
diamonds. Diamonds are treated like “wild cards,” which means they can
be considered any other symbol if it would increase a player’s prize.
For example, a player who rolls 7
7
DD
would earn a prize for getting three sevens. There is
one exception to this rule, however: a diamond cannot be considered a
cherry unless the player also gets one real cherry. This prevents a dud
roll like, 0
DD
0
from being
scored as 0
C
0
.
Diamonds are also special in another way. Every diamond that appears
in a combination doubles the amount of the final prize. So
7
7
DD
would actually be scored
higher than 7
7
7
. Three
sevens would earn you $80, but two sevens and a diamond would earn you
$160. One seven and two diamonds would be even better, resulting in a
prize that has been doubled twice, or $320. A jackpot occurs when a
player rolls DD
DD
DD
. Then a
player earns $100 doubled three times, which is $800.
(#tab:prizes) Each play of the slot machine costs $1. A
player’s symbols determine how much they win. Diamonds (DD
)
are wild, and each diamond doubles the final prize. * = any
symbol.
DD DD DD |
100 |
7 7 7 |
80 |
BBB BBB BBB |
40 |
BB BB BB |
25 |
B B B |
10 |
C C C |
10 |
Any combination of bars |
5 |
C C * |
5 |
C * C |
5 |
* C C |
5 |
C * * |
2 |
* C * |
2 |
* * C |
2 |
To create your play
function, you will need to write a
program that can take the output of get_symbols
and
calculate the correct prize based on Table @ref(tab:prizes).
In R, programs are saved either as R scripts or as functions. We’ll
save your program as a function named score
. When you are
finished, you will be able to use score
to calculate a
prize like this:
score(c("DD", "DD", "DD"))
## 800
After that it will be easy to create the full slot machine, like
this:
play <- function() {
symbols <- get_symbols()
print(symbols)
score(symbols)
}
The print
command prints its output to the console
window, which makes print
a useful way to display messages
from within the body of a function.
You may notice that play
calls a new function,
print
. This will help play
display the three
slot machine symbols, since they do not get returned by the last line of
the function. The print
command prints its output to the
console window – even if R calls it from within a function.
In [Project 1: Weighted Dice], I encouraged you to write all of your
R code in an R script, a text file where you can compose and save code.
That advice will become very important as you work through this chapter.
Remember that you can open an R script in RStudio by going to the menu
bar and clicking on File > New File > R Script.
Strategy
Scoring slot-machine results is a complex task that will require a
complex algorithm. You can make this, and other coding tasks, easier by
using a simple strategy:
- Break complex tasks into simple subtasks.
- Use concrete examples.
- Describe your solutions in English, then convert them to R.
Let’s start by looking at how you can divide a program into subtasks
that are simple to work with.
A program is a set of step-by-step instructions for your computer to
follow. Taken together, these instructions may accomplish something very
sophisticated. Taken apart, each individual step will likely be simple
and straightforward.
You can make coding easier by identifying the individual steps or
subtasks within your program. You can then work on each subtask
separately. If a subtask seems complicated, try to divide it again into
even subtasks that are even more simple. You can often reduce an R
program into substasks so simple that each can be performed with a
preexisting function.
R programs contain two types of subtasks: sequential steps and
parallel cases.
Sequential Steps
One way to subdivide a program is into a series of sequential steps.
The play
function takes the approach. First, it generates
three symbols (step 1), then it displays them in the console window
(step 2), and then it scores them (step 3):
play <- function() {
# step 1: generate symbols
symbols <- get_symbols()
# step 2: display the symbols
print(symbols)
# step 3: score the symbols
score(symbols)
}
To have R execute steps in sequence, place the steps one after
another in an R script or function body.
Parallel Cases
Another way to divide a task is to spot groups of similar cases
within the task. Some tasks require different algorithms for different
groups of input. If you can identify those groups, you can work out
their algorithms one at a time.
For example, score
will need to calculate the prize one
way if symbols
contains three of a kind (In that case,
score
will need to match the common symbol to a prize).
score
will need to calculate the prize a second way if the
symbols are all bars (In that case, score
can just assign a
prize of $5). And, finally, score
will need to calculate
the prize in a third way if the symbols do not contain three of a kind
or all bars (In that case, score
must count the number of
cherries present). score
will never use all three of these
algorithms at once; it will always choose just one algorithm to run
based on the combination of symbols.
Diamonds complicate all of this because diamonds can be treated as
wild cards. Let’s ignore that for now and focus on the simpler case
where diamonds double the prize but are not wilds. score
can double the prize as necessary after it runs one of the following
algorithms.
Adding the score
cases to the play
steps
reveals a strategy for the complete slot machine program.
We’ve already solved the first few steps in this strategy. Our
program can get three slot machine symbols with the
get_symbols
function. Then it can display the symbols with
the print
function. Now let’s examine how the program can
handle the parallel score cases.
Exercise 1: Breaking down a program into sequential steps
Write a function called greet that takes a person’s name as input and
performs the following steps in sequence:
- Prints a welcome message to the console.
- Asks the user for their favorite color.
- Prints a personalized message to the console that includes the
person’s name and favorite color.
Click to see solution
greet <- function(name) {
# step 1: print welcome message
print(paste("Hello, welcome!", name))
# step 2: ask for favorite color
favorite_color <- readline(prompt = "What is your favorite color? ")
# step 3: print personalized message
print(paste("Your favorite color is", favorite_color, name))
}
Exercise 2: Handling parallel cases
Write a function called calculate_prize that takes a vector of slot
machine symbols as input and returns the corresponding prize amount. The
function should handle the following cases:
- If the symbols contain three of a kind, the prize is $10.
- If the symbols are all bars, the prize is $5.
- If the symbols do not contain three of a kind or all bars, the prize
is the number of cherries present.
Click to see solution
calculate_prize <- function(symbols) {
# check for three of a kind
if (length(unique(symbols)) == 1) {
return(10)
}
# check for all bars
if (all(symbols == "bar")) {
return(5)
}
# count the number of cherries
cherries <- sum(symbols == "cherry")
return(cherries)
}
if Statements
Linking cases together in parallel requires a bit of structure; your
program faces a fork in the road whenever it must choose between cases.
You can help the program navigate this fork with an if
statement.
An if
statement tells R to do a certain task for a
certain case. In English you would say something like, “If this is true,
do that.” In R, you would say:
if (this) {
that
}
The this
object should be a logical test or an R
expression that evaluates to a single TRUE
or
FALSE
. If this
evaluates to TRUE
,
R will run all of the code that appears between the braces that follow
the if
statement (i.e., between the {
and
}
symbols). If this
evaluates to
FALSE
, R will skip the code between the braces without
running it.
For example, you could write an if
statement that
ensures some object, num
, is positive:
if (num < 0) {
num <- num * -1
}
If num < 0
is TRUE
, R will multiply
num
by negative one, which will make num
positive:
num <- -2
if (num < 0) {
num <- num * -1
}
num
## 2
If num < 0
is FALSE
, R will do nothing
and num
will remain as it is—positive (or zero):
num <- 4
if (num < 0) {
num <- num * -1
}
num
## 4
The condition of an if
statement must evaluate to a
single TRUE
or FALSE
. If the
condition creates a vector of TRUE
s and FALSE
s
(which is easier to make than you may think), your if
statement will print a warning message and use only the first element of
the vector. Remember that you can condense vectors of logical values to
a single TRUE
or FALSE
with the functions
any
and all
.
You don’t have to limit your if
statements to a single
line of code; you can include as many lines as you like between the
braces. For example, the following code uses many lines to ensure that
num
is positive. The additional lines print some
informative statements if num
begins as a negative number.
R will skip the entire code block—print
statements and
all—if num
begins as a positive number:
num <- -1
if (num < 0) {
print("num is negative.")
print("Don't worry, I'll fix it.")
num <- num * -1
print("Now num is positive.")
}
## "num is negative."
## "Don't worry, I'll fix it."
## "Now num is positive."
num
## 1
Try the following quizzes to develop your understanding of
if
statements.
Quizz 1: What will this return ?
x <- 1
if (3 == 3) {
x <- 2
}
x
Click to see solution
The code will return the number 2. x
begins as 1, and
then R encounters the if
statement. Since the condition
evaluates to TRUE
, R will run x <- 2
,
changing the value of x
.
Quizz 2: What will this return ?
x <- 1
if (TRUE) {
x <- 2
}
x
Click to see solution
This code will also return the number 2. It works the same as the
code in Quiz A, except the condition in this statement is already
TRUE
. R doesn’t even need to evaluate it. As a result, the
code inside the if
statement will be run, and
x
will be set to 2.
Quizz 3: What will this return ?
x <- 1
if (x == 1) {
x <- 2
if (x == 1) {
x <- 3
}
}
x
Click to see solution
Once again, the code will return the number 2. x
starts
out as 1, and the condition of the first if
statement will
evaluate to TRUE
, which causes R to run the code in the
body of the if
statement. First, R sets x
equal to 2, then R evaluates the second if
statement, which
is in the body of the first. This time x == 1
will evaluate
to FALSE
because x
now equals 2. As a result,
R ignores x <- 3
and exits both if
statements.
Exercise 1: Using if statements to make a decision
Write a function called check_age that takes a person’s age as input
and returns a message indicating whether they are eligible to vote or
not. If the person is 18 or older, they are eligible to vote.
Click to see solution
check_age <- function(age) {
if (age >= 18) {
return("You are eligible to vote.")
} else {
return("You are not eligible to vote.")
}
}
else Statements
if
statements tell R what to do when your condition is
true, but you can also tell R what to do when the condition is
false. else
is a counterpart to if
that extends an if
statement to include a second case. In
English, you would say, “If this is true, do plan A; else do plan B.” In
R, you would say:
if (this) {
Plan A
} else {
Plan B
}
When this
evaluates to TRUE
, R will run the
code in the first set of braces, but not the code in the second. When
this
evaluates to FALSE
, R will run the code
in the second set of braces, but not the first. You can use this
arrangement to cover all of the possible cases. For example, you could
write some code that rounds a decimal to the nearest integer.
Start with a decimal:
a <- 3.14
Then isolate the decimal component with trunc
:
dec <- a - trunc(a)
dec
## 0.14
trunc
takes a number and returns only the portion of the
number that appears to the left of the decimal place (i.e., the integer
part of the number).
a - trunc(a)
is a convenient way to return the decimal
part of a
.
Then use an if else
tree to round the number (either up
or down):
if (dec >= 0.5) {
a <- trunc(a) + 1
} else {
a <- trunc(a)
}
a
## 3
If your situation has more than two mutually exclusive cases, you can
string multiple if
and else
statements
together by adding a new if
statement immediately after
else
. For example:
a <- 1
b <- 1
if (a > b) {
print("A wins!")
} else if (a < b) {
print("B wins!")
} else {
print("Tie.")
}
## "Tie."
R will work through the if
conditions until one
evaluates to TRUE
, then R will ignore any remaining
if
and else
clauses in the tree. If no
conditions evaluate to TRUE
, R will run the final
else
statement.
If two if
statements describe mutually exclusive events,
it is better to join the if
statements with an
else if
than to list them separately. This lets R ignore
the second if
statement whenever the first returns a
TRUE
, which saves work.
You can use if
and else
to link the
subtasks in your slot-machine function. Open a fresh R script, and copy
this code into it. The code will be the skeleton of our final
score
function.
if ( # Case 1: all the same <1>) {
prize <- # look up the prize <3>
} else if ( # Case 2: all bars <2> ) {
prize <- # assign $5 <4>
} else {
# count cherries <5>
prize <- # calculate a prize <7>
}
# count diamonds <6>
# double the prize if necessary <8>
Our skeleton is rather incomplete; there are many sections that are
just code comments instead of real code. However, we’ve reduced the
program to eight simple subtasks:
<1> - Test whether the symbols are three of a
kind.
<2> - Test whether the symbols are all
bars.
<3> - Look up the prize for three of a kind based
on the common symbol.
<4> - Assign a prize of $5.
<5> - Count the number of cherries.
<6> - Count the number of diamonds.
<7> - Calculate a prize based on the number of
cherries.
<8> - Adjust the prize for diamonds.
If you like, you can reorganize your flow chart around these tasks.
The chart will describe the same strategy, but in a more precise way.
I’ll use a diamond shape to symbolize an if else
decision.
Now we can work through the subtasks one at a time, adding R code to
the if
tree as we go. Each subtask will be easy to solve if
you set up a concrete example to work with and try to describe a
solution in English before coding in R.
The first subtask asks you to test whether the symbols are three of a
kind. How should you begin writing the code for this subtask?
You know that the final score
function will look
something like this:
score <- function(symbols) {
# calculate a prize
prize
}
Its argument, symbols
, will be the output of
get_symbols
, a vector that contains three character
strings. You could start writing score
as I have written
it, by defining an object named score
and then slowly
filling in the body of the function. However, this would be a bad idea.
The eventual function will have eight separate parts, and it will not
work correctly until all of those parts are written (and
themselves work correctly). This means you would have to write the
entire score
function before you could test any of the
subtasks. If score
doesn’t work—which is very likely—you
will not know which subtask needs fixed.
You can save yourself time and headaches if you focus on one subtask
at a time. For each subtask, create a concrete example that you can test
your code on. For example, you know that score
will need to
work on a vector named symbols
that contains three
character strings. If you make a real vector named symbols
,
you can run the code for many of your subtasks on the vector as you
go:
symbols <- c("7", "7", "7")
If a piece of code does not work on symbols
, you will
know that you need to fix it before you move on. You can change the
value of symbols
from subtask to subtask to ensure that
your code works in every situation:
symbols <- c("B", "BB", "BBB")
symbols <- c("C", "DD", "0")
Only combine your subtasks into a score
function once
each subtask works on a concrete example. If you follow this plan, you
will spend more time using your functions and less time trying to figure
out why they do not work.
After you set up a concrete example, try to describe how you will do
the subtask in English. The more precisely you can describe your
solution, the easier it will be to write your R code.
Our first subtask asks us to “test whether the symbols are three of a
kind.” This phrase does not suggest any useful R code to me. However, I
could describe a more precise test for three of a kind: three symbols
will be the same if the first symbol is equal to the second and the
second symbol is equal to the third. Or, even more precisely:
A vector named symbols
will contain three of the
same symbol if the first element of symbols
is equal to the
second element of symbols
and the second element of
symbols
is equal to the third element of
symbols
.
Exercise 1: Write a test
Turn the preceding statement into a logical test written in R. Use
your knowledge of logical tests, Boolean operators, and subsetting from
[R Notation]. The test should work with the vector symbols
and return a TRUE
if and only if each element in
symbols
is the same. Be sure to test your code on
symbols
.
Click to see solution
Here are a couple of ways to test that symbols
contains
three of the same symbol. The first method parallels the English
suggestion above, but there are other ways to do the same test. There is
no right or wrong answer, so long as your solution works, which is easy
to check because you’ve created a vector named symbols
:
symbols
## "7" "7" "7"
symbols[1] == symbols[2] & symbols[2] == symbols[3]
## TRUE
symbols[1] == symbols[2] & symbols[1] == symbols[3]
## TRUE
all(symbols == symbols[1])
## TRUE
As your vocabulary of R functions broadens, you’ll think of more ways
to do basic tasks. One method that I like for checking three of a kind
is:
length(unique(symbols) == 1)
The unique
function returns every unique term that
appears in a vector. If your symbols
vector contains three
of a kind (i.e., one unique term that appears three times), then
unique(symbols)
will return a vector of length
1
.
Now that you have a working test, you can add it to your slot-machine
script:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
if (same) {
prize <- # look up the prize
} else if ( # Case 2: all bars ) {
prize <- # assign $5
} else {
# count cherries
prize <- # calculate a prize
}
# count diamonds
# double the prize if necessary
&&
and ||
behave like
&
and |
but can sometimes be more
efficient. The double operators will not evaluate the second test in a
pair of tests if the first test makes the result clear. For example, if
symbols[1]
does not equal symbols[2]
in the
next expression, &&
will not evaluate
symbols[2] == symbols[3]
; it can immediately return a
FALSE
for the whole expression (because
FALSE & TRUE
and FALSE & FALSE
both
evaluate to FALSE
). This efficiency can speed up your
programs; however, double operators are not appropriate everywhere.
&&
and ||
are not vectorized, which
means they can only handle a single logical test on each side of the
operator.
The second prize case occurs when all the symbols are a type of bar,
for example, B
, BB
, and BBB
.
Let’s begin by creating a concrete example to work with:
symbols <- c("B", "BBB", "BB")
Exercise 2: Test for all bars
Use R’s logical and Boolean operators to write a test that will
determine whether a vector named symbols
contains only
symbols that are a type of bar. Check whether your test works with our
example symbols
vector. Remember to describe how the test
should work in English, and then convert the solution to R.
Click to see solution
As with many things in R, there are multiple ways to test whether
symbols
contains all bars. For example, you could write a
very long test that uses multiple Boolean operators, like this:
(symbols[1] == "B" | symbols[1] == "BB" | symbols[1] == "BBB") &
(symbols[2] == "B" | symbols[2] == "BB" | symbols[2] == "BBB") &
(symbols[3] == "B" | symbols[3] == "BB" | symbols[3] == "BBB")
## TRUE
However, this is not a very efficient solution, because R has to run
nine logical tests (and you have to type them). You can often replace
multiple |
operators with a single %in%
. Also,
you can check that a test is true for each element in a vector with
all
. These two changes shorten the preceding code to:
all(symbols %in% c("B", "BB", "BBB"))
## TRUE
Let’s add this code to our script:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
prize <- # look up the prize
} else if (all(bars)) {
prize <- # assign $5
} else {
# count cherries
prize <- # calculate a prize
}
# count diamonds
# double the prize if necessary
You may have noticed that I split this test up into two steps,
bars
and all(bars)
. That’s just a matter of
personal preference. Wherever possible, I like to write my code so it
can be read with function and object names conveying what they do.
You also may have noticed that our test for Case 2 will capture some
symbols that should be in Case 1 because they contain three of a
kind:
symbols <- c("B", "B", "B")
all(symbols %in% c("B", "BB", "BBB"))
## TRUE
That won’t be a problem, however, because we’ve connected our cases
with else if
in the if
tree. As soon as R
comes to a case that evaluates to TRUE
, it will skip over
the rest of the tree. Think of it this way: each else
tells
R to only run the code that follows it if none of the previous
conditions have been met. So when we have three of the same type of
bar, R will evaluate the code for Case 1 and then skip the code for Case
2 (and Case 3).
Our next subtask is to assign a prize for symbols
. When
the symbols
vector contains three of the same symbol, the
prize will depend on which symbol there are three of. If there are three
DD
s, the prize will be $100; if there are three
7
s, the prize will be $80; and so on.
This suggests another if
tree. You could assign a prize
with some code like this:
if (same) {
symbol <- symbols[1]
if (symbol == "DD") {
prize <- 800
} else if (symbol == "7") {
prize <- 80
} else if (symbol == "BBB") {
prize <- 40
} else if (symbol == "BB") {
prize <- 5
} else if (symbol == "B") {
prize <- 10
} else if (symbol == "C") {
prize <- 10
} else if (symbol == "0") {
prize <- 0
}
}
While this code will work, it is a bit long to write and read, and it
may require R to perform multiple logical tests before delivering the
correct prize. We can do better with a different method.
Lookup Tables
Very often in R, the simplest way to do something will involve
subsetting. How could you use subsetting here? Since you know the exact
relationship between the symbols and their prizes, you can create a
vector that captures this information. This vector can store symbols as
names and prize values as elements:
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
payouts
## DD 7 BBB BB B C 0
## 100 80 40 25 10 10 0
Now you can extract the correct prize for any symbol by subsetting
the vector with the symbol’s name:
payouts["DD"]
## DD
## 100
payouts["B"]
## B
## 10
If you want to leave behind the symbol’s name when subsetting, you
can run the unname
function on the output:
unname(payouts["DD"])
## 100
unname
returns a copy of an object with the names
attribute removed.
payouts
is a type of lookup table, an R object
that you can use to look up values. Subsetting payouts
provides a simple way to find the prize for a symbol. It doesn’t take
many lines of code, and it does the same amount of work whether your
symbol is DD
or 0
. You can create lookup
tables in R by creating named objects that can be subsetted in clever
ways.
Sadly, our method is not quite automatic; we need to tell R which
symbol to look up in payouts
. Or do we? What would happen
if you subsetted payouts
by symbols[1]
? Give
it a try:
symbols <- c("7", "7", "7")
symbols[1]
## "7"
payouts[symbols[1]]
## 7
## 80
symbols <- c("C", "C", "C")
payouts[symbols[1]]
## C
## 10
You don’t need to know the exact symbol to look up because you can
tell R to look up whichever symbol happens to be in
symbols
. You can find this symbol with
symbols[1]
, symbols[2]
, or
symbols[3]
, because each contains the same symbol in this
case. You now have a simple automated way to calculate the prize when
symbols
contains three of a kind. Let’s add it to our code
and then look at Case 2:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
prize <- unname(payouts[symbols[1]])
} else if (all(bars)) {
prize <- # assign $5
} else {
# count cherries
prize <- # calculate a prize
}
# count diamonds
# double the prize if necessary
Case 2 occurs whenever the symbols are all bars. In that case, the
prize will be $5, which is easy to assign:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
prize <- unname(payouts[symbols[1]])
} else if (all(bars)) {
prize <- 5
} else {
# count cherries
prize <- # calculate a prize
}
# count diamonds
# double the prize if necessary
Now we can work on the last case. Here, you’ll need to know how many
cherries are in symbols
before you can calculate a
prize.
Exercise 1: Find C’s
How can you tell which elements of a vector named symbols are a C?
Devise a test and try it out
Click to see solution
symbols <- c("C", "DD", "C")
symbols == "C"
## TRUE FALSE TRUE
It’d be even more useful to count how many of the symbols are
cherries. You can do this with sum
, which expects numeric
input, not logical. Knowing this, R will coerce the TRUE
s
and FALSE
s to 1
s and 0
s before
doing the summation. As a result, sum
will return the
number of TRUE
s, which is also the number of cherries:
sum(symbols == "C")
## 2
You can use the same method to count the number of diamonds in
symbols
:
sum(symbols == "DD")
## 1
Let’s add both of these subtasks to the program skeleton:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
prize <- unname(payouts[symbols[1]])
} else if (all(bars)) {
prize <- 5
} else {
cherries <- sum(symbols == "C")
prize <- # calculate a prize
}
diamonds <- sum(symbols == "DD")
# double the prize if necessary
Since Case 3 appears further down the if
tree than Cases
1 and 2, the code in Case 3 will only be applied to players that do not
have three of a kind or all bars. According to the slot machine’s payout
scheme, these players will win $5 if they have two cherries and $2 if
they have one cherry. If the player has no cherries, she gets a prize of
$0. We don’t need to worry about three cherries because that outcome is
already covered in Case 1.
As in Case 1, you could write an if
tree that handles
each combination of cherries, but just like in Case 1, this would be an
inefficient solution:
if (cherries == 2) {
prize <- 5
} else if (cherries == 1) {
prize <- 2
} else {}
prize <- 0
}
Again, I think the best solution will involve subsetting. If you are
feeling ambitious, you can try to work this solution out on your own,
but you will learn just as quickly by mentally working through the
following proposed solution.
We know that our prize should be $0 if we have no cherries, $2 if we
have one cherry, and $5 if we have two cherries. You can create a vector
that contains this information. This will be a very simple lookup
table:
c(0, 2, 5)
Now, like in Case 1, you can subset the vector to retrieve the
correct prize. In this case, the prize’s aren’t identified by a symbol
name, but by the number of cherries present. Do we have that
information? Yes, it is stored in cherries
. We can use
basic integer subsetting to get the correct prize from the prior lookup
table, for example, c(0, 2, 5)[1]
.
cherries
isn’t exactly suited for integer subsetting
because it could contain a zero, but that’s easy to fix. We can subset
with cherries + 1
. Now when cherries
equals
zero, we have:
cherries + 1
## 1
c(0, 2, 5)[cherries + 1]
## 0
When cherries
equals one, we have:
cherries + 1
## 2
c(0, 2, 5)[cherries + 1]
## 2
And when cherries
equals two, we have:
cherries + 1
## 3
c(0, 2, 5)[cherries + 1]
## 5
Examine these solutions until you are satisfied that they return the
correct prize for each number of cherries. Then add the code to your
script, as follows:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
prize <- unname(payouts[symbols[1]])
} else if (all(bars)) {
prize <- 5
} else {
cherries <- sum(symbols == "C")
prize <- c(0, 2, 5)[cherries + 1]
}
diamonds <- sum(symbols == "DD")
# double the prize if necessary
Lookup Tables Versus if Trees
This is the second time we’ve created a lookup table to avoid writing
an if
tree. Why is this technique helpful and why does it
keep appearing? Many if
trees in R are essential. They
provide a useful way to tell R to use different algorithms in different
cases. However, if
trees are not appropriate
everywhere.
if
trees have a couple of drawbacks. First, they require
R to run multiple tests as it works its way down the if
tree, which can create unnecessary work. Second, as you’ll see in
[Speed], it can be difficult to use if
trees in vectorized
code, a style of code that takes advantage of R’s programming strengths
to create fast programs. Lookup tables do not suffer from either of
these drawbacks.
You won’t be able to replace every if
tree with a lookup
table, nor should you. However, you can usually use lookup tables to
avoid assigning variables with if
trees. As a general rule,
use an if
tree if each branch of the tree runs different
code. Use a lookup table if each branch of the tree only
assigns a different value.
To convert an if
tree to a lookup table, identify the
values to be assigned and store them in a vector. Next, identify the
selection criteria used in the conditions of the if
tree.
If the conditions use character strings, give your vector names and use
name-based subsetting. If the conditions use integers, use integer-based
subsetting.
The final subtask is to double the prize once for every diamond
present. This means that the final prize will be some multiple of the
current prize. For example, if no diamonds are present, the prize will
be:
prize * 1 # 1 = 2 ^ 0
If one diamond is present, it will be:
prize * 2 # 2 = 2 ^ 1
If two diamonds are present, it will be:
prize * 4 # 4 = 2 ^ 2
And if three diamonds are present, it will be:
prize * 8 # 8 = 2 ^ 3
Exercise 2: Adjust for Diamonds
Write a method for adjusting prize
based on
diamonds
. Describe a solution in English first, and then
write your code.
Click to see solution
Here is a concise solution inspired by the previous pattern. The
adjusted prize will equal:
prize * 2 ^ diamonds
which gives us our final score
script:
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
if (same) {
payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25,
"B" = 10, "C" = 10, "0" = 0)
prize <- unname(payouts[symbols[1]])
} else if (all(bars)) {
prize <- 5
} else {
cherries <- sum(symbols == "C")
prize <- c(0, 2, 5)[cherries + 1]
}
diamonds <- sum(symbols == "DD")
prize * 2 ^ diamonds
Summary
An R program is a set of instructions for your computer to follow
that has been organized into a sequence of steps and cases. This may
make programs seem simple, but don’t be fooled: you can create
complicated results with the right combination of simple steps (and
cases).
As a programmer, you are more likely to be fooled in the opposite
way. A program may seem impossible to write when you know that it must
do something impressive. Do not panic in these situations. Divide the
job before you into simple tasks, and then divide the tasks again. You
can visualize the relationship between tasks with a flow chart if it
helps. Then work on the subtasks one at a time. Describe solutions in
English, then convert them to R code. Test each solution against
concrete examples as you go. Once each of your subtasks works, combine
your code into a function that you can share and reuse.
R provides tools that can help you do this. You can manage cases with
if
and else
statements. You can create a
lookup table with objects and subsetting. You can add code comments with
#
. And you can save your programs as a function with
function
.
Things often go wrong when people write programs. It will be up to
you to find the source of any errors that occur and to fix them. It
should be easy to find the source of your errors if you use a stepwise
approach to writing functions, writing—and then testing—one bit at a
time. However, if the source of an error eludes you, or you find
yourself working with large chunks of untested code, consider using R’s
built in debugging tools, described in [Debugging R Code].
The next two chapters will teach you more tools that you can use in
your programs. As you master these tools, you will find it easier to
write R programs that let you do whatever you wish to your data. In
[S3], you will learn how to use R’s S3 system, an invisible hand that
shapes many parts of R. You will use the system to build a custom class
for your slot machine output, and you will tell R how to display objects
that have your class.
LS0tCnRpdGxlOiAiUHJvZ3JhbXMgaW4gUiIKb3V0cHV0OiBodG1sX25vdGVib29rCmNvZGVfZm9sZGluZzogaGlkZQotLS0KCgojIyBJbnRyb2R1Y3Rpb24KClNsb3QgbWFjaGluZXMgYXJlIGEgcG9wdWxhciBmb3JtIG9mIGdhbWJsaW5nIGluIGNhc2lub3MsIG9mZmVyaW5nIHBsYXllcnMgYSBjaGFuY2UgdG8gd2luIHByaXplcyBieSBtYXRjaGluZyBzeW1ib2xzIG9uIGEgc3Bpbm5pbmcgcmVlbC4gVGhlc2UgbWFjaGluZXMgYXJlIGtub3duIGZvciB0aGVpciBsb3cgcGF5b3V0IHJhdGVzLCB3aGljaCBjb250cmlidXRlIHNpZ25pZmljYW50bHkgdG8gY2FzaW5vIHByb2ZpdHMuIEluIHRoaXMgcHJvamVjdCwgeW91IHdpbGwgY3JlYXRlIGEgdmlydHVhbCBzbG90IG1hY2hpbmUgYmFzZWQgb24gcmVhbC1saWZlIFZpZGVvIExvdHRlcnkgVGVybWluYWxzIChWTFRzKSBmcm9tIE1hbml0b2JhLCBDYW5hZGEsIHdoaWNoIHdlcmUgaW52b2x2ZWQgaW4gYSBzY2FuZGFsIGluIHRoZSAxOTkwcy4gVGhlIGdvYWwgaXMgdG8gdW5kZXJzdGFuZCB0aGUgcGF5b3V0IHJhdGVzIG9mIHRoZXNlIG1hY2hpbmVzIHRocm91Z2ggcHJvZ3JhbW1pbmcgYW5kIHNpbXVsYXRpb25zLgoKKipTbG90IE1hY2hpbmUgQmFzaWNzOioqCgotICAgQSBzbG90IG1hY2hpbmUgY29uc2lzdHMgb2YgYSBzcGlubmluZyByZWVsIHdpdGggdmFyaW91cyBzeW1ib2xzLgoKLSAgIFBsYXllcnMgaW5zZXJ0IGEgc21hbGwgZmVlIGFuZCBwdWxsIGEgbGV2ZXIgdG8gc3BpbiB0aGUgcmVlbC4KCi0gICBUaGUgbWFjaGluZSBnZW5lcmF0ZXMgYSByYW5kb20gY29tYmluYXRpb24gb2Ygc3ltYm9scy4KCi0gICBJZiB0aGUgc3ltYm9scyBtYXRjaCBhIHdpbm5pbmcgcGF0dGVybiwgdGhlIHBsYXllciB3aW5zIGEgcHJpemUuCgoqKkxvdyBQYXlvdXQgUmF0ZXM6KioKCi0gICBTbG90IG1hY2hpbmVzIGFyZSBkZXNpZ25lZCB0byBoYXZlIGxvdyBwYXlvdXQgcmF0ZXMsIHR5cGljYWxseSBhcm91bmQgOTAtOTUgY2VudHMgZm9yIGV2ZXJ5IGRvbGxhciBzcGVudC4KCi0gICBUaGlzIG1lYW5zIGNhc2lub3Mga2VlcCBhIHNpZ25pZmljYW50IHBvcnRpb24gb2YgdGhlIG1vbmV5IHdhZ2VyZWQgb24gdGhlc2UgbWFjaGluZXMuCgotICAgRGVzcGl0ZSB0aGlzLCBzbG90IG1hY2hpbmVzIHJlbWFpbiBleHRyZW1lbHkgcG9wdWxhciBhbW9uZyBnYW1ibGVycy4KCioqTWFuaXRvYmEgVkxUIFNjYW5kYWw6KioKCi0gICBJbiB0aGUgMTk5MHMsIFZMVHMgaW4gTWFuaXRvYmEgd2VyZSBhdCB0aGUgY2VudGVyIG9mIGEgc2NhbmRhbCBkdWUgdG8gdGhlaXIgbG93IHBheW91dCByYXRlcy4KCi0gICBUaGVzZSBWTFRzIHdlcmUgZm91bmQgdG8gaGF2ZSBldmVuIGxvd2VyIHBheW91dCByYXRlcyB0aGFuIHR5cGljYWwgc2xvdCBtYWNoaW5lcywgbGVhZGluZyB0byBpbmNyZWFzZWQgcHJvZml0cyBmb3IgdGhlIGNhc2lubyBhbmQgcmVkdWNlZCB3aW5uaW5ncyBmb3IgcGxheWVycy4KCi0gICBZb3VyIHRhc2sgaXMgdG8gcmVjcmVhdGUgdGhlc2UgVkxUcyBpbiBhIHZpcnR1YWwgZW52aXJvbm1lbnQgdG8gaW52ZXN0aWdhdGUgdGhlaXIgcGF5b3V0IHJhdGVzLgoKKipQcm9qZWN0IE9iamVjdGl2ZXM6KioKCjEuICAqKkJ1aWxkIGEgVmlydHVhbCBTbG90IE1hY2hpbmU6KiogQ3JlYXRlIGEgcHJvZ3JhbSB0aGF0IHNpbXVsYXRlcyB0aGUgYmVoYXZpb3Igb2YgdGhlIE1hbml0b2JhIFZMVHMsIGluY2x1ZGluZyBzcGlubmluZyB0aGUgcmVlbCBhbmQgZGV0ZXJtaW5pbmcgd2lubmluZyBjb21iaW5hdGlvbnMuCgoyLiAgKipJbnZlc3RpZ2F0ZSBQYXlvdXQgUmF0ZXM6KiogQ2FsY3VsYXRlIGFuZCBhbmFseXplIHRoZSBwYXlvdXQgcmF0ZXMgb2YgdGhlc2UgVkxUcyBieSBydW5uaW5nIHNpbXVsYXRpb25zIGFuZCBjb21wYXJpbmcgdGhlbSB0byB0aGUgYWR2ZXJ0aXNlZCByYXRlcy4KCjMuICAqKlVuZGVyc3RhbmQgdGhlIFNjYW5kYWw6KiogVGhyb3VnaCB5b3VyIHNpbXVsYXRpb25zLCB1bmNvdmVyIHRoZSByZWFzb25zIGJlaGluZCB0aGUgc2NhbmRhbCBhbmQgdGhlIGltcGFjdCBvZiBsb3cgcGF5b3V0IHJhdGVzIG9uIHBsYXllcnMuCgoqKlN0ZXBzIHRvIFJlY3JlYXRlIHRoZSBWTFRzOioqCgoxLiAgKipEYXRhIENvbGxlY3Rpb246KiogR2F0aGVyIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzeW1ib2xzIG9uIHRoZSBWTFQgcmVlbHMgYW5kIHRoZWlyIHByb2JhYmlsaXRpZXMgb2YgYXBwZWFyaW5nLgoKMi4gICoqUmFuZG9tIE51bWJlciBHZW5lcmF0aW9uOioqIEltcGxlbWVudCBhIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIHRvIHNpbXVsYXRlIHRoZSBzcGlubmluZyBvZiB0aGUgcmVlbHMuCgozLiAgKipTeW1ib2wgU2VsZWN0aW9uOioqIFVzZSB0aGUgZ2VuZXJhdGVkIHJhbmRvbSBudW1iZXJzIHRvIHNlbGVjdCBzeW1ib2xzIGZvciBlYWNoIHJlZWwgcG9zaXRpb24uCgo0LiAgKipXaW5uaW5nIENvbWJpbmF0aW9uczoqKiBEZWZpbmUgdGhlIHdpbm5pbmcgcGF0dGVybnMgYW5kIGNhbGN1bGF0ZSB0aGUgcHJvYmFiaWxpdHkgb2YgaGl0dGluZyBlYWNoIGNvbWJpbmF0aW9uLgoKNS4gICoqUGF5b3V0IENhbGN1bGF0aW9uOioqIERldGVybWluZSB0aGUgcGF5b3V0IGZvciBlYWNoIHdpbm5pbmcgY29tYmluYXRpb24gYW5kIHRoZSBvdmVyYWxsIHBheW91dCByYXRlLgoKNi4gICoqU2ltdWxhdGlvbnM6KiogUnVuIG11bHRpcGxlIHNpbXVsYXRpb25zIHRvIHZhbGlkYXRlIHRoZSBjYWxjdWxhdGVkIHBheW91dCByYXRlcyBhbmQgYW5hbHl6ZSB0aGUgcmVzdWx0cy4KCioqRXhwZWN0ZWQgT3V0Y29tZXM6KioKCi0gICBBIGZ1bGx5IGZ1bmN0aW9uYWwgdmlydHVhbCBzbG90IG1hY2hpbmUgdGhhdCBtaW1pY3MgdGhlIGJlaGF2aW9yIG9mIHRoZSBNYW5pdG9iYSBWTFRzLgoKLSAgIEluc2lnaHRzIGludG8gdGhlIGxvdyBwYXlvdXQgcmF0ZXMgb2YgdGhlc2UgbWFjaGluZXMgYW5kIHRoZWlyIGltcGFjdCBvbiBwbGF5ZXJzJyB3aW5uaW5ncy4KCi0gICBBIGRlZXBlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBNYW5pdG9iYSBWTFQgc2NhbmRhbCBhbmQgdGhlIGltcG9ydGFuY2Ugb2YgcGF5b3V0IHJhdGVzIGluIGdhbWJsaW5nLgoKSW4gdGhpcyBjaGFwdGVyLCB5b3Ugd2lsbCBidWlsZCBhIHJlYWwsIHdvcmtpbmcgc2xvdCBtYWNoaW5lIHRoYXQgeW91IGNhbiBwbGF5IGJ5IHJ1bm5pbmcgYW4gUiBmdW5jdGlvbi4gV2hlbiB5b3UncmUgZmluaXNoZWQsIHlvdSdsbCBiZSBhYmxlIHRvIHBsYXkgaXQgbGlrZSB0aGlzOgoKYGBgIHtyfQpwbGF5KCkKIyMgMCAwIERECiMjICQwCgpwbGF5KCkKIyMgNyA3IDcKIyMgJDgwCmBgYAoKVGhlIGBwbGF5YCBmdW5jdGlvbiB3aWxsIG5lZWQgdG8gZG8gdHdvIHRoaW5ncy4gRmlyc3QsIGl0IHdpbGwgbmVlZCB0byByYW5kb21seSBnZW5lcmF0ZSB0aHJlZSBzeW1ib2xzOyBhbmQsIHNlY29uZCwgaXQgd2lsbCBuZWVkIHRvIGNhbGN1bGF0ZSBhIHByaXplIGJhc2VkIG9uIHRob3NlIHN5bWJvbHMuCgpUaGUgZmlyc3Qgc3RlcCBpcyBlYXN5IHRvIHNpbXVsYXRlLiBZb3UgY2FuIHJhbmRvbWx5IGdlbmVyYXRlIHRocmVlIHN5bWJvbHMgd2l0aCB0aGUgYHNhbXBsZWAgZnVuY3Rpb27igJRqdXN0IGxpa2UgeW91IHJhbmRvbWx5ICJyb2xsZWQiIHR3byBkaWNlIGluIFtQcm9qZWN0IDE6IFdlaWdodGVkIERpY2VdLiBUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIGdlbmVyYXRlcyB0aHJlZSBzeW1ib2xzIGZyb20gYSBncm91cCBvZiBjb21tb24gc2xvdCBtYWNoaW5lIHN5bWJvbHM6IGRpYW1vbmRzIChgRERgKSwgc2V2ZW5zIChgN2ApLCB0cmlwbGUgYmFycyAoYEJCQmApLCBkb3VibGUgYmFycyAoYEJCYCksIHNpbmdsZSBiYXJzIChgQmApLCBjaGVycmllcyAoYENgKSwgYW5kIHplcm9lcyAoYDBgKS4gVGhlIHN5bWJvbHMgYXJlIHNlbGVjdGVkIHJhbmRvbWx5LCBhbmQgZWFjaCBzeW1ib2wgYXBwZWFycyB3aXRoIGEgZGlmZmVyZW50IHByb2JhYmlsaXR5OgoKYGBgIHtyfQpnZXRfc3ltYm9scyA8LSBmdW5jdGlvbigpIHsKICB3aGVlbCA8LSBjKCJERCIsICI3IiwgIkJCQiIsICJCQiIsICJCIiwgIkMiLCAiMCIpCiAgc2FtcGxlKHdoZWVsLCBzaXplID0gMywgcmVwbGFjZSA9IFRSVUUsIAogICAgcHJvYiA9IGMoMC4wMywgMC4wMywgMC4wNiwgMC4xLCAwLjI1LCAwLjAxLCAwLjUyKSkKfQpgYGAKCllvdSBjYW4gdXNlIGBnZXRfc3ltYm9sc2AgdG8gZ2VuZXJhdGUgdGhlIHN5bWJvbHMgdXNlZCBpbiB5b3VyIHNsb3QgbWFjaGluZToKCmBgYCB7cn0KZ2V0X3N5bWJvbHMoKQojIyAiQkJCIiAiMCIgICAiQyIgIAoKZ2V0X3N5bWJvbHMoKQojIyAiMCIgIjAiICIwIgoKZ2V0X3N5bWJvbHMoKQojIyAiNyIgIjAiICJCIgpgYGAKCmBnZXRfc3ltYm9sc2AgdXNlcyB0aGUgcHJvYmFiaWxpdGllcyBvYnNlcnZlZCBpbiBhIGdyb3VwIG9mIHZpZGVvIGxvdHRlcnkgdGVybWluYWxzIGZyb20gTWFuaXRvYmEsIENhbmFkYS4gVGhlc2Ugc2xvdCBtYWNoaW5lcyBiZWNhbWUgYnJpZWZseSBjb250cm92ZXJzaWFsIGluIHRoZSAxOTkwcywgd2hlbiBhIHJlcG9ydGVyIGRlY2lkZWQgdG8gdGVzdCB0aGVpciBwYXlvdXQgcmF0ZS4gVGhlIG1hY2hpbmVzIGFwcGVhcmVkIHRvIHBheSBvdXQgb25seSA0MCBjZW50cyBvbiB0aGUgZG9sbGFyLCBldmVuIHRob3VnaCB0aGUgbWFudWZhY3R1cmVyIGNsYWltZWQgdGhleSB3b3VsZCBwYXkgb3V0IDkyIGNlbnRzIG9uIHRoZSBkb2xsYXIuIFRoZSBvcmlnaW5hbCBkYXRhIGNvbGxlY3RlZCBvbiB0aGUgbWFjaGluZXMgYW5kIGEgZGVzY3JpcHRpb24gb2YgdGhlIGNvbnRyb3ZlcnN5IGlzIGF2YWlsYWJsZSBvbmxpbmUgaW4gW2Egam91cm5hbCBhcnRpY2xlIGJ5IFcuIEpvaG4gQnJhdW5dKGh0dHA6Ly9iaXQubHkvanNlX0JyYXVuKS4gVGhlIGNvbnRyb3ZlcnN5IGRpZWQgZG93biB3aGVuIGFkZGl0aW9uYWwgdGVzdGluZyBzaG93ZWQgdGhhdCB0aGUgbWFudWZhY3R1cmVyIHdhcyBjb3JyZWN0LgoKVGhlIE1hbml0b2JhIHNsb3QgbWFjaGluZXMgdXNlIHRoZSBjb21wbGljYXRlZCBwYXlvdXQgc2NoZW1lIHNob3duIGluIFRhYmxlIFxAcmVmKHRhYjpwcml6ZXMpLiBBIHBsYXllciB3aWxsIHdpbiBhIHByaXplIGlmIGhlIGdldHM6CgotICAgVGhyZWUgb2YgdGhlIHNhbWUgdHlwZSBvZiBzeW1ib2wgKGV4Y2VwdCBmb3IgdGhyZWUgemVyb2VzKQotICAgVGhyZWUgYmFycyAob2YgbWl4ZWQgdmFyaWV0eSkKLSAgIE9uZSBvciBtb3JlIGNoZXJyaWVzCgpPdGhlcndpc2UsIHRoZSBwbGF5ZXIgcmVjZWl2ZXMgbm8gcHJpemUuCgpUaGUgbW9uZXRhcnkgdmFsdWUgb2YgdGhlIHByaXplIGlzIGRldGVybWluZWQgYnkgdGhlIGV4YWN0IGNvbWJpbmF0aW9uIG9mIHN5bWJvbHMgYW5kIGlzIGZ1cnRoZXIgbW9kaWZpZWQgYnkgdGhlIHByZXNlbmNlIG9mIGRpYW1vbmRzLiBEaWFtb25kcyBhcmUgdHJlYXRlZCBsaWtlICJ3aWxkIGNhcmRzLCIgd2hpY2ggbWVhbnMgdGhleSBjYW4gYmUgY29uc2lkZXJlZCBhbnkgb3RoZXIgc3ltYm9sIGlmIGl0IHdvdWxkIGluY3JlYXNlIGEgcGxheWVyJ3MgcHJpemUuIEZvciBleGFtcGxlLCBhIHBsYXllciB3aG8gcm9sbHMgYDdgIGA3YCBgRERgIHdvdWxkIGVhcm4gYSBwcml6ZSBmb3IgZ2V0dGluZyB0aHJlZSBzZXZlbnMuIFRoZXJlIGlzIG9uZSBleGNlcHRpb24gdG8gdGhpcyBydWxlLCBob3dldmVyOiBhIGRpYW1vbmQgY2Fubm90IGJlIGNvbnNpZGVyZWQgYSBjaGVycnkgdW5sZXNzIHRoZSBwbGF5ZXIgYWxzbyBnZXRzIG9uZSByZWFsIGNoZXJyeS4gVGhpcyBwcmV2ZW50cyBhIGR1ZCByb2xsIGxpa2UsIGAwYCBgRERgIGAwYCBmcm9tIGJlaW5nIHNjb3JlZCBhcyBgMGAgYENgIGAwYC4KCkRpYW1vbmRzIGFyZSBhbHNvIHNwZWNpYWwgaW4gYW5vdGhlciB3YXkuIEV2ZXJ5IGRpYW1vbmQgdGhhdCBhcHBlYXJzIGluIGEgY29tYmluYXRpb24gZG91YmxlcyB0aGUgYW1vdW50IG9mIHRoZSBmaW5hbCBwcml6ZS4gU28gYDdgIGA3YCBgRERgIHdvdWxkIGFjdHVhbGx5IGJlIHNjb3JlZCAqaGlnaGVyKiB0aGFuIGA3YCBgN2AgYDdgLiBUaHJlZSBzZXZlbnMgd291bGQgZWFybiB5b3UgXCQ4MCwgYnV0IHR3byBzZXZlbnMgYW5kIGEgZGlhbW9uZCB3b3VsZCBlYXJuIHlvdSBcJDE2MC4gT25lIHNldmVuIGFuZCB0d28gZGlhbW9uZHMgd291bGQgYmUgZXZlbiBiZXR0ZXIsIHJlc3VsdGluZyBpbiBhIHByaXplIHRoYXQgaGFzIGJlZW4gZG91YmxlZCB0d2ljZSwgb3IgXCQzMjAuIEEgamFja3BvdCBvY2N1cnMgd2hlbiBhIHBsYXllciByb2xscyBgRERgIGBERGAgYEREYC4gVGhlbiBhIHBsYXllciBlYXJucyBcJDEwMCBkb3VibGVkIHRocmVlIHRpbWVzLCB3aGljaCBpcyBcJDgwMC4KCnwgQ29tYmluYXRpb24gICAgICAgICAgICAgfCBQcml6ZShcJCkgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwKfCBgREQgIEREICBERGAgICAgICAgICAgICB8IDEwMCAgICAgICB8CnwgYDcgIDcgIDdgICAgICAgICAgICAgICAgfCA4MCAgICAgICAgfAp8IGBCQkIgIEJCQiAgQkJCYCAgICAgICAgIHwgNDAgICAgICAgIHwKfCBgQkIgIEJCICBCQmAgICAgICAgICAgICB8IDI1ICAgICAgICB8CnwgYEIgIEIgIEJgICAgICAgICAgICAgICAgfCAxMCAgICAgICAgfAp8IGBDICBDICBDYCAgICAgICAgICAgICAgIHwgMTAgICAgICAgIHwKfCBBbnkgY29tYmluYXRpb24gb2YgYmFycyB8IDUgICAgICAgICB8CnwgYEMgIEMgICpgICAgICAgICAgICAgICAgfCA1ICAgICAgICAgfAp8IGBDICAqICBDYCAgICAgICAgICAgICAgIHwgNSAgICAgICAgIHwKfCBgKiAgQyAgQ2AgICAgICAgICAgICAgICB8IDUgICAgICAgICB8CnwgYEMgICogICpgICAgICAgICAgICAgICAgfCAyICAgICAgICAgfAp8IGAqICBDICAqYCAgICAgICAgICAgICAgIHwgMiAgICAgICAgIHwKfCBgKiAgKiAgQ2AgICAgICAgICAgICAgICB8IDIgICAgICAgICB8Cgo6ICgjdGFiOnByaXplcykgRWFjaCBwbGF5IG9mIHRoZSBzbG90IG1hY2hpbmUgY29zdHMgXCQxLiBBIHBsYXllcidzIHN5bWJvbHMgZGV0ZXJtaW5lIGhvdyBtdWNoIHRoZXkgd2luLiBEaWFtb25kcyAoYEREYCkgYXJlIHdpbGQsIGFuZCBlYWNoIGRpYW1vbmQgZG91YmxlcyB0aGUgZmluYWwgcHJpemUuIFwqID0gYW55IHN5bWJvbC4KClRvIGNyZWF0ZSB5b3VyIGBwbGF5YCBmdW5jdGlvbiwgeW91IHdpbGwgbmVlZCB0byB3cml0ZSBhIHByb2dyYW0gdGhhdCBjYW4gdGFrZSB0aGUgb3V0cHV0IG9mIGBnZXRfc3ltYm9sc2AgYW5kIGNhbGN1bGF0ZSB0aGUgY29ycmVjdCBwcml6ZSBiYXNlZCBvbiBUYWJsZSBcQHJlZih0YWI6cHJpemVzKS4KCkluIFIsIHByb2dyYW1zIGFyZSBzYXZlZCBlaXRoZXIgYXMgUiBzY3JpcHRzIG9yIGFzIGZ1bmN0aW9ucy4gV2UnbGwgc2F2ZSB5b3VyIHByb2dyYW0gYXMgYSBmdW5jdGlvbiBuYW1lZCBgc2NvcmVgLiBXaGVuIHlvdSBhcmUgZmluaXNoZWQsIHlvdSB3aWxsIGJlIGFibGUgdG8gdXNlIGBzY29yZWAgdG8gY2FsY3VsYXRlIGEgcHJpemUgbGlrZSB0aGlzOgoKYGBgIHtyfQpzY29yZShjKCJERCIsICJERCIsICJERCIpKQojIyA4MDAKYGBgCgpBZnRlciB0aGF0IGl0IHdpbGwgYmUgZWFzeSB0byBjcmVhdGUgdGhlIGZ1bGwgc2xvdCBtYWNoaW5lLCBsaWtlIHRoaXM6CgpgYGAge3J9CnBsYXkgPC0gZnVuY3Rpb24oKSB7CiAgc3ltYm9scyA8LSBnZXRfc3ltYm9scygpCiAgcHJpbnQoc3ltYm9scykKICBzY29yZShzeW1ib2xzKQp9CmBgYAoKClRoZSBgcHJpbnRgIGNvbW1hbmQgcHJpbnRzIGl0cyBvdXRwdXQgdG8gdGhlIGNvbnNvbGUgd2luZG93LCB3aGljaCBtYWtlcyBgcHJpbnRgIGEgdXNlZnVsIHdheSB0byBkaXNwbGF5IG1lc3NhZ2VzIGZyb20gd2l0aGluIHRoZSBib2R5IG9mIGEgZnVuY3Rpb24uCgoKWW91IG1heSBub3RpY2UgdGhhdCBgcGxheWAgY2FsbHMgYSBuZXcgZnVuY3Rpb24sIGBwcmludGAuIFRoaXMgd2lsbCBoZWxwIGBwbGF5YCBkaXNwbGF5IHRoZSB0aHJlZSBzbG90IG1hY2hpbmUgc3ltYm9scywgc2luY2UgdGhleSBkbyBub3QgZ2V0IHJldHVybmVkIGJ5IHRoZSBsYXN0IGxpbmUgb2YgdGhlIGZ1bmN0aW9uLiBUaGUgYHByaW50YCBjb21tYW5kIHByaW50cyBpdHMgb3V0cHV0IHRvIHRoZSBjb25zb2xlIHdpbmRvdyAtLSBldmVuIGlmIFIgY2FsbHMgaXQgZnJvbSB3aXRoaW4gYSBmdW5jdGlvbi4KCkluIFtQcm9qZWN0IDE6IFdlaWdodGVkIERpY2VdLCBJIGVuY291cmFnZWQgeW91IHRvIHdyaXRlIGFsbCBvZiB5b3VyIFIgY29kZSBpbiBhbiBSIHNjcmlwdCwgYSB0ZXh0IGZpbGUgd2hlcmUgeW91IGNhbiBjb21wb3NlIGFuZCBzYXZlIGNvZGUuIFRoYXQgYWR2aWNlIHdpbGwgYmVjb21lIHZlcnkgaW1wb3J0YW50IGFzIHlvdSB3b3JrIHRocm91Z2ggdGhpcyBjaGFwdGVyLiBSZW1lbWJlciB0aGF0IHlvdSBjYW4gb3BlbiBhbiBSIHNjcmlwdCBpbiBSU3R1ZGlvIGJ5IGdvaW5nIHRvIHRoZSBtZW51IGJhciBhbmQgY2xpY2tpbmcgb24gRmlsZSBcPiBOZXcgRmlsZSBcPiBSIFNjcmlwdC4KCiMjIFN0cmF0ZWd5CgpTY29yaW5nIHNsb3QtbWFjaGluZSByZXN1bHRzIGlzIGEgY29tcGxleCB0YXNrIHRoYXQgd2lsbCByZXF1aXJlIGEgY29tcGxleCBhbGdvcml0aG0uIFlvdSBjYW4gbWFrZSB0aGlzLCBhbmQgb3RoZXIgY29kaW5nIHRhc2tzLCBlYXNpZXIgYnkgdXNpbmcgYSBzaW1wbGUgc3RyYXRlZ3k6CgotICAgQnJlYWsgY29tcGxleCB0YXNrcyBpbnRvIHNpbXBsZSBzdWJ0YXNrcy4KLSAgIFVzZSBjb25jcmV0ZSBleGFtcGxlcy4KLSAgIERlc2NyaWJlIHlvdXIgc29sdXRpb25zIGluIEVuZ2xpc2gsIHRoZW4gY29udmVydCB0aGVtIHRvIFIuCgpMZXQncyBzdGFydCBieSBsb29raW5nIGF0IGhvdyB5b3UgY2FuIGRpdmlkZSBhIHByb2dyYW0gaW50byBzdWJ0YXNrcyB0aGF0IGFyZSBzaW1wbGUgdG8gd29yayB3aXRoLgoKQSBwcm9ncmFtIGlzIGEgc2V0IG9mIHN0ZXAtYnktc3RlcCBpbnN0cnVjdGlvbnMgZm9yIHlvdXIgY29tcHV0ZXIgdG8gZm9sbG93LiBUYWtlbiB0b2dldGhlciwgdGhlc2UgaW5zdHJ1Y3Rpb25zIG1heSBhY2NvbXBsaXNoIHNvbWV0aGluZyB2ZXJ5IHNvcGhpc3RpY2F0ZWQuIFRha2VuIGFwYXJ0LCBlYWNoIGluZGl2aWR1YWwgc3RlcCB3aWxsIGxpa2VseSBiZSBzaW1wbGUgYW5kIHN0cmFpZ2h0Zm9yd2FyZC4KCllvdSBjYW4gbWFrZSBjb2RpbmcgZWFzaWVyIGJ5IGlkZW50aWZ5aW5nIHRoZSBpbmRpdmlkdWFsIHN0ZXBzIG9yIHN1YnRhc2tzIHdpdGhpbiB5b3VyIHByb2dyYW0uIFlvdSBjYW4gdGhlbiB3b3JrIG9uIGVhY2ggc3VidGFzayBzZXBhcmF0ZWx5LiBJZiBhIHN1YnRhc2sgc2VlbXMgY29tcGxpY2F0ZWQsIHRyeSB0byBkaXZpZGUgaXQgYWdhaW4gaW50byBldmVuIHN1YnRhc2tzIHRoYXQgYXJlIGV2ZW4gbW9yZSBzaW1wbGUuIFlvdSBjYW4gb2Z0ZW4gcmVkdWNlIGFuIFIgcHJvZ3JhbSBpbnRvIHN1YnN0YXNrcyBzbyBzaW1wbGUgdGhhdCBlYWNoIGNhbiBiZSBwZXJmb3JtZWQgd2l0aCBhIHByZWV4aXN0aW5nIGZ1bmN0aW9uLgoKUiBwcm9ncmFtcyBjb250YWluIHR3byB0eXBlcyBvZiBzdWJ0YXNrczogc2VxdWVudGlhbCBzdGVwcyBhbmQgcGFyYWxsZWwgY2FzZXMuCgojIyMgU2VxdWVudGlhbCBTdGVwcwoKT25lIHdheSB0byBzdWJkaXZpZGUgYSBwcm9ncmFtIGlzIGludG8gYSBzZXJpZXMgb2Ygc2VxdWVudGlhbCBzdGVwcy4gVGhlIGBwbGF5YCBmdW5jdGlvbiB0YWtlcyB0aGUgYXBwcm9hY2guIEZpcnN0LCBpdCBnZW5lcmF0ZXMgdGhyZWUgc3ltYm9scyAoc3RlcCAxKSwgdGhlbiBpdCBkaXNwbGF5cyB0aGVtIGluIHRoZSBjb25zb2xlIHdpbmRvdyAoc3RlcCAyKSwgYW5kIHRoZW4gaXQgc2NvcmVzIHRoZW0gKHN0ZXAgMyk6CgpgYGAge3J9CnBsYXkgPC0gZnVuY3Rpb24oKSB7CgogICMgc3RlcCAxOiBnZW5lcmF0ZSBzeW1ib2xzCiAgc3ltYm9scyA8LSBnZXRfc3ltYm9scygpCgogICMgc3RlcCAyOiBkaXNwbGF5IHRoZSBzeW1ib2xzCiAgcHJpbnQoc3ltYm9scykKCiAgIyBzdGVwIDM6IHNjb3JlIHRoZSBzeW1ib2xzCiAgc2NvcmUoc3ltYm9scykKfQpgYGAKClRvIGhhdmUgUiBleGVjdXRlIHN0ZXBzIGluIHNlcXVlbmNlLCBwbGFjZSB0aGUgc3RlcHMgb25lIGFmdGVyIGFub3RoZXIgaW4gYW4gUiBzY3JpcHQgb3IgZnVuY3Rpb24gYm9keS4KCiMjIyBQYXJhbGxlbCBDYXNlcwoKQW5vdGhlciB3YXkgdG8gZGl2aWRlIGEgdGFzayBpcyB0byBzcG90IGdyb3VwcyBvZiBzaW1pbGFyIGNhc2VzIHdpdGhpbiB0aGUgdGFzay4gU29tZSB0YXNrcyByZXF1aXJlIGRpZmZlcmVudCBhbGdvcml0aG1zIGZvciBkaWZmZXJlbnQgZ3JvdXBzIG9mIGlucHV0LiBJZiB5b3UgY2FuIGlkZW50aWZ5IHRob3NlIGdyb3VwcywgeW91IGNhbiB3b3JrIG91dCB0aGVpciBhbGdvcml0aG1zIG9uZSBhdCBhIHRpbWUuCgpGb3IgZXhhbXBsZSwgYHNjb3JlYCB3aWxsIG5lZWQgdG8gY2FsY3VsYXRlIHRoZSBwcml6ZSBvbmUgd2F5IGlmIGBzeW1ib2xzYCBjb250YWlucyB0aHJlZSBvZiBhIGtpbmQgKEluIHRoYXQgY2FzZSwgYHNjb3JlYCB3aWxsIG5lZWQgdG8gbWF0Y2ggdGhlIGNvbW1vbiBzeW1ib2wgdG8gYSBwcml6ZSkuIGBzY29yZWAgd2lsbCBuZWVkIHRvIGNhbGN1bGF0ZSB0aGUgcHJpemUgYSBzZWNvbmQgd2F5IGlmIHRoZSBzeW1ib2xzIGFyZSBhbGwgYmFycyAoSW4gdGhhdCBjYXNlLCBgc2NvcmVgIGNhbiBqdXN0IGFzc2lnbiBhIHByaXplIG9mIFwkNSkuIEFuZCwgZmluYWxseSwgYHNjb3JlYCB3aWxsIG5lZWQgdG8gY2FsY3VsYXRlIHRoZSBwcml6ZSBpbiBhIHRoaXJkIHdheSBpZiB0aGUgc3ltYm9scyBkbyBub3QgY29udGFpbiB0aHJlZSBvZiBhIGtpbmQgb3IgYWxsIGJhcnMgKEluIHRoYXQgY2FzZSwgYHNjb3JlYCBtdXN0IGNvdW50IHRoZSBudW1iZXIgb2YgY2hlcnJpZXMgcHJlc2VudCkuIGBzY29yZWAgd2lsbCBuZXZlciB1c2UgYWxsIHRocmVlIG9mIHRoZXNlIGFsZ29yaXRobXMgYXQgb25jZTsgaXQgd2lsbCBhbHdheXMgY2hvb3NlIGp1c3Qgb25lIGFsZ29yaXRobSB0byBydW4gYmFzZWQgb24gdGhlIGNvbWJpbmF0aW9uIG9mIHN5bWJvbHMuCgpEaWFtb25kcyBjb21wbGljYXRlIGFsbCBvZiB0aGlzIGJlY2F1c2UgZGlhbW9uZHMgY2FuIGJlIHRyZWF0ZWQgYXMgd2lsZCBjYXJkcy4gTGV0J3MgaWdub3JlIHRoYXQgZm9yIG5vdyBhbmQgZm9jdXMgb24gdGhlIHNpbXBsZXIgY2FzZSB3aGVyZSBkaWFtb25kcyBkb3VibGUgdGhlIHByaXplIGJ1dCBhcmUgbm90IHdpbGRzLiBgc2NvcmVgIGNhbiBkb3VibGUgdGhlIHByaXplIGFzIG5lY2Vzc2FyeSBhZnRlciBpdCBydW5zIG9uZSBvZiB0aGUgZm9sbG93aW5nIGFsZ29yaXRobXMuCgpBZGRpbmcgdGhlIGBzY29yZWAgY2FzZXMgdG8gdGhlIGBwbGF5YCBzdGVwcyByZXZlYWxzIGEgc3RyYXRlZ3kgZm9yIHRoZSBjb21wbGV0ZSBzbG90IG1hY2hpbmUgcHJvZ3JhbS4KCldlJ3ZlIGFscmVhZHkgc29sdmVkIHRoZSBmaXJzdCBmZXcgc3RlcHMgaW4gdGhpcyBzdHJhdGVneS4gT3VyIHByb2dyYW0gY2FuIGdldCB0aHJlZSBzbG90IG1hY2hpbmUgc3ltYm9scyB3aXRoIHRoZSBgZ2V0X3N5bWJvbHNgIGZ1bmN0aW9uLiBUaGVuIGl0IGNhbiBkaXNwbGF5IHRoZSBzeW1ib2xzIHdpdGggdGhlIGBwcmludGAgZnVuY3Rpb24uIE5vdyBsZXQncyBleGFtaW5lIGhvdyB0aGUgcHJvZ3JhbSBjYW4gaGFuZGxlIHRoZSBwYXJhbGxlbCBzY29yZSBjYXNlcy4KCiMjIyBFeGVyY2lzZSAxOiBCcmVha2luZyBkb3duIGEgcHJvZ3JhbSBpbnRvIHNlcXVlbnRpYWwgc3RlcHMKCldyaXRlIGEgZnVuY3Rpb24gY2FsbGVkIGdyZWV0IHRoYXQgdGFrZXMgYSBwZXJzb24ncyBuYW1lIGFzIGlucHV0IGFuZCBwZXJmb3JtcyB0aGUgZm9sbG93aW5nIHN0ZXBzIGluIHNlcXVlbmNlOgoKMS4gIFByaW50cyBhIHdlbGNvbWUgbWVzc2FnZSB0byB0aGUgY29uc29sZS4KMi4gIEFza3MgdGhlIHVzZXIgZm9yIHRoZWlyIGZhdm9yaXRlIGNvbG9yLgozLiAgUHJpbnRzIGEgcGVyc29uYWxpemVkIG1lc3NhZ2UgdG8gdGhlIGNvbnNvbGUgdGhhdCBpbmNsdWRlcyB0aGUgcGVyc29uJ3MgbmFtZSBhbmQgZmF2b3JpdGUgY29sb3IuCgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCmBgYHtyfQpncmVldCA8LSBmdW5jdGlvbihuYW1lKSB7CiAgIyBzdGVwIDE6IHByaW50IHdlbGNvbWUgbWVzc2FnZQogIHByaW50KHBhc3RlKCJIZWxsbywgd2VsY29tZSEiLCBuYW1lKSkKICAKICAjIHN0ZXAgMjogYXNrIGZvciBmYXZvcml0ZSBjb2xvcgogIGZhdm9yaXRlX2NvbG9yIDwtIHJlYWRsaW5lKHByb21wdCA9ICJXaGF0IGlzIHlvdXIgZmF2b3JpdGUgY29sb3I/ICIpCiAgCiAgIyBzdGVwIDM6IHByaW50IHBlcnNvbmFsaXplZCBtZXNzYWdlCiAgcHJpbnQocGFzdGUoIllvdXIgZmF2b3JpdGUgY29sb3IgaXMiLCBmYXZvcml0ZV9jb2xvciwgbmFtZSkpCn0KYGBgCgo8L2RldGFpbHM+CgojIyMgRXhlcmNpc2UgMjogSGFuZGxpbmcgcGFyYWxsZWwgY2FzZXMKCldyaXRlIGEgZnVuY3Rpb24gY2FsbGVkIGNhbGN1bGF0ZV9wcml6ZSB0aGF0IHRha2VzIGEgdmVjdG9yIG9mIHNsb3QgbWFjaGluZSBzeW1ib2xzIGFzIGlucHV0IGFuZCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHByaXplIGFtb3VudC4gVGhlIGZ1bmN0aW9uIHNob3VsZCBoYW5kbGUgdGhlIGZvbGxvd2luZyBjYXNlczoKCi0gICBJZiB0aGUgc3ltYm9scyBjb250YWluIHRocmVlIG9mIGEga2luZCwgdGhlIHByaXplIGlzIFwkMTAuCi0gICBJZiB0aGUgc3ltYm9scyBhcmUgYWxsIGJhcnMsIHRoZSBwcml6ZSBpcyBcJDUuCi0gICBJZiB0aGUgc3ltYm9scyBkbyBub3QgY29udGFpbiB0aHJlZSBvZiBhIGtpbmQgb3IgYWxsIGJhcnMsIHRoZSBwcml6ZSBpcyB0aGUgbnVtYmVyIG9mIGNoZXJyaWVzIHByZXNlbnQuCgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCmBgYHtyfQpjYWxjdWxhdGVfcHJpemUgPC0gZnVuY3Rpb24oc3ltYm9scykgewogICMgY2hlY2sgZm9yIHRocmVlIG9mIGEga2luZAogIGlmIChsZW5ndGgodW5pcXVlKHN5bWJvbHMpKSA9PSAxKSB7CiAgICByZXR1cm4oMTApCiAgfQogIAogICMgY2hlY2sgZm9yIGFsbCBiYXJzCiAgaWYgKGFsbChzeW1ib2xzID09ICJiYXIiKSkgewogICAgcmV0dXJuKDUpCiAgfQogIAogICMgY291bnQgdGhlIG51bWJlciBvZiBjaGVycmllcwogIGNoZXJyaWVzIDwtIHN1bShzeW1ib2xzID09ICJjaGVycnkiKQogIHJldHVybihjaGVycmllcykKfQpgYGAKCjwvZGV0YWlscz4KCiMjIGlmIFN0YXRlbWVudHMKCkxpbmtpbmcgY2FzZXMgdG9nZXRoZXIgaW4gcGFyYWxsZWwgcmVxdWlyZXMgYSBiaXQgb2Ygc3RydWN0dXJlOyB5b3VyIHByb2dyYW0gZmFjZXMgYSBmb3JrIGluIHRoZSByb2FkIHdoZW5ldmVyIGl0IG11c3QgY2hvb3NlIGJldHdlZW4gY2FzZXMuIFlvdSBjYW4gaGVscCB0aGUgcHJvZ3JhbSBuYXZpZ2F0ZSB0aGlzIGZvcmsgd2l0aCBhbiBgaWZgIHN0YXRlbWVudC4KCkFuIGBpZmAgc3RhdGVtZW50IHRlbGxzIFIgdG8gZG8gYSBjZXJ0YWluIHRhc2sgZm9yIGEgY2VydGFpbiBjYXNlLiBJbiBFbmdsaXNoIHlvdSB3b3VsZCBzYXkgc29tZXRoaW5nIGxpa2UsICJJZiB0aGlzIGlzIHRydWUsIGRvIHRoYXQuIiBJbiBSLCB5b3Ugd291bGQgc2F5OgoKYGBgIHtyfQppZiAodGhpcykgewogIHRoYXQKfQpgYGAKClRoZSBgdGhpc2Agb2JqZWN0IHNob3VsZCBiZSBhIGxvZ2ljYWwgdGVzdCBvciBhbiBSIGV4cHJlc3Npb24gdGhhdCBldmFsdWF0ZXMgdG8gYSBzaW5nbGUgYFRSVUVgIG9yIGBGQUxTRWAuIElmIGB0aGlzYCBldmFsdWF0ZXMgdG8gYFRSVUVgLCBSIHdpbGwgcnVuIGFsbCBvZiB0aGUgY29kZSB0aGF0IGFwcGVhcnMgYmV0d2VlbiB0aGUgYnJhY2VzIHRoYXQgZm9sbG93IHRoZSBgaWZgIHN0YXRlbWVudCAoaS5lLiwgYmV0d2VlbiB0aGUgYHtgIGFuZCBgfWAgc3ltYm9scykuIElmIGB0aGlzYCBldmFsdWF0ZXMgdG8gYEZBTFNFYCwgUiB3aWxsIHNraXAgdGhlIGNvZGUgYmV0d2VlbiB0aGUgYnJhY2VzIHdpdGhvdXQgcnVubmluZyBpdC4KCkZvciBleGFtcGxlLCB5b3UgY291bGQgd3JpdGUgYW4gYGlmYCBzdGF0ZW1lbnQgdGhhdCBlbnN1cmVzIHNvbWUgb2JqZWN0LCBgbnVtYCwgaXMgcG9zaXRpdmU6CgpgYGAge3J9CmlmIChudW0gPCAwKSB7CiAgbnVtIDwtIG51bSAqIC0xCn0KYGBgCgpJZiBgbnVtIDwgMGAgaXMgYFRSVUVgLCBSIHdpbGwgbXVsdGlwbHkgYG51bWAgYnkgbmVnYXRpdmUgb25lLCB3aGljaCB3aWxsIG1ha2UgYG51bWAgcG9zaXRpdmU6CgpgYGAge3J9Cm51bSA8LSAtMgoKaWYgKG51bSA8IDApIHsKICBudW0gPC0gbnVtICogLTEKfQoKbnVtCiMjIDIKYGBgCgpJZiBgbnVtIDwgMGAgaXMgYEZBTFNFYCwgUiB3aWxsIGRvIG5vdGhpbmcgYW5kIGBudW1gIHdpbGwgcmVtYWluIGFzIGl0IGlz4oCUcG9zaXRpdmUgKG9yIHplcm8pOgoKYGBgIHtyfQpudW0gPC0gNAoKaWYgKG51bSA8IDApIHsKICBudW0gPC0gbnVtICogLTEKfQoKbnVtCiMjIDQKYGBgCgpUaGUgY29uZGl0aW9uIG9mIGFuIGBpZmAgc3RhdGVtZW50IG11c3QgZXZhbHVhdGUgdG8gYSAqc2luZ2xlKiBgVFJVRWAgb3IgYEZBTFNFYC4gSWYgdGhlIGNvbmRpdGlvbiBjcmVhdGVzIGEgdmVjdG9yIG9mIGBUUlVFYHMgYW5kIGBGQUxTRWBzICh3aGljaCBpcyBlYXNpZXIgdG8gbWFrZSB0aGFuIHlvdSBtYXkgdGhpbmspLCB5b3VyIGBpZmAgc3RhdGVtZW50IHdpbGwgcHJpbnQgYSB3YXJuaW5nIG1lc3NhZ2UgYW5kIHVzZSBvbmx5IHRoZSBmaXJzdCBlbGVtZW50IG9mIHRoZSB2ZWN0b3IuIFJlbWVtYmVyIHRoYXQgeW91IGNhbiBjb25kZW5zZSB2ZWN0b3JzIG9mIGxvZ2ljYWwgdmFsdWVzIHRvIGEgc2luZ2xlIGBUUlVFYCBvciBgRkFMU0VgIHdpdGggdGhlIGZ1bmN0aW9ucyBgYW55YCBhbmQgYGFsbGAuCgpZb3UgZG9uJ3QgaGF2ZSB0byBsaW1pdCB5b3VyIGBpZmAgc3RhdGVtZW50cyB0byBhIHNpbmdsZSBsaW5lIG9mIGNvZGU7IHlvdSBjYW4gaW5jbHVkZSBhcyBtYW55IGxpbmVzIGFzIHlvdSBsaWtlIGJldHdlZW4gdGhlIGJyYWNlcy4gRm9yIGV4YW1wbGUsIHRoZSBmb2xsb3dpbmcgY29kZSB1c2VzIG1hbnkgbGluZXMgdG8gZW5zdXJlIHRoYXQgYG51bWAgaXMgcG9zaXRpdmUuIFRoZSBhZGRpdGlvbmFsIGxpbmVzIHByaW50IHNvbWUgaW5mb3JtYXRpdmUgc3RhdGVtZW50cyBpZiBgbnVtYCBiZWdpbnMgYXMgYSBuZWdhdGl2ZSBudW1iZXIuIFIgd2lsbCBza2lwIHRoZSBlbnRpcmUgY29kZSBibG9ja+KAlGBwcmludGAgc3RhdGVtZW50cyBhbmQgYWxs4oCUaWYgYG51bWAgYmVnaW5zIGFzIGEgcG9zaXRpdmUgbnVtYmVyOgoKYGBgIHtyfQpudW0gPC0gLTEKCmlmIChudW0gPCAwKSB7CiAgcHJpbnQoIm51bSBpcyBuZWdhdGl2ZS4iKQogIHByaW50KCJEb24ndCB3b3JyeSwgSSdsbCBmaXggaXQuIikKICBudW0gPC0gbnVtICogLTEKICBwcmludCgiTm93IG51bSBpcyBwb3NpdGl2ZS4iKQp9CiMjICJudW0gaXMgbmVnYXRpdmUuIgojIyAiRG9uJ3Qgd29ycnksIEknbGwgZml4IGl0LiIKIyMgIk5vdyBudW0gaXMgcG9zaXRpdmUuIgoKbnVtCiMjIDEKYGBgCgpUcnkgdGhlIGZvbGxvd2luZyBxdWl6emVzIHRvIGRldmVsb3AgeW91ciB1bmRlcnN0YW5kaW5nIG9mIGBpZmAgc3RhdGVtZW50cy4KCiMjIyBRdWl6eiAxOiBXaGF0IHdpbGwgdGhpcyByZXR1cm4gPwoKYGBgIHtyfQp4IDwtIDEKaWYgKDMgPT0gMykgewogIHggPC0gMgp9CngKYGBgCgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KClRoZSBjb2RlIHdpbGwgcmV0dXJuIHRoZSBudW1iZXIgMi4gYHhgIGJlZ2lucyBhcyAxLCBhbmQgdGhlbiBSIGVuY291bnRlcnMgdGhlIGBpZmAgc3RhdGVtZW50LiBTaW5jZSB0aGUgY29uZGl0aW9uIGV2YWx1YXRlcyB0byBgVFJVRWAsIFIgd2lsbCBydW4gYHggPC0gMmAsIGNoYW5naW5nIHRoZSB2YWx1ZSBvZiBgeGAuCgo8L2RldGFpbHM+CgojIyMgUXVpenogMjogV2hhdCB3aWxsIHRoaXMgcmV0dXJuID8KCmBgYCB7cn0KeCA8LSAxCmlmIChUUlVFKSB7CiAgeCA8LSAyCn0KeApgYGAKCjxkZXRhaWxzPgoKPHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHNvbHV0aW9uPC9zdW1tYXJ5PgoKVGhpcyBjb2RlIHdpbGwgYWxzbyByZXR1cm4gdGhlIG51bWJlciAyLiBJdCB3b3JrcyB0aGUgc2FtZSBhcyB0aGUgY29kZSBpbiBRdWl6IEEsIGV4Y2VwdCB0aGUgY29uZGl0aW9uIGluIHRoaXMgc3RhdGVtZW50IGlzIGFscmVhZHkgYFRSVUVgLiBSIGRvZXNuJ3QgZXZlbiBuZWVkIHRvIGV2YWx1YXRlIGl0LiBBcyBhIHJlc3VsdCwgdGhlIGNvZGUgaW5zaWRlIHRoZSBgaWZgIHN0YXRlbWVudCB3aWxsIGJlIHJ1biwgYW5kIGB4YCB3aWxsIGJlIHNldCB0byAyLgoKPC9kZXRhaWxzPgoKIyMjIFF1aXp6IDM6IFdoYXQgd2lsbCB0aGlzIHJldHVybiA/CgpgYGAge3J9CnggPC0gMQppZiAoeCA9PSAxKSB7CiAgeCA8LSAyCiAgaWYgKHggPT0gMSkgewogICAgeCA8LSAzCiAgfQp9CngKYGBgCgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCk9uY2UgYWdhaW4sIHRoZSBjb2RlIHdpbGwgcmV0dXJuIHRoZSBudW1iZXIgMi4gYHhgIHN0YXJ0cyBvdXQgYXMgMSwgYW5kIHRoZSBjb25kaXRpb24gb2YgdGhlIGZpcnN0IGBpZmAgc3RhdGVtZW50IHdpbGwgZXZhbHVhdGUgdG8gYFRSVUVgLCB3aGljaCBjYXVzZXMgUiB0byBydW4gdGhlIGNvZGUgaW4gdGhlIGJvZHkgb2YgdGhlIGBpZmAgc3RhdGVtZW50LiBGaXJzdCwgUiBzZXRzIGB4YCBlcXVhbCB0byAyLCB0aGVuIFIgZXZhbHVhdGVzIHRoZSBzZWNvbmQgYGlmYCBzdGF0ZW1lbnQsIHdoaWNoIGlzIGluIHRoZSBib2R5IG9mIHRoZSBmaXJzdC4gVGhpcyB0aW1lIGB4ID09IDFgIHdpbGwgZXZhbHVhdGUgdG8gYEZBTFNFYCBiZWNhdXNlIGB4YCBub3cgZXF1YWxzIDIuIEFzIGEgcmVzdWx0LCBSIGlnbm9yZXMgYHggPC0gM2AgYW5kIGV4aXRzIGJvdGggYGlmYCBzdGF0ZW1lbnRzLgoKPC9kZXRhaWxzPgoKIyMjIEV4ZXJjaXNlIDE6IFVzaW5nIGlmIHN0YXRlbWVudHMgdG8gbWFrZSBhIGRlY2lzaW9uCgpXcml0ZSBhIGZ1bmN0aW9uIGNhbGxlZCBjaGVja19hZ2UgdGhhdCB0YWtlcyBhIHBlcnNvbidzIGFnZSBhcyBpbnB1dCBhbmQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZyB3aGV0aGVyIHRoZXkgYXJlIGVsaWdpYmxlIHRvIHZvdGUgb3Igbm90LiBJZiB0aGUgcGVyc29uIGlzIDE4IG9yIG9sZGVyLCB0aGV5IGFyZSBlbGlnaWJsZSB0byB2b3RlLgoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KY2hlY2tfYWdlIDwtIGZ1bmN0aW9uKGFnZSkgewogIGlmIChhZ2UgPj0gMTgpIHsKICAgIHJldHVybigiWW91IGFyZSBlbGlnaWJsZSB0byB2b3RlLiIpCiAgfSBlbHNlIHsKICAgIHJldHVybigiWW91IGFyZSBub3QgZWxpZ2libGUgdG8gdm90ZS4iKQogIH0KfQpgYGAKCjwvZGV0YWlscz4KCiMjIyBFeGVyY2lzZSAyOiBVc2luZyBpZiBzdGF0ZW1lbnRzIHRvIHBlcmZvcm0gbXVsdGlwbGUgYWN0aW9ucwoKV3JpdGUgYSBmdW5jdGlvbiBjYWxsZWQgcHJvY2Vzc19zY29yZSB0aGF0IHRha2VzIGEgc2NvcmUgYXMgaW5wdXQgYW5kIHBlcmZvcm1zIHRoZSBmb2xsb3dpbmcgYWN0aW9uczoKCiogSWYgdGhlIHNjb3JlIGlzIG5lZ2F0aXZlLCBtdWx0aXBseSBpdCBieSAtMSB0byBtYWtlIGl0IHBvc2l0aXZlLgoqIFByaW50IGEgbWVzc2FnZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIHNjb3JlIGlzIHBvc2l0aXZlIG9yIG5lZ2F0aXZlLgoqIFJldHVybiB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIHNjb3JlLgoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KcHJvY2Vzc19zY29yZSA8LSBmdW5jdGlvbihzY29yZSkgewogIGlmIChzY29yZSA8IDApIHsKICAgIHByaW50KCJUaGUgc2NvcmUgd2FzIG5lZ2F0aXZlLiBJJ2xsIGZpeCBpdC4iKQogICAgc2NvcmUgPC0gc2NvcmUgKiAtMQogIH0KICBwcmludChwYXN0ZSgiVGhlIHNjb3JlIGlzIG5vdyIsIHNjb3JlKSkKICByZXR1cm4oYWJzKHNjb3JlKSkKfQpgYGAKCjwvZGV0YWlscz4KCiMjIGVsc2UgU3RhdGVtZW50cwoKYGlmYCBzdGF0ZW1lbnRzIHRlbGwgUiB3aGF0IHRvIGRvIHdoZW4geW91ciBjb25kaXRpb24gaXMgKnRydWUqLCBidXQgeW91IGNhbiBhbHNvIHRlbGwgUiB3aGF0IHRvIGRvIHdoZW4gdGhlIGNvbmRpdGlvbiBpcyAqZmFsc2UqLiBgZWxzZWAgaXMgYSBjb3VudGVycGFydCB0byBgaWZgIHRoYXQgZXh0ZW5kcyBhbiBgaWZgIHN0YXRlbWVudCB0byBpbmNsdWRlIGEgc2Vjb25kIGNhc2UuIEluIEVuZ2xpc2gsIHlvdSB3b3VsZCBzYXksICJJZiB0aGlzIGlzIHRydWUsIGRvIHBsYW4gQTsgZWxzZSBkbyBwbGFuIEIuIiBJbiBSLCB5b3Ugd291bGQgc2F5OgoKYGBgIHtyfQppZiAodGhpcykgewogIFBsYW4gQQp9IGVsc2UgewogIFBsYW4gQgp9CmBgYAoKV2hlbiBgdGhpc2AgZXZhbHVhdGVzIHRvIGBUUlVFYCwgUiB3aWxsIHJ1biB0aGUgY29kZSBpbiB0aGUgZmlyc3Qgc2V0IG9mIGJyYWNlcywgYnV0IG5vdCB0aGUgY29kZSBpbiB0aGUgc2Vjb25kLiBXaGVuIGB0aGlzYCBldmFsdWF0ZXMgdG8gYEZBTFNFYCwgUiB3aWxsIHJ1biB0aGUgY29kZSBpbiB0aGUgc2Vjb25kIHNldCBvZiBicmFjZXMsIGJ1dCBub3QgdGhlIGZpcnN0LiBZb3UgY2FuIHVzZSB0aGlzIGFycmFuZ2VtZW50IHRvIGNvdmVyIGFsbCBvZiB0aGUgcG9zc2libGUgY2FzZXMuIEZvciBleGFtcGxlLCB5b3UgY291bGQgd3JpdGUgc29tZSBjb2RlIHRoYXQgcm91bmRzIGEgZGVjaW1hbCB0byB0aGUgbmVhcmVzdCBpbnRlZ2VyLgoKU3RhcnQgd2l0aCBhIGRlY2ltYWw6CgpgYGAge3J9CmEgPC0gMy4xNApgYGAKClRoZW4gaXNvbGF0ZSB0aGUgZGVjaW1hbCBjb21wb25lbnQgd2l0aCBgdHJ1bmNgOgoKYGBgIHtyfQpkZWMgPC0gYSAtIHRydW5jKGEpCmRlYwojIyAwLjE0CmBgYAoKCmB0cnVuY2AgdGFrZXMgYSBudW1iZXIgYW5kIHJldHVybnMgb25seSB0aGUgcG9ydGlvbiBvZiB0aGUgbnVtYmVyIHRoYXQgYXBwZWFycyB0byB0aGUgbGVmdCBvZiB0aGUgZGVjaW1hbCBwbGFjZSAoaS5lLiwgdGhlIGludGVnZXIgcGFydCBvZiB0aGUgbnVtYmVyKS4gCgpgYSAtIHRydW5jKGEpYCBpcyBhIGNvbnZlbmllbnQgd2F5IHRvIHJldHVybiB0aGUgZGVjaW1hbCBwYXJ0IG9mIGBhYC4KClRoZW4gdXNlIGFuIGBpZiBlbHNlYCB0cmVlIHRvIHJvdW5kIHRoZSBudW1iZXIgKGVpdGhlciB1cCBvciBkb3duKToKCmBgYCB7cn0KaWYgKGRlYyA+PSAwLjUpIHsKICBhIDwtIHRydW5jKGEpICsgMQp9IGVsc2UgewogIGEgPC0gdHJ1bmMoYSkKfQoKYQojIyAzCmBgYAoKSWYgeW91ciBzaXR1YXRpb24gaGFzIG1vcmUgdGhhbiB0d28gbXV0dWFsbHkgZXhjbHVzaXZlIGNhc2VzLCB5b3UgY2FuIHN0cmluZyBtdWx0aXBsZSBgaWZgIGFuZCBgZWxzZWAgc3RhdGVtZW50cyB0b2dldGhlciBieSBhZGRpbmcgYSBuZXcgYGlmYCBzdGF0ZW1lbnQgaW1tZWRpYXRlbHkgYWZ0ZXIgYGVsc2VgLiBGb3IgZXhhbXBsZToKCmBgYCB7cn0KYSA8LSAxCmIgPC0gMQoKaWYgKGEgPiBiKSB7CiAgcHJpbnQoIkEgd2lucyEiKQp9IGVsc2UgaWYgKGEgPCBiKSB7CiAgcHJpbnQoIkIgd2lucyEiKQp9IGVsc2UgewogIHByaW50KCJUaWUuIikKfQojIyAiVGllLiIKYGBgCgpSIHdpbGwgd29yayB0aHJvdWdoIHRoZSBgaWZgIGNvbmRpdGlvbnMgdW50aWwgb25lIGV2YWx1YXRlcyB0byBgVFJVRWAsIHRoZW4gUiB3aWxsIGlnbm9yZSBhbnkgcmVtYWluaW5nIGBpZmAgYW5kIGBlbHNlYCBjbGF1c2VzIGluIHRoZSB0cmVlLiBJZiBubyBjb25kaXRpb25zIGV2YWx1YXRlIHRvIGBUUlVFYCwgUiB3aWxsIHJ1biB0aGUgZmluYWwgYGVsc2VgIHN0YXRlbWVudC4KCklmIHR3byBgaWZgIHN0YXRlbWVudHMgZGVzY3JpYmUgbXV0dWFsbHkgZXhjbHVzaXZlIGV2ZW50cywgaXQgaXMgYmV0dGVyIHRvIGpvaW4gdGhlIGBpZmAgc3RhdGVtZW50cyB3aXRoIGFuIGBlbHNlIGlmYCB0aGFuIHRvIGxpc3QgdGhlbSBzZXBhcmF0ZWx5LiBUaGlzIGxldHMgUiBpZ25vcmUgdGhlIHNlY29uZCBgaWZgIHN0YXRlbWVudCB3aGVuZXZlciB0aGUgZmlyc3QgcmV0dXJucyBhIGBUUlVFYCwgd2hpY2ggc2F2ZXMgd29yay4KCllvdSBjYW4gdXNlIGBpZmAgYW5kIGBlbHNlYCB0byBsaW5rIHRoZSBzdWJ0YXNrcyBpbiB5b3VyIHNsb3QtbWFjaGluZSBmdW5jdGlvbi4gT3BlbiBhIGZyZXNoIFIgc2NyaXB0LCBhbmQgY29weSB0aGlzIGNvZGUgaW50byBpdC4gVGhlIGNvZGUgd2lsbCBiZSB0aGUgc2tlbGV0b24gb2Ygb3VyIGZpbmFsIGBzY29yZWAgZnVuY3Rpb24uCgpgYGAge3J9CmlmICggIyBDYXNlIDE6IGFsbCB0aGUgc2FtZSA8MT4pIHsKICBwcml6ZSA8LSAjIGxvb2sgdXAgdGhlIHByaXplIDwzPgp9IGVsc2UgaWYgKCAjIENhc2UgMjogYWxsIGJhcnMgPDI+ICkgewogIHByaXplIDwtICMgYXNzaWduICQ1IDw0Pgp9IGVsc2UgewogICMgY291bnQgY2hlcnJpZXMgPDU+CiAgcHJpemUgPC0gIyBjYWxjdWxhdGUgYSBwcml6ZSA8Nz4KfQoKIyBjb3VudCBkaWFtb25kcyA8Nj4KIyBkb3VibGUgdGhlIHByaXplIGlmIG5lY2Vzc2FyeSA8OD4KYGBgCgpPdXIgc2tlbGV0b24gaXMgcmF0aGVyIGluY29tcGxldGU7IHRoZXJlIGFyZSBtYW55IHNlY3Rpb25zIHRoYXQgYXJlIGp1c3QgY29kZSBjb21tZW50cyBpbnN0ZWFkIG9mIHJlYWwgY29kZS4gSG93ZXZlciwgd2UndmUgcmVkdWNlZCB0aGUgcHJvZ3JhbSB0byBlaWdodCBzaW1wbGUgc3VidGFza3M6CgoqKlw8MVw+KiogLSBUZXN0IHdoZXRoZXIgdGhlIHN5bWJvbHMgYXJlIHRocmVlIG9mIGEga2luZC5cCioqXDwyXD4qKiAtIFRlc3Qgd2hldGhlciB0aGUgc3ltYm9scyBhcmUgYWxsIGJhcnMuXAoqKlw8M1w+KiogLSBMb29rIHVwIHRoZSBwcml6ZSBmb3IgdGhyZWUgb2YgYSBraW5kIGJhc2VkIG9uIHRoZSBjb21tb24gc3ltYm9sLlwKKipcPDRcPioqIC0gQXNzaWduIGEgcHJpemUgb2YgXCQ1LlwKKipcPDVcPioqIC0gQ291bnQgdGhlIG51bWJlciBvZiBjaGVycmllcy5cCioqXDw2XD4qKiAtIENvdW50IHRoZSBudW1iZXIgb2YgZGlhbW9uZHMuXAoqKlw8N1w+KiogLSBDYWxjdWxhdGUgYSBwcml6ZSBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIGNoZXJyaWVzLlwKKipcPDhcPioqIC0gQWRqdXN0IHRoZSBwcml6ZSBmb3IgZGlhbW9uZHMuCgpJZiB5b3UgbGlrZSwgeW91IGNhbiByZW9yZ2FuaXplIHlvdXIgZmxvdyBjaGFydCBhcm91bmQgdGhlc2UgdGFza3MuIFRoZSBjaGFydCB3aWxsIGRlc2NyaWJlIHRoZSBzYW1lIHN0cmF0ZWd5LCBidXQgaW4gYSBtb3JlIHByZWNpc2Ugd2F5LiBJJ2xsIHVzZSBhIGRpYW1vbmQgc2hhcGUgdG8gc3ltYm9saXplIGFuIGBpZiBlbHNlYCBkZWNpc2lvbi4KCk5vdyB3ZSBjYW4gd29yayB0aHJvdWdoIHRoZSBzdWJ0YXNrcyBvbmUgYXQgYSB0aW1lLCBhZGRpbmcgUiBjb2RlIHRvIHRoZSBgaWZgIHRyZWUgYXMgd2UgZ28uIEVhY2ggc3VidGFzayB3aWxsIGJlIGVhc3kgdG8gc29sdmUgaWYgeW91IHNldCB1cCBhIGNvbmNyZXRlIGV4YW1wbGUgdG8gd29yayB3aXRoIGFuZCB0cnkgdG8gZGVzY3JpYmUgYSBzb2x1dGlvbiBpbiBFbmdsaXNoIGJlZm9yZSBjb2RpbmcgaW4gUi4KClRoZSBmaXJzdCBzdWJ0YXNrIGFza3MgeW91IHRvIHRlc3Qgd2hldGhlciB0aGUgc3ltYm9scyBhcmUgdGhyZWUgb2YgYSBraW5kLiBIb3cgc2hvdWxkIHlvdSBiZWdpbiB3cml0aW5nIHRoZSBjb2RlIGZvciB0aGlzIHN1YnRhc2s/CgpZb3Uga25vdyB0aGF0IHRoZSBmaW5hbCBgc2NvcmVgIGZ1bmN0aW9uIHdpbGwgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgoKYGBgIHtyfQpzY29yZSA8LSBmdW5jdGlvbihzeW1ib2xzKSB7CgogICMgY2FsY3VsYXRlIGEgcHJpemUKCiAgcHJpemUKfQpgYGAKCkl0cyBhcmd1bWVudCwgYHN5bWJvbHNgLCB3aWxsIGJlIHRoZSBvdXRwdXQgb2YgYGdldF9zeW1ib2xzYCwgYSB2ZWN0b3IgdGhhdCBjb250YWlucyB0aHJlZSBjaGFyYWN0ZXIgc3RyaW5ncy4gWW91IGNvdWxkIHN0YXJ0IHdyaXRpbmcgYHNjb3JlYCBhcyBJIGhhdmUgd3JpdHRlbiBpdCwgYnkgZGVmaW5pbmcgYW4gb2JqZWN0IG5hbWVkIGBzY29yZWAgYW5kIHRoZW4gc2xvd2x5IGZpbGxpbmcgaW4gdGhlIGJvZHkgb2YgdGhlIGZ1bmN0aW9uLiBIb3dldmVyLCB0aGlzIHdvdWxkIGJlIGEgYmFkIGlkZWEuIFRoZSBldmVudHVhbCBmdW5jdGlvbiB3aWxsIGhhdmUgZWlnaHQgc2VwYXJhdGUgcGFydHMsIGFuZCBpdCB3aWxsIG5vdCB3b3JrIGNvcnJlY3RseSB1bnRpbCAqYWxsKiBvZiB0aG9zZSBwYXJ0cyBhcmUgd3JpdHRlbiAoYW5kIHRoZW1zZWx2ZXMgd29yayBjb3JyZWN0bHkpLiBUaGlzIG1lYW5zIHlvdSB3b3VsZCBoYXZlIHRvIHdyaXRlIHRoZSBlbnRpcmUgYHNjb3JlYCBmdW5jdGlvbiBiZWZvcmUgeW91IGNvdWxkIHRlc3QgYW55IG9mIHRoZSBzdWJ0YXNrcy4gSWYgYHNjb3JlYCBkb2Vzbid0IHdvcmvigJR3aGljaCBpcyB2ZXJ5IGxpa2VseeKAlHlvdSB3aWxsIG5vdCBrbm93IHdoaWNoIHN1YnRhc2sgbmVlZHMgZml4ZWQuCgpZb3UgY2FuIHNhdmUgeW91cnNlbGYgdGltZSBhbmQgaGVhZGFjaGVzIGlmIHlvdSBmb2N1cyBvbiBvbmUgc3VidGFzayBhdCBhIHRpbWUuIEZvciBlYWNoIHN1YnRhc2ssIGNyZWF0ZSBhIGNvbmNyZXRlIGV4YW1wbGUgdGhhdCB5b3UgY2FuIHRlc3QgeW91ciBjb2RlIG9uLiBGb3IgZXhhbXBsZSwgeW91IGtub3cgdGhhdCBgc2NvcmVgIHdpbGwgbmVlZCB0byB3b3JrIG9uIGEgdmVjdG9yIG5hbWVkIGBzeW1ib2xzYCB0aGF0IGNvbnRhaW5zIHRocmVlIGNoYXJhY3RlciBzdHJpbmdzLiBJZiB5b3UgbWFrZSBhIHJlYWwgdmVjdG9yIG5hbWVkIGBzeW1ib2xzYCwgeW91IGNhbiBydW4gdGhlIGNvZGUgZm9yIG1hbnkgb2YgeW91ciBzdWJ0YXNrcyBvbiB0aGUgdmVjdG9yIGFzIHlvdSBnbzoKCmBgYCB7cn0Kc3ltYm9scyA8LSBjKCI3IiwgIjciLCAiNyIpCmBgYAoKSWYgYSBwaWVjZSBvZiBjb2RlIGRvZXMgbm90IHdvcmsgb24gYHN5bWJvbHNgLCB5b3Ugd2lsbCBrbm93IHRoYXQgeW91IG5lZWQgdG8gZml4IGl0IGJlZm9yZSB5b3UgbW92ZSBvbi4gWW91IGNhbiBjaGFuZ2UgdGhlIHZhbHVlIG9mIGBzeW1ib2xzYCBmcm9tIHN1YnRhc2sgdG8gc3VidGFzayB0byBlbnN1cmUgdGhhdCB5b3VyIGNvZGUgd29ya3MgaW4gZXZlcnkgc2l0dWF0aW9uOgoKYGBgIHtyfQpzeW1ib2xzIDwtIGMoIkIiLCAiQkIiLCAiQkJCIikKc3ltYm9scyA8LSBjKCJDIiwgIkREIiwgIjAiKQpgYGAKCk9ubHkgY29tYmluZSB5b3VyIHN1YnRhc2tzIGludG8gYSBgc2NvcmVgIGZ1bmN0aW9uIG9uY2UgZWFjaCBzdWJ0YXNrIHdvcmtzIG9uIGEgY29uY3JldGUgZXhhbXBsZS4gSWYgeW91IGZvbGxvdyB0aGlzIHBsYW4sIHlvdSB3aWxsIHNwZW5kIG1vcmUgdGltZSB1c2luZyB5b3VyIGZ1bmN0aW9ucyBhbmQgbGVzcyB0aW1lIHRyeWluZyB0byBmaWd1cmUgb3V0IHdoeSB0aGV5IGRvIG5vdCB3b3JrLgoKQWZ0ZXIgeW91IHNldCB1cCBhIGNvbmNyZXRlIGV4YW1wbGUsIHRyeSB0byBkZXNjcmliZSBob3cgeW91IHdpbGwgZG8gdGhlIHN1YnRhc2sgaW4gRW5nbGlzaC4gVGhlIG1vcmUgcHJlY2lzZWx5IHlvdSBjYW4gZGVzY3JpYmUgeW91ciBzb2x1dGlvbiwgdGhlIGVhc2llciBpdCB3aWxsIGJlIHRvIHdyaXRlIHlvdXIgUiBjb2RlLgoKT3VyIGZpcnN0IHN1YnRhc2sgYXNrcyB1cyB0byAidGVzdCB3aGV0aGVyIHRoZSBzeW1ib2xzIGFyZSB0aHJlZSBvZiBhIGtpbmQuIiBUaGlzIHBocmFzZSBkb2VzIG5vdCBzdWdnZXN0IGFueSB1c2VmdWwgUiBjb2RlIHRvIG1lLiBIb3dldmVyLCBJIGNvdWxkIGRlc2NyaWJlIGEgbW9yZSBwcmVjaXNlIHRlc3QgZm9yIHRocmVlIG9mIGEga2luZDogdGhyZWUgc3ltYm9scyB3aWxsIGJlIHRoZSBzYW1lIGlmIHRoZSBmaXJzdCBzeW1ib2wgaXMgZXF1YWwgdG8gdGhlIHNlY29uZCBhbmQgdGhlIHNlY29uZCBzeW1ib2wgaXMgZXF1YWwgdG8gdGhlIHRoaXJkLiBPciwgZXZlbiBtb3JlIHByZWNpc2VseToKCipBIHZlY3RvciBuYW1lZCBgc3ltYm9sc2Agd2lsbCBjb250YWluIHRocmVlIG9mIHRoZSBzYW1lIHN5bWJvbCBpZiB0aGUgZmlyc3QgZWxlbWVudCBvZiBgc3ltYm9sc2AgaXMgZXF1YWwgdG8gdGhlIHNlY29uZCBlbGVtZW50IG9mIGBzeW1ib2xzYCBhbmQgdGhlIHNlY29uZCBlbGVtZW50IG9mIGBzeW1ib2xzYCBpcyBlcXVhbCB0byB0aGUgdGhpcmQgZWxlbWVudCBvZiBgc3ltYm9sc2AqLgoKIyMjIEV4ZXJjaXNlIDE6IFdyaXRlIGEgdGVzdAoKVHVybiB0aGUgcHJlY2VkaW5nIHN0YXRlbWVudCBpbnRvIGEgbG9naWNhbCB0ZXN0IHdyaXR0ZW4gaW4gUi4gVXNlIHlvdXIga25vd2xlZGdlIG9mIGxvZ2ljYWwgdGVzdHMsIEJvb2xlYW4gb3BlcmF0b3JzLCBhbmQgc3Vic2V0dGluZyBmcm9tIFtSIE5vdGF0aW9uXS4gVGhlIHRlc3Qgc2hvdWxkIHdvcmsgd2l0aCB0aGUgdmVjdG9yIGBzeW1ib2xzYCBhbmQgcmV0dXJuIGEgYFRSVUVgIF9pZiBhbmQgb25seSBpZl8gZWFjaCBlbGVtZW50IGluIGBzeW1ib2xzYCBpcyB0aGUgc2FtZS4gQmUgc3VyZSB0byB0ZXN0IHlvdXIgY29kZSBvbiBgc3ltYm9sc2AuCgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCkhlcmUgYXJlIGEgY291cGxlIG9mIHdheXMgdG8gdGVzdCB0aGF0IGBzeW1ib2xzYCBjb250YWlucyB0aHJlZSBvZiB0aGUgc2FtZSBzeW1ib2wuIFRoZSBmaXJzdCBtZXRob2QgcGFyYWxsZWxzIHRoZSBFbmdsaXNoIHN1Z2dlc3Rpb24gYWJvdmUsIGJ1dCB0aGVyZSBhcmUgb3RoZXIgd2F5cyB0byBkbyB0aGUgc2FtZSB0ZXN0LiBUaGVyZSBpcyBubyByaWdodCBvciB3cm9uZyBhbnN3ZXIsIHNvIGxvbmcgYXMgeW91ciBzb2x1dGlvbiB3b3Jrcywgd2hpY2ggaXMgZWFzeSB0byBjaGVjayBiZWNhdXNlIHlvdSd2ZSBjcmVhdGVkIGEgdmVjdG9yIG5hbWVkIGBzeW1ib2xzYDoKCmBgYCB7cn0Kc3ltYm9scwojIyAgIjciICI3IiAiNyIKCnN5bWJvbHNbMV0gPT0gc3ltYm9sc1syXSAmIHN5bWJvbHNbMl0gPT0gc3ltYm9sc1szXQojIyBUUlVFCgpzeW1ib2xzWzFdID09IHN5bWJvbHNbMl0gJiBzeW1ib2xzWzFdID09IHN5bWJvbHNbM10KIyMgVFJVRQoKYWxsKHN5bWJvbHMgPT0gc3ltYm9sc1sxXSkKIyMgVFJVRQpgYGAKCkFzIHlvdXIgdm9jYWJ1bGFyeSBvZiBSIGZ1bmN0aW9ucyBicm9hZGVucywgeW91J2xsIHRoaW5rIG9mIG1vcmUgd2F5cyB0byBkbyBiYXNpYyB0YXNrcy4gT25lIG1ldGhvZCB0aGF0IEkgbGlrZSBmb3IgY2hlY2tpbmcgdGhyZWUgb2YgYSBraW5kIGlzOgoKYGBgIHtyfQpsZW5ndGgodW5pcXVlKHN5bWJvbHMpID09IDEpCmBgYAoKVGhlIGB1bmlxdWVgIGZ1bmN0aW9uIHJldHVybnMgZXZlcnkgdW5pcXVlIHRlcm0gdGhhdCBhcHBlYXJzIGluIGEgdmVjdG9yLiBJZiB5b3VyIGBzeW1ib2xzYCB2ZWN0b3IgY29udGFpbnMgdGhyZWUgb2YgYSBraW5kIChpLmUuLCBvbmUgdW5pcXVlIHRlcm0gdGhhdCBhcHBlYXJzIHRocmVlIHRpbWVzKSwgdGhlbiBgdW5pcXVlKHN5bWJvbHMpYCB3aWxsIHJldHVybiBhIHZlY3RvciBvZiBsZW5ndGggYDFgLgoKTm93IHRoYXQgeW91IGhhdmUgYSB3b3JraW5nIHRlc3QsIHlvdSBjYW4gYWRkIGl0IHRvIHlvdXIgc2xvdC1tYWNoaW5lIHNjcmlwdDoKCmBgYCB7cn0Kc2FtZSA8LSBzeW1ib2xzWzFdID09IHN5bWJvbHNbMl0gJiYgc3ltYm9sc1syXSA9PSBzeW1ib2xzWzNdCgppZiAoc2FtZSkgewogIHByaXplIDwtICMgbG9vayB1cCB0aGUgcHJpemUKfSBlbHNlIGlmICggIyBDYXNlIDI6IGFsbCBiYXJzICkgewogIHByaXplIDwtICMgYXNzaWduICQ1Cn0gZWxzZSB7CiAgIyBjb3VudCBjaGVycmllcwogIHByaXplIDwtICMgY2FsY3VsYXRlIGEgcHJpemUKfQoKIyBjb3VudCBkaWFtb25kcwojIGRvdWJsZSB0aGUgcHJpemUgaWYgbmVjZXNzYXJ5CmBgYAoKCmAmJmAgYW5kIGB8fGAgYmVoYXZlIGxpa2UgYCZgIGFuZCBgfGAgYnV0IGNhbiBzb21ldGltZXMgYmUgbW9yZSBlZmZpY2llbnQuIFRoZSBkb3VibGUgb3BlcmF0b3JzIHdpbGwgbm90IGV2YWx1YXRlIHRoZSBzZWNvbmQgdGVzdCBpbiBhIHBhaXIgb2YgdGVzdHMgaWYgdGhlIGZpcnN0IHRlc3QgbWFrZXMgdGhlIHJlc3VsdCBjbGVhci4gRm9yIGV4YW1wbGUsIGlmIGBzeW1ib2xzWzFdYCBkb2VzIG5vdCBlcXVhbCBgc3ltYm9sc1syXWAgaW4gdGhlIG5leHQgZXhwcmVzc2lvbiwgYCYmYCB3aWxsIG5vdCBldmFsdWF0ZSBgc3ltYm9sc1syXSA9PSBzeW1ib2xzWzNdYDsgaXQgY2FuIGltbWVkaWF0ZWx5IHJldHVybiBhIGBGQUxTRWAgZm9yIHRoZSB3aG9sZSBleHByZXNzaW9uIChiZWNhdXNlIGBGQUxTRSAmIFRSVUVgIGFuZCBgRkFMU0UgJiBGQUxTRWAgYm90aCBldmFsdWF0ZSB0byBgRkFMU0VgKS4gVGhpcyBlZmZpY2llbmN5IGNhbiBzcGVlZCB1cCB5b3VyIHByb2dyYW1zOyBob3dldmVyLCBkb3VibGUgb3BlcmF0b3JzIGFyZSBub3QgYXBwcm9wcmlhdGUgZXZlcnl3aGVyZS4gYCYmYCBhbmQgYHx8YCBhcmUgbm90IHZlY3Rvcml6ZWQsIHdoaWNoIG1lYW5zIHRoZXkgY2FuIG9ubHkgaGFuZGxlIGEgc2luZ2xlIGxvZ2ljYWwgdGVzdCBvbiBlYWNoIHNpZGUgb2YgdGhlIG9wZXJhdG9yLgoKClRoZSBzZWNvbmQgcHJpemUgY2FzZSBvY2N1cnMgd2hlbiBhbGwgdGhlIHN5bWJvbHMgYXJlIGEgdHlwZSBvZiBiYXIsIGZvciBleGFtcGxlLCBgQmAsIGBCQmAsIGFuZCBgQkJCYC4gTGV0J3MgYmVnaW4gYnkgY3JlYXRpbmcgYSBjb25jcmV0ZSBleGFtcGxlIHRvIHdvcmsgd2l0aDoKCmBgYCB7cn0Kc3ltYm9scyA8LSBjKCJCIiwgIkJCQiIsICJCQiIpCmBgYAo8L2RldGFpbHM+CgoKIyMjIEV4ZXJjaXNlIDI6IFRlc3QgZm9yIGFsbCBiYXJzClVzZSBSJ3MgbG9naWNhbCBhbmQgQm9vbGVhbiBvcGVyYXRvcnMgdG8gd3JpdGUgYSB0ZXN0IHRoYXQgd2lsbCBkZXRlcm1pbmUgd2hldGhlciBhIHZlY3RvciBuYW1lZCBgc3ltYm9sc2AgY29udGFpbnMgb25seSBzeW1ib2xzIHRoYXQgYXJlIGEgdHlwZSBvZiBiYXIuIENoZWNrIHdoZXRoZXIgeW91ciB0ZXN0IHdvcmtzIHdpdGggb3VyIGV4YW1wbGUgYHN5bWJvbHNgIHZlY3Rvci4gUmVtZW1iZXIgdG8gZGVzY3JpYmUgaG93IHRoZSB0ZXN0IHNob3VsZCB3b3JrIGluIEVuZ2xpc2gsIGFuZCB0aGVuIGNvbnZlcnQgdGhlIHNvbHV0aW9uIHRvIFIuCgoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CkFzIHdpdGggbWFueSB0aGluZ3MgaW4gUiwgdGhlcmUgYXJlIG11bHRpcGxlIHdheXMgdG8gdGVzdCB3aGV0aGVyIGBzeW1ib2xzYCBjb250YWlucyBhbGwgYmFycy4gRm9yIGV4YW1wbGUsIHlvdSBjb3VsZCB3cml0ZSBhIHZlcnkgbG9uZyB0ZXN0IHRoYXQgdXNlcyBtdWx0aXBsZSBCb29sZWFuIG9wZXJhdG9ycywgbGlrZSB0aGlzOgoKCmBgYCB7cn0KKHN5bWJvbHNbMV0gPT0gIkIiIHwgc3ltYm9sc1sxXSA9PSAiQkIiIHwgc3ltYm9sc1sxXSA9PSAiQkJCIikgJgogIChzeW1ib2xzWzJdID09ICJCIiB8IHN5bWJvbHNbMl0gPT0gIkJCIiB8IHN5bWJvbHNbMl0gPT0gIkJCQiIpICYKICAoc3ltYm9sc1szXSA9PSAiQiIgfCBzeW1ib2xzWzNdID09ICJCQiIgfCBzeW1ib2xzWzNdID09ICJCQkIiKQojIyBUUlVFCmBgYAoKSG93ZXZlciwgdGhpcyBpcyBub3QgYSB2ZXJ5IGVmZmljaWVudCBzb2x1dGlvbiwgYmVjYXVzZSBSIGhhcyB0byBydW4gbmluZSBsb2dpY2FsIHRlc3RzIChhbmQgeW91IGhhdmUgdG8gdHlwZSB0aGVtKS4gWW91IGNhbiBvZnRlbiByZXBsYWNlIG11bHRpcGxlIGB8YCBvcGVyYXRvcnMgd2l0aCBhIHNpbmdsZSBgJWluJWAuIEFsc28sIHlvdSBjYW4gY2hlY2sgdGhhdCBhIHRlc3QgaXMgdHJ1ZSBmb3IgZWFjaCBlbGVtZW50IGluIGEgdmVjdG9yIHdpdGggYGFsbGAuIFRoZXNlIHR3byBjaGFuZ2VzIHNob3J0ZW4gdGhlIHByZWNlZGluZyBjb2RlIHRvOgoKYGBgIHtyfQphbGwoc3ltYm9scyAlaW4lIGMoIkIiLCAiQkIiLCAiQkJCIikpCiMjIFRSVUUKYGBgCgpMZXQncyBhZGQgdGhpcyBjb2RlIHRvIG91ciBzY3JpcHQ6CgpgYGAge3J9CnNhbWUgPC0gc3ltYm9sc1sxXSA9PSBzeW1ib2xzWzJdICYmIHN5bWJvbHNbMl0gPT0gc3ltYm9sc1szXQpiYXJzIDwtIHN5bWJvbHMgJWluJSBjKCJCIiwgIkJCIiwgIkJCQiIpCgppZiAoc2FtZSkgewogIHByaXplIDwtICMgbG9vayB1cCB0aGUgcHJpemUKfSBlbHNlIGlmIChhbGwoYmFycykpIHsKICBwcml6ZSA8LSAjIGFzc2lnbiAkNQp9IGVsc2UgewogICMgY291bnQgY2hlcnJpZXMKICBwcml6ZSA8LSAjIGNhbGN1bGF0ZSBhIHByaXplCn0KCiMgY291bnQgZGlhbW9uZHMKIyBkb3VibGUgdGhlIHByaXplIGlmIG5lY2Vzc2FyeQpgYGAKCllvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgSSBzcGxpdCB0aGlzIHRlc3QgdXAgaW50byB0d28gc3RlcHMsIGBiYXJzYCBhbmQgYGFsbChiYXJzKWAuIFRoYXQncyBqdXN0IGEgbWF0dGVyIG9mIHBlcnNvbmFsIHByZWZlcmVuY2UuIFdoZXJldmVyIHBvc3NpYmxlLCBJIGxpa2UgdG8gd3JpdGUgbXkgY29kZSBzbyBpdCBjYW4gYmUgcmVhZCB3aXRoIGZ1bmN0aW9uIGFuZCBvYmplY3QgbmFtZXMgY29udmV5aW5nIHdoYXQgdGhleSBkby4KCllvdSBhbHNvIG1heSBoYXZlIG5vdGljZWQgdGhhdCBvdXIgdGVzdCBmb3IgQ2FzZSAyIHdpbGwgY2FwdHVyZSBzb21lIHN5bWJvbHMgdGhhdCBzaG91bGQgYmUgaW4gQ2FzZSAxIGJlY2F1c2UgdGhleSBjb250YWluIHRocmVlIG9mIGEga2luZDoKCmBgYCB7cn0Kc3ltYm9scyA8LSBjKCJCIiwgIkIiLCAiQiIpCmFsbChzeW1ib2xzICVpbiUgYygiQiIsICJCQiIsICJCQkIiKSkKIyMgVFJVRQpgYGAKClRoYXQgd29uJ3QgYmUgYSBwcm9ibGVtLCBob3dldmVyLCBiZWNhdXNlIHdlJ3ZlIGNvbm5lY3RlZCBvdXIgY2FzZXMgd2l0aCBgZWxzZSBpZmAgaW4gdGhlIGBpZmAgdHJlZS4gQXMgc29vbiBhcyBSIGNvbWVzIHRvIGEgY2FzZSB0aGF0IGV2YWx1YXRlcyB0byBgVFJVRWAsIGl0IHdpbGwgc2tpcCBvdmVyIHRoZSByZXN0IG9mIHRoZSB0cmVlLiBUaGluayBvZiBpdCB0aGlzIHdheTogZWFjaCBgZWxzZWAgdGVsbHMgUiB0byBvbmx5IHJ1biB0aGUgY29kZSB0aGF0IGZvbGxvd3MgaXQgKmlmIG5vbmUgb2YgdGhlIHByZXZpb3VzIGNvbmRpdGlvbnMgaGF2ZSBiZWVuIG1ldCouIFNvIHdoZW4gd2UgaGF2ZSB0aHJlZSBvZiB0aGUgc2FtZSB0eXBlIG9mIGJhciwgUiB3aWxsIGV2YWx1YXRlIHRoZSBjb2RlIGZvciBDYXNlIDEgYW5kIHRoZW4gc2tpcCB0aGUgY29kZSBmb3IgQ2FzZSAyIChhbmQgQ2FzZSAzKS4KCk91ciBuZXh0IHN1YnRhc2sgaXMgdG8gYXNzaWduIGEgcHJpemUgZm9yIGBzeW1ib2xzYC4gV2hlbiB0aGUgYHN5bWJvbHNgIHZlY3RvciBjb250YWlucyB0aHJlZSBvZiB0aGUgc2FtZSBzeW1ib2wsIHRoZSBwcml6ZSB3aWxsIGRlcGVuZCBvbiB3aGljaCBzeW1ib2wgdGhlcmUgYXJlIHRocmVlIG9mLiBJZiB0aGVyZSBhcmUgdGhyZWUgYEREYHMsIHRoZSBwcml6ZSB3aWxsIGJlIFwkMTAwOyBpZiB0aGVyZSBhcmUgdGhyZWUgYDdgcywgdGhlIHByaXplIHdpbGwgYmUgXCQ4MDsgYW5kIHNvIG9uLgoKVGhpcyBzdWdnZXN0cyBhbm90aGVyIGBpZmAgdHJlZS4gWW91IGNvdWxkIGFzc2lnbiBhIHByaXplIHdpdGggc29tZSBjb2RlIGxpa2UgdGhpczoKCmBgYCB7cn0KaWYgKHNhbWUpIHsKICBzeW1ib2wgPC0gc3ltYm9sc1sxXQogIGlmIChzeW1ib2wgPT0gIkREIikgewogICAgcHJpemUgPC0gODAwCiAgfSBlbHNlIGlmIChzeW1ib2wgPT0gIjciKSB7CiAgICBwcml6ZSA8LSA4MAogIH0gZWxzZSBpZiAoc3ltYm9sID09ICJCQkIiKSB7CiAgICBwcml6ZSA8LSA0MAogIH0gZWxzZSBpZiAoc3ltYm9sID09ICJCQiIpIHsKICAgIHByaXplIDwtIDUKICB9IGVsc2UgaWYgKHN5bWJvbCA9PSAiQiIpIHsKICAgIHByaXplIDwtIDEwCiAgfSBlbHNlIGlmIChzeW1ib2wgPT0gIkMiKSB7CiAgICBwcml6ZSA8LSAxMAogIH0gZWxzZSBpZiAoc3ltYm9sID09ICIwIikgewogICAgcHJpemUgPC0gMAogIH0KfQpgYGAKCldoaWxlIHRoaXMgY29kZSB3aWxsIHdvcmssIGl0IGlzIGEgYml0IGxvbmcgdG8gd3JpdGUgYW5kIHJlYWQsIGFuZCBpdCBtYXkgcmVxdWlyZSBSIHRvIHBlcmZvcm0gbXVsdGlwbGUgbG9naWNhbCB0ZXN0cyBiZWZvcmUgZGVsaXZlcmluZyB0aGUgY29ycmVjdCBwcml6ZS4gV2UgY2FuIGRvIGJldHRlciB3aXRoIGEgZGlmZmVyZW50IG1ldGhvZC4KCjwvZGV0YWlscz4KIyMgTG9va3VwIFRhYmxlcwoKVmVyeSBvZnRlbiBpbiBSLCB0aGUgc2ltcGxlc3Qgd2F5IHRvIGRvIHNvbWV0aGluZyB3aWxsIGludm9sdmUgc3Vic2V0dGluZy4gSG93IGNvdWxkIHlvdSB1c2Ugc3Vic2V0dGluZyBoZXJlPyBTaW5jZSB5b3Uga25vdyB0aGUgZXhhY3QgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN5bWJvbHMgYW5kIHRoZWlyIHByaXplcywgeW91IGNhbiBjcmVhdGUgYSB2ZWN0b3IgdGhhdCBjYXB0dXJlcyB0aGlzIGluZm9ybWF0aW9uLiBUaGlzIHZlY3RvciBjYW4gc3RvcmUgc3ltYm9scyBhcyBuYW1lcyBhbmQgcHJpemUgdmFsdWVzIGFzIGVsZW1lbnRzOgoKYGBgIHtyfQpwYXlvdXRzIDwtIGMoIkREIiA9IDEwMCwgIjciID0gODAsICJCQkIiID0gNDAsICJCQiIgPSAyNSwgCiAgIkIiID0gMTAsICJDIiA9IDEwLCAiMCIgPSAwKQpwYXlvdXRzCiMjICBERCAgIDcgQkJCICBCQiAgIEIgICBDICAgMCAKIyMgMTAwICA4MCAgNDAgIDI1ICAxMCAgMTAgICAwIApgYGAKCk5vdyB5b3UgY2FuIGV4dHJhY3QgdGhlIGNvcnJlY3QgcHJpemUgZm9yIGFueSBzeW1ib2wgYnkgc3Vic2V0dGluZyB0aGUgdmVjdG9yIHdpdGggdGhlIHN5bWJvbCdzIG5hbWU6CgpgYGAge3J9CnBheW91dHNbIkREIl0KIyMgIEREIAojIyAxMDAgCgpwYXlvdXRzWyJCIl0KIyMgIEIKIyMgMTAKYGBgCgpJZiB5b3Ugd2FudCB0byBsZWF2ZSBiZWhpbmQgdGhlIHN5bWJvbCdzIG5hbWUgd2hlbiBzdWJzZXR0aW5nLCB5b3UgY2FuIHJ1biB0aGUgYHVubmFtZWAgZnVuY3Rpb24gb24gdGhlIG91dHB1dDoKCmBgYCB7cn0KdW5uYW1lKHBheW91dHNbIkREIl0pCiMjIDEwMCAKYGBgCgpgdW5uYW1lYCByZXR1cm5zIGEgY29weSBvZiBhbiBvYmplY3Qgd2l0aCB0aGUgbmFtZXMgYXR0cmlidXRlIHJlbW92ZWQuCgpgcGF5b3V0c2AgaXMgYSB0eXBlIG9mICpsb29rdXAgdGFibGUqLCBhbiBSIG9iamVjdCB0aGF0IHlvdSBjYW4gdXNlIHRvIGxvb2sgdXAgdmFsdWVzLiBTdWJzZXR0aW5nIGBwYXlvdXRzYCBwcm92aWRlcyBhIHNpbXBsZSB3YXkgdG8gZmluZCB0aGUgcHJpemUgZm9yIGEgc3ltYm9sLiBJdCBkb2Vzbid0IHRha2UgbWFueSBsaW5lcyBvZiBjb2RlLCBhbmQgaXQgZG9lcyB0aGUgc2FtZSBhbW91bnQgb2Ygd29yayB3aGV0aGVyIHlvdXIgc3ltYm9sIGlzIGBERGAgb3IgYDBgLiBZb3UgY2FuIGNyZWF0ZSBsb29rdXAgdGFibGVzIGluIFIgYnkgY3JlYXRpbmcgbmFtZWQgb2JqZWN0cyB0aGF0IGNhbiBiZSBzdWJzZXR0ZWQgaW4gY2xldmVyIHdheXMuCgpTYWRseSwgb3VyIG1ldGhvZCBpcyBub3QgcXVpdGUgYXV0b21hdGljOyB3ZSBuZWVkIHRvIHRlbGwgUiB3aGljaCBzeW1ib2wgdG8gbG9vayB1cCBpbiBgcGF5b3V0c2AuIE9yIGRvIHdlPyBXaGF0IHdvdWxkIGhhcHBlbiBpZiB5b3Ugc3Vic2V0dGVkIGBwYXlvdXRzYCBieSBgc3ltYm9sc1sxXWA/IEdpdmUgaXQgYSB0cnk6CgpgYGAge3J9CnN5bWJvbHMgPC0gYygiNyIsICI3IiwgIjciKQpzeW1ib2xzWzFdCiMjICI3IgoKcGF5b3V0c1tzeW1ib2xzWzFdXQojIyAgNyAKIyMgODAgCgpzeW1ib2xzIDwtIGMoIkMiLCAiQyIsICJDIikKcGF5b3V0c1tzeW1ib2xzWzFdXQojIyAgQyAKIyMgMTAgCmBgYAoKWW91IGRvbid0IG5lZWQgdG8ga25vdyB0aGUgZXhhY3Qgc3ltYm9sIHRvIGxvb2sgdXAgYmVjYXVzZSB5b3UgY2FuIHRlbGwgUiB0byBsb29rIHVwIHdoaWNoZXZlciBzeW1ib2wgaGFwcGVucyB0byBiZSBpbiBgc3ltYm9sc2AuIFlvdSBjYW4gZmluZCB0aGlzIHN5bWJvbCB3aXRoIGBzeW1ib2xzWzFdYCwgYHN5bWJvbHNbMl1gLCBvciBgc3ltYm9sc1szXWAsIGJlY2F1c2UgZWFjaCBjb250YWlucyB0aGUgc2FtZSBzeW1ib2wgaW4gdGhpcyBjYXNlLiBZb3Ugbm93IGhhdmUgYSBzaW1wbGUgYXV0b21hdGVkIHdheSB0byBjYWxjdWxhdGUgdGhlIHByaXplIHdoZW4gYHN5bWJvbHNgIGNvbnRhaW5zIHRocmVlIG9mIGEga2luZC4gTGV0J3MgYWRkIGl0IHRvIG91ciBjb2RlIGFuZCB0aGVuIGxvb2sgYXQgQ2FzZSAyOgoKYGBgIHtyfQpzYW1lIDwtIHN5bWJvbHNbMV0gPT0gc3ltYm9sc1syXSAmJiBzeW1ib2xzWzJdID09IHN5bWJvbHNbM10KYmFycyA8LSBzeW1ib2xzICVpbiUgYygiQiIsICJCQiIsICJCQkIiKQoKaWYgKHNhbWUpIHsKICBwYXlvdXRzIDwtIGMoIkREIiA9IDEwMCwgIjciID0gODAsICJCQkIiID0gNDAsICJCQiIgPSAyNSwgCiAgICAiQiIgPSAxMCwgIkMiID0gMTAsICIwIiA9IDApCiAgcHJpemUgPC0gdW5uYW1lKHBheW91dHNbc3ltYm9sc1sxXV0pCn0gZWxzZSBpZiAoYWxsKGJhcnMpKSB7CiAgcHJpemUgPC0gIyBhc3NpZ24gJDUKfSBlbHNlIHsKICAjIGNvdW50IGNoZXJyaWVzCiAgcHJpemUgPC0gIyBjYWxjdWxhdGUgYSBwcml6ZQp9CgojIGNvdW50IGRpYW1vbmRzCiMgZG91YmxlIHRoZSBwcml6ZSBpZiBuZWNlc3NhcnkKYGBgCgpDYXNlIDIgb2NjdXJzIHdoZW5ldmVyIHRoZSBzeW1ib2xzIGFyZSBhbGwgYmFycy4gSW4gdGhhdCBjYXNlLCB0aGUgcHJpemUgd2lsbCBiZSBcJDUsIHdoaWNoIGlzIGVhc3kgdG8gYXNzaWduOgoKYGBgIHtyfQpzYW1lIDwtIHN5bWJvbHNbMV0gPT0gc3ltYm9sc1syXSAmJiBzeW1ib2xzWzJdID09IHN5bWJvbHNbM10KYmFycyA8LSBzeW1ib2xzICVpbiUgYygiQiIsICJCQiIsICJCQkIiKQoKaWYgKHNhbWUpIHsKICBwYXlvdXRzIDwtIGMoIkREIiA9IDEwMCwgIjciID0gODAsICJCQkIiID0gNDAsICJCQiIgPSAyNSwgCiAgICAiQiIgPSAxMCwgIkMiID0gMTAsICIwIiA9IDApCiAgcHJpemUgPC0gdW5uYW1lKHBheW91dHNbc3ltYm9sc1sxXV0pCn0gZWxzZSBpZiAoYWxsKGJhcnMpKSB7CiAgcHJpemUgPC0gNQp9IGVsc2UgewogICMgY291bnQgY2hlcnJpZXMKICBwcml6ZSA8LSAjIGNhbGN1bGF0ZSBhIHByaXplCn0KCiMgY291bnQgZGlhbW9uZHMKIyBkb3VibGUgdGhlIHByaXplIGlmIG5lY2Vzc2FyeQpgYGAKCk5vdyB3ZSBjYW4gd29yayBvbiB0aGUgbGFzdCBjYXNlLiBIZXJlLCB5b3UnbGwgbmVlZCB0byBrbm93IGhvdyBtYW55IGNoZXJyaWVzIGFyZSBpbiBgc3ltYm9sc2AgYmVmb3JlIHlvdSBjYW4gY2FsY3VsYXRlIGEgcHJpemUuCgojIyMgRXhlcmNpc2UgMTogRmluZCBDJ3MKCkhvdyBjYW4geW91IHRlbGwgd2hpY2ggZWxlbWVudHMgb2YgYSB2ZWN0b3IgbmFtZWQgc3ltYm9scyBhcmUgYSBDPyBEZXZpc2UgYSB0ZXN0IGFuZCB0cnkgaXQgb3V0Cgo8ZGV0YWlscz4KCjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KYGBge3J9CnN5bWJvbHMgPC0gYygiQyIsICJERCIsICJDIikKc3ltYm9scyA9PSAiQyIKIyMgVFJVRSBGQUxTRSAgVFJVRQpgYGAKCkl0J2QgYmUgZXZlbiBtb3JlIHVzZWZ1bCB0byBjb3VudCBob3cgbWFueSBvZiB0aGUgc3ltYm9scyBhcmUgY2hlcnJpZXMuIFlvdSBjYW4gZG8gdGhpcyB3aXRoIGBzdW1gLCB3aGljaCBleHBlY3RzIG51bWVyaWMgaW5wdXQsIG5vdCBsb2dpY2FsLiBLbm93aW5nIHRoaXMsIFIgd2lsbCBjb2VyY2UgdGhlIGBUUlVFYHMgYW5kIGBGQUxTRWBzIHRvIGAxYHMgYW5kIGAwYHMgYmVmb3JlIGRvaW5nIHRoZSBzdW1tYXRpb24uIEFzIGEgcmVzdWx0LCBgc3VtYCB3aWxsIHJldHVybiB0aGUgbnVtYmVyIG9mIGBUUlVFYHMsIHdoaWNoIGlzIGFsc28gdGhlIG51bWJlciBvZiBjaGVycmllczoKCmBgYCB7cn0Kc3VtKHN5bWJvbHMgPT0gIkMiKQojIyAyCmBgYAoKWW91IGNhbiB1c2UgdGhlIHNhbWUgbWV0aG9kIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgZGlhbW9uZHMgaW4gYHN5bWJvbHNgOgoKYGBgIHtyfQpzdW0oc3ltYm9scyA9PSAiREQiKQojIyAxCmBgYAoKPC9kZXRhaWxzPgoKTGV0J3MgYWRkIGJvdGggb2YgdGhlc2Ugc3VidGFza3MgdG8gdGhlIHByb2dyYW0gc2tlbGV0b246CgpgYGAge3J9CnNhbWUgPC0gc3ltYm9sc1sxXSA9PSBzeW1ib2xzWzJdICYmIHN5bWJvbHNbMl0gPT0gc3ltYm9sc1szXQpiYXJzIDwtIHN5bWJvbHMgJWluJSBjKCJCIiwgIkJCIiwgIkJCQiIpCgppZiAoc2FtZSkgewogIHBheW91dHMgPC0gYygiREQiID0gMTAwLCAiNyIgPSA4MCwgIkJCQiIgPSA0MCwgIkJCIiA9IDI1LCAKICAgICJCIiA9IDEwLCAiQyIgPSAxMCwgIjAiID0gMCkKICBwcml6ZSA8LSB1bm5hbWUocGF5b3V0c1tzeW1ib2xzWzFdXSkKfSBlbHNlIGlmIChhbGwoYmFycykpIHsKICBwcml6ZSA8LSA1Cn0gZWxzZSB7CiAgY2hlcnJpZXMgPC0gc3VtKHN5bWJvbHMgPT0gIkMiKQogIHByaXplIDwtICMgY2FsY3VsYXRlIGEgcHJpemUKfQoKZGlhbW9uZHMgPC0gc3VtKHN5bWJvbHMgPT0gIkREIikKIyBkb3VibGUgdGhlIHByaXplIGlmIG5lY2Vzc2FyeQpgYGAKClNpbmNlIENhc2UgMyBhcHBlYXJzIGZ1cnRoZXIgZG93biB0aGUgYGlmYCB0cmVlIHRoYW4gQ2FzZXMgMSBhbmQgMiwgdGhlIGNvZGUgaW4gQ2FzZSAzIHdpbGwgb25seSBiZSBhcHBsaWVkIHRvIHBsYXllcnMgdGhhdCBkbyBub3QgaGF2ZSB0aHJlZSBvZiBhIGtpbmQgb3IgYWxsIGJhcnMuIEFjY29yZGluZyB0byB0aGUgc2xvdCBtYWNoaW5lJ3MgcGF5b3V0IHNjaGVtZSwgdGhlc2UgcGxheWVycyB3aWxsIHdpbiBcJDUgaWYgdGhleSBoYXZlIHR3byBjaGVycmllcyBhbmQgXCQyIGlmIHRoZXkgaGF2ZSBvbmUgY2hlcnJ5LiBJZiB0aGUgcGxheWVyIGhhcyBubyBjaGVycmllcywgc2hlIGdldHMgYSBwcml6ZSBvZiBcJDAuIFdlIGRvbid0IG5lZWQgdG8gd29ycnkgYWJvdXQgdGhyZWUgY2hlcnJpZXMgYmVjYXVzZSB0aGF0IG91dGNvbWUgaXMgYWxyZWFkeSBjb3ZlcmVkIGluIENhc2UgMS4KCkFzIGluIENhc2UgMSwgeW91IGNvdWxkIHdyaXRlIGFuIGBpZmAgdHJlZSB0aGF0IGhhbmRsZXMgZWFjaCBjb21iaW5hdGlvbiBvZiBjaGVycmllcywgYnV0IGp1c3QgbGlrZSBpbiBDYXNlIDEsIHRoaXMgd291bGQgYmUgYW4gaW5lZmZpY2llbnQgc29sdXRpb246CgpgYGAge3J9CmlmIChjaGVycmllcyA9PSAyKSB7CiAgcHJpemUgPC0gNQp9IGVsc2UgaWYgKGNoZXJyaWVzID09IDEpIHsKICBwcml6ZSA8LSAyCn0gZWxzZSB7fQogIHByaXplIDwtIDAKfQpgYGAKCkFnYWluLCBJIHRoaW5rIHRoZSBiZXN0IHNvbHV0aW9uIHdpbGwgaW52b2x2ZSBzdWJzZXR0aW5nLiBJZiB5b3UgYXJlIGZlZWxpbmcgYW1iaXRpb3VzLCB5b3UgY2FuIHRyeSB0byB3b3JrIHRoaXMgc29sdXRpb24gb3V0IG9uIHlvdXIgb3duLCBidXQgeW91IHdpbGwgbGVhcm4ganVzdCBhcyBxdWlja2x5IGJ5IG1lbnRhbGx5IHdvcmtpbmcgdGhyb3VnaCB0aGUgZm9sbG93aW5nIHByb3Bvc2VkIHNvbHV0aW9uLgoKV2Uga25vdyB0aGF0IG91ciBwcml6ZSBzaG91bGQgYmUgXCQwIGlmIHdlIGhhdmUgbm8gY2hlcnJpZXMsIFwkMiBpZiB3ZSBoYXZlIG9uZSBjaGVycnksIGFuZCBcJDUgaWYgd2UgaGF2ZSB0d28gY2hlcnJpZXMuIFlvdSBjYW4gY3JlYXRlIGEgdmVjdG9yIHRoYXQgY29udGFpbnMgdGhpcyBpbmZvcm1hdGlvbi4gVGhpcyB3aWxsIGJlIGEgdmVyeSBzaW1wbGUgbG9va3VwIHRhYmxlOgoKYGBgIHtyfQpjKDAsIDIsIDUpCmBgYAoKTm93LCBsaWtlIGluIENhc2UgMSwgeW91IGNhbiBzdWJzZXQgdGhlIHZlY3RvciB0byByZXRyaWV2ZSB0aGUgY29ycmVjdCBwcml6ZS4gSW4gdGhpcyBjYXNlLCB0aGUgcHJpemUncyBhcmVuJ3QgaWRlbnRpZmllZCBieSBhIHN5bWJvbCBuYW1lLCBidXQgYnkgdGhlIG51bWJlciBvZiBjaGVycmllcyBwcmVzZW50LiBEbyB3ZSBoYXZlIHRoYXQgaW5mb3JtYXRpb24/IFllcywgaXQgaXMgc3RvcmVkIGluIGBjaGVycmllc2AuIFdlIGNhbiB1c2UgYmFzaWMgaW50ZWdlciBzdWJzZXR0aW5nIHRvIGdldCB0aGUgY29ycmVjdCBwcml6ZSBmcm9tIHRoZSBwcmlvciBsb29rdXAgdGFibGUsIGZvciBleGFtcGxlLCBgYygwLCAyLCA1KVsxXWAuCgpgY2hlcnJpZXNgIGlzbid0IGV4YWN0bHkgc3VpdGVkIGZvciBpbnRlZ2VyIHN1YnNldHRpbmcgYmVjYXVzZSBpdCBjb3VsZCBjb250YWluIGEgemVybywgYnV0IHRoYXQncyBlYXN5IHRvIGZpeC4gV2UgY2FuIHN1YnNldCB3aXRoIGBjaGVycmllcyArIDFgLiBOb3cgd2hlbiBgY2hlcnJpZXNgIGVxdWFscyB6ZXJvLCB3ZSBoYXZlOgoKYGBgIHtyfQpjaGVycmllcyArIDEKIyMgMQoKYygwLCAyLCA1KVtjaGVycmllcyArIDFdCiMjIDAKYGBgCgpXaGVuIGBjaGVycmllc2AgZXF1YWxzIG9uZSwgd2UgaGF2ZToKCmBgYCB7cn0KY2hlcnJpZXMgKyAxCiMjIDIKCmMoMCwgMiwgNSlbY2hlcnJpZXMgKyAxXQojIyAyCmBgYAoKQW5kIHdoZW4gYGNoZXJyaWVzYCBlcXVhbHMgdHdvLCB3ZSBoYXZlOgoKYGBgIHtyfQpjaGVycmllcyArIDEKIyMgMwoKYygwLCAyLCA1KVtjaGVycmllcyArIDFdCiMjIDUKYGBgCgpFeGFtaW5lIHRoZXNlIHNvbHV0aW9ucyB1bnRpbCB5b3UgYXJlIHNhdGlzZmllZCB0aGF0IHRoZXkgcmV0dXJuIHRoZSBjb3JyZWN0IHByaXplIGZvciBlYWNoIG51bWJlciBvZiBjaGVycmllcy4gVGhlbiBhZGQgdGhlIGNvZGUgdG8geW91ciBzY3JpcHQsIGFzIGZvbGxvd3M6CgpgYGAge3J9CnNhbWUgPC0gc3ltYm9sc1sxXSA9PSBzeW1ib2xzWzJdICYmIHN5bWJvbHNbMl0gPT0gc3ltYm9sc1szXQpiYXJzIDwtIHN5bWJvbHMgJWluJSBjKCJCIiwgIkJCIiwgIkJCQiIpCgppZiAoc2FtZSkgewogIHBheW91dHMgPC0gYygiREQiID0gMTAwLCAiNyIgPSA4MCwgIkJCQiIgPSA0MCwgIkJCIiA9IDI1LCAKICAgICJCIiA9IDEwLCAiQyIgPSAxMCwgIjAiID0gMCkKICBwcml6ZSA8LSB1bm5hbWUocGF5b3V0c1tzeW1ib2xzWzFdXSkKfSBlbHNlIGlmIChhbGwoYmFycykpIHsKICBwcml6ZSA8LSA1Cn0gZWxzZSB7CiAgY2hlcnJpZXMgPC0gc3VtKHN5bWJvbHMgPT0gIkMiKQogIHByaXplIDwtIGMoMCwgMiwgNSlbY2hlcnJpZXMgKyAxXQp9CgpkaWFtb25kcyA8LSBzdW0oc3ltYm9scyA9PSAiREQiKQojIGRvdWJsZSB0aGUgcHJpemUgaWYgbmVjZXNzYXJ5CmBgYAoKCioqTG9va3VwIFRhYmxlcyBWZXJzdXMgaWYgVHJlZXMqKgoKVGhpcyBpcyB0aGUgc2Vjb25kIHRpbWUgd2UndmUgY3JlYXRlZCBhIGxvb2t1cCB0YWJsZSB0byBhdm9pZCB3cml0aW5nIGFuIGBpZmAgdHJlZS4gV2h5IGlzIHRoaXMgdGVjaG5pcXVlIGhlbHBmdWwgYW5kIHdoeSBkb2VzIGl0IGtlZXAgYXBwZWFyaW5nPyBNYW55IGBpZmAgdHJlZXMgaW4gUiBhcmUgZXNzZW50aWFsLiBUaGV5IHByb3ZpZGUgYSB1c2VmdWwgd2F5IHRvIHRlbGwgUiB0byB1c2UgZGlmZmVyZW50IGFsZ29yaXRobXMgaW4gZGlmZmVyZW50IGNhc2VzLiBIb3dldmVyLCBgaWZgIHRyZWVzIGFyZSBub3QgYXBwcm9wcmlhdGUgZXZlcnl3aGVyZS4KCmBpZmAgdHJlZXMgaGF2ZSBhIGNvdXBsZSBvZiBkcmF3YmFja3MuIEZpcnN0LCB0aGV5IHJlcXVpcmUgUiB0byBydW4gbXVsdGlwbGUgdGVzdHMgYXMgaXQgd29ya3MgaXRzIHdheSBkb3duIHRoZSBgaWZgIHRyZWUsIHdoaWNoIGNhbiBjcmVhdGUgdW5uZWNlc3Nhcnkgd29yay4gU2Vjb25kLCBhcyB5b3UnbGwgc2VlIGluIFtTcGVlZF0sIGl0IGNhbiBiZSBkaWZmaWN1bHQgdG8gdXNlIGBpZmAgdHJlZXMgaW4gdmVjdG9yaXplZCBjb2RlLCBhIHN0eWxlIG9mIGNvZGUgdGhhdCB0YWtlcyBhZHZhbnRhZ2Ugb2YgUidzIHByb2dyYW1taW5nIHN0cmVuZ3RocyB0byBjcmVhdGUgZmFzdCBwcm9ncmFtcy4gTG9va3VwIHRhYmxlcyBkbyBub3Qgc3VmZmVyIGZyb20gZWl0aGVyIG9mIHRoZXNlIGRyYXdiYWNrcy4KCllvdSB3b24ndCBiZSBhYmxlIHRvIHJlcGxhY2UgZXZlcnkgYGlmYCB0cmVlIHdpdGggYSBsb29rdXAgdGFibGUsIG5vciBzaG91bGQgeW91LiBIb3dldmVyLCB5b3UgY2FuIHVzdWFsbHkgdXNlIGxvb2t1cCB0YWJsZXMgdG8gYXZvaWQgYXNzaWduaW5nIHZhcmlhYmxlcyB3aXRoIGBpZmAgdHJlZXMuIEFzIGEgZ2VuZXJhbCBydWxlLCB1c2UgYW4gYGlmYCB0cmVlIGlmIGVhY2ggYnJhbmNoIG9mIHRoZSB0cmVlIHJ1bnMgZGlmZmVyZW50IF9jb2RlXy4gVXNlIGEgbG9va3VwIHRhYmxlIGlmIGVhY2ggYnJhbmNoIG9mIHRoZSB0cmVlIG9ubHkgYXNzaWducyBhIGRpZmZlcmVudCBfdmFsdWVfLgoKVG8gY29udmVydCBhbiBgaWZgIHRyZWUgdG8gYSBsb29rdXAgdGFibGUsIGlkZW50aWZ5IHRoZSB2YWx1ZXMgdG8gYmUgYXNzaWduZWQgYW5kIHN0b3JlIHRoZW0gaW4gYSB2ZWN0b3IuIE5leHQsIGlkZW50aWZ5IHRoZSBzZWxlY3Rpb24gY3JpdGVyaWEgdXNlZCBpbiB0aGUgY29uZGl0aW9ucyBvZiB0aGUgYGlmYCB0cmVlLiBJZiB0aGUgY29uZGl0aW9ucyB1c2UgY2hhcmFjdGVyIHN0cmluZ3MsIGdpdmUgeW91ciB2ZWN0b3IgbmFtZXMgYW5kIHVzZSBuYW1lLWJhc2VkIHN1YnNldHRpbmcuIElmIHRoZSBjb25kaXRpb25zIHVzZSBpbnRlZ2VycywgdXNlIGludGVnZXItYmFzZWQgc3Vic2V0dGluZy4KCgpUaGUgZmluYWwgc3VidGFzayBpcyB0byBkb3VibGUgdGhlIHByaXplIG9uY2UgZm9yIGV2ZXJ5IGRpYW1vbmQgcHJlc2VudC4gVGhpcyBtZWFucyB0aGF0IHRoZSBmaW5hbCBwcml6ZSB3aWxsIGJlIHNvbWUgbXVsdGlwbGUgb2YgdGhlIGN1cnJlbnQgcHJpemUuIEZvciBleGFtcGxlLCBpZiBubyBkaWFtb25kcyBhcmUgcHJlc2VudCwgdGhlIHByaXplIHdpbGwgYmU6CgpgYGAge3J9CnByaXplICogMSAgICAgICMgMSA9IDIgXiAwCmBgYAoKSWYgb25lIGRpYW1vbmQgaXMgcHJlc2VudCwgaXQgd2lsbCBiZToKCmBgYCB7cn0KcHJpemUgKiAyICAgICAgIyAyID0gMiBeIDEKYGBgCgpJZiB0d28gZGlhbW9uZHMgYXJlIHByZXNlbnQsIGl0IHdpbGwgYmU6CgpgYGAge3J9CnByaXplICogNCAgICAgICMgNCA9IDIgXiAyCmBgYAoKQW5kIGlmIHRocmVlIGRpYW1vbmRzIGFyZSBwcmVzZW50LCBpdCB3aWxsIGJlOgoKYGBgIHtyfQpwcml6ZSAqIDggICAgICAjIDggPSAyIF4gMwpgYGAKCiMjIyBFeGVyY2lzZSAyOiBBZGp1c3QgZm9yIERpYW1vbmRzCgpXcml0ZSBhIG1ldGhvZCBmb3IgYWRqdXN0aW5nIGBwcml6ZWAgYmFzZWQgb24gYGRpYW1vbmRzYC4gRGVzY3JpYmUgYSBzb2x1dGlvbiBpbiBFbmdsaXNoIGZpcnN0LCBhbmQgdGhlbiB3cml0ZSB5b3VyIGNvZGUuIAoKCjxkZXRhaWxzPgoKPHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHNvbHV0aW9uPC9zdW1tYXJ5PgpIZXJlIGlzIGEgY29uY2lzZSBzb2x1dGlvbiBpbnNwaXJlZCBieSB0aGUgcHJldmlvdXMgcGF0dGVybi4gVGhlIGFkanVzdGVkIHByaXplIHdpbGwgZXF1YWw6CgoKYGBgIHtyfQpwcml6ZSAqIDIgXiBkaWFtb25kcwpgYGAKCndoaWNoIGdpdmVzIHVzIG91ciBmaW5hbCBgc2NvcmVgIHNjcmlwdDoKCmBgYCB7cn0Kc2FtZSA8LSBzeW1ib2xzWzFdID09IHN5bWJvbHNbMl0gJiYgc3ltYm9sc1syXSA9PSBzeW1ib2xzWzNdCmJhcnMgPC0gc3ltYm9scyAlaW4lIGMoIkIiLCAiQkIiLCAiQkJCIikKCmlmIChzYW1lKSB7CiAgcGF5b3V0cyA8LSBjKCJERCIgPSAxMDAsICI3IiA9IDgwLCAiQkJCIiA9IDQwLCAiQkIiID0gMjUsIAogICAgIkIiID0gMTAsICJDIiA9IDEwLCAiMCIgPSAwKQogIHByaXplIDwtIHVubmFtZShwYXlvdXRzW3N5bWJvbHNbMV1dKQp9IGVsc2UgaWYgKGFsbChiYXJzKSkgewogIHByaXplIDwtIDUKfSBlbHNlIHsKICBjaGVycmllcyA8LSBzdW0oc3ltYm9scyA9PSAiQyIpCiAgcHJpemUgPC0gYygwLCAyLCA1KVtjaGVycmllcyArIDFdCn0KCmRpYW1vbmRzIDwtIHN1bShzeW1ib2xzID09ICJERCIpCnByaXplICogMiBeIGRpYW1vbmRzCmBgYAoKPC9kZXRhaWxzPgoKCgoKIyMgU3VtbWFyeQoKQW4gUiBwcm9ncmFtIGlzIGEgc2V0IG9mIGluc3RydWN0aW9ucyBmb3IgeW91ciBjb21wdXRlciB0byBmb2xsb3cgdGhhdCBoYXMgYmVlbiBvcmdhbml6ZWQgaW50byBhIHNlcXVlbmNlIG9mIHN0ZXBzIGFuZCBjYXNlcy4gVGhpcyBtYXkgbWFrZSBwcm9ncmFtcyBzZWVtIHNpbXBsZSwgYnV0IGRvbid0IGJlIGZvb2xlZDogeW91IGNhbiBjcmVhdGUgY29tcGxpY2F0ZWQgcmVzdWx0cyB3aXRoIHRoZSByaWdodCBjb21iaW5hdGlvbiBvZiBzaW1wbGUgc3RlcHMgKGFuZCBjYXNlcykuCgpBcyBhIHByb2dyYW1tZXIsIHlvdSBhcmUgbW9yZSBsaWtlbHkgdG8gYmUgZm9vbGVkIGluIHRoZSBvcHBvc2l0ZSB3YXkuIEEgcHJvZ3JhbSBtYXkgc2VlbSBpbXBvc3NpYmxlIHRvIHdyaXRlIHdoZW4geW91IGtub3cgdGhhdCBpdCBtdXN0IGRvIHNvbWV0aGluZyBpbXByZXNzaXZlLiBEbyBub3QgcGFuaWMgaW4gdGhlc2Ugc2l0dWF0aW9ucy4gRGl2aWRlIHRoZSBqb2IgYmVmb3JlIHlvdSBpbnRvIHNpbXBsZSB0YXNrcywgYW5kIHRoZW4gZGl2aWRlIHRoZSB0YXNrcyBhZ2Fpbi4gWW91IGNhbiB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRhc2tzIHdpdGggYSBmbG93IGNoYXJ0IGlmIGl0IGhlbHBzLiBUaGVuIHdvcmsgb24gdGhlIHN1YnRhc2tzIG9uZSBhdCBhIHRpbWUuIERlc2NyaWJlIHNvbHV0aW9ucyBpbiBFbmdsaXNoLCB0aGVuIGNvbnZlcnQgdGhlbSB0byBSIGNvZGUuIFRlc3QgZWFjaCBzb2x1dGlvbiBhZ2FpbnN0IGNvbmNyZXRlIGV4YW1wbGVzIGFzIHlvdSBnby4gT25jZSBlYWNoIG9mIHlvdXIgc3VidGFza3Mgd29ya3MsIGNvbWJpbmUgeW91ciBjb2RlIGludG8gYSBmdW5jdGlvbiB0aGF0IHlvdSBjYW4gc2hhcmUgYW5kIHJldXNlLgoKUiBwcm92aWRlcyB0b29scyB0aGF0IGNhbiBoZWxwIHlvdSBkbyB0aGlzLiBZb3UgY2FuIG1hbmFnZSBjYXNlcyB3aXRoIGBpZmAgYW5kIGBlbHNlYCBzdGF0ZW1lbnRzLiBZb3UgY2FuIGNyZWF0ZSBhIGxvb2t1cCB0YWJsZSB3aXRoIG9iamVjdHMgYW5kIHN1YnNldHRpbmcuIFlvdSBjYW4gYWRkIGNvZGUgY29tbWVudHMgd2l0aCBgI2AuIEFuZCB5b3UgY2FuIHNhdmUgeW91ciBwcm9ncmFtcyBhcyBhIGZ1bmN0aW9uIHdpdGggYGZ1bmN0aW9uYC4KClRoaW5ncyBvZnRlbiBnbyB3cm9uZyB3aGVuIHBlb3BsZSB3cml0ZSBwcm9ncmFtcy4gSXQgd2lsbCBiZSB1cCB0byB5b3UgdG8gZmluZCB0aGUgc291cmNlIG9mIGFueSBlcnJvcnMgdGhhdCBvY2N1ciBhbmQgdG8gZml4IHRoZW0uIEl0IHNob3VsZCBiZSBlYXN5IHRvIGZpbmQgdGhlIHNvdXJjZSBvZiB5b3VyIGVycm9ycyBpZiB5b3UgdXNlIGEgc3RlcHdpc2UgYXBwcm9hY2ggdG8gd3JpdGluZyBmdW5jdGlvbnMsIHdyaXRpbmfigJRhbmQgdGhlbiB0ZXN0aW5n4oCUb25lIGJpdCBhdCBhIHRpbWUuIEhvd2V2ZXIsIGlmIHRoZSBzb3VyY2Ugb2YgYW4gZXJyb3IgZWx1ZGVzIHlvdSwgb3IgeW91IGZpbmQgeW91cnNlbGYgd29ya2luZyB3aXRoIGxhcmdlIGNodW5rcyBvZiB1bnRlc3RlZCBjb2RlLCBjb25zaWRlciB1c2luZyBSJ3MgYnVpbHQgaW4gZGVidWdnaW5nIHRvb2xzLCBkZXNjcmliZWQgaW4gW0RlYnVnZ2luZyBSIENvZGVdLgoKVGhlIG5leHQgdHdvIGNoYXB0ZXJzIHdpbGwgdGVhY2ggeW91IG1vcmUgdG9vbHMgdGhhdCB5b3UgY2FuIHVzZSBpbiB5b3VyIHByb2dyYW1zLiBBcyB5b3UgbWFzdGVyIHRoZXNlIHRvb2xzLCB5b3Ugd2lsbCBmaW5kIGl0IGVhc2llciB0byB3cml0ZSBSIHByb2dyYW1zIHRoYXQgbGV0IHlvdSBkbyB3aGF0ZXZlciB5b3Ugd2lzaCB0byB5b3VyIGRhdGEuIEluIFtTM10sIHlvdSB3aWxsIGxlYXJuIGhvdyB0byB1c2UgUidzIFMzIHN5c3RlbSwgYW4gaW52aXNpYmxlIGhhbmQgdGhhdCBzaGFwZXMgbWFueSBwYXJ0cyBvZiBSLiBZb3Ugd2lsbCB1c2UgdGhlIHN5c3RlbSB0byBidWlsZCBhIGN1c3RvbSBjbGFzcyBmb3IgeW91ciBzbG90IG1hY2hpbmUgb3V0cHV0LCBhbmQgeW91IHdpbGwgdGVsbCBSIGhvdyB0byBkaXNwbGF5IG9iamVjdHMgdGhhdCBoYXZlIHlvdXIgY2xhc3MuCg==