Making Sense of Survey Data
Now that we have cleaned up our survey data, we can start asking
questions about it! By the end of the previous session,
Collecting and Cleaning
Survey Data, we generated two cleaned datasets:
survey_data_tidy.csv
survey-data_wide.csv
Long, or “tidy” data and wide data each have their pros and cons, and
in this session we’re going to explore the benefits and drawbacks of
each as we explore our data. But first, let’s take a moment to do some
thinking:
To begin, let’s open up our .RProj file, so that our
working directory will be captured. Now, let’s create a new R script,
and call it survey_analysis_script.R.
Load the Tidyverse
Now that we’ve started a new script, we need to load the libraries
that we’ll be using, which in this case is just the Tidyverse.
library(tidyverse)
Load the data
We can now load the two datasets that were generated in the previous
session:
survey_data_tidy <- read_csv("survey_data_tidy.csv")
survey_data_wide <- read_csv("survey_data_wide.csv")
- Take a look at
survey_data_tidy and
survey-data_wide using the View()
command.
View(survey_data_tidy)
View(survey_data_wide)
In groups, spend a few minutes talking about some things you’d
like to know about the data (ie. groups you’d like to count, possible
relationships, etc.).
Taking a closer look at the tidy and
wide datasets, can you think of reasons why certain
questions might be better with either one of the datasets?
Exploring Wide Data
Wide data is easier for humans to read and interpret, and lends
itself well to asking simple questions from single variables, or
columns, of data. Tidy data is better for asking more complicated
questions, as well as asking about multiple variables and possible
relationships between them. Let’s first start with some simple questions
we can ask from the wide version of our data.
A simple first step when exploring a dataset is getting counts of
individual variables. To do this, we can use the count()
function:
What does the sample breadkdown of gender?
survey_data_wide |>
count(gender)
Step-by-step explanation:
- We start with the
survey_data_wide object and use the
pipe, |>, to indicate we want to do something with
it.
- We then use the
count() function to give us a total sum
of whatever variable/column name we put inside the brackets.
What is the sample breakdown of age?
survey_data_wide |>
count(age)
In addition to looking at single variables with the
count() function, we can also generate quick summary tables
across multiple variables by separating them with commas
,:
What is the sample breakdown of age and gender?
survey_data_wide |>
count(age, gender)
## # A tibble: 24 × 3
## age gender n
## <dbl> <chr> <int>
## 1 18 Female 31
## 2 18 Male 34
## 3 18 Non-binary/Other 3
## 4 19 Female 25
## 5 19 Male 24
## 6 19 Non-binary/Other 6
## 7 20 Female 28
## 8 20 Male 17
## 9 20 Non-binary/Other 3
## 10 21 Female 12
## # ℹ 14 more rows
You’ll see the note that there are 14 more rows, and that you can use
the print() function to view more. You can do this you can
do this by specifiying the amount of rows (in this case there are
24)
survey_data_wide |>
count(age, gender) |>
print(n = 24)
You can keep adding additional variables to these, noting that each
variable will add additional rows. If you don’t want to look at the
values in the R console, you can use the View() function to
open it in a separate tab.
survey_data_wide |>
count(age, gender, year_of_study) |>
View()
If this is something you want to come back to, you can save it into
an R object.
demographics_count <- survey_data_wide |>
count(age, gender, year_of_study)
View(demographics_count)
A final thing that can be helpful with the count()
function is adding in the proportion that each sum represents in the
total sample.
survey_data_wide |>
count(gender) |>
mutate(prop = n / sum(n))
Step-by-step explanation:
- Start by piping the
survey_wide object to the
count() function like we’ve been doing.
- Add another pipe to indicate we are passing that count to another
function.
mutate(prop creates a new column called
prop, which stands for proportion (you can name this
whatever you want).
- Everything on the right side of the
= is assigned to
the new prop column.
n is the count for each gender category, and
sum(n) is the total number of every row/person in the
sample.
n / sum(n)) calculates
"count of each category" / "total count", which gives a
proportion.
Your Turn!
See if you can create the following from the
survey_data_wide object:
- A count of each
year_of_study category.
survey_data_wide |>
count(year_of_study)
- A count of each
year_of_study and
hours_per_day.
survey_data_wide |>
count(year_of_study, hours_per_day)
- The count of
year_of_study and its proportion.
survey_data_wide |>
count(year_of_study) |>
mutate(prop = n / sum(n))
- The count of
year_of_study, hours_per_day,
and the proportion
survey_data_wide |>
count(year_of_study, hours_per_day) |>
mutate(prop = n / sum(n))
Simple Barplots as Exploration
In addition to creating summary tables to explore data, creating
simple plots can be another way to explore your data.
One way to do this, is using the base R barplot()
function. This can be done in a few steps.
In this example, we’re going to plot the categories of the
hours_per_day columns.
First, let’s look at the $ operator. When placed after a
data object in R, it allows you to isolate specified columns.
survey_data_wide$hours_per_day
This will show all the values in that column in the R console. Give
it a try with other columns!
Next, we can also use the table function here, to
generate a quick summary table of that column.
table(survey_data_wide$hours_per_day)
Give this a try with some other columns!
Now we’re going to save this table as an object called
hours_table.
hours_table <- table(survey_data_wide$hours_per_day)
Finally, we can feed the hours_table object into the
barplot() function to get our plot.
barplot(hours_table)

You might notice that the bars aren’t in any particular order, which
can be a bit annoying. Let’s clean this up by creating adding another
step.
hours_sorted <- sort(hours_table, decreasing = TRUE)
barplot(hours_sorted)

The sort function is telling R that we want to reorder
the values in hours_table, and the
decreasing = TRUE allows us to see the values from biggest
to smallest. You can change this to decreasing = FALSE to
see smallest to biggest.
When exploring data, it’s not always necessary to add labels to our
plots. However, this chart might be something you want to communicate,
so let’s add some labels!
barplot(hours_sorted,
main = "Hours per day on social media",
xlab = "Hours per day",
ylab = "Number of students")

With the barplot() function:
main is the title of the chart.
xlab is the label on the x (horizontal) axis.
ylad is the label on the y (vertical) axis.
Your Turn!
- Make a barplot for the
feel_increase_stress variable,
that orders the bars from biggest to smallest, and has labels for the
title, and both axes.
Hint: break this into 3 steps:
- Create an object that creates a table of the
feel_increase_stress column
- Create another object that sorts the table in decreasing order
- Create a barplot and add 3 layers of labels.
stress_count <- table(survey_data_wide$feel_increase_stress)
stress_sorted <- sort(stress_count, decreasing = TRUE)
barplot(stress_sorted,
main = "Social media makes me feel anxious or stressed",
xlab = "Feeling anxious or stressed",
ylab = "Number of students")
- Try this with another column!
Moving to Tidy Data
As we’ve seen, working with wide data can be helpful for generating
quick summaries and counts. But what if we want to ask something that’s
a bit more complicated?
In groups, take a look at the data and talk about how you might go
about answering the question, which platforms are most
used?
There are certainly ways to do this with the wide data. One way would
be to use the count() function for each individual column.
However, this is a bit clunky, and then you would have to then deal with
merging the responses into a table (not impossible, but it’s more work).
There is a way to do this is a single code chunk, but it becomes overly
long and complicated:
platform_counts_wide <- survey_wide |>
summarise(
across(
c(`LinkedIn`, Instagram, Reddit, Facebook,
`X (Twitter)`, TikTok, Snapchat),
~ sum(.x))) |>
pivot_longer(
cols = everything(),
names_to = "platform",
values_to = "n_users") |>
arrange(desc(n_users))
platform_counts_wide
We don’t need to understand this code chunk, it is just an example of
what the code looks like. However, if we shift to tidy
data, the code becomes much shorter and simpler.
First, let’s start by taking another look at the tidy data.
View(survey_data_tidy)
You can see that there is the single platforms column
that we are able to query.
Now, let’s do a count of the different categories in this column.
survey_data_tidy |>
count(platforms, name = "n_students")
## # A tibble: 7 × 2
## platforms n_students
## <chr> <int>
## 1 Facebook 3200
## 2 Instagram 5340
## 3 LinkedIn 2520
## 4 Reddit 4100
## 5 Snapchat 2420
## 6 TikTok 5480
## 7 X (Twitter) 2960
In this code, we are using the count() function like we
just did, and the name = "n_students" creates a new column
name for the number for each column. "n_students" was used
to show this is the number of students, but you can put anything you
want here, or leave it blank if preferred.
You can see that this code is very simple, but there is a big problem
with the numbers! Because our tidy data adds additional rows to data, we
are seeing numbers in the thousands when our sample size is only 300.
However, when we cleaned the data, we created a unique ID for each
entry. This was to help with re-identifying responses if needed, but it
can also help us with eliminating redundant rows.
survey_data_tidy |>
distinct(ID, platforms) |>
count(platforms, name = "n_students")
## # A tibble: 7 × 2
## platforms n_students
## <chr> <int>
## 1 Facebook 160
## 2 Instagram 267
## 3 LinkedIn 126
## 4 Reddit 205
## 5 Snapchat 121
## 6 TikTok 274
## 7 X (Twitter) 148
The distinct() function is telling R that we only want
to keep unique combinations of each student ID and
platform, which eliminates any of the redundancy of the
tidy data. As you can see, the numbers are now accurate to our
sample.
As with before, it can be nice to arrange the numbers from biggest to
smallest.
survey_data_tidy |>
distinct(ID, platforms) |>
count(platforms, name = "n_students") |>
arrange(desc(n_students))
## # A tibble: 7 × 2
## platforms n_students
## <chr> <int>
## 1 TikTok 274
## 2 Instagram 267
## 3 Reddit 205
## 4 Facebook 160
## 5 X (Twitter) 148
## 6 LinkedIn 126
## 7 Snapchat 121
In this case, the arrange() function tells R that we
want to change the order of something, and desc(n_students)
specifies that we want the n_students column, which is the
values for each platform, to be listed in descending order (biggest to
smallest).
Finally, once we’re happy with the output of this code chunk, we can
save it as an R object to revisit. We’ll call the object
platform_count, and now we can easily view and work with it
going forward.
platform_count <- survey_data_tidy |>
distinct(ID, platforms) |>
count(platforms, name = "n_students") |>
arrange(desc(n_students))
Going Deeper with Tidy Data
Let’s keep digging into the tidy data, and start asking questions
that are related to our bigger research question, “How does
social media usage influence the mental health of university
students?
Comparison Operators
Comparison operators allow us to look for specific criteria in our
dataset. These return TRUE or FALSE based on
whether the condition is met.
== |
Equal to |
5 == 5 |
TRUE |
!= |
Not equal to |
5 != 3 |
TRUE |
< |
Less than |
3 < 5 |
TRUE |
> |
Greater than |
5 > 3 |
TRUE |
<= |
Less than or equal to |
3 <= 3 |
TRUE |
>= |
Greater than or equal to |
5 >= 3 |
TRUE |
Once we understand these basic comparison operators, we can combine
them using logical operators to create more complex filtering
conditions.
Logical Operators
Logical operators allow us to filter data based on multiple
conditions.
& |
Logical AND (Both conditions must be TRUE) |
(5 > 3) & (4 < 6) |
TRUE |
| |
Logical OR (At least one condition must be TRUE) |
(5 > 3) | (4 > 6) |
TRUE |
! |
Logical NOT (Reverses TRUE/FALSE) |
!(5 > 3) |
FALSE |
Asking Questions with Filtering
The filter() function returns only the rows that meet a
specified condition.
From the feel-question column in our tidy data, these
values indicating whether social media makes students feel connected to
others (feel_connected), anxious or stressed
(feel_increase_stress), distracts them from academic work
(feel_distracted), or improves their mood
(feel_improved_mood).
As part of the bigger research question, “How does social media usage
influence the mental health of university students?”, we can use this
variable to start asking the question, “how many students feel X
because of their social media use?
Let’s first start by asking, “how many students feel anxious
or stressed because of social media?
stressed_count <- survey_data_tidy |>
distinct(ID, feel_question, feel_response) |>
filter(feel_question == "feel_increase_stress") |>
count(feel_response, name = "feel_increase_stress") |>
arrange(desc(feel_increase_stress))
stressed_count
## # A tibble: 5 × 2
## feel_response feel_increase_stress
## <chr> <int>
## 1 Agree 69
## 2 Disagree 69
## 3 Neutral 68
## 4 Strongly disagree 48
## 5 Strongly agree 46
Step-by-step explanation:
- We start by creating a new R object that will save this information,
called
stressed_count.
- We then pipe the
survey_data_tidy object to indicate we
will manipulate it in some way.
- Next,
distinct(ID, feel_question, feel_response) tells
R to only keep unique combinations of ID,
feel-question, and feel_response.
- This is then piped through to the
filter() command, and
feel_question == feel_increase_stress looks for only for
the stressed values in the feel_question column.
- This is piped into the
count() function, to indicate we
want a count of every unique feel_increase_stress answer in
the feel_response column, and gives names the new column of
counts feel_increase_stress.
- Finally, the
arrange(desc(feel_increase_stres)) line
arranges the values from biggest to smallest.
Your Turn!
Hint: Use the code chunk above to guide your solution.
- How many students feel more connected because of their
social media use?
connected_count <- survey_data_tidy |>
distinct(ID, feel_question, feel_response) |>
filter(feel_question == "feel_connected") |>
count(feel_response, name = "feel_connected") |>
arrange(desc(feel_connected))
connected_count
- How many students feel distracted by their social media
use?
distracted_count <- survey_data_tidy |>
distinct(ID, feel_question, feel_response) |>
filter(feel_question == "feel_distracted") |>
count(feel_response, name = "feel_distracted") |>
arrange(desc(feel_distracted))
distracted_count
Asking a Research Question
So far the questions we have been asking of our data have related to
counts, which can be very helpful, but may not get to the bigger
research question we want to ask. As part of the bigger research
question, we might want to ask, “How does heavy usage of social
media affect mental health compared to light usage?
There will be a few steps to answer this question, but let’s break
them down and take them one at a time:
- Define heavy vs. light users
- Because the
feel_response values are in a Likert scale,
we need to convert them to numbers to allow us to get averages.
- Get the average score for each
feel_question for both
light and heavy users.
- Combine the groups
- Plot the comparison
Let’s get started!
Defining heavy vs. light users
In the hours_per_day question, survey respondents were
given four possible answers:
- Less than 2 hours
- 2-4 hours
- 4-6 hours
- More than 6 hours
For the sake of our analysis, let’s say that respondents that
selected “Less than 2 hours” and “2-4 hours” are light
users, and those that selected “4-6 hours” and “More than 6
hours” are heavy users.
Let’s create a new column in our data to classify respondents as
“light” or “heavy” users based on this criteria.
survey_data_tidy <- survey_data_tidy |>
mutate(
usage_group = case_when(
hours_per_day %in% c("Less than 2 hours", "2-4 hours") ~ "Light",
hours_per_day %in% c("4-6 hours", "More than 6 hours") ~ "Heavy",
)
)
Step-by-step explanation:
survey_data_tidy <- survey_data_tidy |> is
telling R that we want to add/do something new to
survey_data_tidy object, and save it back into the
object.
- This data is piped into the
mutate() function, which is
going to create a new column in our data called
usage_group.
- Everything after the
= will be where we define what
goes into this new column.
- The
case_when() function works in the following way:
“if X condition is true, then do Y”.
hours_per_day %in% checks for values that are in the
hours_per_day column, which are specified in the following
brackets.
- The
c in
c("Less than 2 hours", "2-4 hours") tells R we are looking
for multiple values in the hours_per_day column, which in
this case is “Less than 2 hours” and “2-4 hours”.
- If
hours_per_day equals either of these values, they
will be give the value “Light” in the new column.
hours_per_day %in% c("4-6 hours", "More than 6 hours") ~ "Heavy"
does this same process, but if these new conditions are met, they will
be given the value “Heavy” in the new column.
Let’s take a look at survey_data_tidy to see this new
column.
View(survey_data_tidy)
Convert Feel Responses to Numbers
The feel responses are in a Likert/textual format, and calculating
the average of text isn’t something that is possible (the text must be
counted or quantified, then calculated). To allow us to find the
average, we’re going to create another column that applies numerical
values to each Likert response.
Converting Likert responses to numbers.
survey_data_tidy <- survey_data_tidy |>
mutate(
feel_score = case_when(
feel_response == "Strongly disagree" ~ 1,
feel_response == "Disagree" ~ 2,
feel_response == "Neutral" ~ 3,
feel_response == "Agree" ~ 4,
feel_response == "Strongly agree" ~ 5,
)
)
Step-by-step explanation:
survey_data_tidy <- survey_data_tidy |> is
telling R that we want to add/do something new to
survey_data_tidy object, and save it back into the
object.
- The data is piped into the
mutate() function, which is
going to create a new column.
- The new column will be called
feel_score, and will
contain all the information after the =.
- Much like the previous example, we are using
case_when() to tell R that if X, then Y.
- In this case
feel_response == "Strongly disagree" ~ 1,
we are saying, “if the feel_response column has a value
that is”Strongly disagree”, we want to add the value “1” in the new
column.
- Repeat for each value in the Likert scale, and we’re ready to
calculate!
Let’s take another look at survey_data_tidy.
View(survey_data_tidy)
We’re getting close! Let’s now calculate the average for light users.
We’ll do this in two distinct steps.
Step 1: Isolate light users into their own grouping
light_users <- survey_data_tidy |>
filter(usage_group == "Light")
Step-by-step explanation:
- We’re creating a new R object called
light_users, that
will help us easily calculate values in this group.
- After piping
survey_data_tidy, we use the
filter(user_group == "Light") to select only those rows in
the user_group column that have the value “Light”.
We can view this new object:
View(light_users)
Step 2: Calculate the average of light users’ feel responses
light_avgs <- light_users |>
group_by(feel_question) |>
summarise(
avg_feel = mean(feel_score),
.groups = "drop") |>
mutate(usage_group = "Light")
Step-by-step explanation:
- We are creating a new object called
light_avgs that
will hold the averages for all feel responses for light users.
- Pipe the data from the
light_users object into
group_by(feel_question), which tells R to calculate results
separately for each feel question.
- This is piped into the
summarise() function, which sets
up for the actual calculation we want to conduct.
avg_feel will create a new column with the values on
the right side of the =.
mean(feel_score) calculates the average score for each
feel response. This will give a table with one row per
feel_question, and one column containing the average for
each (avg_feel).
.groups = "drop" tells R to get rid of the grouping
structure it uses to calculate the values. In plain language, “we’re
done grouping, give me a regular table now”.
- This is piped into
mutate(user_group = "Light") to add
a new column to the table called user_group, and every row
will get the value “Light”. This step is helpful because when we combine
the light and heavy users into one dataset for plotting, this will keep
all the values sorted by their usage groups.
Let’s take a look at the new table we created!
light_avgs
Your Turn!
Now that you’ve seen how this works for the light users, see if you
can do this for heavy users. This is a secret of using a coding
language, where you don’t need to write every line from scratch, and you
just need to understand code chunks enough to know what parts to
change.
- Isolate heavy users into their own group, and save it as an object
called
heavy_users
heavy_users <- survey_data_tidy |>
filter(usage_group == "Heavy")
- Calculate the average of heavy users’ feel responses, and save it as
an object called
heavy_avgs.
heavy_avgs <- heavy_users |>
group_by(feel_question) |>
summarise(
avg_feel = mean(feel_score),
.groups = "drop") |>
mutate(usage_group = "Heavy")
Combine the Groups
We’re getting close! The next step we need to do is combine the light
and heavy usage groups to make it very easy to plot. This can be done
with a single line of code.
Combining the light and heavy user averages.
feel_avgs <- bind_rows(light_avgs, heavy_avgs)
Step-by-step explanation:
- We’re creating a new R object called
feel_avgs that
will have the averages for all feel responses for both light and heavy
users.
- the
bind_rows() function takes two or more data frames
that have the **same columns*, and combines them by stacking them
vertically.
lights_avgs and heavy_avgs are the two
objects that have the averages, and this will effectively combine
them.
Let’s take a look.
feel_avgs
Plotting the Results
Now that we have our data ready to go, we can now put it into a plot.
Earlier in this session we used the barplot() function,
which is great as a quick way to visualize data in bar charts. However,
a much more powerful visualization package, that is part of the
Tidyverse, is ggplot2.
This will not be a deep dive into ggplot2, but if you are interested
in learning more, check out the session on
Visualization with ggplot.
ggplot offers a number of different visualization types, and as it
works in “layers”, you can keep adding more elements to your
visualizations, making it an extremely powerful and precise tool. As
mentioned, this won’t be a deep dive, but we’ll take a look at what
visualizing our data in ggplot can do for our data.
Visualizing the questions “How does heavy usage of social media
affect mental health compared to light usage?”
ggplot(feel_avgs, aes(x = feel_question, y = avg_feel, fill = usage_group)) +
geom_col(position = "dodge")
Step-by-step explanation:
- Every visualization with ggplot starts with the
ggplot() command to tell R that we’re going to make a
plot.
- The first element to go in the brackets is the data we want to plot,
which in this case is
feel_avgs.
- After a comma
, we use the aes() function
to describe the aesthetics of what the plot will look like. In this
case, we specify that the x-axis will contain feel_question
column in the table, and the y-axis will contain avg_feel,
which is the averages. fill = usage_group indicates that we
want each usage group to be filled with a different colour.
- Now that we’ve specified the aesthetics, we insert a plus sign
+ to add additional elements.
geom_col() specifies the geom, or type of chart we want
to make (there are many!), and position = "dodge" tells R
that we want a separate column for light and heavy users, instead of a
stacked column.
You’ll see that there’s now a plot in the viewer pane in RStudio
(bottom right). Before we get to the data insights from the plot, it’s
worth noting that there’s an issue with the chart. On the y-axis, we see
numbers, which aren’t very good at communicating the Likert scale we’re
visualizing, and the numbers end at 3 (they are chopped off because
that’s where the averages stop). To communicate these findings more
effectively, let’s update the y-axis to be more descriptive and easier
to interpret.
Cleaning up the y-axis of our plot
ggplot(feel_avgs, aes(x = feel_question, y = avg_feel, fill = usage_group)) +
geom_col(position = "dodge") +
scale_y_continuous(
breaks = 1:5,
labels = c(
"1 = Strongly disagree",
"2 = Disagree",
"3 = Neutral",
"4 = Agree",
"5 = Strongly agree"
)
) +
expand_limits(y = 5)
Step-by-step explanation:
Beginning where we left off at the first plot,
- We and a plus sign
+ to tell R we want to add another
layer.
scale_y_continuous( tells R we want to change how the
y-axis looks, and everything in these brackets will add to this.
breaks = 1:5 tells R that we want to put tick marks at
the values 1, 2, 3, 4, 5. 1:5 is shorthand for all the
numbers between 1-5.
- Don’t forget to separate the line with the comma
,!
labels = c("1 = Strongly disagree, ...) replaces the
numbers on the y-axis with whatever textual labels are put in the
quotation marks. Because we specified breaks = 1:5, it will
accept five values. This can be expanded or reduced according to your
plot.
- There are two end brackets
)) that need to be closed.
One for scale_y_continuous( command, and one for
labels = c(.
- Add another plus sign
+ to add another layer.
expand_limits(y = 5) expands the chart to five tick
marks, to make sure we can show the full scale.
Your Turn
The goal of this question is to test yourself in deciphering code
that you might not be familiar with.
- Copy + paste this code in your RStudio editor and run it to see the
results.
- Try to determine what each part of the code is doing.
Hint: Each functional element, or layer, of ggplot is separated by
the plus sign +, and search engines are your friend!
avg_feel_plot <- ggplot(feel_avgs, aes(x = feel_question, y = avg_feel, fill = usage_group)) +
geom_col(position = "dodge") +
scale_y_continuous(
breaks = 1:5,
labels = c(
"1 = Strongly disagree",
"2 = Disagree",
"3 = Neutral",
"4 = Agree",
"5 = Strongly agree"
)
) +
expand_limits(y = 5) +
scale_x_discrete(
labels = c(
feel_connected = "Makes me feel connected",
feel_distracted = "Makes me feel distracted",
feel_improved_mood = "Improves my mood",
feel_increase_stress = "Increases my stress")) +
scale_fill_discrete(
name = NULL,
labels = c("Heavy users", "Light users")) +
labs(
x = "Agree or disagree about social media and your mental health:",
y = "Average feeling response",
title = "Social media and mental health across light and heavy users") +
theme( axis.title.y = element_text(angle = 0, vjust = 0.5))
avg_feel_plot
Wrapping Up
Saving files
We haven’t generated as many files as we did in the previous session,
but you’ll want to save two things:
- The R script for this session:
file > save
- The
survey_data_tidy.csv file that has new
columns:
write_csv(survey_data_tidy, "survey_data_analyzed.csv")
- The final plot we created:
ggsave(filename = "avg_feel_plot.pdf",
plot = avg_feel_plot,
width = 8,
height = 6)
In addition to these files, you can imagine that you might want to
save other snapshots of the data (ie. light_users,
heavy_users, etc.).
Revisiting our file list:
avg_feel_plot.pdf
social-media-survey_ORIGINAL.csv
social-media-survey.csv
survey_analysis_script.R
survey_data_analyzed.csv
survey_data_tidy.csv
survey_data_wide.csv
survey_data.Rproj
survey_cleaning_script.R
survey-data_clean-cols_IDs.csv
survey-data_clean-cols_no-ID.csv
You can see that there’s some inconsistency with how files are named
(hyphens - vs underscores _), and you might
want to think about creating folders to start organizing things. While
this is the end of the session, feel free to give this some thought and
map out how you might want to structure these files in folders, and
potentially rename then to better suit your use.
Finish
And that’s it for the workshop! We covered a lot of ground, but there
is also a lot that we weren’t able to cover. The hope is that these
sessions helped build some confidence in your ability to work with R,
and that you use this as a jumping off point for your learning
journey.
LS0tCnRpdGxlOiAiTWFraW5nIFNlbnNlIG9mIFN1cnZleSBEYXRhIgpwYWdldGl0bGU6ICJNYWtpbmcgU2Vuc2Ugb2YgU3VydmV5IERhdGEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBzaG93ICMgYWxsb3dzIHRvZ2dsaW5nIG9mIHNob3dpbmcgYW5kIGhpZGluZyBjb2RlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICMgYWxsb3dzIHRoZSB1c2VyIHRvIGRvd25sb2FkIHRoZSBzb3VyY2UgLlJtZCBmaWxlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBpbmNsdWRlczoKICAgICAgYWZ0ZXJfYm9keTogZm9vdGVyLmh0bWwgIyBpbmNsdWRlIGEgY3VzdG9tIGZvb3Rlci4KICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5ncyA9IEZBTFNFKQpgYGAKCiMjIE1ha2luZyBTZW5zZSBvZiBTdXJ2ZXkgRGF0YQoKTm93IHRoYXQgd2UgaGF2ZSBjbGVhbmVkIHVwIG91ciBzdXJ2ZXkgZGF0YSwgd2UgY2FuIHN0YXJ0IGFza2luZyBxdWVzdGlvbnMgYWJvdXQgaXQhIEJ5IHRoZSBlbmQgb2YgdGhlIHByZXZpb3VzIHNlc3Npb24sIDxhIGhyZWY9IkJsb2NrOC0yX1NVUl9Db2xsZWN0LWFuZF9jbGVhbi5odG1sIj5Db2xsZWN0aW5nIGFuZCBDbGVhbmluZyBTdXJ2ZXkgRGF0YTwvYT4sIHdlIGdlbmVyYXRlZCB0d28gY2xlYW5lZCBkYXRhc2V0czoKCiogYHN1cnZleV9kYXRhX3RpZHkuY3N2YAoqIGBzdXJ2ZXktZGF0YV93aWRlLmNzdmAKCkxvbmcsIG9yICJ0aWR5IiBkYXRhIGFuZCB3aWRlIGRhdGEgZWFjaCBoYXZlIHRoZWlyIHByb3MgYW5kIGNvbnMsIGFuZCBpbiB0aGlzIHNlc3Npb24gd2UncmUgZ29pbmcgdG8gZXhwbG9yZSB0aGUgYmVuZWZpdHMgYW5kIGRyYXdiYWNrcyBvZiBlYWNoIGFzIHdlIGV4cGxvcmUgb3VyIGRhdGEuIEJ1dCBmaXJzdCwgbGV0J3MgdGFrZSBhIG1vbWVudCB0byBkbyBzb21lIHRoaW5raW5nOgoKVG8gYmVnaW4sIGxldCdzIG9wZW4gdXAgb3VyIGAuUlByb2pgIGZpbGUsIHNvIHRoYXQgb3VyIHdvcmtpbmcgZGlyZWN0b3J5IHdpbGwgYmUgY2FwdHVyZWQuIE5vdywgbGV0J3MgY3JlYXRlIGEgbmV3IFIgc2NyaXB0LCBhbmQgY2FsbCBpdCBgc3VydmV5X2FuYWx5c2lzX3NjcmlwdC5SYC4gCgojIyMgTG9hZCB0aGUgVGlkeXZlcnNlCgpOb3cgdGhhdCB3ZSd2ZSBzdGFydGVkIGEgbmV3IHNjcmlwdCwgd2UgbmVlZCB0byBsb2FkIHRoZSBsaWJyYXJpZXMgdGhhdCB3ZSdsbCBiZSB1c2luZywgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIGp1c3QgdGhlIFRpZHl2ZXJzZS4KCmBgYHtyLCBldmFsPVRSVUUsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIyMgTG9hZCB0aGUgZGF0YQoKV2UgY2FuIG5vdyBsb2FkIHRoZSB0d28gZGF0YXNldHMgdGhhdCB3ZXJlIGdlbmVyYXRlZCBpbiB0aGUgcHJldmlvdXMgc2Vzc2lvbjoKCmBgYHtyLCBldmFsPVRSVUUsIGluY2x1ZGU9RkFMU0V9CnN1cnZleV9kYXRhX3RpZHkgPC0gcmVhZF9jc3YoImRhdGEvc3VydmV5LWNsZWFuaW5nLXdvcmtzaG9wL3N1cnZleV9kYXRhX3RpZHkuY3N2IikKYGBgCgpgYGB7ciwgZXZhbD1UUlVFLCBpbmNsdWRlPUZBTFNFfQpzdXJ2ZXlfZGF0YV93aWRlIDwtIHJlYWRfY3N2KCJkYXRhL3N1cnZleS1jbGVhbmluZy13b3Jrc2hvcC9zdXJ2ZXlfZGF0YV93aWRlLmNzdiIpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3RpZHkgPC0gcmVhZF9jc3YoInN1cnZleV9kYXRhX3RpZHkuY3N2IikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0Kc3VydmV5X2RhdGFfd2lkZSA8LSByZWFkX2Nzdigic3VydmV5X2RhdGFfd2lkZS5jc3YiKQpgYGAKCgo6OjpxdWVzdGlvbgoKMSkgVGFrZSBhIGxvb2sgYXQgYHN1cnZleV9kYXRhX3RpZHlgIGFuZCBgc3VydmV5LWRhdGFfd2lkZWAgdXNpbmcgdGhlIGBWaWV3KClgIGNvbW1hbmQuIApgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScsIGV2YWwgPSBGQUxTRX0KVmlldyhzdXJ2ZXlfZGF0YV90aWR5KQpWaWV3KHN1cnZleV9kYXRhX3dpZGUpCmBgYAoyKSBJbiBncm91cHMsIHNwZW5kIGEgZmV3IG1pbnV0ZXMgdGFsa2luZyBhYm91dCBzb21lIHRoaW5ncyB5b3UnZCBsaWtlIHRvIGtub3cgYWJvdXQgdGhlIGRhdGEgKGllLiBncm91cHMgeW91J2QgbGlrZSB0byBjb3VudCwgcG9zc2libGUgcmVsYXRpb25zaGlwcywgZXRjLikuCgozKSBUYWtpbmcgYSBjbG9zZXIgbG9vayBhdCB0aGUgYHRpZHlgIGFuZCBgd2lkZWAgZGF0YXNldHMsIGNhbiB5b3UgdGhpbmsgb2YgcmVhc29ucyB3aHkgY2VydGFpbiBxdWVzdGlvbnMgbWlnaHQgYmUgYmV0dGVyIHdpdGggZWl0aGVyIG9uZSBvZiB0aGUgZGF0YXNldHM/Cgo6OjoKCiMjIEV4cGxvcmluZyBXaWRlIERhdGEKCldpZGUgZGF0YSBpcyBlYXNpZXIgZm9yIGh1bWFucyB0byByZWFkIGFuZCBpbnRlcnByZXQsIGFuZCBsZW5kcyBpdHNlbGYgd2VsbCB0byBhc2tpbmcgc2ltcGxlIHF1ZXN0aW9ucyBmcm9tIHNpbmdsZSB2YXJpYWJsZXMsIG9yIGNvbHVtbnMsIG9mIGRhdGEuIFRpZHkgZGF0YSBpcyBiZXR0ZXIgZm9yIGFza2luZyBtb3JlIGNvbXBsaWNhdGVkIHF1ZXN0aW9ucywgYXMgd2VsbCBhcyBhc2tpbmcgYWJvdXQgbXVsdGlwbGUgdmFyaWFibGVzIGFuZCBwb3NzaWJsZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlbS4gTGV0J3MgZmlyc3Qgc3RhcnQgd2l0aCBzb21lIHNpbXBsZSBxdWVzdGlvbnMgd2UgY2FuIGFzayBmcm9tIHRoZSAqKndpZGUgdmVyc2lvbioqIG9mIG91ciBkYXRhLgoKQSBzaW1wbGUgZmlyc3Qgc3RlcCB3aGVuIGV4cGxvcmluZyBhIGRhdGFzZXQgaXMgZ2V0dGluZyBjb3VudHMgb2YgaW5kaXZpZHVhbCB2YXJpYWJsZXMuIFRvIGRvIHRoaXMsIHdlIGNhbiB1c2UgdGhlIGBjb3VudCgpYCBmdW5jdGlvbjoKCjo6OndhbGt0aHJvdWdoCgoqKldoYXQgZG9lcyB0aGUgc2FtcGxlIGJyZWFka2Rvd24gb2YgZ2VuZGVyPyoqCmBgYHtyLCBldmFsPUZBTFNFfQpzdXJ2ZXlfZGF0YV93aWRlIHw+CiAgY291bnQoZ2VuZGVyKQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoxKSBXZSBzdGFydCB3aXRoIHRoZSBgc3VydmV5X2RhdGFfd2lkZWAgb2JqZWN0IGFuZCB1c2UgdGhlIHBpcGUsIGB8PmAsIHRvIGluZGljYXRlIHdlIHdhbnQgdG8gZG8gc29tZXRoaW5nIHdpdGggaXQuCjIpIFdlIHRoZW4gdXNlIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gdG8gZ2l2ZSB1cyBhIHRvdGFsIHN1bSBvZiB3aGF0ZXZlciB2YXJpYWJsZS9jb2x1bW4gbmFtZSB3ZSBwdXQgaW5zaWRlIHRoZSBicmFja2V0cy4KOjo6CgoqKldoYXQgaXMgdGhlIHNhbXBsZSBicmVha2Rvd24gb2YgYWdlPyoqCmBgYHtyLCBldmFsPUZBTFNFfQpzdXJ2ZXlfZGF0YV93aWRlIHw+CiAgY291bnQoYWdlKQpgYGAKCkluIGFkZGl0aW9uIHRvIGxvb2tpbmcgYXQgc2luZ2xlIHZhcmlhYmxlcyB3aXRoIHRoZSBgY291bnQoKWAgZnVuY3Rpb24sIHdlIGNhbiBhbHNvIGdlbmVyYXRlIHF1aWNrIHN1bW1hcnkgdGFibGVzIGFjcm9zcyBtdWx0aXBsZSB2YXJpYWJsZXMgYnkgc2VwYXJhdGluZyB0aGVtIHdpdGggY29tbWFzIGAsYDoKCioqV2hhdCBpcyB0aGUgc2FtcGxlIGJyZWFrZG93biBvZiBhZ2UgYW5kIGdlbmRlcj8qKgpgYGB7ciwgZXZhbD1UUlVFfQpzdXJ2ZXlfZGF0YV93aWRlIHw+CiAgY291bnQoYWdlLCBnZW5kZXIpCmBgYAoKWW91J2xsIHNlZSB0aGUgbm90ZSB0aGF0IHRoZXJlIGFyZSAxNCBtb3JlIHJvd3MsIGFuZCB0aGF0IHlvdSBjYW4gdXNlIHRoZSBgcHJpbnQoKWAgZnVuY3Rpb24gdG8gdmlldyBtb3JlLiBZb3UgY2FuIGRvIHRoaXMgeW91IGNhbiBkbyB0aGlzIGJ5IHNwZWNpZml5aW5nIHRoZSBhbW91bnQgb2Ygcm93cyAoaW4gdGhpcyBjYXNlIHRoZXJlIGFyZSAyNCkKYGBge3IsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3dpZGUgfD4KICBjb3VudChhZ2UsIGdlbmRlcikgfD4KICBwcmludChuID0gMjQpCmBgYAoKWW91IGNhbiBrZWVwIGFkZGluZyBhZGRpdGlvbmFsIHZhcmlhYmxlcyB0byB0aGVzZSwgbm90aW5nIHRoYXQgZWFjaCB2YXJpYWJsZSB3aWxsIGFkZCBhZGRpdGlvbmFsIHJvd3MuIElmIHlvdSBkb24ndCB3YW50IHRvIGxvb2sgYXQgdGhlIHZhbHVlcyBpbiB0aGUgUiBjb25zb2xlLCB5b3UgY2FuIHVzZSB0aGUgYFZpZXcoKWAgZnVuY3Rpb24gdG8gb3BlbiBpdCBpbiBhIHNlcGFyYXRlIHRhYi4KYGBge3IsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3dpZGUgfD4KICBjb3VudChhZ2UsIGdlbmRlciwgeWVhcl9vZl9zdHVkeSkgfD4KICBWaWV3KCkKYGBgCgpJZiB0aGlzIGlzIHNvbWV0aGluZyB5b3Ugd2FudCB0byBjb21lIGJhY2sgdG8sIHlvdSBjYW4gc2F2ZSBpdCBpbnRvIGFuIFIgb2JqZWN0LgpgYGB7ciwgZXZhbD1GQUxTRX0KZGVtb2dyYXBoaWNzX2NvdW50IDwtIHN1cnZleV9kYXRhX3dpZGUgfD4KICBjb3VudChhZ2UsIGdlbmRlciwgeWVhcl9vZl9zdHVkeSkKClZpZXcoZGVtb2dyYXBoaWNzX2NvdW50KQpgYGAKCkEgZmluYWwgdGhpbmcgdGhhdCBjYW4gYmUgaGVscGZ1bCB3aXRoIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gaXMgYWRkaW5nIGluIHRoZSBwcm9wb3J0aW9uIHRoYXQgZWFjaCBzdW0gcmVwcmVzZW50cyBpbiB0aGUgdG90YWwgc2FtcGxlLgoKOjo6d2Fsa3Rocm91Z2gKYGBge3IsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3dpZGUgfD4KICBjb3VudChnZW5kZXIpIHw+CiAgbXV0YXRlKHByb3AgPSBuIC8gc3VtKG4pKQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoxKSBTdGFydCBieSBwaXBpbmcgdGhlIGBzdXJ2ZXlfd2lkZWAgb2JqZWN0IHRvIHRoZSBgY291bnQoKWAgZnVuY3Rpb24gbGlrZSB3ZSd2ZSBiZWVuIGRvaW5nLgoyKSBBZGQgYW5vdGhlciBwaXBlIHRvIGluZGljYXRlIHdlIGFyZSBwYXNzaW5nIHRoYXQgY291bnQgdG8gYW5vdGhlciBmdW5jdGlvbi4KMykgYG11dGF0ZShwcm9wYCBjcmVhdGVzIGEgbmV3IGNvbHVtbiBjYWxsZWQgYHByb3BgLCB3aGljaCBzdGFuZHMgZm9yIHByb3BvcnRpb24gKHlvdSBjYW4gbmFtZSB0aGlzIHdoYXRldmVyIHlvdSB3YW50KS4KNCkgRXZlcnl0aGluZyBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgYD1gIGlzIGFzc2lnbmVkIHRvIHRoZSBuZXcgYHByb3BgIGNvbHVtbi4gCjUpIGBuYCBpcyB0aGUgY291bnQgZm9yIGVhY2ggZ2VuZGVyIGNhdGVnb3J5LCBhbmQgYHN1bShuKWAgaXMgdGhlIHRvdGFsIG51bWJlciBvZiBldmVyeSByb3cvcGVyc29uIGluIHRoZSBzYW1wbGUuCjYpIGBuIC8gc3VtKG4pKWAgY2FsY3VsYXRlcyBgImNvdW50IG9mIGVhY2ggY2F0ZWdvcnkiIC8gInRvdGFsIGNvdW50ImAsIHdoaWNoIGdpdmVzIGEgcHJvcG9ydGlvbi4KCjo6OgoKIyMgWW91ciBUdXJuIQoKOjo6cXVlc3Rpb24KU2VlIGlmIHlvdSBjYW4gY3JlYXRlIHRoZSBmb2xsb3dpbmcgZnJvbSB0aGUgYHN1cnZleV9kYXRhX3dpZGVgIG9iamVjdDoKCjEpIEEgY291bnQgb2YgZWFjaCBgeWVhcl9vZl9zdHVkeWAgY2F0ZWdvcnkuCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZXZhbD1GQUxTRX0Kc3VydmV5X2RhdGFfd2lkZSB8PgogIGNvdW50KHllYXJfb2Zfc3R1ZHkpCmBgYAoyKSBBIGNvdW50IG9mIGVhY2ggYHllYXJfb2Zfc3R1ZHlgIGFuZCBgaG91cnNfcGVyX2RheWAuCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZXZhbD1GQUxTRX0Kc3VydmV5X2RhdGFfd2lkZSB8PgogIGNvdW50KHllYXJfb2Zfc3R1ZHksIGhvdXJzX3Blcl9kYXkpCmBgYAozKSBUaGUgY291bnQgb2YgYHllYXJfb2Zfc3R1ZHlgIGFuZCBpdHMgcHJvcG9ydGlvbi4KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBldmFsPUZBTFNFfQpzdXJ2ZXlfZGF0YV93aWRlIHw+CiAgY291bnQoeWVhcl9vZl9zdHVkeSkgfD4KICBtdXRhdGUocHJvcCA9IG4gLyBzdW0obikpCmBgYAo0KSBUaGUgY291bnQgb2YgYHllYXJfb2Zfc3R1ZHlgLCBgaG91cnNfcGVyX2RheWAsIGFuZCB0aGUgcHJvcG9ydGlvbgpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3dpZGUgfD4KICBjb3VudCh5ZWFyX29mX3N0dWR5LCBob3Vyc19wZXJfZGF5KSB8PgogIG11dGF0ZShwcm9wID0gbiAvIHN1bShuKSkKYGBgCjo6OgoKIyMgU2ltcGxlIEJhcnBsb3RzIGFzIEV4cGxvcmF0aW9uCgpJbiBhZGRpdGlvbiB0byBjcmVhdGluZyBzdW1tYXJ5IHRhYmxlcyB0byBleHBsb3JlIGRhdGEsIGNyZWF0aW5nIHNpbXBsZSBwbG90cyBjYW4gYmUgYW5vdGhlciB3YXkgdG8gZXhwbG9yZSB5b3VyIGRhdGEuCgpPbmUgd2F5IHRvIGRvIHRoaXMsIGlzIHVzaW5nIHRoZSBiYXNlIFIgYGJhcnBsb3QoKWAgZnVuY3Rpb24uIFRoaXMgY2FuIGJlIGRvbmUgaW4gYSBmZXcgc3RlcHMuCgoKSW4gdGhpcyBleGFtcGxlLCB3ZSdyZSBnb2luZyB0byBwbG90IHRoZSBjYXRlZ29yaWVzIG9mIHRoZSBgaG91cnNfcGVyX2RheWAgY29sdW1ucy4KCkZpcnN0LCBsZXQncyBsb29rIGF0IHRoZSBgJGAgb3BlcmF0b3IuIFdoZW4gcGxhY2VkIGFmdGVyIGEgZGF0YSBvYmplY3QgaW4gUiwgaXQgYWxsb3dzIHlvdSB0byBpc29sYXRlIHNwZWNpZmllZCBjb2x1bW5zLgoKYGBge3IsIGV2YWw9RkFMU0V9CnN1cnZleV9kYXRhX3dpZGUkaG91cnNfcGVyX2RheQpgYGAKClRoaXMgd2lsbCBzaG93IGFsbCB0aGUgdmFsdWVzIGluIHRoYXQgY29sdW1uIGluIHRoZSBSIGNvbnNvbGUuIEdpdmUgaXQgYSB0cnkgd2l0aCBvdGhlciBjb2x1bW5zIQoKTmV4dCwgd2UgY2FuIGFsc28gdXNlIHRoZSBgdGFibGVgIGZ1bmN0aW9uIGhlcmUsIHRvIGdlbmVyYXRlIGEgcXVpY2sgc3VtbWFyeSB0YWJsZSBvZiB0aGF0IGNvbHVtbi4KCmBgYHtyLCBldmFsPUZBTFNFfQp0YWJsZShzdXJ2ZXlfZGF0YV93aWRlJGhvdXJzX3Blcl9kYXkpCmBgYAoKR2l2ZSB0aGlzIGEgdHJ5IHdpdGggc29tZSBvdGhlciBjb2x1bW5zIQoKTm93IHdlJ3JlIGdvaW5nIHRvIHNhdmUgdGhpcyB0YWJsZSBhcyBhbiBvYmplY3QgY2FsbGVkIGBob3Vyc190YWJsZWAuCgpgYGB7ciwgZXZhbD1UUlVFfQpob3Vyc190YWJsZSA8LSB0YWJsZShzdXJ2ZXlfZGF0YV93aWRlJGhvdXJzX3Blcl9kYXkpCmBgYAoKRmluYWxseSwgd2UgY2FuIGZlZWQgdGhlIGBob3Vyc190YWJsZWAgb2JqZWN0IGludG8gdGhlIGBiYXJwbG90KClgIGZ1bmN0aW9uIHRvIGdldCBvdXIgcGxvdC4KCmBgYHtyLCBldmFsPVRSVUV9CmJhcnBsb3QoaG91cnNfdGFibGUpCmBgYAoKWW91IG1pZ2h0IG5vdGljZSB0aGF0IHRoZSBiYXJzIGFyZW4ndCBpbiBhbnkgcGFydGljdWxhciBvcmRlciwgd2hpY2ggY2FuIGJlIGEgYml0IGFubm95aW5nLiBMZXQncyBjbGVhbiB0aGlzIHVwIGJ5IGNyZWF0aW5nIGFkZGluZyBhbm90aGVyIHN0ZXAuIAoKYGBge3IsIGV2YWw9VFJVRX0KaG91cnNfc29ydGVkIDwtIHNvcnQoaG91cnNfdGFibGUsIGRlY3JlYXNpbmcgPSBUUlVFKQpgYGAKCmBgYHtyLCBldmFsPVRSVUV9CmJhcnBsb3QoaG91cnNfc29ydGVkKQpgYGAKClRoZSBgc29ydGAgZnVuY3Rpb24gaXMgdGVsbGluZyBSIHRoYXQgd2Ugd2FudCB0byByZW9yZGVyIHRoZSB2YWx1ZXMgaW4gYGhvdXJzX3RhYmxlYCwgYW5kIHRoZSBgZGVjcmVhc2luZyA9IFRSVUVgIGFsbG93cyB1cyB0byBzZWUgdGhlIHZhbHVlcyBmcm9tIGJpZ2dlc3QgdG8gc21hbGxlc3QuIFlvdSBjYW4gY2hhbmdlIHRoaXMgdG8gYGRlY3JlYXNpbmcgPSBGQUxTRWAgdG8gc2VlIHNtYWxsZXN0IHRvIGJpZ2dlc3QuCgpXaGVuIGV4cGxvcmluZyBkYXRhLCBpdCdzIG5vdCBhbHdheXMgbmVjZXNzYXJ5IHRvIGFkZCBsYWJlbHMgdG8gb3VyIHBsb3RzLiBIb3dldmVyLCB0aGlzIGNoYXJ0IG1pZ2h0IGJlIHNvbWV0aGluZyB5b3Ugd2FudCB0byBjb21tdW5pY2F0ZSwgc28gbGV0J3MgYWRkIHNvbWUgbGFiZWxzIQoKYGBge3IsIGV2YWw9VFJVRX0KYmFycGxvdChob3Vyc19zb3J0ZWQsCiAgICAgICAgbWFpbiA9ICJIb3VycyBwZXIgZGF5IG9uIHNvY2lhbCBtZWRpYSIsCiAgICAgICAgeGxhYiA9ICJIb3VycyBwZXIgZGF5IiwKICAgICAgICB5bGFiID0gIk51bWJlciBvZiBzdHVkZW50cyIpCmBgYAoKV2l0aCB0aGUgYGJhcnBsb3QoKWAgZnVuY3Rpb246CgoqIGBtYWluYCBpcyB0aGUgdGl0bGUgb2YgdGhlIGNoYXJ0LgoqIGB4bGFiYCBpcyB0aGUgbGFiZWwgb24gdGhlIHggKGhvcml6b250YWwpIGF4aXMuCiogYHlsYWRgIGlzIHRoZSBsYWJlbCBvbiB0aGUgeSAodmVydGljYWwpIGF4aXMuCgojIyBZb3VyIFR1cm4hCgo6OjpxdWVzdGlvbgoKMSkgTWFrZSBhIGJhcnBsb3QgZm9yIHRoZSBgZmVlbF9pbmNyZWFzZV9zdHJlc3NgIHZhcmlhYmxlLCB0aGF0IG9yZGVycyB0aGUgYmFycyBmcm9tIGJpZ2dlc3QgdG8gc21hbGxlc3QsIGFuZCBoYXMgbGFiZWxzIGZvciB0aGUgdGl0bGUsIGFuZCBib3RoIGF4ZXMuCgpIaW50OiBicmVhayB0aGlzIGludG8gMyBzdGVwczoKCiogQ3JlYXRlIGFuIG9iamVjdCB0aGF0IGNyZWF0ZXMgYSB0YWJsZSBvZiB0aGUgYGZlZWxfaW5jcmVhc2Vfc3RyZXNzYCBjb2x1bW4KKiBDcmVhdGUgYW5vdGhlciBvYmplY3QgdGhhdCBzb3J0cyB0aGUgdGFibGUgaW4gZGVjcmVhc2luZyBvcmRlcgoqIENyZWF0ZSBhIGJhcnBsb3QgYW5kIGFkZCAzIGxheWVycyBvZiBsYWJlbHMuCgpgYGB7ciwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScsIGV2YWw9RkFMU0V9CnN0cmVzc19jb3VudCA8LSB0YWJsZShzdXJ2ZXlfZGF0YV93aWRlJGZlZWxfaW5jcmVhc2Vfc3RyZXNzKQoKc3RyZXNzX3NvcnRlZCA8LSBzb3J0KHN0cmVzc19jb3VudCwgZGVjcmVhc2luZyA9IFRSVUUpCgpiYXJwbG90KHN0cmVzc19zb3J0ZWQsCiAgICAgICAgbWFpbiA9ICJTb2NpYWwgbWVkaWEgbWFrZXMgbWUgZmVlbCBhbnhpb3VzIG9yIHN0cmVzc2VkIiwKICAgICAgICB4bGFiID0gIkZlZWxpbmcgYW54aW91cyBvciBzdHJlc3NlZCIsCiAgICAgICAgeWxhYiA9ICJOdW1iZXIgb2Ygc3R1ZGVudHMiKQpgYGAKCjIpIFRyeSB0aGlzIHdpdGggYW5vdGhlciBjb2x1bW4hCgo6OjoKCgojIyBNb3ZpbmcgdG8gVGlkeSBEYXRhCgpBcyB3ZSd2ZSBzZWVuLCB3b3JraW5nIHdpdGggd2lkZSBkYXRhIGNhbiBiZSBoZWxwZnVsIGZvciBnZW5lcmF0aW5nIHF1aWNrIHN1bW1hcmllcyBhbmQgY291bnRzLiBCdXQgd2hhdCBpZiB3ZSB3YW50IHRvIGFzayBzb21ldGhpbmcgdGhhdCdzIGEgYml0IG1vcmUgY29tcGxpY2F0ZWQ/Cgo6OjpxdWVzdGlvbgoKSW4gZ3JvdXBzLCB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YSBhbmQgdGFsayBhYm91dCBob3cgeW91IG1pZ2h0IGdvIGFib3V0IGFuc3dlcmluZyB0aGUgcXVlc3Rpb24sICoqd2hpY2ggcGxhdGZvcm1zIGFyZSBtb3N0IHVzZWQ/KioKCjo6OgoKVGhlcmUgYXJlIGNlcnRhaW5seSB3YXlzIHRvIGRvIHRoaXMgd2l0aCB0aGUgd2lkZSBkYXRhLiBPbmUgd2F5IHdvdWxkIGJlIHRvIHVzZSB0aGUgYGNvdW50KClgIGZ1bmN0aW9uIGZvciBlYWNoIGluZGl2aWR1YWwgY29sdW1uLiBIb3dldmVyLCB0aGlzIGlzIGEgYml0IGNsdW5reSwgYW5kIHRoZW4geW91IHdvdWxkIGhhdmUgdG8gdGhlbiBkZWFsIHdpdGggbWVyZ2luZyB0aGUgcmVzcG9uc2VzIGludG8gYSB0YWJsZSAobm90IGltcG9zc2libGUsIGJ1dCBpdCdzIG1vcmUgd29yaykuIFRoZXJlIGlzIGEgd2F5IHRvIGRvIHRoaXMgaXMgYSBzaW5nbGUgY29kZSBjaHVuaywgYnV0IGl0IGJlY29tZXMgb3Zlcmx5IGxvbmcgYW5kIGNvbXBsaWNhdGVkOgoKYGBge3IsIGV2YWw9RkFMU0V9CnBsYXRmb3JtX2NvdW50c193aWRlIDwtIHN1cnZleV93aWRlIHw+CiAgc3VtbWFyaXNlKAogICAgYWNyb3NzKAogICAgICBjKGBMaW5rZWRJbmAsIEluc3RhZ3JhbSwgUmVkZGl0LCBGYWNlYm9vaywKICAgICAgICBgWCAoVHdpdHRlcilgLCBUaWtUb2ssIFNuYXBjaGF0KSwKICAgICAgfiBzdW0oLngpKSkgfD4KICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gZXZlcnl0aGluZygpLAogICAgbmFtZXNfdG8gPSAicGxhdGZvcm0iLAogICAgdmFsdWVzX3RvID0gIm5fdXNlcnMiKSB8PgogIGFycmFuZ2UoZGVzYyhuX3VzZXJzKSkKCnBsYXRmb3JtX2NvdW50c193aWRlCmBgYAoKV2UgZG9uJ3QgbmVlZCB0byB1bmRlcnN0YW5kIHRoaXMgY29kZSBjaHVuaywgaXQgaXMganVzdCBhbiBleGFtcGxlIG9mIHdoYXQgdGhlIGNvZGUgbG9va3MgbGlrZS4gSG93ZXZlciwgaWYgd2Ugc2hpZnQgdG8gKip0aWR5KiogZGF0YSwgdGhlIGNvZGUgYmVjb21lcyBtdWNoIHNob3J0ZXIgYW5kIHNpbXBsZXIuCgpGaXJzdCwgbGV0J3Mgc3RhcnQgYnkgdGFraW5nIGFub3RoZXIgbG9vayBhdCB0aGUgdGlkeSBkYXRhLgoKYGBge3IsIGV2YWw9RkFMU0V9ClZpZXcoc3VydmV5X2RhdGFfdGlkeSkKYGBgCgpZb3UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIHRoZSBzaW5nbGUgYHBsYXRmb3Jtc2AgY29sdW1uIHRoYXQgd2UgYXJlIGFibGUgdG8gcXVlcnkuCgpOb3csIGxldCdzIGRvIGEgY291bnQgb2YgdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzIGluIHRoaXMgY29sdW1uLgoKYGBge3IsIGV2YWw9VFJVRX0Kc3VydmV5X2RhdGFfdGlkeSB8PgogIGNvdW50KHBsYXRmb3JtcywgbmFtZSA9ICJuX3N0dWRlbnRzIikKYGBgCgpJbiB0aGlzIGNvZGUsIHdlIGFyZSB1c2luZyB0aGUgYGNvdW50KClgIGZ1bmN0aW9uIGxpa2Ugd2UganVzdCBkaWQsIGFuZCB0aGUgYG5hbWUgPSAibl9zdHVkZW50cyJgIGNyZWF0ZXMgYSBuZXcgY29sdW1uIG5hbWUgZm9yIHRoZSBudW1iZXIgZm9yIGVhY2ggY29sdW1uLiBgIm5fc3R1ZGVudHMiYCB3YXMgdXNlZCB0byBzaG93IHRoaXMgaXMgdGhlIG51bWJlciBvZiBzdHVkZW50cywgYnV0IHlvdSBjYW4gcHV0IGFueXRoaW5nIHlvdSB3YW50IGhlcmUsIG9yIGxlYXZlIGl0IGJsYW5rIGlmIHByZWZlcnJlZC4KCllvdSBjYW4gc2VlIHRoYXQgdGhpcyBjb2RlIGlzIHZlcnkgc2ltcGxlLCBidXQgdGhlcmUgaXMgYSBiaWcgcHJvYmxlbSB3aXRoIHRoZSBudW1iZXJzISBCZWNhdXNlIG91ciB0aWR5IGRhdGEgYWRkcyBhZGRpdGlvbmFsIHJvd3MgdG8gZGF0YSwgd2UgYXJlIHNlZWluZyBudW1iZXJzIGluIHRoZSB0aG91c2FuZHMgd2hlbiBvdXIgc2FtcGxlIHNpemUgaXMgb25seSAzMDAuIEhvd2V2ZXIsIHdoZW4gd2UgY2xlYW5lZCB0aGUgZGF0YSwgd2UgY3JlYXRlZCBhIHVuaXF1ZSBJRCBmb3IgZWFjaCBlbnRyeS4gVGhpcyB3YXMgdG8gaGVscCB3aXRoIHJlLWlkZW50aWZ5aW5nIHJlc3BvbnNlcyBpZiBuZWVkZWQsIGJ1dCBpdCBjYW4gYWxzbyBoZWxwIHVzIHdpdGggZWxpbWluYXRpbmcgcmVkdW5kYW50IHJvd3MuCgpgYGB7ciwgZXZhbD1UUlVFfQpzdXJ2ZXlfZGF0YV90aWR5IHw+CiAgZGlzdGluY3QoSUQsIHBsYXRmb3JtcykgfD4KICBjb3VudChwbGF0Zm9ybXMsIG5hbWUgPSAibl9zdHVkZW50cyIpCmBgYAoKVGhlIGBkaXN0aW5jdCgpYCBmdW5jdGlvbiBpcyB0ZWxsaW5nIFIgdGhhdCB3ZSBvbmx5IHdhbnQgdG8ga2VlcCB1bmlxdWUgY29tYmluYXRpb25zIG9mIGVhY2ggc3R1ZGVudCBgSURgIGFuZCBgcGxhdGZvcm1gLCB3aGljaCBlbGltaW5hdGVzIGFueSBvZiB0aGUgcmVkdW5kYW5jeSBvZiB0aGUgdGlkeSBkYXRhLiBBcyB5b3UgY2FuIHNlZSwgdGhlIG51bWJlcnMgYXJlIG5vdyBhY2N1cmF0ZSB0byBvdXIgc2FtcGxlLgoKQXMgd2l0aCBiZWZvcmUsIGl0IGNhbiBiZSBuaWNlIHRvIGFycmFuZ2UgdGhlIG51bWJlcnMgZnJvbSBiaWdnZXN0IHRvIHNtYWxsZXN0LgoKYGBge3IsIGV2YWw9VFJVRX0Kc3VydmV5X2RhdGFfdGlkeSB8PgogIGRpc3RpbmN0KElELCBwbGF0Zm9ybXMpIHw+CiAgY291bnQocGxhdGZvcm1zLCBuYW1lID0gIm5fc3R1ZGVudHMiKSB8PgogIGFycmFuZ2UoZGVzYyhuX3N0dWRlbnRzKSkKYGBgCgpJbiB0aGlzIGNhc2UsIHRoZSBgYXJyYW5nZSgpYCBmdW5jdGlvbiB0ZWxscyBSIHRoYXQgd2Ugd2FudCB0byBjaGFuZ2UgdGhlIG9yZGVyIG9mIHNvbWV0aGluZywgYW5kIGBkZXNjKG5fc3R1ZGVudHMpYCBzcGVjaWZpZXMgdGhhdCB3ZSB3YW50IHRoZSBgbl9zdHVkZW50c2AgY29sdW1uLCB3aGljaCBpcyB0aGUgdmFsdWVzIGZvciBlYWNoIHBsYXRmb3JtLCB0byBiZSBsaXN0ZWQgaW4gZGVzY2VuZGluZyBvcmRlciAoYmlnZ2VzdCB0byBzbWFsbGVzdCkuCgpGaW5hbGx5LCBvbmNlIHdlJ3JlIGhhcHB5IHdpdGggdGhlIG91dHB1dCBvZiB0aGlzIGNvZGUgY2h1bmssIHdlIGNhbiBzYXZlIGl0IGFzIGFuIFIgb2JqZWN0IHRvIHJldmlzaXQuIFdlJ2xsIGNhbGwgdGhlIG9iamVjdCBgcGxhdGZvcm1fY291bnRgLCBhbmQgbm93IHdlIGNhbiBlYXNpbHkgdmlldyBhbmQgd29yayB3aXRoIGl0IGdvaW5nIGZvcndhcmQuCgpgYGB7ciwgZXZhbD1UUlVFfQpwbGF0Zm9ybV9jb3VudCA8LSBzdXJ2ZXlfZGF0YV90aWR5IHw+CiAgZGlzdGluY3QoSUQsIHBsYXRmb3JtcykgfD4KICBjb3VudChwbGF0Zm9ybXMsIG5hbWUgPSAibl9zdHVkZW50cyIpIHw+CiAgYXJyYW5nZShkZXNjKG5fc3R1ZGVudHMpKQpgYGAKCiMjIEdvaW5nIERlZXBlciB3aXRoIFRpZHkgRGF0YQoKTGV0J3Mga2VlcCBkaWdnaW5nIGludG8gdGhlIHRpZHkgZGF0YSwgYW5kIHN0YXJ0IGFza2luZyBxdWVzdGlvbnMgdGhhdCBhcmUgcmVsYXRlZCB0byBvdXIgYmlnZ2VyIHJlc2VhcmNoIHF1ZXN0aW9uLCAqKiJIb3cgZG9lcyBzb2NpYWwgbWVkaWEgdXNhZ2UgaW5mbHVlbmNlIHRoZSBtZW50YWwgaGVhbHRoIG9mIHVuaXZlcnNpdHkgc3R1ZGVudHM/KioKCiMjIyAqKkNvbXBhcmlzb24gT3BlcmF0b3JzKioKCkNvbXBhcmlzb24gb3BlcmF0b3JzIGFsbG93IHVzIHRvIGxvb2sgZm9yIHNwZWNpZmljIGNyaXRlcmlhIGluIG91ciBkYXRhc2V0LiBUaGVzZSByZXR1cm4gYFRSVUVgIG9yIGBGQUxTRWAgYmFzZWQgb24gd2hldGhlciB0aGUgY29uZGl0aW9uIGlzIG1ldC4KCnwgT3BlcmF0b3IgfCBNZWFuaW5nICAgICAgICAgICAgICAgICAgfCBFeGFtcGxlICB8IFJlc3VsdCB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS18CnwgYD09YCAgICAgfCBFcXVhbCB0byAgICAgICAgICAgICAgICAgfCBgNSA9PSA1YCB8IGBUUlVFYCB8CnwgYCE9YCAgICAgfCBOb3QgZXF1YWwgdG8gICAgICAgICAgICAgfCBgNSAhPSAzYCB8IGBUUlVFYCB8CnwgYDxgICAgICAgfCBMZXNzIHRoYW4gICAgICAgICAgICAgICAgfCBgMyA8IDVgICB8IGBUUlVFYCB8CnwgYD5gICAgICAgfCBHcmVhdGVyIHRoYW4gICAgICAgICAgICAgfCBgNSA+IDNgICB8IGBUUlVFYCB8CnwgYDw9YCAgICAgfCBMZXNzIHRoYW4gb3IgZXF1YWwgdG8gICAgfCBgMyA8PSAzYCB8IGBUUlVFYCB8CnwgYD49YCAgICAgfCBHcmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gfCBgNSA+PSAzYCB8IGBUUlVFYCB8CgpPbmNlIHdlIHVuZGVyc3RhbmQgdGhlc2UgYmFzaWMgY29tcGFyaXNvbiBvcGVyYXRvcnMsIHdlIGNhbiBjb21iaW5lIHRoZW0gdXNpbmcgbG9naWNhbCBvcGVyYXRvcnMgdG8gY3JlYXRlIG1vcmUgY29tcGxleCBmaWx0ZXJpbmcgY29uZGl0aW9ucy4KCiMjIyAqKkxvZ2ljYWwgT3BlcmF0b3JzKioKCkxvZ2ljYWwgb3BlcmF0b3JzIGFsbG93IHVzIHRvIGZpbHRlciBkYXRhIGJhc2VkIG9uIG11bHRpcGxlIGNvbmRpdGlvbnMuCgp8IE9wZXJhdG9yIHwgTWVhbmluZyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRXhhbXBsZSAgICAgICAgICAgICB8IFJlc3VsdCAgfAp8LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwKfCBgJmAgICAgICB8IExvZ2ljYWwgQU5EIChCb3RoIGNvbmRpdGlvbnMgbXVzdCBiZSBUUlVFKSAgICAgICB8IGAoNSA+IDMpICYgKDQgPCA2KWAgfCBgVFJVRWAgIHwKfCBgfGAgICAgICB8IExvZ2ljYWwgT1IgKEF0IGxlYXN0IG9uZSBjb25kaXRpb24gbXVzdCBiZSBUUlVFKSB8IGAoNSA+IDMpIHwgKDQgPiA2KWAgfCBgVFJVRWAgIHwKfCBgIWAgICAgICB8IExvZ2ljYWwgTk9UIChSZXZlcnNlcyBUUlVFL0ZBTFNFKSAgICAgICAgICAgICAgICB8IGAhKDUgPiAzKWAgICAgICAgICAgfCBgRkFMU0VgIHwKCgojIyMgQXNraW5nIFF1ZXN0aW9ucyB3aXRoIEZpbHRlcmluZwoKOjo6bm90ZQoKVGhlIGBmaWx0ZXIoKWAgZnVuY3Rpb24gcmV0dXJucyBvbmx5IHRoZSByb3dzIHRoYXQgbWVldCBhIHNwZWNpZmllZCBjb25kaXRpb24uCgo6OjoKCkZyb20gdGhlIGBmZWVsLXF1ZXN0aW9uYCBjb2x1bW4gaW4gb3VyIHRpZHkgZGF0YSwgdGhlc2UgdmFsdWVzIGluZGljYXRpbmcgd2hldGhlciBzb2NpYWwgbWVkaWEgbWFrZXMgc3R1ZGVudHMgZmVlbCBjb25uZWN0ZWQgdG8gb3RoZXJzIChgZmVlbF9jb25uZWN0ZWRgKSwgYW54aW91cyBvciBzdHJlc3NlZCAoYGZlZWxfaW5jcmVhc2Vfc3RyZXNzYCksIGRpc3RyYWN0cyB0aGVtIGZyb20gYWNhZGVtaWMgd29yayAoYGZlZWxfZGlzdHJhY3RlZGApLCBvciBpbXByb3ZlcyB0aGVpciBtb29kIChgZmVlbF9pbXByb3ZlZF9tb29kYCkuIAoKQXMgcGFydCBvZiB0aGUgYmlnZ2VyIHJlc2VhcmNoIHF1ZXN0aW9uLCAiSG93IGRvZXMgc29jaWFsIG1lZGlhIHVzYWdlIGluZmx1ZW5jZSB0aGUgbWVudGFsIGhlYWx0aCBvZiB1bml2ZXJzaXR5IHN0dWRlbnRzPyIsIHdlIGNhbiB1c2UgdGhpcyB2YXJpYWJsZSB0byBzdGFydCBhc2tpbmcgdGhlIHF1ZXN0aW9uLCAqKiJob3cgbWFueSBzdHVkZW50cyBmZWVsIFggYmVjYXVzZSBvZiB0aGVpciBzb2NpYWwgbWVkaWEgdXNlPyoqCgo6Ojp3YWxrdGhyb3VnaAoKTGV0J3MgZmlyc3Qgc3RhcnQgYnkgYXNraW5nLCAiaG93IG1hbnkgc3R1ZGVudHMgZmVlbCAqKmFueGlvdXMgb3Igc3RyZXNzZWQqKiBiZWNhdXNlIG9mIHNvY2lhbCBtZWRpYT8KCmBgYHtyLCBldmFsPVRSVUV9CnN0cmVzc2VkX2NvdW50IDwtIHN1cnZleV9kYXRhX3RpZHkgfD4KICBkaXN0aW5jdChJRCwgZmVlbF9xdWVzdGlvbiwgZmVlbF9yZXNwb25zZSkgfD4KICBmaWx0ZXIoZmVlbF9xdWVzdGlvbiA9PSAiZmVlbF9pbmNyZWFzZV9zdHJlc3MiKSB8PgogIGNvdW50KGZlZWxfcmVzcG9uc2UsIG5hbWUgPSAiZmVlbF9pbmNyZWFzZV9zdHJlc3MiKSB8PgogIGFycmFuZ2UoZGVzYyhmZWVsX2luY3JlYXNlX3N0cmVzcykpCgpzdHJlc3NlZF9jb3VudApgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoqIFdlIHN0YXJ0IGJ5IGNyZWF0aW5nIGEgbmV3IFIgb2JqZWN0IHRoYXQgd2lsbCBzYXZlIHRoaXMgaW5mb3JtYXRpb24sIGNhbGxlZCBgc3RyZXNzZWRfY291bnRgLgoqIFdlIHRoZW4gcGlwZSB0aGUgYHN1cnZleV9kYXRhX3RpZHlgIG9iamVjdCB0byBpbmRpY2F0ZSB3ZSB3aWxsIG1hbmlwdWxhdGUgaXQgaW4gc29tZSB3YXkuCiogTmV4dCwgYGRpc3RpbmN0KElELCBmZWVsX3F1ZXN0aW9uLCBmZWVsX3Jlc3BvbnNlKWAgdGVsbHMgUiB0byBvbmx5IGtlZXAgdW5pcXVlIGNvbWJpbmF0aW9ucyBvZiBgSURgLCBgZmVlbC1xdWVzdGlvbmAsIGFuZCBgZmVlbF9yZXNwb25zZWAuCiogVGhpcyBpcyB0aGVuIHBpcGVkIHRocm91Z2ggdG8gdGhlIGBmaWx0ZXIoKWAgY29tbWFuZCwgYW5kIGBmZWVsX3F1ZXN0aW9uID09IGZlZWxfaW5jcmVhc2Vfc3RyZXNzYCBsb29rcyBmb3Igb25seSBmb3IgdGhlIHN0cmVzc2VkIHZhbHVlcyBpbiB0aGUgYGZlZWxfcXVlc3Rpb25gIGNvbHVtbi4KKiBUaGlzIGlzIHBpcGVkIGludG8gdGhlIGBjb3VudCgpYCBmdW5jdGlvbiwgdG8gaW5kaWNhdGUgd2Ugd2FudCBhIGNvdW50IG9mIGV2ZXJ5IHVuaXF1ZSBgZmVlbF9pbmNyZWFzZV9zdHJlc3NgIGFuc3dlciBpbiB0aGUgYGZlZWxfcmVzcG9uc2VgIGNvbHVtbiwgYW5kIGdpdmVzIG5hbWVzIHRoZSBuZXcgY29sdW1uIG9mIGNvdW50cyBgZmVlbF9pbmNyZWFzZV9zdHJlc3NgLgoqIEZpbmFsbHksIHRoZSBgYXJyYW5nZShkZXNjKGZlZWxfaW5jcmVhc2Vfc3RyZXMpKWAgbGluZSBhcnJhbmdlcyB0aGUgdmFsdWVzIGZyb20gYmlnZ2VzdCB0byBzbWFsbGVzdC4KCjo6OgoKIyMgWW91ciBUdXJuIQoKOjo6cXVlc3Rpb24KCkhpbnQ6IFVzZSB0aGUgY29kZSBjaHVuayBhYm92ZSB0byBndWlkZSB5b3VyIHNvbHV0aW9uLgoKMSkgSG93IG1hbnkgc3R1ZGVudHMgZmVlbCAqbW9yZSBjb25uZWN0ZWQqIGJlY2F1c2Ugb2YgdGhlaXIgc29jaWFsIG1lZGlhIHVzZT8KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZXZhbD1GQUxTRX0KY29ubmVjdGVkX2NvdW50IDwtIHN1cnZleV9kYXRhX3RpZHkgfD4KICBkaXN0aW5jdChJRCwgZmVlbF9xdWVzdGlvbiwgZmVlbF9yZXNwb25zZSkgfD4KICBmaWx0ZXIoZmVlbF9xdWVzdGlvbiA9PSAiZmVlbF9jb25uZWN0ZWQiKSB8PgogIGNvdW50KGZlZWxfcmVzcG9uc2UsIG5hbWUgPSAiZmVlbF9jb25uZWN0ZWQiKSB8PgogIGFycmFuZ2UoZGVzYyhmZWVsX2Nvbm5lY3RlZCkpCgpjb25uZWN0ZWRfY291bnQKYGBgCgoyKSBIb3cgbWFueSBzdHVkZW50cyBmZWVsICpkaXN0cmFjdGVkKiBieSB0aGVpciBzb2NpYWwgbWVkaWEgdXNlPwoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBldmFsPUZBTFNFfQpkaXN0cmFjdGVkX2NvdW50IDwtIHN1cnZleV9kYXRhX3RpZHkgfD4KICBkaXN0aW5jdChJRCwgZmVlbF9xdWVzdGlvbiwgZmVlbF9yZXNwb25zZSkgfD4KICBmaWx0ZXIoZmVlbF9xdWVzdGlvbiA9PSAiZmVlbF9kaXN0cmFjdGVkIikgfD4KICBjb3VudChmZWVsX3Jlc3BvbnNlLCBuYW1lID0gImZlZWxfZGlzdHJhY3RlZCIpIHw+CiAgYXJyYW5nZShkZXNjKGZlZWxfZGlzdHJhY3RlZCkpCgpkaXN0cmFjdGVkX2NvdW50CmBgYAoKOjo6CgojIyBBc2tpbmcgYSBSZXNlYXJjaCBRdWVzdGlvbgoKU28gZmFyIHRoZSBxdWVzdGlvbnMgd2UgaGF2ZSBiZWVuIGFza2luZyBvZiBvdXIgZGF0YSBoYXZlIHJlbGF0ZWQgdG8gY291bnRzLCB3aGljaCBjYW4gYmUgdmVyeSBoZWxwZnVsLCBidXQgbWF5IG5vdCBnZXQgdG8gdGhlIGJpZ2dlciByZXNlYXJjaCBxdWVzdGlvbiB3ZSB3YW50IHRvIGFzay4gQXMgcGFydCBvZiB0aGUgYmlnZ2VyIHJlc2VhcmNoIHF1ZXN0aW9uLCB3ZSBtaWdodCB3YW50IHRvIGFzaywgKioiSG93IGRvZXMgaGVhdnkgdXNhZ2Ugb2Ygc29jaWFsIG1lZGlhIGFmZmVjdCBtZW50YWwgaGVhbHRoIGNvbXBhcmVkIHRvIGxpZ2h0IHVzYWdlPyoqCgpUaGVyZSB3aWxsIGJlIGEgZmV3IHN0ZXBzIHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uLCBidXQgbGV0J3MgYnJlYWsgdGhlbSBkb3duIGFuZCB0YWtlIHRoZW0gb25lIGF0IGEgdGltZToKCjEpIERlZmluZSBoZWF2eSB2cy4gbGlnaHQgdXNlcnMKMikgQmVjYXVzZSB0aGUgYGZlZWxfcmVzcG9uc2VgIHZhbHVlcyBhcmUgaW4gYSBMaWtlcnQgc2NhbGUsIHdlIG5lZWQgdG8gY29udmVydCB0aGVtIHRvIG51bWJlcnMgdG8gYWxsb3cgdXMgdG8gZ2V0IGF2ZXJhZ2VzLgozKSBHZXQgdGhlIGF2ZXJhZ2Ugc2NvcmUgZm9yIGVhY2ggYGZlZWxfcXVlc3Rpb25gIGZvciBib3RoIGxpZ2h0IGFuZCBoZWF2eSB1c2Vycy4KNCkgQ29tYmluZSB0aGUgZ3JvdXBzCjUpIFBsb3QgdGhlIGNvbXBhcmlzb24KCkxldCdzIGdldCBzdGFydGVkIQoKIyMjIERlZmluaW5nIGhlYXZ5IHZzLiBsaWdodCB1c2VycwoKSW4gdGhlIGBob3Vyc19wZXJfZGF5YCBxdWVzdGlvbiwgc3VydmV5IHJlc3BvbmRlbnRzIHdlcmUgZ2l2ZW4gZm91ciBwb3NzaWJsZSBhbnN3ZXJzOgoKKiBMZXNzIHRoYW4gMiBob3VycwoqIDItNCBob3VycwoqIDQtNiBob3VycwoqIE1vcmUgdGhhbiA2IGhvdXJzCgpGb3IgdGhlIHNha2Ugb2Ygb3VyIGFuYWx5c2lzLCBsZXQncyBzYXkgdGhhdCByZXNwb25kZW50cyB0aGF0IHNlbGVjdGVkICJMZXNzIHRoYW4gMiBob3VycyIgYW5kICIyLTQgaG91cnMiIGFyZSAqKmxpZ2h0IHVzZXJzKiosIGFuZCB0aG9zZSB0aGF0IHNlbGVjdGVkICI0LTYgaG91cnMiIGFuZCAiTW9yZSB0aGFuIDYgaG91cnMiIGFyZSAqKmhlYXZ5IHVzZXJzKiouIAoKOjo6d2Fsa3Rocm91Z2gKCkxldCdzIGNyZWF0ZSBhIG5ldyBjb2x1bW4gaW4gb3VyIGRhdGEgdG8gY2xhc3NpZnkgcmVzcG9uZGVudHMgYXMgImxpZ2h0IiBvciAiaGVhdnkiIHVzZXJzIGJhc2VkIG9uIHRoaXMgY3JpdGVyaWEuCgpgYGB7ciwgZXZhbD1UUlVFLCByZXN1bHRzPSJoaWRlIn0KCnN1cnZleV9kYXRhX3RpZHkgPC0gc3VydmV5X2RhdGFfdGlkeSB8PgogIG11dGF0ZSgKICAgIHVzYWdlX2dyb3VwID0gY2FzZV93aGVuKAogICAgICBob3Vyc19wZXJfZGF5ICVpbiUgYygiTGVzcyB0aGFuIDIgaG91cnMiLCAiMi00IGhvdXJzIikgfiAiTGlnaHQiLAogICAgICBob3Vyc19wZXJfZGF5ICVpbiUgYygiNC02IGhvdXJzIiwgIk1vcmUgdGhhbiA2IGhvdXJzIikgfiAiSGVhdnkiLAogICAgKQogICkKCmBgYAoKKipTdGVwLWJ5LXN0ZXAgZXhwbGFuYXRpb246KioKCiogYHN1cnZleV9kYXRhX3RpZHkgPC0gc3VydmV5X2RhdGFfdGlkeSB8PmAgaXMgdGVsbGluZyBSIHRoYXQgd2Ugd2FudCB0byBhZGQvZG8gc29tZXRoaW5nIG5ldyB0byBgc3VydmV5X2RhdGFfdGlkeWAgb2JqZWN0LCBhbmQgc2F2ZSBpdCBiYWNrIGludG8gdGhlIG9iamVjdC4KKiBUaGlzIGRhdGEgaXMgcGlwZWQgaW50byB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiwgd2hpY2ggaXMgZ29pbmcgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbiBpbiBvdXIgZGF0YSBjYWxsZWQgYHVzYWdlX2dyb3VwYC4KKiBFdmVyeXRoaW5nIGFmdGVyIHRoZSBgPWAgd2lsbCBiZSB3aGVyZSB3ZSBkZWZpbmUgd2hhdCBnb2VzIGludG8gdGhpcyBuZXcgY29sdW1uLgoqIFRoZSBgY2FzZV93aGVuKClgIGZ1bmN0aW9uIHdvcmtzIGluIHRoZSBmb2xsb3dpbmcgd2F5OiAiaWYgWCBjb25kaXRpb24gaXMgdHJ1ZSwgdGhlbiBkbyBZIi4gIAoqIGBob3Vyc19wZXJfZGF5ICVpbiVgIGNoZWNrcyBmb3IgdmFsdWVzIHRoYXQgYXJlIGluIHRoZSBgaG91cnNfcGVyX2RheWAgY29sdW1uLCB3aGljaCBhcmUgc3BlY2lmaWVkIGluIHRoZSBmb2xsb3dpbmcgYnJhY2tldHMuCiogVGhlIGBjYCBpbiBgYygiTGVzcyB0aGFuIDIgaG91cnMiLCAiMi00IGhvdXJzIilgIHRlbGxzIFIgd2UgYXJlIGxvb2tpbmcgZm9yIG11bHRpcGxlIHZhbHVlcyBpbiB0aGUgYGhvdXJzX3Blcl9kYXlgIGNvbHVtbiwgd2hpY2ggaW4gdGhpcyBjYXNlIGlzICJMZXNzIHRoYW4gMiBob3VycyIgYW5kICIyLTQgaG91cnMiLgoqIElmIGBob3Vyc19wZXJfZGF5YCBlcXVhbHMgZWl0aGVyIG9mIHRoZXNlIHZhbHVlcywgdGhleSB3aWxsIGJlIGdpdmUgdGhlIHZhbHVlICJMaWdodCIgaW4gdGhlIG5ldyBjb2x1bW4uCiogYGhvdXJzX3Blcl9kYXkgJWluJSBjKCI0LTYgaG91cnMiLCAiTW9yZSB0aGFuIDYgaG91cnMiKSB+ICJIZWF2eSJgIGRvZXMgdGhpcyBzYW1lIHByb2Nlc3MsIGJ1dCBpZiB0aGVzZSBuZXcgY29uZGl0aW9ucyBhcmUgbWV0LCB0aGV5IHdpbGwgYmUgZ2l2ZW4gdGhlIHZhbHVlICJIZWF2eSIgaW4gdGhlIG5ldyBjb2x1bW4uCgo6OjoKCkxldCdzIHRha2UgYSBsb29rIGF0IGBzdXJ2ZXlfZGF0YV90aWR5YCB0byBzZWUgdGhpcyBuZXcgY29sdW1uLgoKYGBge3IsIGV2YWw9RkFMU0V9ClZpZXcoc3VydmV5X2RhdGFfdGlkeSkKYGBgCgoKCiMjIyBDb252ZXJ0IEZlZWwgUmVzcG9uc2VzIHRvIE51bWJlcnMKClRoZSBmZWVsIHJlc3BvbnNlcyBhcmUgaW4gYSBMaWtlcnQvdGV4dHVhbCBmb3JtYXQsIGFuZCBjYWxjdWxhdGluZyB0aGUgYXZlcmFnZSBvZiB0ZXh0IGlzbid0IHNvbWV0aGluZyB0aGF0IGlzIHBvc3NpYmxlICh0aGUgdGV4dCBtdXN0IGJlIGNvdW50ZWQgb3IgcXVhbnRpZmllZCwgdGhlbiBjYWxjdWxhdGVkKS4gVG8gYWxsb3cgdXMgdG8gZmluZCB0aGUgYXZlcmFnZSwgd2UncmUgZ29pbmcgdG8gY3JlYXRlIGFub3RoZXIgY29sdW1uIHRoYXQgYXBwbGllcyBudW1lcmljYWwgdmFsdWVzIHRvIGVhY2ggTGlrZXJ0IHJlc3BvbnNlLgoKOjo6d2Fsa3Rocm91Z2gKCkNvbnZlcnRpbmcgTGlrZXJ0IHJlc3BvbnNlcyB0byBudW1iZXJzLgoKYGBge3IsIGV2YWw9VFJVRSwgcmVzdWx0cz0iaGlkZSJ9CnN1cnZleV9kYXRhX3RpZHkgPC0gc3VydmV5X2RhdGFfdGlkeSB8PgogIG11dGF0ZSgKICAgIGZlZWxfc2NvcmUgPSBjYXNlX3doZW4oCiAgICAgIGZlZWxfcmVzcG9uc2UgPT0gIlN0cm9uZ2x5IGRpc2FncmVlIiB+IDEsCiAgICAgIGZlZWxfcmVzcG9uc2UgPT0gIkRpc2FncmVlIiAgICAgICAgICB+IDIsCiAgICAgIGZlZWxfcmVzcG9uc2UgPT0gIk5ldXRyYWwiICAgICAgICAgICB+IDMsCiAgICAgIGZlZWxfcmVzcG9uc2UgPT0gIkFncmVlIiAgICAgICAgICAgICB+IDQsCiAgICAgIGZlZWxfcmVzcG9uc2UgPT0gIlN0cm9uZ2x5IGFncmVlIiAgICB+IDUsCiAgICApCiAgKQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoqIGBzdXJ2ZXlfZGF0YV90aWR5IDwtIHN1cnZleV9kYXRhX3RpZHkgfD5gIGlzIHRlbGxpbmcgUiB0aGF0IHdlIHdhbnQgdG8gYWRkL2RvIHNvbWV0aGluZyBuZXcgdG8gYHN1cnZleV9kYXRhX3RpZHlgIG9iamVjdCwgYW5kIHNhdmUgaXQgYmFjayBpbnRvIHRoZSBvYmplY3QuCiogVGhlIGRhdGEgaXMgcGlwZWQgaW50byB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiwgd2hpY2ggaXMgZ29pbmcgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbi4KKiBUaGUgbmV3IGNvbHVtbiB3aWxsIGJlIGNhbGxlZCBgZmVlbF9zY29yZWAsIGFuZCB3aWxsIGNvbnRhaW4gYWxsIHRoZSBpbmZvcm1hdGlvbiBhZnRlciB0aGUgYD1gLgoqIE11Y2ggbGlrZSB0aGUgcHJldmlvdXMgZXhhbXBsZSwgd2UgYXJlIHVzaW5nIGBjYXNlX3doZW4oKWAgdG8gdGVsbCBSIHRoYXQgaWYgWCwgdGhlbiBZLgoqIEluIHRoaXMgY2FzZSBgZmVlbF9yZXNwb25zZSA9PSAiU3Ryb25nbHkgZGlzYWdyZWUiIH4gMWAsIHdlIGFyZSBzYXlpbmcsICJpZiB0aGUgYGZlZWxfcmVzcG9uc2VgIGNvbHVtbiBoYXMgYSB2YWx1ZSB0aGF0IGlzICJTdHJvbmdseSBkaXNhZ3JlZSIsIHdlIHdhbnQgdG8gYWRkIHRoZSB2YWx1ZSAiMSIgaW4gdGhlIG5ldyBjb2x1bW4uCiogUmVwZWF0IGZvciBlYWNoIHZhbHVlIGluIHRoZSBMaWtlcnQgc2NhbGUsIGFuZCB3ZSdyZSByZWFkeSB0byBjYWxjdWxhdGUhCgo6OjoKCkxldCdzIHRha2UgYW5vdGhlciBsb29rIGF0IGBzdXJ2ZXlfZGF0YV90aWR5YC4KCmBgYHtyLCBldmFsPUZBTFNFfQoKVmlldyhzdXJ2ZXlfZGF0YV90aWR5KQoKYGBgCgpXZSdyZSBnZXR0aW5nIGNsb3NlISBMZXQncyBub3cgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIGZvciBsaWdodCB1c2Vycy4gV2UnbGwgZG8gdGhpcyBpbiB0d28gZGlzdGluY3Qgc3RlcHMuCgo6Ojp3YWxrdGhyb3VnaAoKU3RlcCAxOiBJc29sYXRlIGxpZ2h0IHVzZXJzIGludG8gdGhlaXIgb3duIGdyb3VwaW5nCgpgYGB7ciwgZXZhbD1UUlVFLCByZXN1bHRzPSJoaWRlIn0KbGlnaHRfdXNlcnMgPC0gc3VydmV5X2RhdGFfdGlkeSB8PgogIGZpbHRlcih1c2FnZV9ncm91cCA9PSAiTGlnaHQiKQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoqIFdlJ3JlIGNyZWF0aW5nIGEgbmV3IFIgb2JqZWN0IGNhbGxlZCBgbGlnaHRfdXNlcnNgLCB0aGF0IHdpbGwgaGVscCB1cyBlYXNpbHkgY2FsY3VsYXRlIHZhbHVlcyBpbiB0aGlzIGdyb3VwLgoqIEFmdGVyIHBpcGluZyAgYHN1cnZleV9kYXRhX3RpZHlgLCB3ZSB1c2UgdGhlIGBmaWx0ZXIodXNlcl9ncm91cCA9PSAiTGlnaHQiKWAgdG8gc2VsZWN0IG9ubHkgdGhvc2Ugcm93cyBpbiB0aGUgYHVzZXJfZ3JvdXBgIGNvbHVtbiB0aGF0IGhhdmUgdGhlIHZhbHVlICJMaWdodCIuCgo6OjoKCldlIGNhbiB2aWV3IHRoaXMgbmV3IG9iamVjdDoKYGBge3IsIGV2YWw9RkFMU0V9ClZpZXcobGlnaHRfdXNlcnMpCmBgYAoKOjo6d2Fsa3Rocm91Z2gKClN0ZXAgMjogQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIGxpZ2h0IHVzZXJzJyBmZWVsIHJlc3BvbnNlcwoKYGBge3IsIGV2YWw9VFJVRSwgcmVzdWx0cz0iaGlkZSJ9CmxpZ2h0X2F2Z3MgPC0gbGlnaHRfdXNlcnMgfD4KICBncm91cF9ieShmZWVsX3F1ZXN0aW9uKSB8PgogIHN1bW1hcmlzZSgKICAgIGF2Z19mZWVsID0gbWVhbihmZWVsX3Njb3JlKSwKICAgIC5ncm91cHMgPSAiZHJvcCIpIHw+CiAgbXV0YXRlKHVzYWdlX2dyb3VwID0gIkxpZ2h0IikKYGBgCgoqKlN0ZXAtYnktc3RlcCBleHBsYW5hdGlvbjoqKgoKKiBXZSBhcmUgY3JlYXRpbmcgYSBuZXcgb2JqZWN0IGNhbGxlZCBgbGlnaHRfYXZnc2AgdGhhdCB3aWxsIGhvbGQgdGhlIGF2ZXJhZ2VzIGZvciBhbGwgZmVlbCByZXNwb25zZXMgZm9yIGxpZ2h0IHVzZXJzLgoqIFBpcGUgdGhlIGRhdGEgZnJvbSB0aGUgYGxpZ2h0X3VzZXJzYCBvYmplY3QgaW50byBgZ3JvdXBfYnkoZmVlbF9xdWVzdGlvbilgLCB3aGljaCB0ZWxscyBSIHRvIGNhbGN1bGF0ZSByZXN1bHRzIHNlcGFyYXRlbHkgZm9yIGVhY2ggZmVlbCBxdWVzdGlvbi4KKiBUaGlzIGlzIHBpcGVkIGludG8gdGhlIGBzdW1tYXJpc2UoKWAgZnVuY3Rpb24sIHdoaWNoIHNldHMgdXAgZm9yIHRoZSBhY3R1YWwgY2FsY3VsYXRpb24gd2Ugd2FudCB0byBjb25kdWN0LgoqIGBhdmdfZmVlbGAgd2lsbCBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggdGhlIHZhbHVlcyBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgYD1gLgoqIGBtZWFuKGZlZWxfc2NvcmUpYCBjYWxjdWxhdGVzIHRoZSBhdmVyYWdlIHNjb3JlIGZvciBlYWNoIGZlZWwgcmVzcG9uc2UuIFRoaXMgd2lsbCBnaXZlIGEgdGFibGUgd2l0aCBvbmUgcm93IHBlciBgZmVlbF9xdWVzdGlvbmAsIGFuZCBvbmUgY29sdW1uIGNvbnRhaW5pbmcgdGhlIGF2ZXJhZ2UgZm9yIGVhY2ggKGBhdmdfZmVlbGApLgoqIGAuZ3JvdXBzID0gImRyb3AiYCB0ZWxscyBSIHRvIGdldCByaWQgb2YgdGhlIGdyb3VwaW5nIHN0cnVjdHVyZSBpdCB1c2VzIHRvIGNhbGN1bGF0ZSB0aGUgdmFsdWVzLiBJbiBwbGFpbiBsYW5ndWFnZSwgIndlJ3JlIGRvbmUgZ3JvdXBpbmcsIGdpdmUgbWUgYSByZWd1bGFyIHRhYmxlIG5vdyIuCiogVGhpcyBpcyBwaXBlZCBpbnRvIGBtdXRhdGUodXNlcl9ncm91cCA9ICJMaWdodCIpYCB0byBhZGQgYSBuZXcgY29sdW1uIHRvIHRoZSB0YWJsZSBjYWxsZWQgYHVzZXJfZ3JvdXBgLCBhbmQgZXZlcnkgcm93IHdpbGwgZ2V0IHRoZSB2YWx1ZSAiTGlnaHQiLiBUaGlzIHN0ZXAgaXMgaGVscGZ1bCBiZWNhdXNlIHdoZW4gd2UgY29tYmluZSB0aGUgbGlnaHQgYW5kIGhlYXZ5IHVzZXJzIGludG8gb25lIGRhdGFzZXQgZm9yIHBsb3R0aW5nLCB0aGlzIHdpbGwga2VlcCBhbGwgdGhlIHZhbHVlcyBzb3J0ZWQgYnkgdGhlaXIgdXNhZ2UgZ3JvdXBzLgoKOjo6CgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgbmV3IHRhYmxlIHdlIGNyZWF0ZWQhCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlnaHRfYXZncwpgYGAKCiMjIFlvdXIgVHVybiEKCjo6OnF1ZXN0aW9uCgpOb3cgdGhhdCB5b3UndmUgc2VlbiBob3cgdGhpcyB3b3JrcyBmb3IgdGhlIGxpZ2h0IHVzZXJzLCBzZWUgaWYgeW91IGNhbiBkbyB0aGlzIGZvciBoZWF2eSB1c2Vycy4gVGhpcyBpcyBhIHNlY3JldCBvZiB1c2luZyBhIGNvZGluZyBsYW5ndWFnZSwgd2hlcmUgeW91IGRvbid0IG5lZWQgdG8gd3JpdGUgZXZlcnkgbGluZSBmcm9tIHNjcmF0Y2gsIGFuZCB5b3UganVzdCBuZWVkIHRvIHVuZGVyc3RhbmQgY29kZSBjaHVua3MgZW5vdWdoIHRvIGtub3cgd2hhdCBwYXJ0cyB0byBjaGFuZ2UuCgoxKSBJc29sYXRlIGhlYXZ5IHVzZXJzIGludG8gdGhlaXIgb3duIGdyb3VwLCBhbmQgc2F2ZSBpdCBhcyBhbiBvYmplY3QgY2FsbGVkIGBoZWF2eV91c2Vyc2AKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBldmFsPVRSVUUsIHJlc3VsdHM9ImhpZGUifQpoZWF2eV91c2VycyA8LSBzdXJ2ZXlfZGF0YV90aWR5IHw+CiAgZmlsdGVyKHVzYWdlX2dyb3VwID09ICJIZWF2eSIpCmBgYAoKMikgQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIGhlYXZ5IHVzZXJzJyBmZWVsIHJlc3BvbnNlcywgYW5kIHNhdmUgaXQgYXMgYW4gb2JqZWN0IGNhbGxlZCBgaGVhdnlfYXZnc2AuCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZXZhbD1UUlVFLCByZXN1bHRzPSJoaWRlIn0KaGVhdnlfYXZncyA8LSBoZWF2eV91c2VycyB8PgogIGdyb3VwX2J5KGZlZWxfcXVlc3Rpb24pIHw+CiAgc3VtbWFyaXNlKAogICAgYXZnX2ZlZWwgPSBtZWFuKGZlZWxfc2NvcmUpLAogICAgLmdyb3VwcyA9ICJkcm9wIikgfD4KICBtdXRhdGUodXNhZ2VfZ3JvdXAgPSAiSGVhdnkiKQpgYGAKCjo6OgoKCiMjIyBDb21iaW5lIHRoZSBHcm91cHMKCldlJ3JlIGdldHRpbmcgY2xvc2UhIFRoZSBuZXh0IHN0ZXAgd2UgbmVlZCB0byBkbyBpcyBjb21iaW5lIHRoZSBsaWdodCBhbmQgaGVhdnkgdXNhZ2UgZ3JvdXBzIHRvIG1ha2UgaXQgdmVyeSBlYXN5IHRvIHBsb3QuIFRoaXMgY2FuIGJlIGRvbmUgd2l0aCBhIHNpbmdsZSBsaW5lIG9mIGNvZGUuCgo6Ojp3YWxrdGhyb3VnaAoKQ29tYmluaW5nIHRoZSBsaWdodCBhbmQgaGVhdnkgdXNlciBhdmVyYWdlcy4KCmBgYHtyLCBldmFsPVRSVUUsIHJlc3VsdHM9ImhpZGUifQpmZWVsX2F2Z3MgPC0gYmluZF9yb3dzKGxpZ2h0X2F2Z3MsIGhlYXZ5X2F2Z3MpCmBgYAoKKipTdGVwLWJ5LXN0ZXAgZXhwbGFuYXRpb246KioKCiogV2UncmUgY3JlYXRpbmcgYSBuZXcgUiBvYmplY3QgY2FsbGVkIGBmZWVsX2F2Z3NgIHRoYXQgd2lsbCBoYXZlIHRoZSBhdmVyYWdlcyBmb3IgYWxsIGZlZWwgcmVzcG9uc2VzIGZvciBib3RoIGxpZ2h0IGFuZCBoZWF2eSB1c2Vycy4KKiB0aGUgYGJpbmRfcm93cygpYCBmdW5jdGlvbiB0YWtlcyB0d28gb3IgbW9yZSBkYXRhIGZyYW1lcyB0aGF0IGhhdmUgdGhlICoqc2FtZSBjb2x1bW5zKiwgYW5kIGNvbWJpbmVzIHRoZW0gYnkgc3RhY2tpbmcgdGhlbSB2ZXJ0aWNhbGx5LgoqIGBsaWdodHNfYXZnc2AgYW5kIGBoZWF2eV9hdmdzYCBhcmUgdGhlIHR3byBvYmplY3RzIHRoYXQgaGF2ZSB0aGUgYXZlcmFnZXMsIGFuZCB0aGlzIHdpbGwgZWZmZWN0aXZlbHkgY29tYmluZSB0aGVtLgoKOjo6CgoKTGV0J3MgdGFrZSBhIGxvb2suCgpgYGB7ciwgZXZhbD1GQUxTRX0KZmVlbF9hdmdzCmBgYAoKIyMjIFBsb3R0aW5nIHRoZSBSZXN1bHRzCgpOb3cgdGhhdCB3ZSBoYXZlIG91ciBkYXRhIHJlYWR5IHRvIGdvLCB3ZSBjYW4gbm93IHB1dCBpdCBpbnRvIGEgcGxvdC4gRWFybGllciBpbiB0aGlzIHNlc3Npb24gd2UgdXNlZCB0aGUgYGJhcnBsb3QoKWAgZnVuY3Rpb24sIHdoaWNoIGlzIGdyZWF0IGFzIGEgcXVpY2sgd2F5IHRvIHZpc3VhbGl6ZSBkYXRhIGluIGJhciBjaGFydHMuIEhvd2V2ZXIsIGEgbXVjaCBtb3JlIHBvd2VyZnVsIHZpc3VhbGl6YXRpb24gcGFja2FnZSwgdGhhdCBpcyBwYXJ0IG9mIHRoZSBUaWR5dmVyc2UsIGlzIGdncGxvdDIuIAoKVGhpcyB3aWxsIG5vdCBiZSBhIGRlZXAgZGl2ZSBpbnRvIGdncGxvdDIsIGJ1dCBpZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gbGVhcm5pbmcgbW9yZSwgY2hlY2sgb3V0IHRoZSBzZXNzaW9uIG9uIDxhIGhyZWY9IkJsb2NrNS0yX2dncGxvdC5odG1sIj5WaXN1YWxpemF0aW9uIHdpdGggZ2dwbG90PC9hPi4KCmdncGxvdCBvZmZlcnMgYSBudW1iZXIgb2YgZGlmZmVyZW50IHZpc3VhbGl6YXRpb24gdHlwZXMsIGFuZCBhcyBpdCB3b3JrcyBpbiAibGF5ZXJzIiwgeW91IGNhbiBrZWVwIGFkZGluZyBtb3JlIGVsZW1lbnRzIHRvIHlvdXIgdmlzdWFsaXphdGlvbnMsIG1ha2luZyBpdCBhbiBleHRyZW1lbHkgcG93ZXJmdWwgYW5kIHByZWNpc2UgdG9vbC4gQXMgbWVudGlvbmVkLCB0aGlzIHdvbid0IGJlIGEgZGVlcCBkaXZlLCBidXQgd2UnbGwgdGFrZSBhIGxvb2sgYXQgd2hhdCB2aXN1YWxpemluZyBvdXIgZGF0YSBpbiBnZ3Bsb3QgY2FuIGRvIGZvciBvdXIgZGF0YS4KCjo6OndhbGt0aHJvdWdoCgpWaXN1YWxpemluZyB0aGUgcXVlc3Rpb25zICJIb3cgZG9lcyBoZWF2eSB1c2FnZSBvZiBzb2NpYWwgbWVkaWEgYWZmZWN0IG1lbnRhbCBoZWFsdGggY29tcGFyZWQgdG8gbGlnaHQgdXNhZ2U/IgoKYGBge3IsIGV2YWw9RkFMU0V9CmdncGxvdChmZWVsX2F2Z3MsIGFlcyh4ID0gZmVlbF9xdWVzdGlvbiwgeSA9IGF2Z19mZWVsLCBmaWxsID0gdXNhZ2VfZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgoqIEV2ZXJ5IHZpc3VhbGl6YXRpb24gd2l0aCBnZ3Bsb3Qgc3RhcnRzIHdpdGggdGhlIGBnZ3Bsb3QoKWAgY29tbWFuZCB0byB0ZWxsIFIgdGhhdCB3ZSdyZSBnb2luZyB0byBtYWtlIGEgcGxvdC4KKiBUaGUgZmlyc3QgZWxlbWVudCB0byBnbyBpbiB0aGUgYnJhY2tldHMgaXMgdGhlIGRhdGEgd2Ugd2FudCB0byBwbG90LCB3aGljaCBpbiB0aGlzIGNhc2UgaXMgYGZlZWxfYXZnc2AuCiogQWZ0ZXIgYSBjb21tYSBgLGAgd2UgdXNlIHRoZSBgYWVzKClgIGZ1bmN0aW9uIHRvIGRlc2NyaWJlIHRoZSBhZXN0aGV0aWNzIG9mIHdoYXQgdGhlIHBsb3Qgd2lsbCBsb29rIGxpa2UuIEluIHRoaXMgY2FzZSwgd2Ugc3BlY2lmeSB0aGF0IHRoZSB4LWF4aXMgd2lsbCBjb250YWluIGBmZWVsX3F1ZXN0aW9uYCBjb2x1bW4gaW4gdGhlIHRhYmxlLCBhbmQgdGhlIHktYXhpcyB3aWxsIGNvbnRhaW4gYGF2Z19mZWVsYCwgd2hpY2ggaXMgdGhlIGF2ZXJhZ2VzLiBgZmlsbCA9IHVzYWdlX2dyb3VwYCBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IGVhY2ggdXNhZ2UgZ3JvdXAgdG8gYmUgZmlsbGVkIHdpdGggYSBkaWZmZXJlbnQgY29sb3VyLgoqIE5vdyB0aGF0IHdlJ3ZlIHNwZWNpZmllZCB0aGUgYWVzdGhldGljcywgd2UgaW5zZXJ0IGEgcGx1cyBzaWduIGArYCB0byBhZGQgYWRkaXRpb25hbCBlbGVtZW50cy4KKiBgZ2VvbV9jb2woKWAgc3BlY2lmaWVzIHRoZSBnZW9tLCBvciB0eXBlIG9mIGNoYXJ0IHdlIHdhbnQgdG8gbWFrZSAodGhlcmUgYXJlIG1hbnkhKSwgYW5kIGBwb3NpdGlvbiA9ICJkb2RnZSJgIHRlbGxzIFIgdGhhdCB3ZSB3YW50IGEgc2VwYXJhdGUgY29sdW1uIGZvciBsaWdodCBhbmQgaGVhdnkgdXNlcnMsIGluc3RlYWQgb2YgYSBzdGFja2VkIGNvbHVtbi4KCjo6OgoKWW91J2xsIHNlZSB0aGF0IHRoZXJlJ3Mgbm93IGEgcGxvdCBpbiB0aGUgdmlld2VyIHBhbmUgaW4gUlN0dWRpbyAoYm90dG9tIHJpZ2h0KS4gQmVmb3JlIHdlIGdldCB0byB0aGUgZGF0YSBpbnNpZ2h0cyBmcm9tIHRoZSBwbG90LCBpdCdzIHdvcnRoIG5vdGluZyB0aGF0IHRoZXJlJ3MgYW4gaXNzdWUgd2l0aCB0aGUgY2hhcnQuIE9uIHRoZSB5LWF4aXMsIHdlIHNlZSBudW1iZXJzLCB3aGljaCBhcmVuJ3QgdmVyeSBnb29kIGF0IGNvbW11bmljYXRpbmcgdGhlIExpa2VydCBzY2FsZSB3ZSdyZSB2aXN1YWxpemluZywgYW5kIHRoZSBudW1iZXJzIGVuZCBhdCAzICh0aGV5IGFyZSBjaG9wcGVkIG9mZiBiZWNhdXNlIHRoYXQncyB3aGVyZSB0aGUgYXZlcmFnZXMgc3RvcCkuIFRvIGNvbW11bmljYXRlIHRoZXNlIGZpbmRpbmdzIG1vcmUgZWZmZWN0aXZlbHksIGxldCdzIHVwZGF0ZSB0aGUgeS1heGlzIHRvIGJlIG1vcmUgZGVzY3JpcHRpdmUgYW5kIGVhc2llciB0byBpbnRlcnByZXQuCgo6Ojp3YWxrdGhyb3VnaAoKQ2xlYW5pbmcgdXAgdGhlIHktYXhpcyBvZiBvdXIgcGxvdAoKYGBge3IsIGV2YWw9RkFMU0V9CmdncGxvdChmZWVsX2F2Z3MsIGFlcyh4ID0gZmVlbF9xdWVzdGlvbiwgeSA9IGF2Z19mZWVsLCBmaWxsID0gdXNhZ2VfZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgYnJlYWtzID0gMTo1LAogICAgbGFiZWxzID0gYygKICAgICAgIjEgPSBTdHJvbmdseSBkaXNhZ3JlZSIsCiAgICAgICIyID0gRGlzYWdyZWUiLAogICAgICAiMyA9IE5ldXRyYWwiLAogICAgICAiNCA9IEFncmVlIiwKICAgICAgIjUgPSBTdHJvbmdseSBhZ3JlZSIKICAgICkKICApICsKICBleHBhbmRfbGltaXRzKHkgPSA1KQpgYGAKCioqU3RlcC1ieS1zdGVwIGV4cGxhbmF0aW9uOioqCgpCZWdpbm5pbmcgd2hlcmUgd2UgbGVmdCBvZmYgYXQgdGhlIGZpcnN0IHBsb3QsCgoqIFdlIGFuZCBhIHBsdXMgc2lnbiBgK2AgdG8gdGVsbCBSIHdlIHdhbnQgdG8gYWRkIGFub3RoZXIgbGF5ZXIuCiogYHNjYWxlX3lfY29udGludW91cyhgIHRlbGxzIFIgd2Ugd2FudCB0byBjaGFuZ2UgaG93IHRoZSB5LWF4aXMgbG9va3MsIGFuZCBldmVyeXRoaW5nIGluIHRoZXNlIGJyYWNrZXRzIHdpbGwgYWRkIHRvIHRoaXMuCiogYGJyZWFrcyA9IDE6NWAgdGVsbHMgUiB0aGF0IHdlIHdhbnQgdG8gcHV0IHRpY2sgbWFya3MgYXQgdGhlIHZhbHVlcyAxLCAyLCAzLCA0LCA1LiBgMTo1YCBpcyBzaG9ydGhhbmQgZm9yIGFsbCB0aGUgbnVtYmVycyBiZXR3ZWVuIDEtNS4gCiogRG9uJ3QgZm9yZ2V0IHRvIHNlcGFyYXRlIHRoZSBsaW5lIHdpdGggdGhlIGNvbW1hIGAsYCEKKiBgbGFiZWxzID0gYygiMSA9IFN0cm9uZ2x5IGRpc2FncmVlLCAuLi4pYCByZXBsYWNlcyB0aGUgbnVtYmVycyBvbiB0aGUgeS1heGlzIHdpdGggd2hhdGV2ZXIgdGV4dHVhbCBsYWJlbHMgYXJlIHB1dCBpbiB0aGUgcXVvdGF0aW9uIG1hcmtzLiBCZWNhdXNlIHdlIHNwZWNpZmllZCBgYnJlYWtzID0gMTo1YCwgaXQgd2lsbCBhY2NlcHQgZml2ZSB2YWx1ZXMuIFRoaXMgY2FuIGJlIGV4cGFuZGVkIG9yIHJlZHVjZWQgYWNjb3JkaW5nIHRvIHlvdXIgcGxvdC4KKiBUaGVyZSBhcmUgdHdvIGVuZCBicmFja2V0cyBgKSlgIHRoYXQgbmVlZCB0byBiZSBjbG9zZWQuIE9uZSBmb3IgYHNjYWxlX3lfY29udGludW91cyhgIGNvbW1hbmQsIGFuZCBvbmUgZm9yIGBsYWJlbHMgPSBjKGAuCiogQWRkIGFub3RoZXIgcGx1cyBzaWduIGArYCB0byBhZGQgYW5vdGhlciBsYXllci4KKiBgZXhwYW5kX2xpbWl0cyh5ID0gNSlgIGV4cGFuZHMgdGhlIGNoYXJ0IHRvIGZpdmUgdGljayBtYXJrcywgdG8gbWFrZSBzdXJlIHdlIGNhbiBzaG93IHRoZSBmdWxsIHNjYWxlLgoKOjo6CgojIyBZb3VyIFR1cm4KCjo6OnF1ZXN0aW9uCgpUaGUgZ29hbCBvZiB0aGlzIHF1ZXN0aW9uIGlzIHRvIHRlc3QgeW91cnNlbGYgaW4gZGVjaXBoZXJpbmcgY29kZSB0aGF0IHlvdSBtaWdodCBub3QgYmUgZmFtaWxpYXIgd2l0aC4gCgoxKSBDb3B5ICsgcGFzdGUgdGhpcyBjb2RlIGluIHlvdXIgUlN0dWRpbyBlZGl0b3IgYW5kIHJ1biBpdCB0byBzZWUgdGhlIHJlc3VsdHMuCjIpIFRyeSB0byBkZXRlcm1pbmUgd2hhdCBlYWNoIHBhcnQgb2YgdGhlIGNvZGUgaXMgZG9pbmcuCgpIaW50OiBFYWNoIGZ1bmN0aW9uYWwgZWxlbWVudCwgb3IgbGF5ZXIsIG9mIGdncGxvdCBpcyBzZXBhcmF0ZWQgYnkgdGhlIHBsdXMgc2lnbiBgK2AsIGFuZCBzZWFyY2ggZW5naW5lcyBhcmUgeW91ciBmcmllbmQhCgpgYGB7ciwgZXZhbD1GQUxTRX0KYXZnX2ZlZWxfcGxvdCA8LSBnZ3Bsb3QoZmVlbF9hdmdzLCBhZXMoeCA9IGZlZWxfcXVlc3Rpb24sIHkgPSBhdmdfZmVlbCwgZmlsbCA9IHVzYWdlX2dyb3VwKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIGJyZWFrcyA9IDE6NSwKICAgIGxhYmVscyA9IGMoCiAgICAgICIxID0gU3Ryb25nbHkgZGlzYWdyZWUiLAogICAgICAiMiA9IERpc2FncmVlIiwKICAgICAgIjMgPSBOZXV0cmFsIiwKICAgICAgIjQgPSBBZ3JlZSIsCiAgICAgICI1ID0gU3Ryb25nbHkgYWdyZWUiCiAgICApCiAgKSArCiAgZXhwYW5kX2xpbWl0cyh5ID0gNSkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgICBsYWJlbHMgPSBjKAogICAgICBmZWVsX2Nvbm5lY3RlZCAgICAgID0gIk1ha2VzIG1lIGZlZWwgY29ubmVjdGVkIiwKICAgICAgZmVlbF9kaXN0cmFjdGVkICAgICA9ICJNYWtlcyBtZSBmZWVsIGRpc3RyYWN0ZWQiLAogICAgICBmZWVsX2ltcHJvdmVkX21vb2QgID0gIkltcHJvdmVzIG15IG1vb2QiLAogICAgICBmZWVsX2luY3JlYXNlX3N0cmVzcyA9ICJJbmNyZWFzZXMgbXkgc3RyZXNzIikpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKAogICAgbmFtZSAgID0gTlVMTCwKICAgIGxhYmVscyA9IGMoIkhlYXZ5IHVzZXJzIiwgIkxpZ2h0IHVzZXJzIikpICsKICBsYWJzKAogICAgeCAgICAgPSAiQWdyZWUgb3IgZGlzYWdyZWUgYWJvdXQgc29jaWFsIG1lZGlhIGFuZCB5b3VyIG1lbnRhbCBoZWFsdGg6IiwKICAgIHkgICAgID0gIkF2ZXJhZ2UgZmVlbGluZyByZXNwb25zZSIsCiAgICB0aXRsZSA9ICJTb2NpYWwgbWVkaWEgYW5kIG1lbnRhbCBoZWFsdGggYWNyb3NzIGxpZ2h0IGFuZCBoZWF2eSB1c2VycyIpICsKICB0aGVtZSggYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLjUpKQoKYXZnX2ZlZWxfcGxvdApgYGAKCgo6OjoKCiMjIFdyYXBwaW5nIFVwCgojIyMgU2F2aW5nIGZpbGVzCgpXZSBoYXZlbid0IGdlbmVyYXRlZCBhcyBtYW55IGZpbGVzIGFzIHdlIGRpZCBpbiB0aGUgcHJldmlvdXMgc2Vzc2lvbiwgYnV0IHlvdSdsbCB3YW50IHRvIHNhdmUgdHdvIHRoaW5nczoKCjEpIFRoZSBSIHNjcmlwdCBmb3IgdGhpcyBzZXNzaW9uOiBgZmlsZSA+IHNhdmVgCjIpIFRoZSBgc3VydmV5X2RhdGFfdGlkeS5jc3ZgIGZpbGUgdGhhdCBoYXMgbmV3IGNvbHVtbnM6IApgYGB7ciwgZXZhbD1GQUxTRX0Kd3JpdGVfY3N2KHN1cnZleV9kYXRhX3RpZHksICJzdXJ2ZXlfZGF0YV9hbmFseXplZC5jc3YiKQpgYGAKMykgVGhlIGZpbmFsIHBsb3Qgd2UgY3JlYXRlZDoKYGBge3IsIGV2YWw9RkFMU0V9Cmdnc2F2ZShmaWxlbmFtZSA9ICJhdmdfZmVlbF9wbG90LnBkZiIsIAogIHBsb3QgPSBhdmdfZmVlbF9wbG90LCAKICB3aWR0aCA9IDgsIAogIGhlaWdodCA9IDYpCmBgYAoKSW4gYWRkaXRpb24gdG8gdGhlc2UgZmlsZXMsIHlvdSBjYW4gaW1hZ2luZSB0aGF0IHlvdSBtaWdodCB3YW50IHRvIHNhdmUgb3RoZXIgc25hcHNob3RzIG9mIHRoZSBkYXRhIChpZS4gYGxpZ2h0X3VzZXJzYCwgYGhlYXZ5X3VzZXJzYCwgZXRjLikuCgojIyMgUmV2aXNpdGluZyBvdXIgZmlsZSBsaXN0OiAKCi0gYGF2Z19mZWVsX3Bsb3QucGRmYAotIGBzb2NpYWwtbWVkaWEtc3VydmV5X09SSUdJTkFMLmNzdmAKLSBgc29jaWFsLW1lZGlhLXN1cnZleS5jc3ZgCi0gYHN1cnZleV9hbmFseXNpc19zY3JpcHQuUmAKLSBgc3VydmV5X2RhdGFfYW5hbHl6ZWQuY3N2YAotIGBzdXJ2ZXlfZGF0YV90aWR5LmNzdmAKLSBgc3VydmV5X2RhdGFfd2lkZS5jc3ZgCi0gYHN1cnZleV9kYXRhLlJwcm9qYAotIGBzdXJ2ZXlfY2xlYW5pbmdfc2NyaXB0LlJgCi0gYHN1cnZleS1kYXRhX2NsZWFuLWNvbHNfSURzLmNzdmAKLSBgc3VydmV5LWRhdGFfY2xlYW4tY29sc19uby1JRC5jc3ZgCgpZb3UgY2FuIHNlZSB0aGF0IHRoZXJlJ3Mgc29tZSBpbmNvbnNpc3RlbmN5IHdpdGggaG93IGZpbGVzIGFyZSBuYW1lZCAoaHlwaGVucyBgLWAgdnMgdW5kZXJzY29yZXMgYF9gKSwgYW5kIHlvdSBtaWdodCB3YW50IHRvIHRoaW5rIGFib3V0IGNyZWF0aW5nIGZvbGRlcnMgdG8gc3RhcnQgb3JnYW5pemluZyB0aGluZ3MuIFdoaWxlIHRoaXMgaXMgdGhlIGVuZCBvZiB0aGUgc2Vzc2lvbiwgZmVlbCBmcmVlIHRvIGdpdmUgdGhpcyBzb21lIHRob3VnaHQgYW5kIG1hcCBvdXQgaG93IHlvdSBtaWdodCB3YW50IHRvIHN0cnVjdHVyZSB0aGVzZSBmaWxlcyBpbiBmb2xkZXJzLCBhbmQgcG90ZW50aWFsbHkgcmVuYW1lIHRoZW4gdG8gYmV0dGVyIHN1aXQgeW91ciB1c2UuCgojIyBGaW5pc2gKCkFuZCB0aGF0J3MgaXQgZm9yIHRoZSB3b3Jrc2hvcCEgV2UgY292ZXJlZCBhIGxvdCBvZiBncm91bmQsIGJ1dCB0aGVyZSBpcyBhbHNvIGEgbG90IHRoYXQgd2Ugd2VyZW4ndCBhYmxlIHRvIGNvdmVyLiBUaGUgaG9wZSBpcyB0aGF0IHRoZXNlIHNlc3Npb25zIGhlbHBlZCBidWlsZCBzb21lIGNvbmZpZGVuY2UgaW4geW91ciBhYmlsaXR5IHRvIHdvcmsgd2l0aCBSLCBhbmQgdGhhdCB5b3UgdXNlIHRoaXMgYXMgYSBqdW1waW5nIG9mZiBwb2ludCBmb3IgeW91ciBsZWFybmluZyBqb3VybmV5LgoKCgoK