Instructions
This second assignment reviews the Describing Data content.
You will use the describing_data.Rmd file I reviewed as part of
the lectures for this week to complete this assignment. You will
copy and paste relevant code from that file and update it to
answer the questions in this assignment. You will respond to questions
in each section after executing relevant code to answer a question. You
will submit this assignment to its Submissions folder on
D2L. You will submit two files:
- this completed R Markdown script, and
- preferably a PDF (if you already installed
TinyTeX properly), otherwise a HTML (if you did
not install TinyTeX properly yet), rendered version of it
to D2L.
To start:
First, create a folder on your computer to save all relevant files
for this course. If you did not do so already, you will want to create a
folder named GSB 519 that contains all of the materials for
this course.
Second, inside of GSB 519, you will create a folder to host
assignments. You can name that folder assignments.
Third, inside of assignments, you will create folders for
each assignment. You can name the folder for this first assignment:
describing_data.
Fourth, create two additional folders in describing_data
named scripts, data, and plots. Store this
script in the scripts folder and the data for this assignment
in the data folder.
Fifth, go to the File menu in RStudio, select
New Project…, choose Existing Directory, go to your
~/GSB 519/assignments/describing_data folder to select it as
the top-level directory for this R Project.
Global Settings
The first code chunk sets the global settings for the remaining code
chunks in the document. Do not change anything in this code
chunk.
Load Packages
In this code chunk, we load two packages we need for this
assignment:
- here,
- tidyverse,
- readxl, and
- skimr.
Make sure you installed these packages when you reviewed the
analytical lecture.
We will use functions from these packages to examine the data. Do
not change anything in this code chunk.
### load libraries for use in current working session
## library "here" for project workflow
library(here)
## tidyverse for data manipulation and plotting
# loads eight different libraries simultaneously
library(tidyverse)
## readxl to import/export Excel data
library(readxl)
## skimr to summarize data
library(skimr)
Task 1: Import Data
We will use the same data as in the analytical lecture:
clients.xlsx. After you load the data, then you will
execute other commands on the data.
Use the read_excel() and here()
functions to load the second sheet from this Excel data file
for this working session. Save the data as the object
clients_s2_raw.
Question 1.1: After you load the data, look at your
Global Environment window. How many observations and variables
are there in the data?
Response 1.1: 919 observations and 14
variables.
Question 1.2: Use the glimpse()
function to view a preview of values for each variable in the data.
Which is the first value of the product_type variable?
How many variables are treated as numeric (i.e., dbl)
when you import the data?
Response 1.2: First value of product type is
computers and 9 variables are treated as numeric variables.
#### Q1.1
### import and save data as object
## use read_excel() to import the csv data file
clients_s2_raw <- read_excel(
## use here() to locate file in our project directory;
here("data", "clients.xlsx"),
## specify sheet
sheet = 2
)
#### Q1.2
### glimpse data
glimpse(clients_s2_raw)
Task 2: Clean Data
For your second task, you will clean the data. Apply the
rename() function to rename:
- credit.term to credit_term,
and
- HavingChildren_flg to
having_children_flg.
In the same piped command, use mutate() and
across() functions to convert to factors:
- month,
- sex,
- education,
- product_type,
- having_children_flg,
- region,
- family_status,
- phone_operator,
- is_client, and
- bad_client_target.
Save the result as a new data object named:
clients_s2_work. Apply glimpse() to
clients_s2_work to preview the working data.
Question 2.1: How many factor variables
(indicated by fct) are there now in the data?
Response 2.1: 10.
Use map() and unique() functions to
examine the levels for all of the factor variables. Then, recode the
factor levels for the various factors appropriately:
- for month, recode the levels from
7-12 to July-December;
- for sex, recode the levels just like in the lecture
script;
- for education, recode the levels just like in the
lecture script and add “Incomplete Secondary Education” =
“Incomplete secondary education” and “PhD Degree” =
“PhD degree”;
- for product_type, recode the levels just like in
the lecture script except remove Garden Equipment and
Children’s Goods and add “Fishing and Hunting
Supplies” = “Fishing and hunting supplies”;
- for region, recode the levels 0-2
to East, Midwest, and
West, respectively (i.e., 0 =
East, and so on);
- for having_children_flg,
is_client, and bad_client_target,
recode the levels 0-1 to No and
Yes, respectively.
Save the changes to clients_s2_work. Use
map() and unique() functions again to
examine the levels for all of the factor variables.
Question 2.2: How many factor levels are there for
product_type? How many factor levels are there for
education?
Response 2.2: 6 for education, and 19 for
product type.
clients_s2_work <-clients_s2_raw %>% rename(credit_term=credit.term,having_children_flg=HavingChildren_flg) %>%
mutate(across(c(month,sex,education,product_type,having_children_flg,region,family_status,phone_operator,is_client,bad_client_target),factor))
glimpse(clients_s2_work)
map(clients_s2_work %>% select(c(month,sex,education,product_type,having_children_flg,region,family_status,phone_operator,is_client,bad_client_target)),unique)
clients_s2_work <-clients_s2_work %>%
mutate(month=fct_recode(month,
"July"="7",
"August"="8",
"September"="9",
"October"="10",
"November"="11",
"December"="12"),
sex=fct_recode(sex,
"Male"="male",
"Female"="female"),
education=fct_recode(education,
"Secondary Special Education"="Secondary special education",
"Higher Education"="Higher education",
"Incomplete Higher Education"="Incomplete higher education",
"Secondary Education"="Secondary education",
"Incomplete Secondary Education"="Incomplete secondary education",
"PhD Degree"="PhD degree"),
product_type=fct_recode(product_type,
"Cell Phones"="Cell phones",
"Household App"="Household app",
"Cosm. & Beaut. Serv."="Cosmetics and beauty services",
"Medical Services"="Medical services",
"Sporting Goods"="Sporting goods",
"Fishing and Hunting Supplies"="Fishing and hunting supplies"
),
region=fct_recode(region,
"East"="0",
"Midwest"="1",
"West"="2"),
having_children_flg=fct_recode(having_children_flg,
"No"="0",
"Yes"="1"),
is_client=fct_recode(is_client,
"No"="0",
"Yes"="1"),
bad_client_target=fct_recode(bad_client_target,
"No"="0",
"Yes"="1"))
map(clients_s2_work %>% select(c(month,sex,education,product_type,having_children_flg,region,family_status,phone_operator,is_client,bad_client_target)),unique)
Task 3: Summary of Variables
Summarize clients_s2_work using the
skim_without_charts() fuctnion. Group by
sex and select the credit_term,
education, is_client, and
income variables to examine.
Question 3.1: What is the 75th percentile
of income for men? How many women are
clients?
Response 3.1: 36000.
clients_s2_work%>%
group_by(sex)%>%
select(credit_term,education,is_client,income)%>%
skim_without_charts()
Task 4: Discrete Variables
For this task, you will plot a discrete variable.
Produce a horizontal bar plot of product_type that
calculates the percentages of individuals in each category. Correctly
label the axes. Do NOT order the categories yet.
Question 4.1: Which two product types are most
popular?
Response 4.1: Cell phones and household
appliances.
Examine the present order of the product_type
categories with the levels() function. Reorder the
categories by their reverse frequency. Examine the changed order of the
product_type categories.
Question 4.2: What were the first and last
categories originally? What are the first and last categories after the
reordering?
Response 4.2: Audio & video, Windows &
doors after reordering it is Construction materials and
computers.
Produce a second horizontal bar plot of product_type
that calculates the percentages of individuals in each category.
Correctly label the axes. This plot should use the now ordered version
of product_type. Add text to the middle of the bars to
indicate their percentage values. Change the size of the text to a value
of 2.
Question 4.3: What percentage bought items were
windows and doors? What percentage of bought items were
furniture?
Response 4.3: 1.4 and 26.3.
clients_s2_work%>%
ggplot(aes(x=product_type,y=..count../sum(..count..)*100))+
geom_bar()
levels(clients_s2_work$product_type)
product_type_order<-clients_s2_work%>%count(product_type)%>%
arrange(desc(n))%>%
mutate(pct=round(n/sum(n),3)*100)
clients_s2_work$product_type<-factor(clients_s2_work$product_type,levels=product_type_order$product_type)
levels(clients_s2_work$product_type)
product_type_order%>%
ggplot(aes(x=reorder(product_type,desc(pct)),y=pct,label=pct))+
geom_bar(stat="identity")+
geom_text(size=2,position=position_stack(vjust=.5))
Task 5: Continuous Variables
For this task, you will plot a continuous variable.
Produce a histogram plot for credit_term. Color the
histogram blue, choose 10 bins, add
text that prints the count value for each bin, and use
8 breaks for the x-axis. Label the axes
appropriately.
Question 5.1: Are there more individuals with a
credit term of roughly 10-12.5 or 35-37.5?
Are there more than 10 individuals with a credit term
in the 21-23 range?
Response 5.1: There are more individuals with a
credit term of 10-12.5 than 35-37.5. There are not more than 10
individuals with a credit term in the 21-23 range.
Produce a density plot for credit_term. Fill the
histogram purple, make it half transparent, and make
the color of the density curve white. Label the axes
appropriately. Provide a title and subtitle for the plot.
Question 5.2: How many modes do you see for
credit terms falling between 0 to 20
months?
Response 5.2: There are 3 modes.
clients_s2_work%>%
ggplot(aes(x=credit_term))+
geom_histogram(bins = 10,fill="blue")+
stat_bin(aes(y=..count..,label=..count..),geom="text",bins = 10,vjust=-.5)+
scale_x_continuous(breaks = c(5,10,15,20,25,30,35,40))+
labs(x="Credit Term")
clients_s2_work%>%
ggplot(aes(x=credit_term,y=..density..))+
geom_histogram(bins = 10,fill="purple",alpha=.5)+
geom_density(color="white",aes(y=..density..))+
stat_bin(aes(y=..density..,label=..count..),geom="text",bins = 10,vjust=-.5)+
scale_x_continuous(breaks = c(5,10,15,20,25,30,35,40))+
labs(x="Credit Term")
Task 6: Multiple Variables
For this task, you will produce plots involving multiple
variables.
Produce a bar plot calculating the percentage of
men and women with various phone operators.
Place phone_operator on the x-axis and
sex as the fill and
group aesthetics. Produce a dodged bar plot.
Add text on top of the bars with the relevant percentages. Label the
axes and legend appropriately. Provide an appropriate title. Save the
plot as phone_gender_plot. Print the plot by
highlighting the saved object.
Question 6.1: Which phone operator is most
often used by men and women?
Response 6.1: AT&T is most used by men and
women use US Cellular more.
Produce a scatterplot of credit_term (x-axis) and
credit_amount (y-axis). Add a loess
line and color the points blue with transparency. Save
the plot as credit_term_amount_plot.
Question 6.2: Using the loess line
as a guide, are larger credit amounts associated with
lower or higher credit terms?
Response 6.2: WRITE YOUR ANSWER BETWEEN THESE
ASTERISKS.
Produce a boxplot of income (y-axis) as a function
of family_status (x-axis). Fill the boxplots by
family_status, color the outliers in
darkred, include the jittered data points, exclude the
legend, and appropriately label the axes. Save the plot as
income_fam_stat_plot.
Question 6.3: Which category of family
status has the largest outliers?
Response 6.3: WRITE YOUR ANSWER BETWEEN THESE
ASTERISKS.
phone_gender_plot<-clients_s2_work%>%count(sex,phone_operator)%>%group_by(phone_operator)%>%
mutate(pct=n/sum(n)*100,pct=round(pct,1))%>%
ggplot(aes(x=phone_operator,y=pct,fill=sex,group=sex))+
geom_bar(stat="identity",position="dodge")+
geom_text(aes(label=paste0(pct,"%")),vjust=-.5)+
coord_cartesian(ylim = c(0,100))+
labs(x="Phone Operator",y="Percentage",title="Distribution of Phone Operator by Sex")
phone_gender_plot
Task 7: Save Plots and Data
For this task, you will save the plots from the sixth task and the
working data. Save the working data, clients_s2_work as
the data file: clients_s2_work.csv in the
data folder of the project directory.
Save the three plots from the sixth task as png
files in the plots folder of the project directory.
Save phone_gender_plot as
phone_gender.png,
credit_term_amount_plot as
credit_term_amount.png, and
income_fam_stat_plot as
income_fam_stat.png. Use a width of 6 inches
and height of 6 inches.
Task 8: Conceptual Questions
For your last task, you will respond to conceptual questions based on
the conceptual lectures for this week.
Question 8.1: What is a percentile of a
variable?
Response 8.1: WRITE YOUR ANSWER BETWEEN THESE
ASTERISKS.
Question 8.2: What is the difference between the
variance and standard deviation of a variable?
Response 8.2: WRITE YOUR ANSWER BETWEEN THESE
ASTERISKS.
Question 8.3: What five statistics are computed in a
boxplot? How is a boxplot useful for evaluating variables?
Response 8.3: WRITE YOUR ANSWER BETWEEN THESE
ASTERISKS.
LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQ6IERlc2NyaWJpbmcgRGF0YSINCmF1dGhvcjogIk1heWEgRXN0ZWxsIg0KZGF0ZTogIjIwMjItMTAtMjIiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQplZGl0b3Jfb3B0aW9uczoNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCi0tLQ0KDQojIyBJbnN0cnVjdGlvbnMNCg0KVGhpcyBzZWNvbmQgYXNzaWdubWVudCByZXZpZXdzIHRoZSAqRGVzY3JpYmluZyBEYXRhKiBjb250ZW50LiANCllvdSB3aWxsIHVzZSB0aGUgKmRlc2NyaWJpbmdfZGF0YS5SbWQqIGZpbGUgSSByZXZpZXdlZCBhcyBwYXJ0IG9mIHRoZSBsZWN0dXJlcyBmb3IgdGhpcyB3ZWVrIHRvIGNvbXBsZXRlIHRoaXMgYXNzaWdubWVudC4gDQpZb3Ugd2lsbCAqY29weSBhbmQgcGFzdGUqIHJlbGV2YW50IGNvZGUgZnJvbSB0aGF0IGZpbGUgYW5kIHVwZGF0ZSBpdCB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9ucyBpbiB0aGlzIGFzc2lnbm1lbnQuIA0KWW91IHdpbGwgcmVzcG9uZCB0byBxdWVzdGlvbnMgaW4gZWFjaCBzZWN0aW9uIGFmdGVyIGV4ZWN1dGluZyByZWxldmFudCBjb2RlIHRvIGFuc3dlciBhIHF1ZXN0aW9uLiANCllvdSB3aWxsIHN1Ym1pdCB0aGlzIGFzc2lnbm1lbnQgdG8gaXRzICpTdWJtaXNzaW9ucyogZm9sZGVyIG9uICpEMkwqLg0KWW91IHdpbGwgc3VibWl0ICp0d28qIGZpbGVzOg0KDQoxLiB0aGlzIGNvbXBsZXRlZCAqUiBNYXJrZG93biogc2NyaXB0LCBhbmQgDQoyLiBwcmVmZXJhYmx5IGEgKlBERiogKGlmIHlvdSBhbHJlYWR5IGluc3RhbGxlZCBgVGlueVRlWGAgcHJvcGVybHkpLCBvdGhlcndpc2UgYSAqSFRNTCogKGlmIHlvdSBkaWQgbm90IGluc3RhbGwgYFRpbnlUZVhgIHByb3Blcmx5IHlldCksIHJlbmRlcmVkIHZlcnNpb24gb2YgaXQgdG8gKkQyTCouDQoNClRvIHN0YXJ0Og0KDQpGaXJzdCwgY3JlYXRlIGEgZm9sZGVyIG9uIHlvdXIgY29tcHV0ZXIgdG8gc2F2ZSBhbGwgcmVsZXZhbnQgZmlsZXMgZm9yIHRoaXMgY291cnNlLiANCklmIHlvdSBkaWQgbm90IGRvIHNvIGFscmVhZHksIHlvdSB3aWxsIHdhbnQgdG8gY3JlYXRlIGEgZm9sZGVyIG5hbWVkICpHU0IgNTE5KiB0aGF0IGNvbnRhaW5zIGFsbCBvZiB0aGUgbWF0ZXJpYWxzIGZvciB0aGlzIGNvdXJzZS4NCg0KU2Vjb25kLCBpbnNpZGUgb2YgKkdTQiA1MTkqLCB5b3Ugd2lsbCBjcmVhdGUgYSBmb2xkZXIgdG8gaG9zdCBhc3NpZ25tZW50cy4NCllvdSBjYW4gbmFtZSB0aGF0IGZvbGRlciAqYXNzaWdubWVudHMqLg0KDQpUaGlyZCwgaW5zaWRlIG9mICphc3NpZ25tZW50cyosIHlvdSB3aWxsIGNyZWF0ZSBmb2xkZXJzIGZvciBlYWNoIGFzc2lnbm1lbnQuDQpZb3UgY2FuIG5hbWUgdGhlIGZvbGRlciBmb3IgdGhpcyBmaXJzdCBhc3NpZ25tZW50OiAqZGVzY3JpYmluZ19kYXRhKi4NCg0KRm91cnRoLCBjcmVhdGUgdHdvIGFkZGl0aW9uYWwgZm9sZGVycyBpbiAqZGVzY3JpYmluZ19kYXRhKiBuYW1lZCAqc2NyaXB0cyosICpkYXRhKiwgYW5kICpwbG90cyouDQpTdG9yZSB0aGlzIHNjcmlwdCBpbiB0aGUgKnNjcmlwdHMqIGZvbGRlciBhbmQgdGhlIGRhdGEgZm9yIHRoaXMgYXNzaWdubWVudCBpbiB0aGUgKmRhdGEqIGZvbGRlci4NCg0KRmlmdGgsIGdvIHRvIHRoZSAqRmlsZSogbWVudSBpbiAqUlN0dWRpbyosIHNlbGVjdCAqTmV3IFByb2plY3QuLi4qLCBjaG9vc2UgKkV4aXN0aW5nIERpcmVjdG9yeSosIGdvIHRvIHlvdXIgKn4vR1NCIDUxOS9hc3NpZ25tZW50cy9kZXNjcmliaW5nX2RhdGEqIGZvbGRlciB0byBzZWxlY3QgaXQgYXMgdGhlIHRvcC1sZXZlbCBkaXJlY3RvcnkgZm9yIHRoaXMgKipSIFByb2plY3QqKi4gIA0KDQojIyBHbG9iYWwgU2V0dGluZ3MNCg0KVGhlIGZpcnN0IGNvZGUgY2h1bmsgc2V0cyB0aGUgZ2xvYmFsIHNldHRpbmdzIGZvciB0aGUgcmVtYWluaW5nIGNvZGUgY2h1bmtzIGluIHRoZSBkb2N1bWVudC4NCkRvICpub3QqIGNoYW5nZSBhbnl0aGluZyBpbiB0aGlzIGNvZGUgY2h1bmsuDQoNCmBgYHtyLCBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KIyMjIHNwZWNpZnkgZWNobyBzZXR0aW5nIGZvciBhbGwgY29kZSBjaHVua3MNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIyBMb2FkIFBhY2thZ2VzDQoNCkluIHRoaXMgY29kZSBjaHVuaywgd2UgbG9hZCB0d28gcGFja2FnZXMgd2UgbmVlZCBmb3IgdGhpcyBhc3NpZ25tZW50Og0KDQoxLiAqKmhlcmUqKiwNCjIuICoqdGlkeXZlcnNlKiosDQozLiAqKnJlYWR4bCoqLCBhbmQNCjQuICoqc2tpbXIqKi4NCg0KTWFrZSBzdXJlIHlvdSBpbnN0YWxsZWQgdGhlc2UgcGFja2FnZXMgd2hlbiB5b3UgcmV2aWV3ZWQgdGhlIGFuYWx5dGljYWwgbGVjdHVyZS4NCg0KV2Ugd2lsbCB1c2UgZnVuY3Rpb25zIGZyb20gdGhlc2UgcGFja2FnZXMgdG8gZXhhbWluZSB0aGUgZGF0YS4gDQpEbyAqbm90KiBjaGFuZ2UgYW55dGhpbmcgaW4gdGhpcyBjb2RlIGNodW5rLg0KDQpgYGB7ciwgbGlicmFyaWVzLCBtZXNzYWdlID0gRkFMU0V9DQojIyMgbG9hZCBsaWJyYXJpZXMgZm9yIHVzZSBpbiBjdXJyZW50IHdvcmtpbmcgc2Vzc2lvbg0KIyMgbGlicmFyeSAiaGVyZSIgZm9yIHByb2plY3Qgd29ya2Zsb3cNCmxpYnJhcnkoaGVyZSkNCg0KIyMgdGlkeXZlcnNlIGZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgcGxvdHRpbmcNCiMgbG9hZHMgZWlnaHQgZGlmZmVyZW50IGxpYnJhcmllcyBzaW11bHRhbmVvdXNseQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMjIHJlYWR4bCB0byBpbXBvcnQvZXhwb3J0IEV4Y2VsIGRhdGENCmxpYnJhcnkocmVhZHhsKQ0KDQojIyBza2ltciB0byBzdW1tYXJpemUgZGF0YQ0KbGlicmFyeShza2ltcikNCmBgYA0KDQojIyBUYXNrIDE6IEltcG9ydCBEYXRhDQoNCldlIHdpbGwgdXNlIHRoZSBzYW1lIGRhdGEgYXMgaW4gdGhlIGFuYWx5dGljYWwgbGVjdHVyZTogKipjbGllbnRzLnhsc3gqKi4NCkFmdGVyIHlvdSBsb2FkIHRoZSBkYXRhLCB0aGVuIHlvdSB3aWxsIGV4ZWN1dGUgb3RoZXIgY29tbWFuZHMgb24gdGhlIGRhdGEuDQoNClVzZSB0aGUgKipyZWFkX2V4Y2VsKCkqKiBhbmQgKipoZXJlKCkqKiBmdW5jdGlvbnMgdG8gbG9hZCB0aGUgKnNlY29uZCBzaGVldCogZnJvbSB0aGlzIEV4Y2VsIGRhdGEgZmlsZSBmb3IgdGhpcyB3b3JraW5nIHNlc3Npb24uIA0KU2F2ZSB0aGUgZGF0YSBhcyB0aGUgb2JqZWN0ICoqY2xpZW50c19zMl9yYXcqKi4gDQoNCioqUXVlc3Rpb24gMS4xKio6IEFmdGVyIHlvdSBsb2FkIHRoZSBkYXRhLCBsb29rIGF0IHlvdXIgKkdsb2JhbCBFbnZpcm9ubWVudCogd2luZG93LiANCkhvdyBtYW55IG9ic2VydmF0aW9ucyBhbmQgdmFyaWFibGVzIGFyZSB0aGVyZSBpbiB0aGUgZGF0YT8NCg0KKipSZXNwb25zZSAxLjEqKjogKjkxOSBvYnNlcnZhdGlvbnMgYW5kIDE0IHZhcmlhYmxlcyouDQoNCioqUXVlc3Rpb24gMS4yKio6IFVzZSB0aGUgKipnbGltcHNlKCkqKiBmdW5jdGlvbiB0byB2aWV3IGEgcHJldmlldyBvZiB2YWx1ZXMgZm9yIGVhY2ggdmFyaWFibGUgaW4gdGhlIGRhdGEuIA0KV2hpY2ggaXMgdGhlIGZpcnN0IHZhbHVlIG9mIHRoZSAqKnByb2R1Y3RfdHlwZSoqIHZhcmlhYmxlPw0KSG93IG1hbnkgdmFyaWFibGVzIGFyZSB0cmVhdGVkIGFzIG51bWVyaWMgKGkuZS4sICoqZGJsKiopIHdoZW4geW91IGltcG9ydCB0aGUgZGF0YT8NCg0KKipSZXNwb25zZSAxLjIqKjogKkZpcnN0IHZhbHVlIG9mIHByb2R1Y3QgdHlwZSBpcyBjb21wdXRlcnMgYW5kIDkgdmFyaWFibGVzIGFyZSB0cmVhdGVkIGFzIG51bWVyaWMgdmFyaWFibGVzKi4NCg0KYGBge3IsIHRhc2sxfQ0KIyMjIyBRMS4xDQojIyMgaW1wb3J0IGFuZCBzYXZlIGRhdGEgYXMgb2JqZWN0DQojIyB1c2UgcmVhZF9leGNlbCgpIHRvIGltcG9ydCB0aGUgY3N2IGRhdGEgZmlsZQ0KY2xpZW50c19zMl9yYXcgPC0gcmVhZF9leGNlbCgNCiAgIyMgdXNlIGhlcmUoKSB0byBsb2NhdGUgZmlsZSBpbiBvdXIgcHJvamVjdCBkaXJlY3Rvcnk7DQogIGhlcmUoImRhdGEiLCAiY2xpZW50cy54bHN4IiksDQogICMjIHNwZWNpZnkgc2hlZXQNCiAgc2hlZXQgPSAyDQopDQoNCiMjIyMgUTEuMg0KIyMjIGdsaW1wc2UgZGF0YQ0KZ2xpbXBzZShjbGllbnRzX3MyX3JhdykNCmBgYA0KDQojIyBUYXNrIDI6IENsZWFuIERhdGENCg0KRm9yIHlvdXIgc2Vjb25kIHRhc2ssIHlvdSB3aWxsIGNsZWFuIHRoZSBkYXRhLg0KQXBwbHkgdGhlICoqcmVuYW1lKCkqKiBmdW5jdGlvbiB0byByZW5hbWU6IA0KDQoxLiAqKmNyZWRpdC50ZXJtKiogdG8gKipjcmVkaXRfdGVybSoqLCBhbmQNCjIuICoqSGF2aW5nQ2hpbGRyZW5fZmxnKiogdG8gKipoYXZpbmdfY2hpbGRyZW5fZmxnKiouDQoNCkluIHRoZSBzYW1lIHBpcGVkIGNvbW1hbmQsIHVzZSAqKm11dGF0ZSgpKiogYW5kICoqYWNyb3NzKCkqKiBmdW5jdGlvbnMgdG8gY29udmVydCB0byBmYWN0b3JzOg0KDQoxLiAqKm1vbnRoKiosDQoyLiAqKnNleCoqLA0KMy4gKiplZHVjYXRpb24qKiwNCjQuICoqcHJvZHVjdF90eXBlKiosDQo1LiAqKmhhdmluZ19jaGlsZHJlbl9mbGcqKiwNCjYuICoqcmVnaW9uKiosDQo3LiAqKmZhbWlseV9zdGF0dXMqKiwNCjguICoqcGhvbmVfb3BlcmF0b3IqKiwNCjkuICoqaXNfY2xpZW50KiosIGFuZA0KMTAuICoqYmFkX2NsaWVudF90YXJnZXQqKi4NCg0KU2F2ZSB0aGUgcmVzdWx0IGFzIGEgbmV3IGRhdGEgb2JqZWN0IG5hbWVkOiAqKmNsaWVudHNfczJfd29yayoqLg0KQXBwbHkgKipnbGltcHNlKCkqKiB0byAqKmNsaWVudHNfczJfd29yayoqIHRvIHByZXZpZXcgdGhlIHdvcmtpbmcgZGF0YS4NCg0KKipRdWVzdGlvbiAyLjEqKjogSG93IG1hbnkgKmZhY3RvciogdmFyaWFibGVzIChpbmRpY2F0ZWQgYnkgKmZjdCopIGFyZSB0aGVyZSBub3cgaW4gdGhlIGRhdGE/DQoNCioqUmVzcG9uc2UgMi4xKio6ICoxMCouDQoNClVzZSAqKm1hcCgpKiogYW5kICoqdW5pcXVlKCkqKiBmdW5jdGlvbnMgdG8gZXhhbWluZSB0aGUgbGV2ZWxzIGZvciBhbGwgb2YgdGhlIGZhY3RvciB2YXJpYWJsZXMuDQpUaGVuLCByZWNvZGUgdGhlIGZhY3RvciBsZXZlbHMgZm9yIHRoZSB2YXJpb3VzIGZhY3RvcnMgYXBwcm9wcmlhdGVseToNCg0KMS4gZm9yICoqbW9udGgqKiwgcmVjb2RlIHRoZSBsZXZlbHMgZnJvbSAqKjctMTIqKiB0byAqKkp1bHktRGVjZW1iZXIqKjsNCjIuIGZvciAqKnNleCoqLCByZWNvZGUgdGhlIGxldmVscyBqdXN0IGxpa2UgaW4gdGhlIGxlY3R1cmUgc2NyaXB0Ow0KMy4gZm9yICoqZWR1Y2F0aW9uKiosIHJlY29kZSB0aGUgbGV2ZWxzIGp1c3QgbGlrZSBpbiB0aGUgbGVjdHVyZSBzY3JpcHQgYW5kIGFkZCAqKiJJbmNvbXBsZXRlIFNlY29uZGFyeSBFZHVjYXRpb24iID0gIkluY29tcGxldGUgc2Vjb25kYXJ5IGVkdWNhdGlvbiIqKiBhbmQgKioiUGhEIERlZ3JlZSIgPSAiUGhEIGRlZ3JlZSIqKjsNCjQuIGZvciAqKnByb2R1Y3RfdHlwZSoqLCByZWNvZGUgdGhlIGxldmVscyBqdXN0IGxpa2UgaW4gdGhlIGxlY3R1cmUgc2NyaXB0IGV4Y2VwdCByZW1vdmUgKipHYXJkZW4gRXF1aXBtZW50KiogYW5kICoqQ2hpbGRyZW4ncyBHb29kcyoqIGFuZCBhZGQgKioiRmlzaGluZyBhbmQgSHVudGluZyBTdXBwbGllcyIgPSAiRmlzaGluZyBhbmQgaHVudGluZyBzdXBwbGllcyIqKjsgDQo1LiBmb3IgKipyZWdpb24qKiwgcmVjb2RlIHRoZSBsZXZlbHMgKiowLTIqKiB0byAqKkVhc3QqKiwgKipNaWR3ZXN0KiosIGFuZCAqKldlc3QqKiwgcmVzcGVjdGl2ZWx5IChpLmUuLCAqKjAqKiA9ICoqRWFzdCoqLCBhbmQgc28gb24pOw0KNi4gZm9yICoqaGF2aW5nX2NoaWxkcmVuX2ZsZyoqLCAqKmlzX2NsaWVudCoqLCBhbmQgKipiYWRfY2xpZW50X3RhcmdldCoqLCByZWNvZGUgdGhlIGxldmVscyAqKjAtMSoqIHRvICoqTm8qKiBhbmQgKipZZXMqKiwgcmVzcGVjdGl2ZWx5Lg0KDQpTYXZlIHRoZSBjaGFuZ2VzIHRvICoqY2xpZW50c19zMl93b3JrKiouDQpVc2UgKiptYXAoKSoqIGFuZCAqKnVuaXF1ZSgpKiogZnVuY3Rpb25zIGFnYWluIHRvIGV4YW1pbmUgdGhlIGxldmVscyBmb3IgYWxsIG9mIHRoZSBmYWN0b3IgdmFyaWFibGVzLg0KDQoqKlF1ZXN0aW9uIDIuMioqOiBIb3cgbWFueSBmYWN0b3IgbGV2ZWxzIGFyZSB0aGVyZSBmb3IgKipwcm9kdWN0X3R5cGUqKj8NCkhvdyBtYW55IGZhY3RvciBsZXZlbHMgYXJlIHRoZXJlIGZvciAqKmVkdWNhdGlvbioqPw0KDQoqKlJlc3BvbnNlIDIuMioqOiAqNiBmb3IgZWR1Y2F0aW9uLCBhbmQgMTkgZm9yIHByb2R1Y3QgdHlwZSouDQoNCmBgYHtyLCB0YXNrMn0NCmNsaWVudHNfczJfd29yayA8LWNsaWVudHNfczJfcmF3ICU+JSByZW5hbWUoY3JlZGl0X3Rlcm09Y3JlZGl0LnRlcm0saGF2aW5nX2NoaWxkcmVuX2ZsZz1IYXZpbmdDaGlsZHJlbl9mbGcpICU+JSANCiBtdXRhdGUoYWNyb3NzKGMobW9udGgsc2V4LGVkdWNhdGlvbixwcm9kdWN0X3R5cGUsaGF2aW5nX2NoaWxkcmVuX2ZsZyxyZWdpb24sZmFtaWx5X3N0YXR1cyxwaG9uZV9vcGVyYXRvcixpc19jbGllbnQsYmFkX2NsaWVudF90YXJnZXQpLGZhY3RvcikpDQoNCmdsaW1wc2UoY2xpZW50c19zMl93b3JrKQ0KDQptYXAoY2xpZW50c19zMl93b3JrICU+JSBzZWxlY3QoYyhtb250aCxzZXgsZWR1Y2F0aW9uLHByb2R1Y3RfdHlwZSxoYXZpbmdfY2hpbGRyZW5fZmxnLHJlZ2lvbixmYW1pbHlfc3RhdHVzLHBob25lX29wZXJhdG9yLGlzX2NsaWVudCxiYWRfY2xpZW50X3RhcmdldCkpLHVuaXF1ZSkNCg0KY2xpZW50c19zMl93b3JrIDwtY2xpZW50c19zMl93b3JrICU+JSANCiAgbXV0YXRlKG1vbnRoPWZjdF9yZWNvZGUobW9udGgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJKdWx5Ij0iNyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJBdWd1c3QiPSI4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlcHRlbWJlciI9IjkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiT2N0b2JlciI9IjEwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdmVtYmVyIj0iMTEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiRGVjZW1iZXIiPSIxMiIpLA0KICAgICAgICAgc2V4PWZjdF9yZWNvZGUoc2V4LA0KICAgICAgICAgICAgICAgICAgICAgICJNYWxlIj0ibWFsZSIsDQogICAgICAgICAgICAgICAgICAgICAgIkZlbWFsZSI9ImZlbWFsZSIpLA0KICAgICAgICAgZWR1Y2F0aW9uPWZjdF9yZWNvZGUoZWR1Y2F0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNlY29uZGFyeSBTcGVjaWFsIEVkdWNhdGlvbiI9IlNlY29uZGFyeSBzcGVjaWFsIGVkdWNhdGlvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGlnaGVyIEVkdWNhdGlvbiI9IkhpZ2hlciBlZHVjYXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkluY29tcGxldGUgSGlnaGVyIEVkdWNhdGlvbiI9IkluY29tcGxldGUgaGlnaGVyIGVkdWNhdGlvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2Vjb25kYXJ5IEVkdWNhdGlvbiI9IlNlY29uZGFyeSBlZHVjYXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkluY29tcGxldGUgU2Vjb25kYXJ5IEVkdWNhdGlvbiI9IkluY29tcGxldGUgc2Vjb25kYXJ5IGVkdWNhdGlvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGhEIERlZ3JlZSI9IlBoRCBkZWdyZWUiKSwNCiAgICAgICAgIHByb2R1Y3RfdHlwZT1mY3RfcmVjb2RlKHByb2R1Y3RfdHlwZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDZWxsIFBob25lcyI9IkNlbGwgcGhvbmVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIb3VzZWhvbGQgQXBwIj0iSG91c2Vob2xkIGFwcCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29zbS4gJiBCZWF1dC4gU2Vydi4iPSJDb3NtZXRpY3MgYW5kIGJlYXV0eSBzZXJ2aWNlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVkaWNhbCBTZXJ2aWNlcyI9Ik1lZGljYWwgc2VydmljZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNwb3J0aW5nIEdvb2RzIj0iU3BvcnRpbmcgZ29vZHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZpc2hpbmcgYW5kIEh1bnRpbmcgU3VwcGxpZXMiPSJGaXNoaW5nIGFuZCBodW50aW5nIHN1cHBsaWVzIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgcmVnaW9uPWZjdF9yZWNvZGUocmVnaW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVhc3QiPSIwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJNaWR3ZXN0Ij0iMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VzdCI9IjIiKSwNCiAgICAgICAgIGhhdmluZ19jaGlsZHJlbl9mbGc9ZmN0X3JlY29kZShoYXZpbmdfY2hpbGRyZW5fZmxnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJObyI9IjAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJZZXMiPSIxIiksDQogICAgICAgICBpc19jbGllbnQ9ZmN0X3JlY29kZShpc19jbGllbnQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8iPSIwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJZZXMiPSIxIiksDQogICAgICAgICBiYWRfY2xpZW50X3RhcmdldD1mY3RfcmVjb2RlKGJhZF9jbGllbnRfdGFyZ2V0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8iPSIwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlllcyI9IjEiKSkNCg0KbWFwKGNsaWVudHNfczJfd29yayAlPiUgc2VsZWN0KGMobW9udGgsc2V4LGVkdWNhdGlvbixwcm9kdWN0X3R5cGUsaGF2aW5nX2NoaWxkcmVuX2ZsZyxyZWdpb24sZmFtaWx5X3N0YXR1cyxwaG9uZV9vcGVyYXRvcixpc19jbGllbnQsYmFkX2NsaWVudF90YXJnZXQpKSx1bmlxdWUpDQoNCg0KYGBgDQoNCiMjIFRhc2sgMzogU3VtbWFyeSBvZiBWYXJpYWJsZXMNCg0KU3VtbWFyaXplICoqY2xpZW50c19zMl93b3JrKiogdXNpbmcgdGhlICoqc2tpbV93aXRob3V0X2NoYXJ0cygpKiogZnVjdG5pb24uDQpHcm91cCBieSAqKnNleCoqIGFuZCBzZWxlY3QgdGhlICoqY3JlZGl0X3Rlcm0qKiwgKiplZHVjYXRpb24qKiwgKippc19jbGllbnQqKiwgYW5kICoqaW5jb21lKiogdmFyaWFibGVzIHRvIGV4YW1pbmUuDQoNCioqUXVlc3Rpb24gMy4xKio6IFdoYXQgaXMgdGhlICo3NXRoIHBlcmNlbnRpbGUqIG9mICppbmNvbWUqIGZvciAqbWVuKj8NCkhvdyBtYW55ICp3b21lbiogYXJlIGNsaWVudHM/DQoNCioqUmVzcG9uc2UgMy4xKio6ICozNjAwMCouDQoNCmBgYHtyLCB0YXNrM30NCmNsaWVudHNfczJfd29yayU+JQ0KICBncm91cF9ieShzZXgpJT4lDQogIHNlbGVjdChjcmVkaXRfdGVybSxlZHVjYXRpb24saXNfY2xpZW50LGluY29tZSklPiUNCiAgc2tpbV93aXRob3V0X2NoYXJ0cygpDQpgYGANCg0KIyMgVGFzayA0OiBEaXNjcmV0ZSBWYXJpYWJsZXMNCg0KRm9yIHRoaXMgdGFzaywgeW91IHdpbGwgcGxvdCBhIGRpc2NyZXRlIHZhcmlhYmxlLg0KDQpQcm9kdWNlIGEgaG9yaXpvbnRhbCBiYXIgcGxvdCBvZiAqKnByb2R1Y3RfdHlwZSoqIHRoYXQgY2FsY3VsYXRlcyB0aGUgcGVyY2VudGFnZXMgb2YgaW5kaXZpZHVhbHMgaW4gZWFjaCBjYXRlZ29yeS4NCkNvcnJlY3RseSBsYWJlbCB0aGUgYXhlcy4NCkRvIE5PVCBvcmRlciB0aGUgY2F0ZWdvcmllcyB5ZXQuDQoNCioqUXVlc3Rpb24gNC4xKio6IFdoaWNoIHR3byBwcm9kdWN0IHR5cGVzIGFyZSBtb3N0IHBvcHVsYXI/DQoNCioqUmVzcG9uc2UgNC4xKio6ICpDZWxsIHBob25lcyBhbmQgaG91c2Vob2xkIGFwcGxpYW5jZXMuKg0KDQpFeGFtaW5lIHRoZSBwcmVzZW50IG9yZGVyIG9mIHRoZSAqKnByb2R1Y3RfdHlwZSoqIGNhdGVnb3JpZXMgd2l0aCB0aGUgKipsZXZlbHMoKSoqIGZ1bmN0aW9uLg0KUmVvcmRlciB0aGUgY2F0ZWdvcmllcyBieSB0aGVpciByZXZlcnNlIGZyZXF1ZW5jeS4NCkV4YW1pbmUgdGhlIGNoYW5nZWQgb3JkZXIgb2YgdGhlICoqcHJvZHVjdF90eXBlKiogY2F0ZWdvcmllcy4NCg0KKipRdWVzdGlvbiA0LjIqKjogV2hhdCB3ZXJlIHRoZSBmaXJzdCBhbmQgbGFzdCBjYXRlZ29yaWVzIG9yaWdpbmFsbHk/DQpXaGF0IGFyZSB0aGUgZmlyc3QgYW5kIGxhc3QgY2F0ZWdvcmllcyBhZnRlciB0aGUgcmVvcmRlcmluZz8NCg0KKipSZXNwb25zZSA0LjIqKjogKkF1ZGlvICYgdmlkZW8sIFdpbmRvd3MgJiBkb29ycyBhZnRlciByZW9yZGVyaW5nIGl0IGlzIENvbnN0cnVjdGlvbiBtYXRlcmlhbHMgYW5kIGNvbXB1dGVycyouDQoNClByb2R1Y2UgYSBzZWNvbmQgaG9yaXpvbnRhbCBiYXIgcGxvdCBvZiAqKnByb2R1Y3RfdHlwZSoqIHRoYXQgY2FsY3VsYXRlcyB0aGUgcGVyY2VudGFnZXMgb2YgaW5kaXZpZHVhbHMgaW4gZWFjaCBjYXRlZ29yeS4NCkNvcnJlY3RseSBsYWJlbCB0aGUgYXhlcy4NClRoaXMgcGxvdCBzaG91bGQgdXNlIHRoZSBub3cgb3JkZXJlZCB2ZXJzaW9uIG9mICoqcHJvZHVjdF90eXBlKiouDQpBZGQgdGV4dCB0byB0aGUgbWlkZGxlIG9mIHRoZSBiYXJzIHRvIGluZGljYXRlIHRoZWlyIHBlcmNlbnRhZ2UgdmFsdWVzLg0KQ2hhbmdlIHRoZSBzaXplIG9mIHRoZSB0ZXh0IHRvIGEgdmFsdWUgb2YgKioyKiouDQoNCioqUXVlc3Rpb24gNC4zKio6IFdoYXQgcGVyY2VudGFnZSBib3VnaHQgaXRlbXMgd2VyZSAqd2luZG93cyBhbmQgZG9vcnMqPw0KV2hhdCBwZXJjZW50YWdlIG9mIGJvdWdodCBpdGVtcyB3ZXJlICpmdXJuaXR1cmUqPw0KDQoqKlJlc3BvbnNlIDQuMyoqOiAqMS40IGFuZCAyNi4zKi4NCg0KYGBge3IsIHRhc2s0fQ0KY2xpZW50c19zMl93b3JrJT4lDQogIGdncGxvdChhZXMoeD1wcm9kdWN0X3R5cGUseT0uLmNvdW50Li4vc3VtKC4uY291bnQuLikqMTAwKSkrDQogIGdlb21fYmFyKCkNCg0KbGV2ZWxzKGNsaWVudHNfczJfd29yayRwcm9kdWN0X3R5cGUpDQoNCnByb2R1Y3RfdHlwZV9vcmRlcjwtY2xpZW50c19zMl93b3JrJT4lY291bnQocHJvZHVjdF90eXBlKSU+JQ0KICBhcnJhbmdlKGRlc2MobikpJT4lDQogIG11dGF0ZShwY3Q9cm91bmQobi9zdW0obiksMykqMTAwKQ0KDQpjbGllbnRzX3MyX3dvcmskcHJvZHVjdF90eXBlPC1mYWN0b3IoY2xpZW50c19zMl93b3JrJHByb2R1Y3RfdHlwZSxsZXZlbHM9cHJvZHVjdF90eXBlX29yZGVyJHByb2R1Y3RfdHlwZSkNCg0KbGV2ZWxzKGNsaWVudHNfczJfd29yayRwcm9kdWN0X3R5cGUpDQoNCnByb2R1Y3RfdHlwZV9vcmRlciU+JQ0KICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihwcm9kdWN0X3R5cGUsZGVzYyhwY3QpKSx5PXBjdCxsYWJlbD1wY3QpKSsNCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsNCiAgZ2VvbV90ZXh0KHNpemU9Mixwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0uNSkpDQoNCg0KYGBgDQoNCiMjIFRhc2sgNTogQ29udGludW91cyBWYXJpYWJsZXMNCg0KRm9yIHRoaXMgdGFzaywgeW91IHdpbGwgcGxvdCBhIGNvbnRpbnVvdXMgdmFyaWFibGUuDQoNClByb2R1Y2UgYSBoaXN0b2dyYW0gcGxvdCBmb3IgKipjcmVkaXRfdGVybSoqLg0KQ29sb3IgdGhlIGhpc3RvZ3JhbSAqKmJsdWUqKiwgY2hvb3NlICoqMTAqKiBiaW5zLCBhZGQgdGV4dCB0aGF0IHByaW50cyB0aGUgY291bnQgdmFsdWUgZm9yIGVhY2ggYmluLCBhbmQgdXNlICoqOCoqIGJyZWFrcyBmb3IgdGhlIHgtYXhpcy4NCkxhYmVsIHRoZSBheGVzIGFwcHJvcHJpYXRlbHkuDQoNCioqUXVlc3Rpb24gNS4xKio6IEFyZSB0aGVyZSBtb3JlIGluZGl2aWR1YWxzIHdpdGggYSAqY3JlZGl0IHRlcm0qIG9mIHJvdWdobHkgKjEwLTEyLjUqIG9yICozNS0zNy41Kj8NCkFyZSB0aGVyZSBtb3JlIHRoYW4gKjEwKiBpbmRpdmlkdWFscyB3aXRoIGEgKmNyZWRpdCB0ZXJtKiBpbiB0aGUgKjIxLTIzKiByYW5nZT8NCg0KKipSZXNwb25zZSA1LjEqKjogKlRoZXJlIGFyZSBtb3JlIGluZGl2aWR1YWxzIHdpdGggYSBjcmVkaXQgdGVybSBvZiAxMC0xMi41IHRoYW4gMzUtMzcuNS4gVGhlcmUgYXJlIG5vdCBtb3JlIHRoYW4gMTAgaW5kaXZpZHVhbHMgd2l0aCBhIGNyZWRpdCB0ZXJtIGluIHRoZSAyMS0yMyByYW5nZSouDQoNClByb2R1Y2UgYSBkZW5zaXR5IHBsb3QgZm9yICoqY3JlZGl0X3Rlcm0qKi4NCkZpbGwgdGhlIGhpc3RvZ3JhbSAqKnB1cnBsZSoqLCBtYWtlIGl0IGhhbGYgdHJhbnNwYXJlbnQsIGFuZCBtYWtlIHRoZSBjb2xvciBvZiB0aGUgZGVuc2l0eSBjdXJ2ZSAqKndoaXRlKiouDQpMYWJlbCB0aGUgYXhlcyBhcHByb3ByaWF0ZWx5Lg0KUHJvdmlkZSBhIHRpdGxlIGFuZCBzdWJ0aXRsZSBmb3IgdGhlIHBsb3QuDQoNCioqUXVlc3Rpb24gNS4yKio6IEhvdyBtYW55IG1vZGVzIGRvIHlvdSBzZWUgZm9yICpjcmVkaXQgdGVybXMqIGZhbGxpbmcgYmV0d2VlbiAqMCogdG8gKjIwKiBtb250aHM/DQoNCioqUmVzcG9uc2UgNS4yKio6ICpUaGVyZSBhcmUgMyBtb2RlcyouDQoNCmBgYHtyLCB0YXNrNX0NCmNsaWVudHNfczJfd29yayU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y3JlZGl0X3Rlcm0pKSsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwLGZpbGw9ImJsdWUiKSsNCiAgc3RhdF9iaW4oYWVzKHk9Li5jb3VudC4uLGxhYmVsPS4uY291bnQuLiksZ2VvbT0idGV4dCIsYmlucyA9IDEwLHZqdXN0PS0uNSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDUsMTAsMTUsMjAsMjUsMzAsMzUsNDApKSsNCiAgbGFicyh4PSJDcmVkaXQgVGVybSIpDQoNCg0KY2xpZW50c19zMl93b3JrJT4lDQogIGdncGxvdChhZXMoeD1jcmVkaXRfdGVybSx5PS4uZGVuc2l0eS4uKSkrDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMCxmaWxsPSJwdXJwbGUiLGFscGhhPS41KSsNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yPSJ3aGl0ZSIsYWVzKHk9Li5kZW5zaXR5Li4pKSsNCiAgc3RhdF9iaW4oYWVzKHk9Li5kZW5zaXR5Li4sbGFiZWw9Li5jb3VudC4uKSxnZW9tPSJ0ZXh0IixiaW5zID0gMTAsdmp1c3Q9LS41KSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoNSwxMCwxNSwyMCwyNSwzMCwzNSw0MCkpKw0KICAgIGxhYnMoeD0iQ3JlZGl0IFRlcm0iKQ0KYGBgDQoNCiMjIFRhc2sgNjogTXVsdGlwbGUgVmFyaWFibGVzDQoNCkZvciB0aGlzIHRhc2ssIHlvdSB3aWxsIHByb2R1Y2UgcGxvdHMgaW52b2x2aW5nIG11bHRpcGxlIHZhcmlhYmxlcy4NCg0KUHJvZHVjZSBhIGJhciBwbG90IGNhbGN1bGF0aW5nIHRoZSAqcGVyY2VudGFnZSogb2YgKm1lbiogYW5kICp3b21lbiogd2l0aCB2YXJpb3VzICpwaG9uZSBvcGVyYXRvcnMqLg0KUGxhY2UgKipwaG9uZV9vcGVyYXRvcioqIG9uIHRoZSB4LWF4aXMgYW5kICoqc2V4KiogYXMgdGhlICoqZmlsbCoqIGFuZCAqKmdyb3VwKiogYWVzdGhldGljcy4NClByb2R1Y2UgYSAqZG9kZ2VkKiBiYXIgcGxvdC4NCkFkZCB0ZXh0IG9uIHRvcCBvZiB0aGUgYmFycyB3aXRoIHRoZSByZWxldmFudCBwZXJjZW50YWdlcy4NCkxhYmVsIHRoZSBheGVzIGFuZCBsZWdlbmQgYXBwcm9wcmlhdGVseS4NClByb3ZpZGUgYW4gYXBwcm9wcmlhdGUgdGl0bGUuDQpTYXZlIHRoZSBwbG90IGFzICoqcGhvbmVfZ2VuZGVyX3Bsb3QqKi4NClByaW50IHRoZSBwbG90IGJ5IGhpZ2hsaWdodGluZyB0aGUgc2F2ZWQgb2JqZWN0Lg0KDQoqKlF1ZXN0aW9uIDYuMSoqOiBXaGljaCAqcGhvbmUgb3BlcmF0b3IqIGlzIG1vc3Qgb2Z0ZW4gdXNlZCBieSAqbWVuKiBhbmQgKndvbWVuKj8NCg0KKipSZXNwb25zZSA2LjEqKjogKkFUJlQgaXMgbW9zdCB1c2VkIGJ5IG1lbiBhbmQgd29tZW4gdXNlIFVTIENlbGx1bGFyIG1vcmUqLg0KDQpQcm9kdWNlIGEgc2NhdHRlcnBsb3Qgb2YgKipjcmVkaXRfdGVybSoqICh4LWF4aXMpIGFuZCAqKmNyZWRpdF9hbW91bnQqKiAoeS1heGlzKS4NCkFkZCBhICoqbG9lc3MqKiBsaW5lIGFuZCBjb2xvciB0aGUgcG9pbnRzICoqYmx1ZSoqIHdpdGggdHJhbnNwYXJlbmN5Lg0KU2F2ZSB0aGUgcGxvdCBhcyAqKmNyZWRpdF90ZXJtX2Ftb3VudF9wbG90KiouDQoNCioqUXVlc3Rpb24gNi4yKio6IFVzaW5nIHRoZSAqKmxvZXNzKiogbGluZSBhcyBhIGd1aWRlLCBhcmUgbGFyZ2VyICpjcmVkaXQgYW1vdW50cyogYXNzb2NpYXRlZCB3aXRoICpsb3dlciogb3IgKmhpZ2hlciogKmNyZWRpdCB0ZXJtcyo/DQoNCioqUmVzcG9uc2UgNi4yKio6ICpXUklURSBZT1VSIEFOU1dFUiBCRVRXRUVOIFRIRVNFIEFTVEVSSVNLUyouDQoNClByb2R1Y2UgYSBib3hwbG90IG9mICoqaW5jb21lKiogKHktYXhpcykgYXMgYSBmdW5jdGlvbiBvZiAqKmZhbWlseV9zdGF0dXMqKiAoeC1heGlzKS4NCkZpbGwgdGhlIGJveHBsb3RzIGJ5ICoqZmFtaWx5X3N0YXR1cyoqLCBjb2xvciB0aGUgb3V0bGllcnMgaW4gKipkYXJrcmVkKiosIGluY2x1ZGUgdGhlIGppdHRlcmVkIGRhdGEgcG9pbnRzLCBleGNsdWRlIHRoZSBsZWdlbmQsIGFuZCBhcHByb3ByaWF0ZWx5IGxhYmVsIHRoZSBheGVzLg0KU2F2ZSB0aGUgcGxvdCBhcyAqKmluY29tZV9mYW1fc3RhdF9wbG90KiouDQoNCioqUXVlc3Rpb24gNi4zKio6IFdoaWNoIGNhdGVnb3J5IG9mICpmYW1pbHkgc3RhdHVzKiBoYXMgdGhlIGxhcmdlc3Qgb3V0bGllcnM/DQoNCioqUmVzcG9uc2UgNi4zKio6ICpXUklURSBZT1VSIEFOU1dFUiBCRVRXRUVOIFRIRVNFIEFTVEVSSVNLUyouDQoNCmBgYHtyLCB0YXNrNn0NCnBob25lX2dlbmRlcl9wbG90PC1jbGllbnRzX3MyX3dvcmslPiVjb3VudChzZXgscGhvbmVfb3BlcmF0b3IpJT4lZ3JvdXBfYnkocGhvbmVfb3BlcmF0b3IpJT4lDQogIG11dGF0ZShwY3Q9bi9zdW0obikqMTAwLHBjdD1yb3VuZChwY3QsMSkpJT4lDQogIGdncGxvdChhZXMoeD1waG9uZV9vcGVyYXRvcix5PXBjdCxmaWxsPXNleCxncm91cD1zZXgpKSsNCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJkb2RnZSIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlMChwY3QsIiUiKSksdmp1c3Q9LS41KSsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMTAwKSkrDQogIGxhYnMoeD0iUGhvbmUgT3BlcmF0b3IiLHk9IlBlcmNlbnRhZ2UiLHRpdGxlPSJEaXN0cmlidXRpb24gb2YgUGhvbmUgT3BlcmF0b3IgYnkgU2V4IikNCg0KcGhvbmVfZ2VuZGVyX3Bsb3QNCmBgYA0KDQojIyBUYXNrIDc6IFNhdmUgUGxvdHMgYW5kIERhdGENCg0KRm9yIHRoaXMgdGFzaywgeW91IHdpbGwgc2F2ZSB0aGUgcGxvdHMgZnJvbSB0aGUgc2l4dGggdGFzayBhbmQgdGhlIHdvcmtpbmcgZGF0YS4NClNhdmUgdGhlIHdvcmtpbmcgZGF0YSwgKipjbGllbnRzX3MyX3dvcmsqKiBhcyB0aGUgZGF0YSBmaWxlOiAqKmNsaWVudHNfczJfd29yay5jc3YqKiBpbiB0aGUgKipkYXRhKiogZm9sZGVyIG9mIHRoZSBwcm9qZWN0IGRpcmVjdG9yeS4NCg0KU2F2ZSB0aGUgdGhyZWUgcGxvdHMgZnJvbSB0aGUgc2l4dGggdGFzayBhcyAqKnBuZyoqIGZpbGVzIGluIHRoZSAqKnBsb3RzKiogZm9sZGVyIG9mIHRoZSBwcm9qZWN0IGRpcmVjdG9yeS4NClNhdmUgKipwaG9uZV9nZW5kZXJfcGxvdCoqIGFzICoqcGhvbmVfZ2VuZGVyLnBuZyoqLCAqKmNyZWRpdF90ZXJtX2Ftb3VudF9wbG90KiogYXMgKipjcmVkaXRfdGVybV9hbW91bnQucG5nKiosIGFuZCAqKmluY29tZV9mYW1fc3RhdF9wbG90KiogYXMgKippbmNvbWVfZmFtX3N0YXQucG5nKiouDQpVc2UgYSB3aWR0aCBvZiAqNiBpbmNoZXMqIGFuZCBoZWlnaHQgb2YgKjYgaW5jaGVzKi4NCg0KYGBge3IsIHRhc2s3fQ0KDQpgYGANCg0KIyMgVGFzayA4OiBDb25jZXB0dWFsIFF1ZXN0aW9ucw0KDQpGb3IgeW91ciBsYXN0IHRhc2ssIHlvdSB3aWxsIHJlc3BvbmQgdG8gY29uY2VwdHVhbCBxdWVzdGlvbnMgYmFzZWQgb24gdGhlIGNvbmNlcHR1YWwgbGVjdHVyZXMgZm9yIHRoaXMgd2Vlay4NCg0KKipRdWVzdGlvbiA4LjEqKjogV2hhdCBpcyBhIHBlcmNlbnRpbGUgb2YgYSB2YXJpYWJsZT8NCg0KKipSZXNwb25zZSA4LjEqKjogKldSSVRFIFlPVVIgQU5TV0VSIEJFVFdFRU4gVEhFU0UgQVNURVJJU0tTKi4NCg0KKipRdWVzdGlvbiA4LjIqKjogV2hhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB2YXJpYW5jZSBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGEgdmFyaWFibGU/DQoNCioqUmVzcG9uc2UgOC4yKio6ICpXUklURSBZT1VSIEFOU1dFUiBCRVRXRUVOIFRIRVNFIEFTVEVSSVNLUyouDQoNCioqUXVlc3Rpb24gOC4zKio6IFdoYXQgZml2ZSBzdGF0aXN0aWNzIGFyZSBjb21wdXRlZCBpbiBhIGJveHBsb3Q/DQpIb3cgaXMgYSBib3hwbG90IHVzZWZ1bCBmb3IgZXZhbHVhdGluZyB2YXJpYWJsZXM/DQoNCioqUmVzcG9uc2UgOC4zKio6ICpXUklURSBZT1VSIEFOU1dFUiBCRVRXRUVOIFRIRVNFIEFTVEVSSVNLUyouDQo=