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:

  1. 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.

  2. 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.

  3. 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:

  1. 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
  1. 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

  1. 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:

  1. Select all the faces from the deck.
  2. Select the first 10 rows and all columns of the deck.
  3. 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:

  1. function(deck): This defines a function that takes one argument, our deck DataFrame.

  2. 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
  3. 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.

  4. The selected row (representing a single card) is assigned to card.

  5. 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:

  1. Modify the deal_card function to deal multiple cards at once.
  2. 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:

  1. 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, ...].

  2. deck[sample(nrow(deck)), ]: This uses the random permutation to reorder all rows of the deck. It’s equivalent to randomly shuffling the cards.

  3. 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.

  4. 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:

  1. Shuffle the deck and deal the top 3 cards.
  2. 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:

  1. 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.
  2. 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.
  3. 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:

  1. 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:

  1. 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.
  2. 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”.
  3. 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:

  1. Change all the “Jack” cards to have a value of 11.
  2. 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

  1. 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

  1. Create a subset of the deck containing only cards with values greater than 10.
  2. 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, ]

Missing Information

Let’s introduce and handle missing values:

# Introduce some NA values
deck$value[sample(nrow(deck), 5)] <- NA

# Count NA values
sum(is.na(deck$value))
[1] 5
# Remove rows with NA values
deck_clean <- na.omit(deck)

# View results
sum(is.na(deck_clean$value))
[1] 0

The first line of code introduces some missing values (NA) into the value column of the deck dataframe:

Here’s what’s happening:

  • sample(nrow(deck), 5) generates a random sample of 5 row indices from the deck dataframe.
  • deck$value[…] selects the corresponding values in the value column.
  • <- NA assigns NA values to these selected positions. Counting NA Values

The next line of code counts the number of NA values in the value column

Here’s what’s happening:

  • is.na(deck$value) checks which values in the value column are NA, returning a logical vector (TRUE for NA, FALSE otherwise).
  • sum(…) sums up the number of TRUE values in this logical vector, effectively counting the number of NA values.
  • Removing Rows with NA Values

The next line of code creates a new dataframe, deck_clean, by removing rows with NA values from the deck dataframe.

Here’s what’s happening:

  • na.omit(deck) removes rows with NA values from the deck dataframe. By default, na.omit() removes rows with NA values in any column.
  • The resulting dataframe is assigned to a new variable, deck_clean.
  • Verifying the Results

The final line of code verifies that the NA values have been removed from the deck_clean dataframe

This should return 0, indicating that there are no NA values in the value column of deck_clean.

Exercise 8: Handling Missing Data

  1. Replace all NA values in the ‘value’ column with the mean value of the non-NA entries.
# Your code here
Click to see solution
deck$value[is.na(deck$value)] <- mean(deck$value, na.rm = TRUE)

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

  1. 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

  1. 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:

  1. Initialize a shuffled deck
  2. Deal hands to players
  3. Allow players to draw and discard cards
  4. 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