R Notebook: Working with DataFrames
Introduction
Welcome to this comprehensive lecture on working with DataFrames in
R! DataFrames are one of the most fundamental and versatile data
structures in R, making them essential for any data analysis task. In
this session, we’ll explore various operations and concepts related to
DataFrames using a deck of cards as our primary example.
We’ve chosen a deck of cards as our dataset because it provides a
relatable and intuitive structure that can demonstrate many DataFrame
operations effectively. Each card in our deck will be represented as a
row in our DataFrame, with attributes like face, suit, and value as
columns.
Let’s begin by loading the necessary libraries and our deck of
cards:
library(dplyr)
library(readr)
# Load the deck of cards
deck <- read_csv(url("https://nayelbettache.github.io/documents/STSCI_2120/deck.csv"))
Let’s break down what’s happening here:
library(dplyr)
: This loads the dplyr package, which
provides a set of tools for efficiently manipulating datasets in R.
dplyr is part of the tidyverse ecosystem and offers functions like
filter()
, select()
, and mutate()
that we’ll use throughout this notebook.
library(readr)
: This loads the readr package, which
provides a fast and friendly way to read rectangular data (like CSV
files). It’s generally faster than base R’s read.csv() function and
automatically handles many common CSV formats.
deck <- read_csv("deck_of_cards.csv")
: This line
reads our CSV file containing the deck of cards data and stores it in a
DataFrame called deck
. The read_csv()
function
from readr is being used here.
Now, let’s take a look at the first few rows of our deck:
head(deck)
The head()
function gives us a quick preview of our
DataFrame. It shows the first 6 rows by default. This is always a good
first step when working with a new dataset to understand its structure
and content.
Our deck DataFrame has three columns: - face
: The face
value of the card (e.g., “Ace”, “2”, “King”) - suit
: The
suit of the card (Hearts, Diamonds, Clubs, Spades) - value
:
The numerical value of the card (e.g., Ace might be 1, King might be
13)
Selecting Values
In R, there are multiple ways to select values from a DataFrame.
Understanding these methods is crucial for effective data manipulation.
Let’s explore three common approaches:
- Using column names:
deck$suit
[1] "spades" "spades" "spades" "spades" "spades" "spades" "spades" "spades" "spades"
[10] "spades" "spades" "spades" "spades" "clubs" "clubs" "clubs" "clubs" "clubs"
[19] "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "diamonds"
[28] "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds"
[37] "diamonds" "diamonds" "diamonds" "hearts" "hearts" "hearts" "hearts" "hearts" "hearts"
[46] "hearts" "hearts" "hearts" "hearts" "hearts" "hearts" "hearts"
deck[["face"]]
[1] "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three" "two"
[13] "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three"
[25] "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four"
[37] "three" "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five"
[49] "four" "three" "two" "ace"
Here’s what’s happening:
deck$suit
: This uses the $
operator to
access the “suit” column of the deck DataFrame. It returns a vector
containing all the values in the “suit” column.
deck[["face"]]
: This uses double square brackets
[[]]
to access the “face” column. Like $
, it
returns a vector of all values in the “face” column.
The main difference between these two methods is that
[[]]
can be used with variables containing column names,
while $
cannot. For example:
column_name <- "value"
deck[[column_name]] # This works
[1] 13 12 11 10 9 8 7 6 5 4 3 2 1 13 12 11 10 9 8 7 6 5 4 3 2 1 13 12 11 10 9 8 7
[34] 6 5 4 3 2 1 13 12 11 10 9 8 7 6 5 4 3 2 1
# deck$column_name # This would not work as expected
- Using indices:
deck[1:5, 2] # First 5 rows, second column
This method uses R’s built-in indexing. The format is
dataframe[rows, columns]
: - 1:5
specifies rows
1 through 5 - 2
specifies the second column
This approach is very flexible: - deck[1:5, ]
would
select the first 5 rows and all columns - deck[, 2]
would
select all rows of the second column - deck[1:5, 1:2]
would
select the first 5 rows of the first two columns
- Using dplyr’s select function:
select(deck, face, suit)
The select()
function from dplyr provides a more
intuitive and readable way to choose columns: - The first argument is
the DataFrame - Subsequent arguments are the names of columns you want
to select
This method is particularly useful when you need to select multiple
columns or use more complex selection criteria. For example:
# Select columns that start with "s"
select(deck, starts_with("s"))
# Select all columns except "value"
select(deck, -value)
Exercise 1: Selecting Values
Now, let’s practice these selection methods:
- Select all the faces from the deck.
- Select the first 10 rows and all columns of the deck.
- Use dplyr to select only the ‘value’ column.
# Your code here
Click to see solution
# 1. Select all the faces
deck$face
[1] "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three" "two"
[13] "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three"
[25] "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four"
[37] "three" "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five"
[49] "four" "three" "two" "ace"
# 2. Select first 10 rows and all columns
deck[1:10, ]
# 3. Use dplyr to select only the 'value' column
select(deck, value)
Explanation: 1. We use the $
operator to select the
‘face’ column, which returns a vector of all faces. 2. We use bracket
notation []
with 1:10
to select the first 10
rows, and leave the column part empty to select all columns. 3. We use
dplyr’s select()
function to choose only the ‘value’
column. This returns a DataFrame with one column, not a vector.
Deal a Card
In card games, dealing is a fundamental operation. Let’s create a
function to simulate dealing a card from our deck:
deal_card <- function(deck) {
card <- deck[sample(nrow(deck), 1), ]
return(card)
}
dealt_card <- deal_card(deck)
print(dealt_card)
Let’s break down this deal_card()
function:
function(deck)
: This defines a function that takes
one argument, our deck DataFrame.
sample(nrow(deck), 1)
:
nrow(deck)
returns the number of rows in the deck
sample(x, size)
randomly samples size
numbers from 1 to x
- So this generates one random row number
deck[sample(nrow(deck), 1), ]
: This selects the
randomly chosen row from the deck. The comma with nothing after it means
we select all columns for this row.
The selected row (representing a single card) is assigned to
card
.
return(card)
sends this randomly selected card back
as the output of the function.
When we call deal_card(deck)
, it runs this function and
returns a single, randomly selected card from our deck.
Exercise 2: Dealing Cards
Let’s extend our dealing functionality:
- Modify the
deal_card
function to deal multiple cards at
once.
- Deal a hand of 5 cards and display them.
# Your code here
Click to see solution
# 1. Modify deal_card function
deal_cards <- function(deck, n) {
cards <- deck[sample(nrow(deck), n), ]
return(cards)
}
# 2. Deal a hand of 5 cards
hand <- deal_cards(deck, 5)
print(hand)
Explanation: 1. We modify the function to take an additional argument
n
, which is the number of cards to deal. 2. We use
sample(nrow(deck), n)
to get n
random row
numbers. 3. We select these rows from the deck to create our hand of
cards. 4. We then use this new function to deal a hand of 5 cards and
display it.
Shuffle the Deck
Shuffling is another crucial operation in card games. In DataFrame
terms, this means randomly reordering our rows:
shuffle_deck <- function(deck) {
shuffled_deck <- deck[sample(nrow(deck)), ]
rownames(shuffled_deck) <- NULL
return(shuffled_deck)
}
shuffled_deck <- shuffle_deck(deck)
head(shuffled_deck)
Let’s break down this shuffle_deck()
function:
sample(nrow(deck))
: This creates a random
permutation of the numbers from 1 to the number of rows in the deck. For
example, if we have 52 cards, this might return something like
[23, 7, 52, 1, 18, ...]
.
deck[sample(nrow(deck)), ]
: This uses the random
permutation to reorder all rows of the deck. It’s equivalent to randomly
shuffling the cards.
rownames(shuffled_deck) <- NULL
: This resets the
row names of the shuffled deck. When we reorder the rows, R keeps the
original row names by default, which can be confusing. Setting them to
NULL causes R to use sequential numbers as row names.
The function returns this shuffled deck.
After shuffling, we use head()
to view the first few
rows of the shuffled deck, demonstrating that the order has indeed
changed.
Exercise 3: Shuffling
Now, let’s combine our shuffling and dealing operations:
- Shuffle the deck and deal the top 3 cards.
- Create a function that shuffles the deck and deals a specified
number of hands with a specified number of cards each.
# Your code here
Click to see solution
# 1. Shuffle and deal top 3 cards
top_3 <- head(shuffle_deck(deck), 3)
# 2. Function to shuffle and deal multiple hands
shuffle_and_deal <- function(deck, num_hands, cards_per_hand) {
shuffled <- shuffle_deck(deck)
hands <- list()
for (i in 1:num_hands) {
start <- (i - 1) * cards_per_hand + 1
end <- i * cards_per_hand
hands[[i]] <- shuffled[start:end, ]
}
return(hands)
}
# Example usage:
game_hands <- shuffle_and_deal(deck, 4, 5) # 4 hands, 5 cards each
Explanation: 1. We first shuffle the deck using our
shuffle_deck()
function, then use head()
to
get the first 3 cards. 2. For the second part: - We create a function
that takes the deck, number of hands, and cards per hand as arguments. -
We shuffle the deck first. - We create an empty list to store the hands.
- We use a for loop to deal the appropriate number of cards to each
hand. - We use list indexing to add each hand to our list of hands. -
Finally, we return the list of hands.
Dollar Signs and Double Brackets
In R, we can access DataFrame columns using $
or
[[]]
. Understanding the differences between these methods
is crucial for effective R programming:
# Using $
deck$suit
[1] "spades" "spades" "spades" "spades" "spades" "spades" "spades" "spades" "spades"
[10] "spades" "spades" "spades" "spades" "clubs" "clubs" "clubs" "clubs" "clubs"
[19] "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "clubs" "diamonds"
[28] "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds" "diamonds"
[37] "diamonds" "diamonds" "diamonds" "hearts" "hearts" "hearts" "hearts" "hearts" "hearts"
[46] "hearts" "hearts" "hearts" "hearts" "hearts" "hearts" "hearts"
# Using [[]]
deck[["face"]]
[1] "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three" "two"
[13] "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four" "three"
[25] "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five" "four"
[37] "three" "two" "ace" "king" "queen" "jack" "ten" "nine" "eight" "seven" "six" "five"
[49] "four" "three" "two" "ace"
# Using [[]] with variables
column_name <- "value"
deck[[column_name]]
[1] 13 12 11 10 9 8 7 6 5 4 3 2 1 13 12 11 10 9 8 7 6 5 4 3 2 1 13 12 11 10 9 8 7
[34] 6 5 4 3 2 1 13 12 11 10 9 8 7 6 5 4 3 2 1
Let’s break down these methods:
deck$suit
:
- This uses the
$
operator to directly access the “suit”
column.
- It’s quick and intuitive, but has limitations.
- It doesn’t work with variable column names.
- It can sometimes cause issues in complex operations or function
calls.
deck[["face"]]
:
- This uses double square brackets
[[]]
to access the
“face” column.
- It’s more flexible than the
$
operator.
- It works with variable column names (as shown in the third
example).
- It’s generally safer in function calls and complex operations.
- It clearly indicates that you’re extracting a single column.
deck[[column_name]]
:
- This demonstrates using
[[]]
with a variable containing
the column name.
- This flexibility is particularly useful when writing functions that
need to work with different columns.
Both $
and [[]]
return a vector of values
from the specified column. The main difference is in their flexibility
and how they behave in certain contexts (like inside functions or with
variable column names).
Exercise 4: Column Access
Let’s practice using these access methods:
- Create a function that takes a column name as an argument and
returns the unique values in that column.
# Your code here
Click to see solution
get_unique_values <- function(df, column_name) {
unique(df[[column_name]])
}
# Example usage:
unique_suits <- get_unique_values(deck, "suit")
print(unique_suits)
[1] "spades" "clubs" "diamonds" "hearts"
Explanation: - We define a function get_unique_values
that takes two arguments: a DataFrame df
and a
column_name
. - Inside the function, we use
df[[column_name]]
to access the specified column. We can’t
use $
here because we need to use the variable
column_name
. - We wrap this in the unique()
function, which returns only the unique values from the vector. - This
function is flexible - it can be used with any DataFrame and any column
name. - In the example usage, we get the unique suits from our deck.
Modifying Values
Modifying values in a DataFrame is a common operation in data
cleaning and transformation. Let’s look at how we can change values in
our deck:
# Change the value of the first card to 100
deck$value[1] <- 100
# Change the face of the last card to "Joker"
deck$face[nrow(deck)] <- "Joker"
# View the changes
head(deck, 1)
tail(deck, 1)
Let’s break down what’s happening here:
deck$value[1] <- 100
:
- This accesses the ‘value’ column of the deck using
$
.
[1]
selects the first element of this column.
- We assign the value 100 to this element, changing the value of the
first card.
deck$face[nrow(deck)] <- "Joker"
:
- Similar to the first operation, but we’re changing the ‘face’
column.
nrow(deck)
gives us the number of rows in the deck,
effectively selecting the last row.
- We change the face of the last card to “Joker”.
- We use
head(deck, 1)
and tail(deck, 1)
to
view the first and last rows of the deck, confirming our changes.
This method of direct assignment is straightforward but should be
used cautiously. It’s easy to accidentally modify data you didn’t intend
to change.
Exercise 5: Value Modification
Now, let’s try some more complex modifications:
- Change all the “Jack” cards to have a value of 11.
- Add a new column called “color” based on the suit (red for Hearts
and Diamonds, black for Clubs and Spades).
# Your code here
Click to see solution
# 1. Change Jack values to 11
deck$value[deck$face == "Jack"] <- 11
# 2. Add color column
deck$color <- ifelse(deck$suit %in% c("Hearts", "Diamonds"), "Red", "Black")
Explanation: 1.
deck$value[deck$face == "Jack"] <- 11
: -
deck$face == "Jack"
creates a logical vector, TRUE for Jack
cards, FALSE for others. - We use this to index deck$value
,
selecting only the values for Jack cards. - We assign 11 to these
selected values.
Changing Values in Place
mutate() is a verb function in dplyr that allows you to add new
columns or modify existing ones in a data frame. The basic syntax
is:
mutate(data, new_column = expression)
Where:
- data is the data frame you want to modify.
- new_column is the name of the new column you want to create or the
existing column you want to modify.
- expression is the operation you want to perform to create or modify
the column.
Let’s use dplyr’s mutate
function:
deck <- mutate(deck,
value = ifelse(face == "King", 13, value),
value = ifelse(face == "Queen", 12, value))
# View the changes
filter(deck, face %in% c("King", "Queen"))
Using mutate to Update the value Column
The code uses the mutate function from the dplyr package to update
the value column in the deck dataframe.
The mutate Function
The mutate function takes a dataframe as input and returns a new
dataframe with the modified columns. In this case, the mutate function
is used to update the value column in the deck dataframe.
The ifelse Function
The ifelse function is a vectorized conditional statement that checks
a condition and returns one value if the condition is TRUE and another
value if the condition is FALSE.
In the first ifelse statement, the condition is face == “King”. If
this condition is TRUE, the value returned is 13; otherwise, the
original value in the value column is returned.
In the second ifelse statement, the condition is face == “Queen”. If
this condition is TRUE, the value returned is 12; otherwise, the
original value in the value column is returned (which may have already
been updated by the previous ifelse statement).
The mutate Statement
The mutate statement is used to update the value column in the deck
dataframe. The value column is updated twice, first to assign a value of
13 to the “King” cards, and then to assign a value of 12 to the “Queen”
cards.
However, there’s a subtle issue with this code. The second ifelse
statement will only update the “Queen” cards if they haven’t already
been updated by the first ifelse statement. Since the first ifelse
statement doesn’t update the “Queen” cards, the second ifelse statement
will work as expected.
The filter Function
The filter function is used to select a subset of rows from the deck
dataframe where the face column is either “King” or “Queen”. This allows
us to view the changes made to the value column for these specific
cards.
Exercise 6: In-Place Modifications
- Use
mutate
to add a new column “is_face_card” that is
TRUE for Jack, Queen, and King, and FALSE otherwise.
# Your code here
Click to see solution
deck <- mutate(deck,
is_face_card = face %in% c("Jack", "Queen", "King"))
Logical Subsetting
Let’s practice logical subsetting:
# Get all Hearts
hearts <- deck[deck$suit == "Hearts", ]
# Get all face cards
face_cards <- deck[deck$face %in% c("Jack", "Queen", "King"), ]
# View results
head(hearts)
head(face_cards)
The code uses logical subsetting to extract specific rows from the
deck dataframe based on certain conditions.
Getting All Hearts
The first line of code uses the following syntax to get all rows
where the suit column is “Hearts”:
Here’s what’s happening:
- deck$suit == “Hearts” is a logical expression that checks if the
value in the suit column is equal to “Hearts”. This will return a vector
of TRUE and FALSE values, where TRUE indicates that the row has a suit
of “Hearts”.
- The square brackets [] are used to subset the deck dataframe based
on this logical expression. The comma inside the brackets indicates that
we want to select rows (if there were no comma, it would select
columns).
- The resulting subset of rows is assigned to a new dataframe called
hearts. Getting All Face Cards
The second line of code uses the following syntax to get all rows
where the face column is “Jack”, “Queen”, or “King”:
Here’s what’s happening:
- deck$face %in% c(“Jack”, “Queen”, “King”) is a logical expression
that checks if the value in the face column is one of the values in the
vector c(“Jack”, “Queen”, “King”). This will return a vector of TRUE and
FALSE values, where TRUE indicates that the row has a face that is one
of the specified values.
- The rest of the syntax is the same as before: the square brackets []
are used to subset the deck dataframe based on this logical expression,
and the resulting subset of rows is assigned to a new dataframe called
face_cards.
Viewing the Results
The final two lines of code use the head() function to view the first
few rows of the hearts and face_cards dataframes
This allows us to verify that the subsetting worked correctly and see
the resulting dataframes.
Exercise 7: Logical Subsetting
- Create a subset of the deck containing only cards with values
greater than 10.
- Create a subset of red cards (Hearts and Diamonds) with odd
values.
# Your code here
Click to see solution
# 1. Cards with values > 10
# 2. Red cards with odd values
red_odd_cards <- deck[deck$suit %in% c("Hearts", "Diamonds") & deck$value %% 2 == 1, ]
Environments
An environment in R is a self-contained space where you can store and
manage variables, functions, and other objects. Environments are useful
for organizing your code and data, and for avoiding naming conflicts.
Let’s explore environments:
# Create a new environment
card_env <- new.env()
# Assign a variable to the new environment
card_env$ace_value <- 1
# Access the variable
card_env$ace_value
[1] 1
Creating a New Environment
To create a new environment, you can use the new.env() function.
This creates a new, empty environment and assigns it to the variable
card_env.
Assigning a Variable to the New Environment
To assign a variable to the new environment, you can use the $
operator.
This assigns the value 1 to the variable ace_value in the card_env
environment.
Accessing the Variable
To access the variable, you can use the $ operator again. This
returns the value of the ace_value variable in the card_env environment,
which is 1.
Environment Details
Here are some additional details about the card_env environment.
The ls() function lists the objects in the environment, which in this
case is just the ace_value variable. The typeof() and class() functions
return the type and class of the environment, respectively.
Working with Environments
Let’s use environments to manage game state:
game_env <- new.env()
with(game_env, {
deck <- shuffle_deck(deck)
player_hand <- deal_card(deck)
})
# Access variables from the environment
game_env$player_hand
Exercise 9: Environment Usage
- Create a function that initializes a game environment with a
shuffled deck and dealt hands for a specified number of players.
# Your code here
Click to see solution
initialize_game <- function(num_players, cards_per_hand) {
game_env <- new.env()
with(game_env, {
deck <- shuffle_deck(deck)
players <- list()
for (i in 1:num_players) {
players[[paste0("Player", i)]] <- deal_cards(deck, cards_per_hand)
deck <- deck[-(1:cards_per_hand), ]
}
})
return(game_env)
}
# Usage:
game <- initialize_game(4, 5)
game$players$Player1
Scoping Rules
Let’s explore R’s lexical scoping:
outer_var <- 10
example_function <- function() {
inner_var <- 5
outer_var + inner_var
}
example_function() # Returns 15
[1] 15
Assignment
Let’s practice different assignment methods:
# Using <-
x <- 5
# Using =
y = 10
# Using ->
15 -> z
# View results
c(x, y, z)
[1] 5 10 15
Exercise 10: Assignment Practice
- Create a function that takes a deck as input and returns a list with
two elements: the red cards and the black cards. Use different
assignment operators for each.
# Your code here
Final Exercise: Putting It All Together
Create a card game simulation that uses environments, closures, and
DataFrames. The game should:
- Initialize a shuffled deck
- Deal hands to players
- Allow players to draw and discard cards
- Keep track of the game state using an environment
# Your code here
Click to see solution
create_card_game <- function(num_players, cards_per_hand) {
game_env <- new.env()
with(game_env, {
deck <- shuffle_deck(deck)
players <- list()
for (i in 1:num_players) {
players[[paste0("Player", i)]] <- deal_cards(deck, cards_per_hand)
}
deck <- deck[-(1:(num_players * cards_per_hand)), ]
turn <- 1
draw_card <- function(player_index) {
if (nrow(deck) == 0) {
stop("No more cards in the deck!")
}
card <- deck[1, ]
deck <<- deck[-1, ]
players[[player_index]] <<- rbind(players[[player_index]], card)
return(card)
}
discard_card <- function(player_index, card_index) {
discarded <- players[[player_index]][card_index, ]
players[[player_index]] <<- players[[player_index]][-card_index, ]
return(discarded)
}
next_turn <- function() {
turn <<- (turn %% num_players) + 1
}
})
return(game_env)
}
# Usage:
game <- create_card_game(4, 5)
game$draw_card(1)
game$discard_card(1, 3)
game$next_turn()
LS0tCnRpdGxlOiAiV29ya2luZyB3aXRoIERhdGFGcmFtZXMgaW4gUjogQSBDb21wcmVoZW5zaXZlIEd1aWRlIgphdXRob3I6IE5heWVsIEJldHRhY2hlCm91dHB1dDogaHRtbF9ub3RlYm9vawpjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIFIgTm90ZWJvb2s6IFdvcmtpbmcgd2l0aCBEYXRhRnJhbWVzCgojIyBJbnRyb2R1Y3Rpb24KCldlbGNvbWUgdG8gdGhpcyBjb21wcmVoZW5zaXZlIGxlY3R1cmUgb24gd29ya2luZyB3aXRoIERhdGFGcmFtZXMgaW4gUiEgRGF0YUZyYW1lcyBhcmUgb25lIG9mIHRoZSBtb3N0IGZ1bmRhbWVudGFsIGFuZCB2ZXJzYXRpbGUgZGF0YSBzdHJ1Y3R1cmVzIGluIFIsIG1ha2luZyB0aGVtIGVzc2VudGlhbCBmb3IgYW55IGRhdGEgYW5hbHlzaXMgdGFzay4gSW4gdGhpcyBzZXNzaW9uLCB3ZSdsbCBleHBsb3JlIHZhcmlvdXMgb3BlcmF0aW9ucyBhbmQgY29uY2VwdHMgcmVsYXRlZCB0byBEYXRhRnJhbWVzIHVzaW5nIGEgZGVjayBvZiBjYXJkcyBhcyBvdXIgcHJpbWFyeSBleGFtcGxlLgoKV2UndmUgY2hvc2VuIGEgZGVjayBvZiBjYXJkcyBhcyBvdXIgZGF0YXNldCBiZWNhdXNlIGl0IHByb3ZpZGVzIGEgcmVsYXRhYmxlIGFuZCBpbnR1aXRpdmUgc3RydWN0dXJlIHRoYXQgY2FuIGRlbW9uc3RyYXRlIG1hbnkgRGF0YUZyYW1lIG9wZXJhdGlvbnMgZWZmZWN0aXZlbHkuIEVhY2ggY2FyZCBpbiBvdXIgZGVjayB3aWxsIGJlIHJlcHJlc2VudGVkIGFzIGEgcm93IGluIG91ciBEYXRhRnJhbWUsIHdpdGggYXR0cmlidXRlcyBsaWtlIGZhY2UsIHN1aXQsIGFuZCB2YWx1ZSBhcyBjb2x1bW5zLgoKTGV0J3MgYmVnaW4gYnkgbG9hZGluZyB0aGUgbmVjZXNzYXJ5IGxpYnJhcmllcyBhbmQgb3VyIGRlY2sgb2YgY2FyZHM6CgpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgZWNobyA9IFRSVUUsIHJlc3VsdHMgPSAiaGlkZSJ9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCgojIExvYWQgdGhlIGRlY2sgb2YgY2FyZHMKZGVjayA8LSByZWFkX2Nzdih1cmwoImh0dHBzOi8vbmF5ZWxiZXR0YWNoZS5naXRodWIuaW8vZG9jdW1lbnRzL1NUU0NJXzIxMjAvZGVjay5jc3YiKSkKYGBgCgpMZXQncyBicmVhayBkb3duIHdoYXQncyBoYXBwZW5pbmcgaGVyZToKCjEuICBgbGlicmFyeShkcGx5cilgOiBUaGlzIGxvYWRzIHRoZSBkcGx5ciBwYWNrYWdlLCB3aGljaCBwcm92aWRlcyBhIHNldCBvZiB0b29scyBmb3IgZWZmaWNpZW50bHkgbWFuaXB1bGF0aW5nIGRhdGFzZXRzIGluIFIuIGRwbHlyIGlzIHBhcnQgb2YgdGhlIHRpZHl2ZXJzZSBlY29zeXN0ZW0gYW5kIG9mZmVycyBmdW5jdGlvbnMgbGlrZSBgZmlsdGVyKClgLCBgc2VsZWN0KClgLCBhbmQgYG11dGF0ZSgpYCB0aGF0IHdlJ2xsIHVzZSB0aHJvdWdob3V0IHRoaXMgbm90ZWJvb2suCgoyLiAgYGxpYnJhcnkocmVhZHIpYDogVGhpcyBsb2FkcyB0aGUgcmVhZHIgcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgYSBmYXN0IGFuZCBmcmllbmRseSB3YXkgdG8gcmVhZCByZWN0YW5ndWxhciBkYXRhIChsaWtlIENTViBmaWxlcykuIEl0J3MgZ2VuZXJhbGx5IGZhc3RlciB0aGFuIGJhc2UgUidzIHJlYWQuY3N2KCkgZnVuY3Rpb24gYW5kIGF1dG9tYXRpY2FsbHkgaGFuZGxlcyBtYW55IGNvbW1vbiBDU1YgZm9ybWF0cy4KCjMuICBgZGVjayA8LSByZWFkX2NzdigiZGVja19vZl9jYXJkcy5jc3YiKWA6IFRoaXMgbGluZSByZWFkcyBvdXIgQ1NWIGZpbGUgY29udGFpbmluZyB0aGUgZGVjayBvZiBjYXJkcyBkYXRhIGFuZCBzdG9yZXMgaXQgaW4gYSBEYXRhRnJhbWUgY2FsbGVkIGBkZWNrYC4gVGhlIGByZWFkX2NzdigpYCBmdW5jdGlvbiBmcm9tIHJlYWRyIGlzIGJlaW5nIHVzZWQgaGVyZS4KCk5vdywgbGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGZpcnN0IGZldyByb3dzIG9mIG91ciBkZWNrOgoKYGBge3J9CmhlYWQoZGVjaykKYGBgCgpUaGUgYGhlYWQoKWAgZnVuY3Rpb24gZ2l2ZXMgdXMgYSBxdWljayBwcmV2aWV3IG9mIG91ciBEYXRhRnJhbWUuIEl0IHNob3dzIHRoZSBmaXJzdCA2IHJvd3MgYnkgZGVmYXVsdC4gVGhpcyBpcyBhbHdheXMgYSBnb29kIGZpcnN0IHN0ZXAgd2hlbiB3b3JraW5nIHdpdGggYSBuZXcgZGF0YXNldCB0byB1bmRlcnN0YW5kIGl0cyBzdHJ1Y3R1cmUgYW5kIGNvbnRlbnQuCgpPdXIgZGVjayBEYXRhRnJhbWUgaGFzIHRocmVlIGNvbHVtbnM6IC0gYGZhY2VgOiBUaGUgZmFjZSB2YWx1ZSBvZiB0aGUgY2FyZCAoZS5nLiwgIkFjZSIsICIyIiwgIktpbmciKSAtIGBzdWl0YDogVGhlIHN1aXQgb2YgdGhlIGNhcmQgKEhlYXJ0cywgRGlhbW9uZHMsIENsdWJzLCBTcGFkZXMpIC0gYHZhbHVlYDogVGhlIG51bWVyaWNhbCB2YWx1ZSBvZiB0aGUgY2FyZCAoZS5nLiwgQWNlIG1pZ2h0IGJlIDEsIEtpbmcgbWlnaHQgYmUgMTMpCgojIyBTZWxlY3RpbmcgVmFsdWVzCgpJbiBSLCB0aGVyZSBhcmUgbXVsdGlwbGUgd2F5cyB0byBzZWxlY3QgdmFsdWVzIGZyb20gYSBEYXRhRnJhbWUuIFVuZGVyc3RhbmRpbmcgdGhlc2UgbWV0aG9kcyBpcyBjcnVjaWFsIGZvciBlZmZlY3RpdmUgZGF0YSBtYW5pcHVsYXRpb24uIExldCdzIGV4cGxvcmUgdGhyZWUgY29tbW9uIGFwcHJvYWNoZXM6CgoxLiAgVXNpbmcgY29sdW1uIG5hbWVzOgoKYGBge3J9CmRlY2skc3VpdApgYGAKCmBgYHtyfQpkZWNrW1siZmFjZSJdXQpgYGAKCkhlcmUncyB3aGF0J3MgaGFwcGVuaW5nOgoKLSAgIGBkZWNrJHN1aXRgOiBUaGlzIHVzZXMgdGhlIGAkYCBvcGVyYXRvciB0byBhY2Nlc3MgdGhlICJzdWl0IiBjb2x1bW4gb2YgdGhlIGRlY2sgRGF0YUZyYW1lLiBJdCByZXR1cm5zIGEgdmVjdG9yIGNvbnRhaW5pbmcgYWxsIHRoZSB2YWx1ZXMgaW4gdGhlICJzdWl0IiBjb2x1bW4uCi0gICBgZGVja1tbImZhY2UiXV1gOiBUaGlzIHVzZXMgZG91YmxlIHNxdWFyZSBicmFja2V0cyBgW1tdXWAgdG8gYWNjZXNzIHRoZSAiZmFjZSIgY29sdW1uLiBMaWtlIGAkYCwgaXQgcmV0dXJucyBhIHZlY3RvciBvZiBhbGwgdmFsdWVzIGluIHRoZSAiZmFjZSIgY29sdW1uLgoKVGhlIG1haW4gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZXNlIHR3byBtZXRob2RzIGlzIHRoYXQgYFtbXV1gIGNhbiBiZSB1c2VkIHdpdGggdmFyaWFibGVzIGNvbnRhaW5pbmcgY29sdW1uIG5hbWVzLCB3aGlsZSBgJGAgY2Fubm90LiBGb3IgZXhhbXBsZToKCmBgYHtyfQpjb2x1bW5fbmFtZSA8LSAidmFsdWUiCmRlY2tbW2NvbHVtbl9uYW1lXV0gICMgVGhpcyB3b3JrcwojIGRlY2skY29sdW1uX25hbWUgICAjIFRoaXMgd291bGQgbm90IHdvcmsgYXMgZXhwZWN0ZWQKYGBgCgoyLiAgVXNpbmcgaW5kaWNlczoKCmBgYHtyfQpkZWNrWzE6NSwgMl0gICMgRmlyc3QgNSByb3dzLCBzZWNvbmQgY29sdW1uCmBgYAoKVGhpcyBtZXRob2QgdXNlcyBSJ3MgYnVpbHQtaW4gaW5kZXhpbmcuIFRoZSBmb3JtYXQgaXMgYGRhdGFmcmFtZVtyb3dzLCBjb2x1bW5zXWA6IC0gYDE6NWAgc3BlY2lmaWVzIHJvd3MgMSB0aHJvdWdoIDUgLSBgMmAgc3BlY2lmaWVzIHRoZSBzZWNvbmQgY29sdW1uCgpUaGlzIGFwcHJvYWNoIGlzIHZlcnkgZmxleGlibGU6IC0gYGRlY2tbMTo1LCBdYCB3b3VsZCBzZWxlY3QgdGhlIGZpcnN0IDUgcm93cyBhbmQgYWxsIGNvbHVtbnMgLSBgZGVja1ssIDJdYCB3b3VsZCBzZWxlY3QgYWxsIHJvd3Mgb2YgdGhlIHNlY29uZCBjb2x1bW4gLSBgZGVja1sxOjUsIDE6Ml1gIHdvdWxkIHNlbGVjdCB0aGUgZmlyc3QgNSByb3dzIG9mIHRoZSBmaXJzdCB0d28gY29sdW1ucwoKMy4gIFVzaW5nIGRwbHlyJ3Mgc2VsZWN0IGZ1bmN0aW9uOgoKYGBge3IgZWNobyA9IFQsIHJlc3VsdHMgPSAnaGlkZSd9CnNlbGVjdChkZWNrLCBmYWNlLCBzdWl0KQpgYGAKClRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uIGZyb20gZHBseXIgcHJvdmlkZXMgYSBtb3JlIGludHVpdGl2ZSBhbmQgcmVhZGFibGUgd2F5IHRvIGNob29zZSBjb2x1bW5zOiAtIFRoZSBmaXJzdCBhcmd1bWVudCBpcyB0aGUgRGF0YUZyYW1lIC0gU3Vic2VxdWVudCBhcmd1bWVudHMgYXJlIHRoZSBuYW1lcyBvZiBjb2x1bW5zIHlvdSB3YW50IHRvIHNlbGVjdAoKVGhpcyBtZXRob2QgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aGVuIHlvdSBuZWVkIHRvIHNlbGVjdCBtdWx0aXBsZSBjb2x1bW5zIG9yIHVzZSBtb3JlIGNvbXBsZXggc2VsZWN0aW9uIGNyaXRlcmlhLiBGb3IgZXhhbXBsZToKCmBgYHtyfQojIFNlbGVjdCBjb2x1bW5zIHRoYXQgc3RhcnQgd2l0aCAicyIKc2VsZWN0KGRlY2ssIHN0YXJ0c193aXRoKCJzIikpCgojIFNlbGVjdCBhbGwgY29sdW1ucyBleGNlcHQgInZhbHVlIgpzZWxlY3QoZGVjaywgLXZhbHVlKQpgYGAKCiMjIyBFeGVyY2lzZSAxOiBTZWxlY3RpbmcgVmFsdWVzCgpOb3csIGxldCdzIHByYWN0aWNlIHRoZXNlIHNlbGVjdGlvbiBtZXRob2RzOgoKMS4gIFNlbGVjdCBhbGwgdGhlIGZhY2VzIGZyb20gdGhlIGRlY2suCjIuICBTZWxlY3QgdGhlIGZpcnN0IDEwIHJvd3MgYW5kIGFsbCBjb2x1bW5zIG9mIHRoZSBkZWNrLgozLiAgVXNlIGRwbHlyIHRvIHNlbGVjdCBvbmx5IHRoZSAndmFsdWUnIGNvbHVtbi4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KIyAxLiBTZWxlY3QgYWxsIHRoZSBmYWNlcwpkZWNrJGZhY2UKCiMgMi4gU2VsZWN0IGZpcnN0IDEwIHJvd3MgYW5kIGFsbCBjb2x1bW5zCmRlY2tbMToxMCwgXQoKIyAzLiBVc2UgZHBseXIgdG8gc2VsZWN0IG9ubHkgdGhlICd2YWx1ZScgY29sdW1uCnNlbGVjdChkZWNrLCB2YWx1ZSkKYGBgCgpFeHBsYW5hdGlvbjogMS4gV2UgdXNlIHRoZSBgJGAgb3BlcmF0b3IgdG8gc2VsZWN0IHRoZSAnZmFjZScgY29sdW1uLCB3aGljaCByZXR1cm5zIGEgdmVjdG9yIG9mIGFsbCBmYWNlcy4gMi4gV2UgdXNlIGJyYWNrZXQgbm90YXRpb24gYFtdYCB3aXRoIGAxOjEwYCB0byBzZWxlY3QgdGhlIGZpcnN0IDEwIHJvd3MsIGFuZCBsZWF2ZSB0aGUgY29sdW1uIHBhcnQgZW1wdHkgdG8gc2VsZWN0IGFsbCBjb2x1bW5zLiAzLiBXZSB1c2UgZHBseXIncyBgc2VsZWN0KClgIGZ1bmN0aW9uIHRvIGNob29zZSBvbmx5IHRoZSAndmFsdWUnIGNvbHVtbi4gVGhpcyByZXR1cm5zIGEgRGF0YUZyYW1lIHdpdGggb25lIGNvbHVtbiwgbm90IGEgdmVjdG9yLgoKPC9kZXRhaWxzPgoKIyMgRGVhbCBhIENhcmQKCkluIGNhcmQgZ2FtZXMsIGRlYWxpbmcgaXMgYSBmdW5kYW1lbnRhbCBvcGVyYXRpb24uIExldCdzIGNyZWF0ZSBhIGZ1bmN0aW9uIHRvIHNpbXVsYXRlIGRlYWxpbmcgYSBjYXJkIGZyb20gb3VyIGRlY2s6CgpgYGB7cn0KZGVhbF9jYXJkIDwtIGZ1bmN0aW9uKGRlY2spIHsKICBjYXJkIDwtIGRlY2tbc2FtcGxlKG5yb3coZGVjayksIDEpLCBdCiAgcmV0dXJuKGNhcmQpCn0KCmRlYWx0X2NhcmQgPC0gZGVhbF9jYXJkKGRlY2spCnByaW50KGRlYWx0X2NhcmQpCmBgYAoKTGV0J3MgYnJlYWsgZG93biB0aGlzIGBkZWFsX2NhcmQoKWAgZnVuY3Rpb246CgoxLiAgYGZ1bmN0aW9uKGRlY2spYDogVGhpcyBkZWZpbmVzIGEgZnVuY3Rpb24gdGhhdCB0YWtlcyBvbmUgYXJndW1lbnQsIG91ciBkZWNrIERhdGFGcmFtZS4KCjIuICBgc2FtcGxlKG5yb3coZGVjayksIDEpYDoKCiAgICAtICAgYG5yb3coZGVjaylgIHJldHVybnMgdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBkZWNrCiAgICAtICAgYHNhbXBsZSh4LCBzaXplKWAgcmFuZG9tbHkgc2FtcGxlcyBgc2l6ZWAgbnVtYmVycyBmcm9tIDEgdG8gYHhgCiAgICAtICAgU28gdGhpcyBnZW5lcmF0ZXMgb25lIHJhbmRvbSByb3cgbnVtYmVyCgozLiAgYGRlY2tbc2FtcGxlKG5yb3coZGVjayksIDEpLCBdYDogVGhpcyBzZWxlY3RzIHRoZSByYW5kb21seSBjaG9zZW4gcm93IGZyb20gdGhlIGRlY2suIFRoZSBjb21tYSB3aXRoIG5vdGhpbmcgYWZ0ZXIgaXQgbWVhbnMgd2Ugc2VsZWN0IGFsbCBjb2x1bW5zIGZvciB0aGlzIHJvdy4KCjQuICBUaGUgc2VsZWN0ZWQgcm93IChyZXByZXNlbnRpbmcgYSBzaW5nbGUgY2FyZCkgaXMgYXNzaWduZWQgdG8gYGNhcmRgLgoKNS4gIGByZXR1cm4oY2FyZClgIHNlbmRzIHRoaXMgcmFuZG9tbHkgc2VsZWN0ZWQgY2FyZCBiYWNrIGFzIHRoZSBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uLgoKV2hlbiB3ZSBjYWxsIGBkZWFsX2NhcmQoZGVjaylgLCBpdCBydW5zIHRoaXMgZnVuY3Rpb24gYW5kIHJldHVybnMgYSBzaW5nbGUsIHJhbmRvbWx5IHNlbGVjdGVkIGNhcmQgZnJvbSBvdXIgZGVjay4KCiMjIyBFeGVyY2lzZSAyOiBEZWFsaW5nIENhcmRzCgpMZXQncyBleHRlbmQgb3VyIGRlYWxpbmcgZnVuY3Rpb25hbGl0eToKCjEuICBNb2RpZnkgdGhlIGBkZWFsX2NhcmRgIGZ1bmN0aW9uIHRvIGRlYWwgbXVsdGlwbGUgY2FyZHMgYXQgb25jZS4KMi4gIERlYWwgYSBoYW5kIG9mIDUgY2FyZHMgYW5kIGRpc3BsYXkgdGhlbS4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KIyAxLiBNb2RpZnkgZGVhbF9jYXJkIGZ1bmN0aW9uCmRlYWxfY2FyZHMgPC0gZnVuY3Rpb24oZGVjaywgbikgewogIGNhcmRzIDwtIGRlY2tbc2FtcGxlKG5yb3coZGVjayksIG4pLCBdCiAgcmV0dXJuKGNhcmRzKQp9CgojIDIuIERlYWwgYSBoYW5kIG9mIDUgY2FyZHMKaGFuZCA8LSBkZWFsX2NhcmRzKGRlY2ssIDUpCnByaW50KGhhbmQpCmBgYAoKRXhwbGFuYXRpb246IDEuIFdlIG1vZGlmeSB0aGUgZnVuY3Rpb24gdG8gdGFrZSBhbiBhZGRpdGlvbmFsIGFyZ3VtZW50IGBuYCwgd2hpY2ggaXMgdGhlIG51bWJlciBvZiBjYXJkcyB0byBkZWFsLiAyLiBXZSB1c2UgYHNhbXBsZShucm93KGRlY2spLCBuKWAgdG8gZ2V0IGBuYCByYW5kb20gcm93IG51bWJlcnMuIDMuIFdlIHNlbGVjdCB0aGVzZSByb3dzIGZyb20gdGhlIGRlY2sgdG8gY3JlYXRlIG91ciBoYW5kIG9mIGNhcmRzLiA0LiBXZSB0aGVuIHVzZSB0aGlzIG5ldyBmdW5jdGlvbiB0byBkZWFsIGEgaGFuZCBvZiA1IGNhcmRzIGFuZCBkaXNwbGF5IGl0LgoKPC9kZXRhaWxzPgoKIyMgU2h1ZmZsZSB0aGUgRGVjawoKU2h1ZmZsaW5nIGlzIGFub3RoZXIgY3J1Y2lhbCBvcGVyYXRpb24gaW4gY2FyZCBnYW1lcy4gSW4gRGF0YUZyYW1lIHRlcm1zLCB0aGlzIG1lYW5zIHJhbmRvbWx5IHJlb3JkZXJpbmcgb3VyIHJvd3M6CgpgYGB7cn0Kc2h1ZmZsZV9kZWNrIDwtIGZ1bmN0aW9uKGRlY2spIHsKICBzaHVmZmxlZF9kZWNrIDwtIGRlY2tbc2FtcGxlKG5yb3coZGVjaykpLCBdCiAgcm93bmFtZXMoc2h1ZmZsZWRfZGVjaykgPC0gTlVMTAogIHJldHVybihzaHVmZmxlZF9kZWNrKQp9CgpzaHVmZmxlZF9kZWNrIDwtIHNodWZmbGVfZGVjayhkZWNrKQpoZWFkKHNodWZmbGVkX2RlY2spCmBgYAoKTGV0J3MgYnJlYWsgZG93biB0aGlzIGBzaHVmZmxlX2RlY2soKWAgZnVuY3Rpb246CgoxLiAgYHNhbXBsZShucm93KGRlY2spKWA6IFRoaXMgY3JlYXRlcyBhIHJhbmRvbSBwZXJtdXRhdGlvbiBvZiB0aGUgbnVtYmVycyBmcm9tIDEgdG8gdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBkZWNrLiBGb3IgZXhhbXBsZSwgaWYgd2UgaGF2ZSA1MiBjYXJkcywgdGhpcyBtaWdodCByZXR1cm4gc29tZXRoaW5nIGxpa2UgYFsyMywgNywgNTIsIDEsIDE4LCAuLi5dYC4KCjIuICBgZGVja1tzYW1wbGUobnJvdyhkZWNrKSksIF1gOiBUaGlzIHVzZXMgdGhlIHJhbmRvbSBwZXJtdXRhdGlvbiB0byByZW9yZGVyIGFsbCByb3dzIG9mIHRoZSBkZWNrLiBJdCdzIGVxdWl2YWxlbnQgdG8gcmFuZG9tbHkgc2h1ZmZsaW5nIHRoZSBjYXJkcy4KCjMuICBgcm93bmFtZXMoc2h1ZmZsZWRfZGVjaykgPC0gTlVMTGA6IFRoaXMgcmVzZXRzIHRoZSByb3cgbmFtZXMgb2YgdGhlIHNodWZmbGVkIGRlY2suIFdoZW4gd2UgcmVvcmRlciB0aGUgcm93cywgUiBrZWVwcyB0aGUgb3JpZ2luYWwgcm93IG5hbWVzIGJ5IGRlZmF1bHQsIHdoaWNoIGNhbiBiZSBjb25mdXNpbmcuIFNldHRpbmcgdGhlbSB0byBOVUxMIGNhdXNlcyBSIHRvIHVzZSBzZXF1ZW50aWFsIG51bWJlcnMgYXMgcm93IG5hbWVzLgoKNC4gIFRoZSBmdW5jdGlvbiByZXR1cm5zIHRoaXMgc2h1ZmZsZWQgZGVjay4KCkFmdGVyIHNodWZmbGluZywgd2UgdXNlIGBoZWFkKClgIHRvIHZpZXcgdGhlIGZpcnN0IGZldyByb3dzIG9mIHRoZSBzaHVmZmxlZCBkZWNrLCBkZW1vbnN0cmF0aW5nIHRoYXQgdGhlIG9yZGVyIGhhcyBpbmRlZWQgY2hhbmdlZC4KCiMjIyBFeGVyY2lzZSAzOiBTaHVmZmxpbmcKCk5vdywgbGV0J3MgY29tYmluZSBvdXIgc2h1ZmZsaW5nIGFuZCBkZWFsaW5nIG9wZXJhdGlvbnM6CgoxLiAgU2h1ZmZsZSB0aGUgZGVjayBhbmQgZGVhbCB0aGUgdG9wIDMgY2FyZHMuCjIuICBDcmVhdGUgYSBmdW5jdGlvbiB0aGF0IHNodWZmbGVzIHRoZSBkZWNrIGFuZCBkZWFscyBhIHNwZWNpZmllZCBudW1iZXIgb2YgaGFuZHMgd2l0aCBhIHNwZWNpZmllZCBudW1iZXIgb2YgY2FyZHMgZWFjaC4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KIyAxLiBTaHVmZmxlIGFuZCBkZWFsIHRvcCAzIGNhcmRzCnRvcF8zIDwtIGhlYWQoc2h1ZmZsZV9kZWNrKGRlY2spLCAzKQoKIyAyLiBGdW5jdGlvbiB0byBzaHVmZmxlIGFuZCBkZWFsIG11bHRpcGxlIGhhbmRzCnNodWZmbGVfYW5kX2RlYWwgPC0gZnVuY3Rpb24oZGVjaywgbnVtX2hhbmRzLCBjYXJkc19wZXJfaGFuZCkgewogIHNodWZmbGVkIDwtIHNodWZmbGVfZGVjayhkZWNrKQogIGhhbmRzIDwtIGxpc3QoKQogIGZvciAoaSBpbiAxOm51bV9oYW5kcykgewogICAgc3RhcnQgPC0gKGkgLSAxKSAqIGNhcmRzX3Blcl9oYW5kICsgMQogICAgZW5kIDwtIGkgKiBjYXJkc19wZXJfaGFuZAogICAgaGFuZHNbW2ldXSA8LSBzaHVmZmxlZFtzdGFydDplbmQsIF0KICB9CiAgcmV0dXJuKGhhbmRzKQp9CgojIEV4YW1wbGUgdXNhZ2U6CmdhbWVfaGFuZHMgPC0gc2h1ZmZsZV9hbmRfZGVhbChkZWNrLCA0LCA1KSAgIyA0IGhhbmRzLCA1IGNhcmRzIGVhY2gKYGBgCgpFeHBsYW5hdGlvbjogMS4gV2UgZmlyc3Qgc2h1ZmZsZSB0aGUgZGVjayB1c2luZyBvdXIgYHNodWZmbGVfZGVjaygpYCBmdW5jdGlvbiwgdGhlbiB1c2UgYGhlYWQoKWAgdG8gZ2V0IHRoZSBmaXJzdCAzIGNhcmRzLiAyLiBGb3IgdGhlIHNlY29uZCBwYXJ0OiAtIFdlIGNyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgdGhlIGRlY2ssIG51bWJlciBvZiBoYW5kcywgYW5kIGNhcmRzIHBlciBoYW5kIGFzIGFyZ3VtZW50cy4gLSBXZSBzaHVmZmxlIHRoZSBkZWNrIGZpcnN0LiAtIFdlIGNyZWF0ZSBhbiBlbXB0eSBsaXN0IHRvIHN0b3JlIHRoZSBoYW5kcy4gLSBXZSB1c2UgYSBmb3IgbG9vcCB0byBkZWFsIHRoZSBhcHByb3ByaWF0ZSBudW1iZXIgb2YgY2FyZHMgdG8gZWFjaCBoYW5kLiAtIFdlIHVzZSBsaXN0IGluZGV4aW5nIHRvIGFkZCBlYWNoIGhhbmQgdG8gb3VyIGxpc3Qgb2YgaGFuZHMuIC0gRmluYWxseSwgd2UgcmV0dXJuIHRoZSBsaXN0IG9mIGhhbmRzLgoKPC9kZXRhaWxzPgoKIyMgRG9sbGFyIFNpZ25zIGFuZCBEb3VibGUgQnJhY2tldHMKCkluIFIsIHdlIGNhbiBhY2Nlc3MgRGF0YUZyYW1lIGNvbHVtbnMgdXNpbmcgYCRgIG9yIGBbW11dYC4gVW5kZXJzdGFuZGluZyB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGVzZSBtZXRob2RzIGlzIGNydWNpYWwgZm9yIGVmZmVjdGl2ZSBSIHByb2dyYW1taW5nOgoKYGBge3J9CiMgVXNpbmcgJApkZWNrJHN1aXQKCiMgVXNpbmcgW1tdXQpkZWNrW1siZmFjZSJdXQoKIyBVc2luZyBbW11dIHdpdGggdmFyaWFibGVzCmNvbHVtbl9uYW1lIDwtICJ2YWx1ZSIKZGVja1tbY29sdW1uX25hbWVdXQpgYGAKCkxldCdzIGJyZWFrIGRvd24gdGhlc2UgbWV0aG9kczoKCjEuICBgZGVjayRzdWl0YDoKICAgIC0gICBUaGlzIHVzZXMgdGhlIGAkYCBvcGVyYXRvciB0byBkaXJlY3RseSBhY2Nlc3MgdGhlICJzdWl0IiBjb2x1bW4uCiAgICAtICAgSXQncyBxdWljayBhbmQgaW50dWl0aXZlLCBidXQgaGFzIGxpbWl0YXRpb25zLgogICAgLSAgIEl0IGRvZXNuJ3Qgd29yayB3aXRoIHZhcmlhYmxlIGNvbHVtbiBuYW1lcy4KICAgIC0gICBJdCBjYW4gc29tZXRpbWVzIGNhdXNlIGlzc3VlcyBpbiBjb21wbGV4IG9wZXJhdGlvbnMgb3IgZnVuY3Rpb24gY2FsbHMuCjIuICBgZGVja1tbImZhY2UiXV1gOgogICAgLSAgIFRoaXMgdXNlcyBkb3VibGUgc3F1YXJlIGJyYWNrZXRzIGBbW11dYCB0byBhY2Nlc3MgdGhlICJmYWNlIiBjb2x1bW4uCiAgICAtICAgSXQncyBtb3JlIGZsZXhpYmxlIHRoYW4gdGhlIGAkYCBvcGVyYXRvci4KICAgIC0gICBJdCB3b3JrcyB3aXRoIHZhcmlhYmxlIGNvbHVtbiBuYW1lcyAoYXMgc2hvd24gaW4gdGhlIHRoaXJkIGV4YW1wbGUpLgogICAgLSAgIEl0J3MgZ2VuZXJhbGx5IHNhZmVyIGluIGZ1bmN0aW9uIGNhbGxzIGFuZCBjb21wbGV4IG9wZXJhdGlvbnMuCiAgICAtICAgSXQgY2xlYXJseSBpbmRpY2F0ZXMgdGhhdCB5b3UncmUgZXh0cmFjdGluZyBhIHNpbmdsZSBjb2x1bW4uCjMuICBgZGVja1tbY29sdW1uX25hbWVdXWA6CiAgICAtICAgVGhpcyBkZW1vbnN0cmF0ZXMgdXNpbmcgYFtbXV1gIHdpdGggYSB2YXJpYWJsZSBjb250YWluaW5nIHRoZSBjb2x1bW4gbmFtZS4KICAgIC0gICBUaGlzIGZsZXhpYmlsaXR5IGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgd2hlbiB3cml0aW5nIGZ1bmN0aW9ucyB0aGF0IG5lZWQgdG8gd29yayB3aXRoIGRpZmZlcmVudCBjb2x1bW5zLgoKQm90aCBgJGAgYW5kIGBbW11dYCByZXR1cm4gYSB2ZWN0b3Igb2YgdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCBjb2x1bW4uIFRoZSBtYWluIGRpZmZlcmVuY2UgaXMgaW4gdGhlaXIgZmxleGliaWxpdHkgYW5kIGhvdyB0aGV5IGJlaGF2ZSBpbiBjZXJ0YWluIGNvbnRleHRzIChsaWtlIGluc2lkZSBmdW5jdGlvbnMgb3Igd2l0aCB2YXJpYWJsZSBjb2x1bW4gbmFtZXMpLgoKIyMjIEV4ZXJjaXNlIDQ6IENvbHVtbiBBY2Nlc3MKCkxldCdzIHByYWN0aWNlIHVzaW5nIHRoZXNlIGFjY2VzcyBtZXRob2RzOgoKMS4gIENyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSBjb2x1bW4gbmFtZSBhcyBhbiBhcmd1bWVudCBhbmQgcmV0dXJucyB0aGUgdW5pcXVlIHZhbHVlcyBpbiB0aGF0IGNvbHVtbi4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KZ2V0X3VuaXF1ZV92YWx1ZXMgPC0gZnVuY3Rpb24oZGYsIGNvbHVtbl9uYW1lKSB7CiAgdW5pcXVlKGRmW1tjb2x1bW5fbmFtZV1dKQp9CgojIEV4YW1wbGUgdXNhZ2U6CnVuaXF1ZV9zdWl0cyA8LSBnZXRfdW5pcXVlX3ZhbHVlcyhkZWNrLCAic3VpdCIpCnByaW50KHVuaXF1ZV9zdWl0cykKYGBgCgpFeHBsYW5hdGlvbjogLSBXZSBkZWZpbmUgYSBmdW5jdGlvbiBgZ2V0X3VuaXF1ZV92YWx1ZXNgIHRoYXQgdGFrZXMgdHdvIGFyZ3VtZW50czogYSBEYXRhRnJhbWUgYGRmYCBhbmQgYSBgY29sdW1uX25hbWVgLiAtIEluc2lkZSB0aGUgZnVuY3Rpb24sIHdlIHVzZSBgZGZbW2NvbHVtbl9uYW1lXV1gIHRvIGFjY2VzcyB0aGUgc3BlY2lmaWVkIGNvbHVtbi4gV2UgY2FuJ3QgdXNlIGAkYCBoZXJlIGJlY2F1c2Ugd2UgbmVlZCB0byB1c2UgdGhlIHZhcmlhYmxlIGBjb2x1bW5fbmFtZWAuIC0gV2Ugd3JhcCB0aGlzIGluIHRoZSBgdW5pcXVlKClgIGZ1bmN0aW9uLCB3aGljaCByZXR1cm5zIG9ubHkgdGhlIHVuaXF1ZSB2YWx1ZXMgZnJvbSB0aGUgdmVjdG9yLiAtIFRoaXMgZnVuY3Rpb24gaXMgZmxleGlibGUgLSBpdCBjYW4gYmUgdXNlZCB3aXRoIGFueSBEYXRhRnJhbWUgYW5kIGFueSBjb2x1bW4gbmFtZS4gLSBJbiB0aGUgZXhhbXBsZSB1c2FnZSwgd2UgZ2V0IHRoZSB1bmlxdWUgc3VpdHMgZnJvbSBvdXIgZGVjay4KCjwvZGV0YWlscz4KCiMjIE1vZGlmeWluZyBWYWx1ZXMKCk1vZGlmeWluZyB2YWx1ZXMgaW4gYSBEYXRhRnJhbWUgaXMgYSBjb21tb24gb3BlcmF0aW9uIGluIGRhdGEgY2xlYW5pbmcgYW5kIHRyYW5zZm9ybWF0aW9uLiBMZXQncyBsb29rIGF0IGhvdyB3ZSBjYW4gY2hhbmdlIHZhbHVlcyBpbiBvdXIgZGVjazoKCmBgYHtyfQojIENoYW5nZSB0aGUgdmFsdWUgb2YgdGhlIGZpcnN0IGNhcmQgdG8gMTAwCmRlY2skdmFsdWVbMV0gPC0gMTAwCgojIENoYW5nZSB0aGUgZmFjZSBvZiB0aGUgbGFzdCBjYXJkIHRvICJKb2tlciIKZGVjayRmYWNlW25yb3coZGVjayldIDwtICJKb2tlciIKCiMgVmlldyB0aGUgY2hhbmdlcwpoZWFkKGRlY2ssIDEpCnRhaWwoZGVjaywgMSkKYGBgCgpMZXQncyBicmVhayBkb3duIHdoYXQncyBoYXBwZW5pbmcgaGVyZToKCjEuICBgZGVjayR2YWx1ZVsxXSA8LSAxMDBgOgogICAgLSAgIFRoaXMgYWNjZXNzZXMgdGhlICd2YWx1ZScgY29sdW1uIG9mIHRoZSBkZWNrIHVzaW5nIGAkYC4KICAgIC0gICBgWzFdYCBzZWxlY3RzIHRoZSBmaXJzdCBlbGVtZW50IG9mIHRoaXMgY29sdW1uLgogICAgLSAgIFdlIGFzc2lnbiB0aGUgdmFsdWUgMTAwIHRvIHRoaXMgZWxlbWVudCwgY2hhbmdpbmcgdGhlIHZhbHVlIG9mIHRoZSBmaXJzdCBjYXJkLgoyLiAgYGRlY2skZmFjZVtucm93KGRlY2spXSA8LSAiSm9rZXIiYDoKICAgIC0gICBTaW1pbGFyIHRvIHRoZSBmaXJzdCBvcGVyYXRpb24sIGJ1dCB3ZSdyZSBjaGFuZ2luZyB0aGUgJ2ZhY2UnIGNvbHVtbi4KICAgIC0gICBgbnJvdyhkZWNrKWAgZ2l2ZXMgdXMgdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBkZWNrLCBlZmZlY3RpdmVseSBzZWxlY3RpbmcgdGhlIGxhc3Qgcm93LgogICAgLSAgIFdlIGNoYW5nZSB0aGUgZmFjZSBvZiB0aGUgbGFzdCBjYXJkIHRvICJKb2tlciIuCjMuICBXZSB1c2UgYGhlYWQoZGVjaywgMSlgIGFuZCBgdGFpbChkZWNrLCAxKWAgdG8gdmlldyB0aGUgZmlyc3QgYW5kIGxhc3Qgcm93cyBvZiB0aGUgZGVjaywgY29uZmlybWluZyBvdXIgY2hhbmdlcy4KClRoaXMgbWV0aG9kIG9mIGRpcmVjdCBhc3NpZ25tZW50IGlzIHN0cmFpZ2h0Zm9yd2FyZCBidXQgc2hvdWxkIGJlIHVzZWQgY2F1dGlvdXNseS4gSXQncyBlYXN5IHRvIGFjY2lkZW50YWxseSBtb2RpZnkgZGF0YSB5b3UgZGlkbid0IGludGVuZCB0byBjaGFuZ2UuCgojIyMgRXhlcmNpc2UgNTogVmFsdWUgTW9kaWZpY2F0aW9uCgpOb3csIGxldCdzIHRyeSBzb21lIG1vcmUgY29tcGxleCBtb2RpZmljYXRpb25zOgoKMS4gIENoYW5nZSBhbGwgdGhlICJKYWNrIiBjYXJkcyB0byBoYXZlIGEgdmFsdWUgb2YgMTEuCjIuICBBZGQgYSBuZXcgY29sdW1uIGNhbGxlZCAiY29sb3IiIGJhc2VkIG9uIHRoZSBzdWl0IChyZWQgZm9yIEhlYXJ0cyBhbmQgRGlhbW9uZHMsIGJsYWNrIGZvciBDbHVicyBhbmQgU3BhZGVzKS4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+Cgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KIyAxLiBDaGFuZ2UgSmFjayB2YWx1ZXMgdG8gMTEKZGVjayR2YWx1ZVtkZWNrJGZhY2UgPT0gIkphY2siXSA8LSAxMQoKIyAyLiBBZGQgY29sb3IgY29sdW1uCmRlY2skY29sb3IgPC0gaWZlbHNlKGRlY2skc3VpdCAlaW4lIGMoIkhlYXJ0cyIsICJEaWFtb25kcyIpLCAiUmVkIiwgIkJsYWNrIikKYGBgCgpFeHBsYW5hdGlvbjogMS4gYGRlY2skdmFsdWVbZGVjayRmYWNlID09ICJKYWNrIl0gPC0gMTFgOiAtIGBkZWNrJGZhY2UgPT0gIkphY2siYCBjcmVhdGVzIGEgbG9naWNhbCB2ZWN0b3IsIFRSVUUgZm9yIEphY2sgY2FyZHMsIEZBTFNFIGZvciBvdGhlcnMuIC0gV2UgdXNlIHRoaXMgdG8gaW5kZXggYGRlY2skdmFsdWVgLCBzZWxlY3Rpbmcgb25seSB0aGUgdmFsdWVzIGZvciBKYWNrIGNhcmRzLiAtIFdlIGFzc2lnbiAxMSB0byB0aGVzZSBzZWxlY3RlZCB2YWx1ZXMuCgo8L2RldGFpbHM+CgojIyBDaGFuZ2luZyBWYWx1ZXMgaW4gUGxhY2UKCm11dGF0ZSgpIGlzIGEgdmVyYiBmdW5jdGlvbiBpbiBkcGx5ciB0aGF0IGFsbG93cyB5b3UgdG8gYWRkIG5ldyBjb2x1bW5zIG9yIG1vZGlmeSBleGlzdGluZyBvbmVzIGluIGEgZGF0YSBmcmFtZS4gVGhlIGJhc2ljIHN5bnRheCBpczoKYGBge3J9Cm11dGF0ZShkYXRhLCBuZXdfY29sdW1uID0gZXhwcmVzc2lvbikKYGBgCldoZXJlOgoKLSBkYXRhIGlzIHRoZSBkYXRhIGZyYW1lIHlvdSB3YW50IHRvIG1vZGlmeS4KLSBuZXdfY29sdW1uIGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uIHlvdSB3YW50IHRvIGNyZWF0ZSBvciB0aGUgZXhpc3RpbmcgY29sdW1uIHlvdSB3YW50IHRvIG1vZGlmeS4KLSBleHByZXNzaW9uIGlzIHRoZSBvcGVyYXRpb24geW91IHdhbnQgdG8gcGVyZm9ybSB0byBjcmVhdGUgb3IgbW9kaWZ5IHRoZSBjb2x1bW4uCgpMZXQncyB1c2UgZHBseXIncyBgbXV0YXRlYCBmdW5jdGlvbjoKCmBgYHtyfQpkZWNrIDwtIG11dGF0ZShkZWNrLCAKICAgICAgICAgICAgICAgdmFsdWUgPSBpZmVsc2UoZmFjZSA9PSAiS2luZyIsIDEzLCB2YWx1ZSksCiAgICAgICAgICAgICAgIHZhbHVlID0gaWZlbHNlKGZhY2UgPT0gIlF1ZWVuIiwgMTIsIHZhbHVlKSkKCiMgVmlldyB0aGUgY2hhbmdlcwpmaWx0ZXIoZGVjaywgZmFjZSAlaW4lIGMoIktpbmciLCAiUXVlZW4iKSkKYGBgCiMjIyMjIFVzaW5nIG11dGF0ZSB0byBVcGRhdGUgdGhlIHZhbHVlIENvbHVtbgoKVGhlIGNvZGUgdXNlcyB0aGUgbXV0YXRlIGZ1bmN0aW9uIGZyb20gdGhlIGRwbHlyIHBhY2thZ2UgdG8gdXBkYXRlIHRoZSB2YWx1ZSBjb2x1bW4gaW4gdGhlIGRlY2sgZGF0YWZyYW1lLgoKIyMjIyMgVGhlIG11dGF0ZSBGdW5jdGlvbgoKVGhlIG11dGF0ZSBmdW5jdGlvbiB0YWtlcyBhIGRhdGFmcmFtZSBhcyBpbnB1dCBhbmQgcmV0dXJucyBhIG5ldyBkYXRhZnJhbWUgd2l0aCB0aGUgbW9kaWZpZWQgY29sdW1ucy4gSW4gdGhpcyBjYXNlLCB0aGUgbXV0YXRlIGZ1bmN0aW9uIGlzIHVzZWQgdG8gdXBkYXRlIHRoZSB2YWx1ZSBjb2x1bW4gaW4gdGhlIGRlY2sgZGF0YWZyYW1lLgoKIyMjIyMgVGhlIGlmZWxzZSBGdW5jdGlvbgoKVGhlIGlmZWxzZSBmdW5jdGlvbiBpcyBhIHZlY3Rvcml6ZWQgY29uZGl0aW9uYWwgc3RhdGVtZW50IHRoYXQgY2hlY2tzIGEgY29uZGl0aW9uIGFuZCByZXR1cm5zIG9uZSB2YWx1ZSBpZiB0aGUgY29uZGl0aW9uIGlzIFRSVUUgYW5kIGFub3RoZXIgdmFsdWUgaWYgdGhlIGNvbmRpdGlvbiBpcyBGQUxTRS4KCkluIHRoZSBmaXJzdCBpZmVsc2Ugc3RhdGVtZW50LCB0aGUgY29uZGl0aW9uIGlzIGZhY2UgPT0gIktpbmciLiBJZiB0aGlzIGNvbmRpdGlvbiBpcyBUUlVFLCB0aGUgdmFsdWUgcmV0dXJuZWQgaXMgMTM7IG90aGVyd2lzZSwgdGhlIG9yaWdpbmFsIHZhbHVlIGluIHRoZSB2YWx1ZSBjb2x1bW4gaXMgcmV0dXJuZWQuCgpJbiB0aGUgc2Vjb25kIGlmZWxzZSBzdGF0ZW1lbnQsIHRoZSBjb25kaXRpb24gaXMgZmFjZSA9PSAiUXVlZW4iLiBJZiB0aGlzIGNvbmRpdGlvbiBpcyBUUlVFLCB0aGUgdmFsdWUgcmV0dXJuZWQgaXMgMTI7IG90aGVyd2lzZSwgdGhlIG9yaWdpbmFsIHZhbHVlIGluIHRoZSB2YWx1ZSBjb2x1bW4gaXMgcmV0dXJuZWQgKHdoaWNoIG1heSBoYXZlIGFscmVhZHkgYmVlbiB1cGRhdGVkIGJ5IHRoZSBwcmV2aW91cyBpZmVsc2Ugc3RhdGVtZW50KS4KCiMjIyMjIFRoZSBtdXRhdGUgU3RhdGVtZW50CgpUaGUgbXV0YXRlIHN0YXRlbWVudCBpcyB1c2VkIHRvIHVwZGF0ZSB0aGUgdmFsdWUgY29sdW1uIGluIHRoZSBkZWNrIGRhdGFmcmFtZS4gVGhlIHZhbHVlIGNvbHVtbiBpcyB1cGRhdGVkIHR3aWNlLCBmaXJzdCB0byBhc3NpZ24gYSB2YWx1ZSBvZiAxMyB0byB0aGUgIktpbmciIGNhcmRzLCBhbmQgdGhlbiB0byBhc3NpZ24gYSB2YWx1ZSBvZiAxMiB0byB0aGUgIlF1ZWVuIiBjYXJkcy4KCkhvd2V2ZXIsIHRoZXJlJ3MgYSBzdWJ0bGUgaXNzdWUgd2l0aCB0aGlzIGNvZGUuIFRoZSBzZWNvbmQgaWZlbHNlIHN0YXRlbWVudCB3aWxsIG9ubHkgdXBkYXRlIHRoZSAiUXVlZW4iIGNhcmRzIGlmIHRoZXkgaGF2ZW4ndCBhbHJlYWR5IGJlZW4gdXBkYXRlZCBieSB0aGUgZmlyc3QgaWZlbHNlIHN0YXRlbWVudC4gU2luY2UgdGhlIGZpcnN0IGlmZWxzZSBzdGF0ZW1lbnQgZG9lc24ndCB1cGRhdGUgdGhlICJRdWVlbiIgY2FyZHMsIHRoZSBzZWNvbmQgaWZlbHNlIHN0YXRlbWVudCB3aWxsIHdvcmsgYXMgZXhwZWN0ZWQuCgojIyMjIyBUaGUgZmlsdGVyIEZ1bmN0aW9uCgpUaGUgZmlsdGVyIGZ1bmN0aW9uIGlzIHVzZWQgdG8gc2VsZWN0IGEgc3Vic2V0IG9mIHJvd3MgZnJvbSB0aGUgZGVjayBkYXRhZnJhbWUgd2hlcmUgdGhlIGZhY2UgY29sdW1uIGlzIGVpdGhlciAiS2luZyIgb3IgIlF1ZWVuIi4gVGhpcyBhbGxvd3MgdXMgdG8gdmlldyB0aGUgY2hhbmdlcyBtYWRlIHRvIHRoZSB2YWx1ZSBjb2x1bW4gZm9yIHRoZXNlIHNwZWNpZmljIGNhcmRzLgoKCiMjIyBFeGVyY2lzZSA2OiBJbi1QbGFjZSBNb2RpZmljYXRpb25zCgoxLiBVc2UgYG11dGF0ZWAgdG8gYWRkIGEgbmV3IGNvbHVtbiAiaXNfZmFjZV9jYXJkIiB0aGF0IGlzIFRSVUUgZm9yIEphY2ssIFF1ZWVuLCBhbmQgS2luZywgYW5kIEZBTFNFIG90aGVyd2lzZS4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+CjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCmBgYHtyfQpkZWNrIDwtIG11dGF0ZShkZWNrLAogICAgICAgICAgICAgICBpc19mYWNlX2NhcmQgPSBmYWNlICVpbiUgYygiSmFjayIsICJRdWVlbiIsICJLaW5nIikpCmBgYAo8L2RldGFpbHM+CgojIyBMb2dpY2FsIFN1YnNldHRpbmcKCkxldCdzIHByYWN0aWNlIGxvZ2ljYWwgc3Vic2V0dGluZzoKCmBgYHtyfQojIEdldCBhbGwgSGVhcnRzCmhlYXJ0cyA8LSBkZWNrW2RlY2skc3VpdCA9PSAiSGVhcnRzIiwgXQoKIyBHZXQgYWxsIGZhY2UgY2FyZHMKZmFjZV9jYXJkcyA8LSBkZWNrW2RlY2skZmFjZSAlaW4lIGMoIkphY2siLCAiUXVlZW4iLCAiS2luZyIpLCBdCgojIFZpZXcgcmVzdWx0cwpoZWFkKGhlYXJ0cykKaGVhZChmYWNlX2NhcmRzKQpgYGAKVGhlIGNvZGUgdXNlcyBsb2dpY2FsIHN1YnNldHRpbmcgdG8gZXh0cmFjdCBzcGVjaWZpYyByb3dzIGZyb20gdGhlIGRlY2sgZGF0YWZyYW1lIGJhc2VkIG9uIGNlcnRhaW4gY29uZGl0aW9ucy4KCiMjIyMjIEdldHRpbmcgQWxsIEhlYXJ0cwoKVGhlIGZpcnN0IGxpbmUgb2YgY29kZSB1c2VzIHRoZSBmb2xsb3dpbmcgc3ludGF4IHRvIGdldCBhbGwgcm93cyB3aGVyZSB0aGUgc3VpdCBjb2x1bW4gaXMgIkhlYXJ0cyI6CgkJCkhlcmUncyB3aGF0J3MgaGFwcGVuaW5nOgoKLSBkZWNrJHN1aXQgPT0gIkhlYXJ0cyIgaXMgYSBsb2dpY2FsIGV4cHJlc3Npb24gdGhhdCBjaGVja3MgaWYgdGhlIHZhbHVlIGluIHRoZSBzdWl0IGNvbHVtbiBpcyBlcXVhbCB0byAiSGVhcnRzIi4gVGhpcyB3aWxsIHJldHVybiBhIHZlY3RvciBvZiBUUlVFIGFuZCBGQUxTRSB2YWx1ZXMsIHdoZXJlIFRSVUUgaW5kaWNhdGVzIHRoYXQgdGhlIHJvdyBoYXMgYSBzdWl0IG9mICJIZWFydHMiLgotIFRoZSBzcXVhcmUgYnJhY2tldHMgW10gYXJlIHVzZWQgdG8gc3Vic2V0IHRoZSBkZWNrIGRhdGFmcmFtZSBiYXNlZCBvbiB0aGlzIGxvZ2ljYWwgZXhwcmVzc2lvbi4gVGhlIGNvbW1hIGluc2lkZSB0aGUgYnJhY2tldHMgaW5kaWNhdGVzIHRoYXQgd2Ugd2FudCB0byBzZWxlY3Qgcm93cyAoaWYgdGhlcmUgd2VyZSBubyBjb21tYSwgaXQgd291bGQgc2VsZWN0IGNvbHVtbnMpLgotIFRoZSByZXN1bHRpbmcgc3Vic2V0IG9mIHJvd3MgaXMgYXNzaWduZWQgdG8gYSBuZXcgZGF0YWZyYW1lIGNhbGxlZCBoZWFydHMuCkdldHRpbmcgQWxsIEZhY2UgQ2FyZHMKClRoZSBzZWNvbmQgbGluZSBvZiBjb2RlIHVzZXMgdGhlIGZvbGxvd2luZyBzeW50YXggdG8gZ2V0IGFsbCByb3dzIHdoZXJlIHRoZSBmYWNlIGNvbHVtbiBpcyAiSmFjayIsICJRdWVlbiIsIG9yICJLaW5nIjoKCkhlcmUncyB3aGF0J3MgaGFwcGVuaW5nOgoKLSBkZWNrJGZhY2UgJWluJSBjKCJKYWNrIiwgIlF1ZWVuIiwgIktpbmciKSBpcyBhIGxvZ2ljYWwgZXhwcmVzc2lvbiB0aGF0IGNoZWNrcyBpZiB0aGUgdmFsdWUgaW4gdGhlIGZhY2UgY29sdW1uIGlzIG9uZSBvZiB0aGUgdmFsdWVzIGluIHRoZSB2ZWN0b3IgYygiSmFjayIsICJRdWVlbiIsICJLaW5nIikuIFRoaXMgd2lsbCByZXR1cm4gYSB2ZWN0b3Igb2YgVFJVRSBhbmQgRkFMU0UgdmFsdWVzLCB3aGVyZSBUUlVFIGluZGljYXRlcyB0aGF0IHRoZSByb3cgaGFzIGEgZmFjZSB0aGF0IGlzIG9uZSBvZiB0aGUgc3BlY2lmaWVkIHZhbHVlcy4KLSBUaGUgcmVzdCBvZiB0aGUgc3ludGF4IGlzIHRoZSBzYW1lIGFzIGJlZm9yZTogdGhlIHNxdWFyZSBicmFja2V0cyBbXSBhcmUgdXNlZCB0byBzdWJzZXQgdGhlIGRlY2sgZGF0YWZyYW1lIGJhc2VkIG9uIHRoaXMgbG9naWNhbCBleHByZXNzaW9uLCBhbmQgdGhlIHJlc3VsdGluZyBzdWJzZXQgb2Ygcm93cyBpcyBhc3NpZ25lZCB0byBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkIGZhY2VfY2FyZHMuCgojIyMjIyBWaWV3aW5nIHRoZSBSZXN1bHRzCgpUaGUgZmluYWwgdHdvIGxpbmVzIG9mIGNvZGUgdXNlIHRoZSBoZWFkKCkgZnVuY3Rpb24gdG8gdmlldyB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgdGhlIGhlYXJ0cyBhbmQgZmFjZV9jYXJkcyBkYXRhZnJhbWVzCgkJClRoaXMgYWxsb3dzIHVzIHRvIHZlcmlmeSB0aGF0IHRoZSBzdWJzZXR0aW5nIHdvcmtlZCBjb3JyZWN0bHkgYW5kIHNlZSB0aGUgcmVzdWx0aW5nIGRhdGFmcmFtZXMuCgojIyMgRXhlcmNpc2UgNzogTG9naWNhbCBTdWJzZXR0aW5nCgoxLiBDcmVhdGUgYSBzdWJzZXQgb2YgdGhlIGRlY2sgY29udGFpbmluZyBvbmx5IGNhcmRzIHdpdGggdmFsdWVzIGdyZWF0ZXIgdGhhbiAxMC4KMi4gQ3JlYXRlIGEgc3Vic2V0IG9mIHJlZCBjYXJkcyAoSGVhcnRzIGFuZCBEaWFtb25kcykgd2l0aCBvZGQgdmFsdWVzLgoKYGBge3J9CiMgWW91ciBjb2RlIGhlcmUKYGBgCgo8ZGV0YWlscz4KPHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHNvbHV0aW9uPC9zdW1tYXJ5PgoKYGBge3J9CiMgMS4gQ2FyZHMgd2l0aCB2YWx1ZXMgPiAxMAoKIyAyLiBSZWQgY2FyZHMgd2l0aCBvZGQgdmFsdWVzCnJlZF9vZGRfY2FyZHMgPC0gZGVja1tkZWNrJHN1aXQgJWluJSBjKCJIZWFydHMiLCAiRGlhbW9uZHMiKSAmIGRlY2skdmFsdWUgJSUgMiA9PSAxLCBdCmBgYAo8L2RldGFpbHM+CgojIyBNaXNzaW5nIEluZm9ybWF0aW9uCgpMZXQncyBpbnRyb2R1Y2UgYW5kIGhhbmRsZSBtaXNzaW5nIHZhbHVlczoKCmBgYHtyfQojIEludHJvZHVjZSBzb21lIE5BIHZhbHVlcwpkZWNrJHZhbHVlW3NhbXBsZShucm93KGRlY2spLCA1KV0gPC0gTkEKCiMgQ291bnQgTkEgdmFsdWVzCnN1bShpcy5uYShkZWNrJHZhbHVlKSkKCiMgUmVtb3ZlIHJvd3Mgd2l0aCBOQSB2YWx1ZXMKZGVja19jbGVhbiA8LSBuYS5vbWl0KGRlY2spCgojIFZpZXcgcmVzdWx0cwpzdW0oaXMubmEoZGVja19jbGVhbiR2YWx1ZSkpCmBgYAoKVGhlIGZpcnN0IGxpbmUgb2YgY29kZSBpbnRyb2R1Y2VzIHNvbWUgbWlzc2luZyB2YWx1ZXMgKE5BKSBpbnRvIHRoZSB2YWx1ZSBjb2x1bW4gb2YgdGhlIGRlY2sgZGF0YWZyYW1lOgoKCkhlcmUncyB3aGF0J3MgaGFwcGVuaW5nOgoKLSBzYW1wbGUobnJvdyhkZWNrKSwgNSkgZ2VuZXJhdGVzIGEgcmFuZG9tIHNhbXBsZSBvZiA1IHJvdyBpbmRpY2VzIGZyb20gdGhlIGRlY2sgZGF0YWZyYW1lLgotIGRlY2skdmFsdWVbLi4uXSBzZWxlY3RzIHRoZSBjb3JyZXNwb25kaW5nIHZhbHVlcyBpbiB0aGUgdmFsdWUgY29sdW1uLgotIDwtIE5BIGFzc2lnbnMgTkEgdmFsdWVzIHRvIHRoZXNlIHNlbGVjdGVkIHBvc2l0aW9ucy4KQ291bnRpbmcgTkEgVmFsdWVzCgpUaGUgbmV4dCBsaW5lIG9mIGNvZGUgY291bnRzIHRoZSBudW1iZXIgb2YgTkEgdmFsdWVzIGluIHRoZSB2YWx1ZSBjb2x1bW4KCkhlcmUncyB3aGF0J3MgaGFwcGVuaW5nOgoKLSBpcy5uYShkZWNrJHZhbHVlKSBjaGVja3Mgd2hpY2ggdmFsdWVzIGluIHRoZSB2YWx1ZSBjb2x1bW4gYXJlIE5BLCByZXR1cm5pbmcgYSBsb2dpY2FsIHZlY3RvciAoVFJVRSBmb3IgTkEsIEZBTFNFIG90aGVyd2lzZSkuCi0gc3VtKC4uLikgc3VtcyB1cCB0aGUgbnVtYmVyIG9mIFRSVUUgdmFsdWVzIGluIHRoaXMgbG9naWNhbCB2ZWN0b3IsIGVmZmVjdGl2ZWx5IGNvdW50aW5nIHRoZSBudW1iZXIgb2YgTkEgdmFsdWVzLgotIFJlbW92aW5nIFJvd3Mgd2l0aCBOQSBWYWx1ZXMKClRoZSBuZXh0IGxpbmUgb2YgY29kZSBjcmVhdGVzIGEgbmV3IGRhdGFmcmFtZSwgZGVja19jbGVhbiwgYnkgcmVtb3Zpbmcgcm93cyB3aXRoIE5BIHZhbHVlcyBmcm9tIHRoZSBkZWNrIGRhdGFmcmFtZS4KCgpIZXJlJ3Mgd2hhdCdzIGhhcHBlbmluZzoKCi0gbmEub21pdChkZWNrKSByZW1vdmVzIHJvd3Mgd2l0aCBOQSB2YWx1ZXMgZnJvbSB0aGUgZGVjayBkYXRhZnJhbWUuIEJ5IGRlZmF1bHQsIG5hLm9taXQoKSByZW1vdmVzIHJvd3Mgd2l0aCBOQSB2YWx1ZXMgaW4gYW55IGNvbHVtbi4KLSBUaGUgcmVzdWx0aW5nIGRhdGFmcmFtZSBpcyBhc3NpZ25lZCB0byBhIG5ldyB2YXJpYWJsZSwgZGVja19jbGVhbi4KLSBWZXJpZnlpbmcgdGhlIFJlc3VsdHMKClRoZSBmaW5hbCBsaW5lIG9mIGNvZGUgdmVyaWZpZXMgdGhhdCB0aGUgTkEgdmFsdWVzIGhhdmUgYmVlbiByZW1vdmVkIGZyb20gdGhlIGRlY2tfY2xlYW4gZGF0YWZyYW1lCgkJClRoaXMgc2hvdWxkIHJldHVybiAwLCBpbmRpY2F0aW5nIHRoYXQgdGhlcmUgYXJlIG5vIE5BIHZhbHVlcyBpbiB0aGUgdmFsdWUgY29sdW1uIG9mIGRlY2tfY2xlYW4uCgoKCiMjIyBFeGVyY2lzZSA4OiBIYW5kbGluZyBNaXNzaW5nIERhdGEKCjEuIFJlcGxhY2UgYWxsIE5BIHZhbHVlcyBpbiB0aGUgJ3ZhbHVlJyBjb2x1bW4gd2l0aCB0aGUgbWVhbiB2YWx1ZSBvZiB0aGUgbm9uLU5BIGVudHJpZXMuCgpgYGB7cn0KIyBZb3VyIGNvZGUgaGVyZQpgYGAKCjxkZXRhaWxzPgo8c3VtbWFyeT5DbGljayB0byBzZWUgc29sdXRpb248L3N1bW1hcnk+CgpgYGB7cn0KZGVjayR2YWx1ZVtpcy5uYShkZWNrJHZhbHVlKV0gPC0gbWVhbihkZWNrJHZhbHVlLCBuYS5ybSA9IFRSVUUpCmBgYAo8L2RldGFpbHM+CgojIyBFbnZpcm9ubWVudHMKCkFuIGVudmlyb25tZW50IGluIFIgaXMgYSBzZWxmLWNvbnRhaW5lZCBzcGFjZSB3aGVyZSB5b3UgY2FuIHN0b3JlIGFuZCBtYW5hZ2UgdmFyaWFibGVzLCBmdW5jdGlvbnMsIGFuZCBvdGhlciBvYmplY3RzLiBFbnZpcm9ubWVudHMgYXJlIHVzZWZ1bCBmb3Igb3JnYW5pemluZyB5b3VyIGNvZGUgYW5kIGRhdGEsIGFuZCBmb3IgYXZvaWRpbmcgbmFtaW5nIGNvbmZsaWN0cy4KTGV0J3MgZXhwbG9yZSBlbnZpcm9ubWVudHM6CgpgYGB7cn0KIyBDcmVhdGUgYSBuZXcgZW52aXJvbm1lbnQKY2FyZF9lbnYgPC0gbmV3LmVudigpCgojIEFzc2lnbiBhIHZhcmlhYmxlIHRvIHRoZSBuZXcgZW52aXJvbm1lbnQKY2FyZF9lbnYkYWNlX3ZhbHVlIDwtIDEKCiMgQWNjZXNzIHRoZSB2YXJpYWJsZQpjYXJkX2VudiRhY2VfdmFsdWUKYGBgCiMjIyMjIENyZWF0aW5nIGEgTmV3IEVudmlyb25tZW50CgpUbyBjcmVhdGUgYSBuZXcgZW52aXJvbm1lbnQsIHlvdSBjYW4gdXNlIHRoZSBuZXcuZW52KCkgZnVuY3Rpb24uCgkJClRoaXMgY3JlYXRlcyBhIG5ldywgZW1wdHkgZW52aXJvbm1lbnQgYW5kIGFzc2lnbnMgaXQgdG8gdGhlIHZhcmlhYmxlIGNhcmRfZW52LgoKIyMjIyMgQXNzaWduaW5nIGEgVmFyaWFibGUgdG8gdGhlIE5ldyBFbnZpcm9ubWVudAoKVG8gYXNzaWduIGEgdmFyaWFibGUgdG8gdGhlIG5ldyBlbnZpcm9ubWVudCwgeW91IGNhbiB1c2UgdGhlICQgb3BlcmF0b3IuCgkJClRoaXMgYXNzaWducyB0aGUgdmFsdWUgMSB0byB0aGUgdmFyaWFibGUgYWNlX3ZhbHVlIGluIHRoZSBjYXJkX2VudiBlbnZpcm9ubWVudC4KCiMjIyMjIEFjY2Vzc2luZyB0aGUgVmFyaWFibGUKClRvIGFjY2VzcyB0aGUgdmFyaWFibGUsIHlvdSBjYW4gdXNlIHRoZSAkIG9wZXJhdG9yIGFnYWluLgpUaGlzIHJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBhY2VfdmFsdWUgdmFyaWFibGUgaW4gdGhlIGNhcmRfZW52IGVudmlyb25tZW50LCB3aGljaCBpcyAxLgoKCQkKIyMjIyMgRW52aXJvbm1lbnQgRGV0YWlscwoKSGVyZSBhcmUgc29tZSBhZGRpdGlvbmFsIGRldGFpbHMgYWJvdXQgdGhlIGNhcmRfZW52IGVudmlyb25tZW50LgoJCQpUaGUgbHMoKSBmdW5jdGlvbiBsaXN0cyB0aGUgb2JqZWN0cyBpbiB0aGUgZW52aXJvbm1lbnQsIHdoaWNoIGluIHRoaXMgY2FzZSBpcyBqdXN0IHRoZSBhY2VfdmFsdWUgdmFyaWFibGUuIFRoZSB0eXBlb2YoKSBhbmQgY2xhc3MoKSBmdW5jdGlvbnMgcmV0dXJuIHRoZSB0eXBlIGFuZCBjbGFzcyBvZiB0aGUgZW52aXJvbm1lbnQsIHJlc3BlY3RpdmVseS4KCiMjIFdvcmtpbmcgd2l0aCBFbnZpcm9ubWVudHMKCkxldCdzIHVzZSBlbnZpcm9ubWVudHMgdG8gbWFuYWdlIGdhbWUgc3RhdGU6CgpgYGB7cn0KZ2FtZV9lbnYgPC0gbmV3LmVudigpCgp3aXRoKGdhbWVfZW52LCB7CiAgZGVjayA8LSBzaHVmZmxlX2RlY2soZGVjaykKICBwbGF5ZXJfaGFuZCA8LSBkZWFsX2NhcmQoZGVjaykKfSkKCiMgQWNjZXNzIHZhcmlhYmxlcyBmcm9tIHRoZSBlbnZpcm9ubWVudApnYW1lX2VudiRwbGF5ZXJfaGFuZApgYGAKCiMjIyBFeGVyY2lzZSA5OiBFbnZpcm9ubWVudCBVc2FnZQoKMS4gQ3JlYXRlIGEgZnVuY3Rpb24gdGhhdCBpbml0aWFsaXplcyBhIGdhbWUgZW52aXJvbm1lbnQgd2l0aCBhIHNodWZmbGVkIGRlY2sgYW5kIGRlYWx0IGhhbmRzIGZvciBhIHNwZWNpZmllZCBudW1iZXIgb2YgcGxheWVycy4KCmBgYHtyfQojIFlvdXIgY29kZSBoZXJlCmBgYAoKPGRldGFpbHM+CjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBzb2x1dGlvbjwvc3VtbWFyeT4KCmBgYHtyfQppbml0aWFsaXplX2dhbWUgPC0gZnVuY3Rpb24obnVtX3BsYXllcnMsIGNhcmRzX3Blcl9oYW5kKSB7CiAgZ2FtZV9lbnYgPC0gbmV3LmVudigpCiAgCiAgd2l0aChnYW1lX2VudiwgewogICAgZGVjayA8LSBzaHVmZmxlX2RlY2soZGVjaykKICAgIHBsYXllcnMgPC0gbGlzdCgpCiAgICBmb3IgKGkgaW4gMTpudW1fcGxheWVycykgewogICAgICBwbGF5ZXJzW1twYXN0ZTAoIlBsYXllciIsIGkpXV0gPC0gZGVhbF9jYXJkcyhkZWNrLCBjYXJkc19wZXJfaGFuZCkKICAgICAgZGVjayA8LSBkZWNrWy0oMTpjYXJkc19wZXJfaGFuZCksIF0KICAgIH0KICB9KQogIAogIHJldHVybihnYW1lX2VudikKfQoKIyBVc2FnZToKZ2FtZSA8LSBpbml0aWFsaXplX2dhbWUoNCwgNSkKZ2FtZSRwbGF5ZXJzJFBsYXllcjEKYGBgCjwvZGV0YWlscz4KCiMjIFNjb3BpbmcgUnVsZXMKCkxldCdzIGV4cGxvcmUgUidzIGxleGljYWwgc2NvcGluZzoKCmBgYHtyfQpvdXRlcl92YXIgPC0gMTAKCmV4YW1wbGVfZnVuY3Rpb24gPC0gZnVuY3Rpb24oKSB7CiAgaW5uZXJfdmFyIDwtIDUKICBvdXRlcl92YXIgKyBpbm5lcl92YXIKfQoKZXhhbXBsZV9mdW5jdGlvbigpICAjIFJldHVybnMgMTUKYGBgCgojIyBBc3NpZ25tZW50CgpMZXQncyBwcmFjdGljZSBkaWZmZXJlbnQgYXNzaWdubWVudCBtZXRob2RzOgoKYGBge3J9CiMgVXNpbmcgPC0KeCA8LSA1CgojIFVzaW5nID0KeSA9IDEwCgojIFVzaW5nIC0+CjE1IC0+IHoKCiMgVmlldyByZXN1bHRzCmMoeCwgeSwgeikKYGBgCgojIyMgRXhlcmNpc2UgMTA6IEFzc2lnbm1lbnQgUHJhY3RpY2UKCjEuIENyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgdGFrZXMgYSBkZWNrIGFzIGlucHV0IGFuZCByZXR1cm5zIGEgbGlzdCB3aXRoIHR3byBlbGVtZW50czogdGhlIHJlZCBjYXJkcyBhbmQgdGhlIGJsYWNrIGNhcmRzLiBVc2UgZGlmZmVyZW50IGFzc2lnbm1lbnQgb3BlcmF0b3JzIGZvciBlYWNoLgoKYGBge3J9CiMgWW91ciBjb2RlIGhlcmUKYGBgCgojIyMgRmluYWwgRXhlcmNpc2U6IFB1dHRpbmcgSXQgQWxsIFRvZ2V0aGVyCgpDcmVhdGUgYSBjYXJkIGdhbWUgc2ltdWxhdGlvbiB0aGF0IHVzZXMgZW52aXJvbm1lbnRzLCBjbG9zdXJlcywgYW5kIERhdGFGcmFtZXMuIFRoZSBnYW1lIHNob3VsZDoKCjEuIEluaXRpYWxpemUgYSBzaHVmZmxlZCBkZWNrCjIuIERlYWwgaGFuZHMgdG8gcGxheWVycwozLiBBbGxvdyBwbGF5ZXJzIHRvIGRyYXcgYW5kIGRpc2NhcmQgY2FyZHMKNC4gS2VlcCB0cmFjayBvZiB0aGUgZ2FtZSBzdGF0ZSB1c2luZyBhbiBlbnZpcm9ubWVudAoKYGBge3J9CiMgWW91ciBjb2RlIGhlcmUKYGBgCgo8ZGV0YWlscz4KPHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHNvbHV0aW9uPC9zdW1tYXJ5PgoKYGBge3J9CmNyZWF0ZV9jYXJkX2dhbWUgPC0gZnVuY3Rpb24obnVtX3BsYXllcnMsIGNhcmRzX3Blcl9oYW5kKSB7CiAgZ2FtZV9lbnYgPC0gbmV3LmVudigpCiAgCiAgd2l0aChnYW1lX2VudiwgewogICAgZGVjayA8LSBzaHVmZmxlX2RlY2soZGVjaykKICAgIHBsYXllcnMgPC0gbGlzdCgpCiAgICBmb3IgKGkgaW4gMTpudW1fcGxheWVycykgewogICAgICBwbGF5ZXJzW1twYXN0ZTAoIlBsYXllciIsIGkpXV0gPC0gZGVhbF9jYXJkcyhkZWNrLCBjYXJkc19wZXJfaGFuZCkKICAgIH0KICAgIGRlY2sgPC0gZGVja1stKDE6KG51bV9wbGF5ZXJzICogY2FyZHNfcGVyX2hhbmQpKSwgXQogICAgCiAgICB0dXJuIDwtIDEKICAgIAogICAgZHJhd19jYXJkIDwtIGZ1bmN0aW9uKHBsYXllcl9pbmRleCkgewogICAgICBpZiAobnJvdyhkZWNrKSA9PSAwKSB7CiAgICAgICAgc3RvcCgiTm8gbW9yZSBjYXJkcyBpbiB0aGUgZGVjayEiKQogICAgICB9CiAgICAgIGNhcmQgPC0gZGVja1sxLCBdCiAgICAgIGRlY2sgPDwtIGRlY2tbLTEsIF0KICAgICAgcGxheWVyc1tbcGxheWVyX2luZGV4XV0gPDwtIHJiaW5kKHBsYXllcnNbW3BsYXllcl9pbmRleF1dLCBjYXJkKQogICAgICByZXR1cm4oY2FyZCkKICAgIH0KICAgIAogICAgZGlzY2FyZF9jYXJkIDwtIGZ1bmN0aW9uKHBsYXllcl9pbmRleCwgY2FyZF9pbmRleCkgewogICAgICBkaXNjYXJkZWQgPC0gcGxheWVyc1tbcGxheWVyX2luZGV4XV1bY2FyZF9pbmRleCwgXQogICAgICBwbGF5ZXJzW1twbGF5ZXJfaW5kZXhdXSA8PC0gcGxheWVyc1tbcGxheWVyX2luZGV4XV1bLWNhcmRfaW5kZXgsIF0KICAgICAgcmV0dXJuKGRpc2NhcmRlZCkKICAgIH0KICAgIAogICAgbmV4dF90dXJuIDwtIGZ1bmN0aW9uKCkgewogICAgICB0dXJuIDw8LSAodHVybiAlJSBudW1fcGxheWVycykgKyAxCiAgICB9CiAgfSkKICAKICByZXR1cm4oZ2FtZV9lbnYpCn0KCiMgVXNhZ2U6CmdhbWUgPC0gY3JlYXRlX2NhcmRfZ2FtZSg0LCA1KQpnYW1lJGRyYXdfY2FyZCgxKQpnYW1lJGRpc2NhcmRfY2FyZCgxLCAzKQpnYW1lJG5leHRfdHVybigpCmBgYAo8L2RldGFpbHM+CgoK