Part 1
Intro
Real Life Applications of ML
- Supervised Classification: Whether a 1st year
college student will graduate
- Supervised Regression: The avg. rating of a
professor for a class
- Unsupervised Clustering: What songs to queue in a
music streaming app
- Unsupervised Dimension Reduction: 5 Most important
attributes to profile a customer
College Student Classification
Application:
Applying Machine learning to predict whether a 1st year college
student will graduate allows for universities to:
- Identify key features that support successful students
- Support individuals with lower probabilities of success
Supervised or Unsupervised:
Since universities measure and retain information about the binary
outcome (Y/N) of whether a college student graduates, this would be a
Supervised Classification problem.
Target Variable:
The target variable is a Binary Y/N of whether the student graduates
or not
Potential Feature Variables:
- High school GPA
- Household Income
- Declared or Undeclared Degree (Y/N)
- Anticipated Degree
- Geographic Location
Data Collection:
Colleges already keep extensive information about students (and
likely buy it from third party sources). Anticipated barriers lie in
accessing the data/gaining data permissions.
Ethical Concerns:
So many… Especially regarding public colleges and universities
(versus private or in regular business). - Could be used (and likely is
used) to optimize college selection for students, reducing opportunity
for low-opportunity students (rather than helping them) - Anticipated
lawsuits for seeming discriminatory against certain segments in
admission process —
Professor Rating Regression
Application:
Applying Machine Learning to predict the average rating (out of 5) of
college professors for the classes they teach:
- Determine certain classes or trends leading to higher or lower avg.
ratings
- Provide strategic feedback to professors to increase their rating
among students
Supervised or Unsupervised:
Since the model would predict a numerical value that can be checked
against actual results, this falls within Supervised Regression
territory.
Target Variable:
The target variable is Average Rating of a professor at the end of a
semester for a class
Potential Feature Variables:
- Number of students in class
- Class name
- Department
- Online/In Person
- Tenure (Y/N)
- Years of experience
Data Collection:
Again, colleges already maintain information about classes and
professors, including professor ratings by semester.
Ethical Concerns:
The biggest ethical concern lies in professors utilizing this model
to change their teaching style for better ratings (and higher pay)
without considering the value that they bring to their students (AKA
optimizing for rating, rather than teaching). —
Clustering Songs for Queue
Application:
Applying Machine Learning to ascertain clusters of songs to be placed
in the queue of a user’s music streaming app:
- Better queue recommendations/clusters lead to higher customer
satisfaction
Supervised or Unsupervised:
- Since this model aims to group songs based on user information, and
since there is no true answer to measure against, this serves as an
Unsupervised Clustering model.
Target Variable:
Unsupervised models do not use target variables
Potential Feature Variables:
- Time of day
- Day of week/month
- Previous songs queued/played by user
- Liked artists
- Liked albums/music types
Data Collection:
Ideally, this would be developed as an employee within one of these
companies. Streaming apps collect extensive user data, which can be
leveraged within the model.
Ethical Concerns:
While users agree to data collection within the terms of use of
streaming apps, they still find direct use of their information
off-putting. Not so much an ethical concern, but a concern of the
brand’s PR (think of the famous Target pregnancy model)
Dimension Reduction for Customer Profiling
Application:
I work in an insurance company, where customer information includes
over one hundred variables. This model reduces the # of variables to be
considered for customer profiling within the business.:
- Identify and strip away customer features deemed unimportant
- Simplify customer profiling for future modeling
Supervised or Unsupervised:
No target variable and no true answer, this would be an Unsupervised
Dimension Reduction model.
Target Variable:
No target variable
Potential Feature Variables:
Literally hundreds of variables, including…
- Age
- Quoted Bodily Injury Limites
- Prior Insurance
- Number of Automobiles vs. # of Drivers (also used for fraud
detection)
- Geographic Location
Data Collection:
Assuming working within an insurance company. Data collection ability
lies on the user’s ability to gain access to the data (or find people
who can make it happen). This can take months, depending on the data
required.
Ethical Concerns:
Insurance is heavily regulated,and customer profiling often fits in
the “grey” are of legal vs not legal..
Part 2
Data Setup & Loading
Setting global chunk options
knitr::opts_chunk$set(
comment = '', fig.width = 6, fig.height = 6,
warning = FALSE, error = FALSE, message = FALSE,
include = TRUE, echo = TRUE, strip.white = TRUE, highlight = TRUE, results = TRUE
)
Loading Libraries
packages = c('tidyverse','tidymodels','here','kknn')
lapply(packages, library, character.only = TRUE)
Lab Questions
1. Is this a supervised or unsupervised learning problem?
Why?
- Since the target variable is contained within the data, and since
the model aims to predict a numerical value, this is a Supervised
Regression model
2. There are 16 variables in this data set. Which variable
is the response variable and which variables are the predictor variables
(aka features)?
- Target Var: cmedv (Median value of owner-occupied homes in
USD 1,000’s)
- Predictor Vars:
- lon: longitude of census tract
- lat: latitude of census tract
- crim: per capita crime rate by town
- zn: proportion of residential land zoned for lots over 25,000
sq.ft
- indus: proportion of non-retail business acres per town
- chas: Charles River dummy variable (= 1 if tract bounds river; 0
otherwise)
- nox: nitric oxides concentration (parts per 10 million) –> aka
air pollution
- rm: average number of rooms per dwelling
- age: proportion of owner-occupied units built prior to 1940
- dis: weighted distances to five Boston employment centers
- rad: index of accessibility to radial highways
- tax: full-value property-tax rate per USD 10,000
- ptratio: pupil-teacher ratio by town
- lstat: percentage of lower status of the population
3. Given the type of variable cmedv is, is this a regression
or classification problem?
- As stated before, this is a Regression problem
4. Fill in the blanks to import the Boston housing data set
(boston.csv). Are there any missing values? What is the minimum and
maximum values of cmedv? What is the average cmedv value?
path <- here('Data','boston.csv')
boston <- readr::read_csv(path)
head(boston)
5. Fill in the blanks to split the data into a training set
and test set using a 70-30% split. Be sure to include the set.seed(123)
so that your train and test sets are the same size as
mine.
set.seed(123)
split <- initial_split(boston, prop = 0.7, strata = cmedv)
train <- training(split)
test <- testing(split)
6. How many observations are in the training set and test
set?
There are 352 observations in the “train” data set
and 154 observations in the “test” data set.
7. Compare the distribution of cmedv between the training
set and test set. Do they appear to have the same distribution or do
they differ significantly?
train %>%
mutate(id = 'train') %>%
bind_rows(test %>% mutate(id = 'test')) %>%
ggplot(aes(cmedv, color = id)) +
geom_density()

8. Fill in the blanks to fit a linear regression model using
the rm feature variable to predict cmedv and compute the RMSE on the
test data. What is the test set RMSE?
# fit model
lm1 <- linear_reg() %>%
fit( cmedv ~ rm, data = train)
# compute the RMSE on the test data
prd1 <- lm1 %>%
predict(test) %>%
bind_cols(test %>% select(cmedv)) %>%
rmse(truth = cmedv, estimate = .pred)
prd1
The test set RMSE is $6,8301 when using rm (average
number of rooms) to estimate cmedv
LS0tDQp0aXRsZTogIk1vZHVsZSA4IExhYiINCnN1YnRpdGxlOiAiSW50cm8gdG8gTWFjaGluZSBMZWFybmluZyINCmF1dGhvcjogIlJvYW4gWmFwcGFudGkiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCg0KDQpoZWFkZXItaW5jbHVkZXM6DQotIFx1c2VwYWNrYWdle3RpdGxlc2VjfQ0KLS0tDQo8YnI+DQoNCiMjIFBhcnQgMSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KIyMjIEludHJvDQoNCiMjIyMgUmVhbCBMaWZlIEFwcGxpY2F0aW9ucyBvZiBNTA0KDQoxLiAqKlN1cGVydmlzZWQgQ2xhc3NpZmljYXRpb24qKjogV2hldGhlciBhIDFzdCB5ZWFyIGNvbGxlZ2Ugc3R1ZGVudCB3aWxsIGdyYWR1YXRlIDxicj4NCjIuICoqU3VwZXJ2aXNlZCBSZWdyZXNzaW9uKio6IFRoZSBhdmcuIHJhdGluZyBvZiBhIHByb2Zlc3NvciBmb3IgYSBjbGFzcyA8YnI+DQozLiAqKlVuc3VwZXJ2aXNlZCBDbHVzdGVyaW5nKio6IFdoYXQgc29uZ3MgdG8gcXVldWUgaW4gYSBtdXNpYyBzdHJlYW1pbmcgYXBwIDxicj4NCjQuICoqVW5zdXBlcnZpc2VkIERpbWVuc2lvbiBSZWR1Y3Rpb24qKjogNSBNb3N0IGltcG9ydGFudCBhdHRyaWJ1dGVzIHRvIHByb2ZpbGUgYSBjdXN0b21lciAgDQoNCi0tLQ0KDQojIyMgQ29sbGVnZSBTdHVkZW50IENsYXNzaWZpY2F0aW9uDQojIyMjIyMgKipBcHBsaWNhdGlvbioqOg0KICBBcHBseWluZyBNYWNoaW5lIGxlYXJuaW5nIHRvIHByZWRpY3Qgd2hldGhlciBhIDFzdCB5ZWFyIGNvbGxlZ2Ugc3R1ZGVudCB3aWxsIA0KICBncmFkdWF0ZSBhbGxvd3MgZm9yIHVuaXZlcnNpdGllcyB0bzo8YnI+DQoNCiAgLSBJZGVudGlmeSBrZXkgZmVhdHVyZXMgdGhhdCBzdXBwb3J0IHN1Y2Nlc3NmdWwgc3R1ZGVudHMNCiAgLSBTdXBwb3J0IGluZGl2aWR1YWxzIHdpdGggbG93ZXIgcHJvYmFiaWxpdGllcyBvZiBzdWNjZXNzPGJyPjxicj4NCg0KIyMjIyMjICoqU3VwZXJ2aXNlZCBvciBVbnN1cGVydmlzZWQqKjoNCiAgU2luY2UgdW5pdmVyc2l0aWVzIG1lYXN1cmUgYW5kIHJldGFpbiBpbmZvcm1hdGlvbiBhYm91dCB0aGUgYmluYXJ5IG91dGNvbWUgKFkvTikgb2YNCiAgd2hldGhlciBhIGNvbGxlZ2Ugc3R1ZGVudCBncmFkdWF0ZXMsIHRoaXMgd291bGQgYmUgYSBTdXBlcnZpc2VkIENsYXNzaWZpY2F0aW9uIHByb2JsZW0uDQogIDxicj48YnI+DQogICAgDQojIyMjIyMgKipUYXJnZXQgVmFyaWFibGUqKjogDQogIFRoZSB0YXJnZXQgdmFyaWFibGUgaXMgYSBCaW5hcnkgWS9OIG9mIHdoZXRoZXIgdGhlIHN0dWRlbnQgZ3JhZHVhdGVzIG9yIG5vdCA8YnI+PGJyPg0KICANCiMjIyMjIyAqKlBvdGVudGlhbCBGZWF0dXJlIFZhcmlhYmxlcyoqOg0KICAtIEhpZ2ggc2Nob29sIEdQQQ0KICAtIEhvdXNlaG9sZCBJbmNvbWUNCiAgLSBEZWNsYXJlZCBvciBVbmRlY2xhcmVkIERlZ3JlZSAoWS9OKQ0KICAtIEFudGljaXBhdGVkIERlZ3JlZQ0KICAtIEdlb2dyYXBoaWMgTG9jYXRpb24gIA0KICA8YnI+DQogIA0KIyMjIyMjICoqRGF0YSBDb2xsZWN0aW9uKio6IA0KICBDb2xsZWdlcyBhbHJlYWR5IGtlZXAgZXh0ZW5zaXZlIGluZm9ybWF0aW9uIGFib3V0IHN0dWRlbnRzIChhbmQgbGlrZWx5IGJ1eSBpdCBmcm9tIHRoaXJkDQogIHBhcnR5IHNvdXJjZXMpLiBBbnRpY2lwYXRlZCBiYXJyaWVycyBsaWUgaW4gYWNjZXNzaW5nIHRoZSBkYXRhL2dhaW5pbmcgZGF0YSBwZXJtaXNzaW9ucy4NCiAgPGJyPjxicj4NCg0KIyMjIyMjICoqRXRoaWNhbCBDb25jZXJucyoqOiANCiAgU28gbWFueS4uLiBFc3BlY2lhbGx5IHJlZ2FyZGluZyBwdWJsaWMgY29sbGVnZXMgYW5kIHVuaXZlcnNpdGllcyAodmVyc3VzIHByaXZhdGUgb3IgaW4NCiAgcmVndWxhciBidXNpbmVzcykuDQogIC0gQ291bGQgYmUgdXNlZCAoYW5kIGxpa2VseSBpcyB1c2VkKSB0byBvcHRpbWl6ZSBjb2xsZWdlIHNlbGVjdGlvbiBmb3Igc3R1ZGVudHMsIHJlZHVjaW5nDQogIG9wcG9ydHVuaXR5IGZvciBsb3ctb3Bwb3J0dW5pdHkgc3R1ZGVudHMgKHJhdGhlciB0aGFuIGhlbHBpbmcgdGhlbSkNCiAgLSBBbnRpY2lwYXRlZCBsYXdzdWl0cyBmb3Igc2VlbWluZyBkaXNjcmltaW5hdG9yeSBhZ2FpbnN0IGNlcnRhaW4gc2VnbWVudHMgaW4gYWRtaXNzaW9uDQogIHByb2Nlc3MNCi0tLQ0KDQoNCiMjIyBQcm9mZXNzb3IgUmF0aW5nIFJlZ3Jlc3Npb24NCiMjIyMjIyAqKkFwcGxpY2F0aW9uKio6DQogIEFwcGx5aW5nIE1hY2hpbmUgTGVhcm5pbmcgdG8gcHJlZGljdCB0aGUgYXZlcmFnZSByYXRpbmcgKG91dCBvZiA1KSBvZiBjb2xsZWdlIHByb2Zlc3NvcnMNCiAgZm9yIHRoZSBjbGFzc2VzIHRoZXkgdGVhY2g6PGJyPg0KDQogIC0gRGV0ZXJtaW5lIGNlcnRhaW4gY2xhc3NlcyBvciB0cmVuZHMgbGVhZGluZyB0byBoaWdoZXIgb3IgbG93ZXIgYXZnLiByYXRpbmdzDQogIC0gUHJvdmlkZSBzdHJhdGVnaWMgZmVlZGJhY2sgdG8gcHJvZmVzc29ycyB0byBpbmNyZWFzZSB0aGVpciByYXRpbmcgYW1vbmcgc3R1ZGVudHM8YnI+PGJyPg0KDQojIyMjIyMgKipTdXBlcnZpc2VkIG9yIFVuc3VwZXJ2aXNlZCoqOg0KICBTaW5jZSB0aGUgbW9kZWwgd291bGQgcHJlZGljdCBhIG51bWVyaWNhbCB2YWx1ZSB0aGF0IGNhbiBiZSBjaGVja2VkIGFnYWluc3QgYWN0dWFsIHJlc3VsdHMsDQogIHRoaXMgZmFsbHMgd2l0aGluIFN1cGVydmlzZWQgUmVncmVzc2lvbiB0ZXJyaXRvcnkuDQogIDxicj48YnI+DQogICAgDQojIyMjIyMgKipUYXJnZXQgVmFyaWFibGUqKjogDQogIFRoZSB0YXJnZXQgdmFyaWFibGUgaXMgQXZlcmFnZSBSYXRpbmcgb2YgYSBwcm9mZXNzb3IgYXQgdGhlIGVuZCBvZiBhIHNlbWVzdGVyIGZvciBhIGNsYXNzIDxicj48YnI+DQogIA0KIyMjIyMjICoqUG90ZW50aWFsIEZlYXR1cmUgVmFyaWFibGVzKio6DQogIC0gTnVtYmVyIG9mIHN0dWRlbnRzIGluIGNsYXNzDQogIC0gQ2xhc3MgbmFtZQ0KICAtIERlcGFydG1lbnQNCiAgLSBPbmxpbmUvSW4gUGVyc29uDQogIC0gVGVudXJlIChZL04pDQogIC0gWWVhcnMgb2YgZXhwZXJpZW5jZQ0KICA8YnI+DQogIA0KIyMjIyMjICoqRGF0YSBDb2xsZWN0aW9uKio6IA0KICBBZ2FpbiwgY29sbGVnZXMgYWxyZWFkeSBtYWludGFpbiBpbmZvcm1hdGlvbiBhYm91dCBjbGFzc2VzIGFuZCBwcm9mZXNzb3JzLCBpbmNsdWRpbmcNCiAgcHJvZmVzc29yIHJhdGluZ3MgYnkgc2VtZXN0ZXIuDQogIDxicj48YnI+DQoNCiMjIyMjIyAqKkV0aGljYWwgQ29uY2VybnMqKjogDQogIFRoZSBiaWdnZXN0IGV0aGljYWwgY29uY2VybiBsaWVzIGluIHByb2Zlc3NvcnMgdXRpbGl6aW5nIHRoaXMgbW9kZWwgdG8gY2hhbmdlIHRoZWlyIA0KICB0ZWFjaGluZyBzdHlsZSBmb3IgYmV0dGVyIHJhdGluZ3MgKGFuZCBoaWdoZXIgcGF5KSB3aXRob3V0IGNvbnNpZGVyaW5nIHRoZSB2YWx1ZSB0aGF0DQogIHRoZXkgYnJpbmcgdG8gdGhlaXIgc3R1ZGVudHMgKEFLQSBvcHRpbWl6aW5nIGZvciByYXRpbmcsIHJhdGhlciB0aGFuIHRlYWNoaW5nKS4NCi0tLQ0KDQoNCiMjIyBDbHVzdGVyaW5nIFNvbmdzIGZvciBRdWV1ZQ0KIyMjIyMjICoqQXBwbGljYXRpb24qKjoNCiAgQXBwbHlpbmcgTWFjaGluZSBMZWFybmluZyB0byBhc2NlcnRhaW4gY2x1c3RlcnMgb2Ygc29uZ3MgdG8gYmUgcGxhY2VkIGluIHRoZSBxdWV1ZQ0KICBvZiBhIHVzZXIncyBtdXNpYyBzdHJlYW1pbmcgYXBwOjxicj4NCg0KICAtIEJldHRlciBxdWV1ZSByZWNvbW1lbmRhdGlvbnMvY2x1c3RlcnMgbGVhZCB0byBoaWdoZXIgY3VzdG9tZXIgc2F0aXNmYWN0aW9uDQogIDxicj48YnI+DQoNCiMjIyMjIyAqKlN1cGVydmlzZWQgb3IgVW5zdXBlcnZpc2VkKio6DQogIC0gU2luY2UgdGhpcyBtb2RlbCBhaW1zIHRvIGdyb3VwIHNvbmdzIGJhc2VkIG9uIHVzZXIgaW5mb3JtYXRpb24sIGFuZCBzaW5jZSB0aGVyZSBpcyBubw0KICB0cnVlIGFuc3dlciB0byBtZWFzdXJlIGFnYWluc3QsIHRoaXMgc2VydmVzIGFzIGFuIFVuc3VwZXJ2aXNlZCBDbHVzdGVyaW5nIG1vZGVsLiANCiAgPGJyPjxicj4NCiAgICANCiMjIyMjIyAqKlRhcmdldCBWYXJpYWJsZSoqOiANCiAgVW5zdXBlcnZpc2VkIG1vZGVscyBkbyBub3QgdXNlIHRhcmdldCB2YXJpYWJsZXMgPGJyPjxicj4NCiAgDQojIyMjIyMgKipQb3RlbnRpYWwgRmVhdHVyZSBWYXJpYWJsZXMqKjoNCiAgLSBUaW1lIG9mIGRheQ0KICAtIERheSBvZiB3ZWVrL21vbnRoDQogIC0gUHJldmlvdXMgc29uZ3MgcXVldWVkL3BsYXllZCBieSB1c2VyDQogIC0gTGlrZWQgYXJ0aXN0cw0KICAtIExpa2VkIGFsYnVtcy9tdXNpYyB0eXBlcyAgDQogIDxicj4NCiAgDQojIyMjIyMgKipEYXRhIENvbGxlY3Rpb24qKjogDQogIElkZWFsbHksIHRoaXMgd291bGQgYmUgZGV2ZWxvcGVkIGFzIGFuIGVtcGxveWVlIHdpdGhpbiBvbmUgb2YgdGhlc2UgY29tcGFuaWVzLiBTdHJlYW1pbmcNCiAgYXBwcyBjb2xsZWN0IGV4dGVuc2l2ZSB1c2VyIGRhdGEsIHdoaWNoIGNhbiBiZSBsZXZlcmFnZWQgd2l0aGluIHRoZSBtb2RlbC4NCiAgPGJyPjxicj4NCg0KIyMjIyMjICoqRXRoaWNhbCBDb25jZXJucyoqOiANCiAgV2hpbGUgdXNlcnMgYWdyZWUgdG8gZGF0YSBjb2xsZWN0aW9uIHdpdGhpbiB0aGUgdGVybXMgb2YgdXNlIG9mIHN0cmVhbWluZyBhcHBzLCB0aGV5IHN0aWxsDQogIGZpbmQgZGlyZWN0IHVzZSBvZiB0aGVpciBpbmZvcm1hdGlvbiBvZmYtcHV0dGluZy4gTm90IHNvIG11Y2ggYW4gZXRoaWNhbCBjb25jZXJuLCBidXQgYSANCiAgY29uY2VybiBvZiB0aGUgYnJhbmQncyBQUiAodGhpbmsgb2YgdGhlIGZhbW91cyBUYXJnZXQgcHJlZ25hbmN5IG1vZGVsKQ0KDQotLS0NCg0KDQojIyMgRGltZW5zaW9uIFJlZHVjdGlvbiBmb3IgQ3VzdG9tZXIgUHJvZmlsaW5nDQojIyMjIyMgKipBcHBsaWNhdGlvbioqOg0KICBJIHdvcmsgaW4gYW4gaW5zdXJhbmNlIGNvbXBhbnksIHdoZXJlIGN1c3RvbWVyIGluZm9ybWF0aW9uIGluY2x1ZGVzIG92ZXIgb25lIGh1bmRyZWQgdmFyaWFibGVzLg0KICBUaGlzIG1vZGVsIHJlZHVjZXMgdGhlICMgb2YgdmFyaWFibGVzIHRvIGJlIGNvbnNpZGVyZWQgZm9yIGN1c3RvbWVyIHByb2ZpbGluZyB3aXRoaW4gdGhlIGJ1c2luZXNzLjo8YnI+DQoNCiAgLSBJZGVudGlmeSBhbmQgc3RyaXAgYXdheSBjdXN0b21lciBmZWF0dXJlcyBkZWVtZWQgdW5pbXBvcnRhbnQNCiAgLSBTaW1wbGlmeSBjdXN0b21lciBwcm9maWxpbmcgZm9yIGZ1dHVyZSBtb2RlbGluZzxicj48YnI+DQoNCiMjIyMjIyAqKlN1cGVydmlzZWQgb3IgVW5zdXBlcnZpc2VkKio6DQogIE5vIHRhcmdldCB2YXJpYWJsZSBhbmQgbm8gdHJ1ZSBhbnN3ZXIsIHRoaXMgd291bGQgYmUgYW4gVW5zdXBlcnZpc2VkIERpbWVuc2lvbiBSZWR1Y3Rpb24gbW9kZWwuDQogIDxicj48YnI+DQogICAgDQojIyMjIyMgKipUYXJnZXQgVmFyaWFibGUqKjogDQogIE5vIHRhcmdldCB2YXJpYWJsZQ0KICA8YnI+PGJyPg0KICANCiMjIyMjIyAqKlBvdGVudGlhbCBGZWF0dXJlIFZhcmlhYmxlcyoqOg0KDQpMaXRlcmFsbHkgKmh1bmRyZWRzKiBvZiB2YXJpYWJsZXMsIGluY2x1ZGluZy4uLg0KDQogIC0gQWdlDQogIC0gUXVvdGVkIEJvZGlseSBJbmp1cnkgTGltaXRlcw0KICAtIFByaW9yIEluc3VyYW5jZQ0KICAtIE51bWJlciBvZiBBdXRvbW9iaWxlcyB2cy4gIyBvZiBEcml2ZXJzIChhbHNvIHVzZWQgZm9yIGZyYXVkIGRldGVjdGlvbikNCiAgLSBHZW9ncmFwaGljIExvY2F0aW9uICANCiAgPGJyPg0KICANCiMjIyMjIyAqKkRhdGEgQ29sbGVjdGlvbioqOiANCiAgQXNzdW1pbmcgd29ya2luZyB3aXRoaW4gYW4gaW5zdXJhbmNlIGNvbXBhbnkuIERhdGEgY29sbGVjdGlvbiBhYmlsaXR5IGxpZXMgb24gdGhlIHVzZXIncyANCiAgYWJpbGl0eSB0byBnYWluIGFjY2VzcyB0byB0aGUgZGF0YSAob3IgZmluZCBwZW9wbGUgd2hvIGNhbiBtYWtlIGl0IGhhcHBlbikuIFRoaXMgY2FuIHRha2UgbW9udGhzLA0KICBkZXBlbmRpbmcgb24gdGhlIGRhdGEgcmVxdWlyZWQuDQogIDxicj48YnI+DQoNCiMjIyMjIyAqKkV0aGljYWwgQ29uY2VybnMqKjogDQogIEluc3VyYW5jZSBpcyBoZWF2aWx5IHJlZ3VsYXRlZCxhbmQgY3VzdG9tZXIgcHJvZmlsaW5nIG9mdGVuIGZpdHMgaW4gdGhlICJncmV5IiBhcmUgb2YgbGVnYWwNCiAgdnMgbm90IGxlZ2FsLi4NCiAgDQogIC0gV2l0aG91dCBnb2luZyBpbnRvIHRvbyBtdWNoIGRldGFpbCwgaG93IHRvIGJhbGFuY2UgcHJvZml0YWJpbGl0eSB2cyBtb3JhbGl0eT8gDQogIC0gV2hhdCdzIGdvb2QgZm9yIHRoZSB0b3RhbCBjdXN0b21lciBiYXNlIHZzLiBjZXJ0YWluIGN1c3RvbWVyIHNlZ21lbnRzPw0KICAtIFJlZCBsaW5pbmc6IDxodHRwczovL3d3dy5pbnN1cmFuY2UudXMvYXJ0aWNsZXMvYmxvZy93aGF0LWlzLXJlZGxpbmluZy13aXRoLWF1dG8taW5zdXJhbmNlPg0KDQotLS0NCg0KDQojIyBQYXJ0IDIgey50YWJzZXQgLnRhYnNldC1waWxsc30NCiMjIyBEYXRhIFNldHVwICYgTG9hZGluZw0KDQpTZXR0aW5nIGdsb2JhbCBjaHVuayBvcHRpb25zDQpgYGB7ciBHbG9iYWwgU2V0dXAsIHNldHVwLCBpbmNsdWRlPVRSVUV9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAnJywgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDYsDQogIHdhcm5pbmcgPSBGQUxTRSwgZXJyb3IgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLA0KICBpbmNsdWRlID0gVFJVRSwgZWNobyA9IFRSVUUsIHN0cmlwLndoaXRlID0gVFJVRSwgaGlnaGxpZ2h0ID0gVFJVRSwgcmVzdWx0cyA9IFRSVUUNCikNCmBgYA0KDQoNCkxvYWRpbmcgTGlicmFyaWVzDQpgYGB7ciBMaWJyYXJpZXMsIHJlc3VsdHMgPSAnaGlkZSd9DQpwYWNrYWdlcyA9IGMoJ3RpZHl2ZXJzZScsJ3RpZHltb2RlbHMnLCdoZXJlJywna2tubicpDQpsYXBwbHkocGFja2FnZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KDQojIyMgTGFiIFF1ZXN0aW9ucw0KDQojIyMjIyMgKioxLiBJcyB0aGlzIGEgc3VwZXJ2aXNlZCBvciB1bnN1cGVydmlzZWQgbGVhcm5pbmcgcHJvYmxlbT8gV2h5PyoqDQogIC0gU2luY2UgdGhlIHRhcmdldCB2YXJpYWJsZSBpcyBjb250YWluZWQgd2l0aGluIHRoZSBkYXRhLCBhbmQgc2luY2UgdGhlIG1vZGVsIGFpbXMgdG8gcHJlZGljdA0KICAgIGEgbnVtZXJpY2FsIHZhbHVlLCB0aGlzIGlzIGEgU3VwZXJ2aXNlZCBSZWdyZXNzaW9uIG1vZGVsDQogICAgPGJyPjxicj4NCiAgICANCiMjIyMjIyAqKjIuIFRoZXJlIGFyZSAxNiB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldC4gV2hpY2ggdmFyaWFibGUgaXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGFuZCB3aGljaCB2YXJpYWJsZXMgYXJlIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzIChha2EgZmVhdHVyZXMpPyoqDQoNCiAgLSAqVGFyZ2V0IFZhcjoqIGNtZWR2IChNZWRpYW4gdmFsdWUgb2Ygb3duZXItb2NjdXBpZWQgaG9tZXMgaW4gVVNEIDEsMDAwJ3MpDQogIC0gKlByZWRpY3RvciBWYXJzOiogIA0KICAgIC0gbG9uOiBsb25naXR1ZGUgb2YgY2Vuc3VzIHRyYWN0DQogICAgLSBsYXQ6IGxhdGl0dWRlIG9mIGNlbnN1cyB0cmFjdA0KICAgIC0gY3JpbTogcGVyIGNhcGl0YSBjcmltZSByYXRlIGJ5IHRvd24NCiAgICAtIHpuOiBwcm9wb3J0aW9uIG9mIHJlc2lkZW50aWFsIGxhbmQgem9uZWQgZm9yIGxvdHMgb3ZlciAyNSwwMDAgc3EuZnQNCiAgICAtIGluZHVzOiBwcm9wb3J0aW9uIG9mIG5vbi1yZXRhaWwgYnVzaW5lc3MgYWNyZXMgcGVyIHRvd24NCiAgICAtIGNoYXM6IENoYXJsZXMgUml2ZXIgZHVtbXkgdmFyaWFibGUgKD0gMSBpZiB0cmFjdCBib3VuZHMgcml2ZXI7IDAgb3RoZXJ3aXNlKQ0KICAgIC0gbm94OiBuaXRyaWMgb3hpZGVzIGNvbmNlbnRyYXRpb24gKHBhcnRzIHBlciAxMCBtaWxsaW9uKSDigJM+IGFrYSBhaXIgcG9sbHV0aW9uDQogICAgLSBybTogYXZlcmFnZSBudW1iZXIgb2Ygcm9vbXMgcGVyIGR3ZWxsaW5nDQogICAgLSBhZ2U6IHByb3BvcnRpb24gb2Ygb3duZXItb2NjdXBpZWQgdW5pdHMgYnVpbHQgcHJpb3IgdG8gMTk0MA0KICAgIC0gZGlzOiB3ZWlnaHRlZCBkaXN0YW5jZXMgdG8gZml2ZSBCb3N0b24gZW1wbG95bWVudCBjZW50ZXJzDQogICAgLSByYWQ6IGluZGV4IG9mIGFjY2Vzc2liaWxpdHkgdG8gcmFkaWFsIGhpZ2h3YXlzDQogICAgLSB0YXg6IGZ1bGwtdmFsdWUgcHJvcGVydHktdGF4IHJhdGUgcGVyIFVTRCAxMCwwMDANCiAgICAtIHB0cmF0aW86IHB1cGlsLXRlYWNoZXIgcmF0aW8gYnkgdG93bg0KICAgIC0gbHN0YXQ6IHBlcmNlbnRhZ2Ugb2YgbG93ZXIgc3RhdHVzIG9mIHRoZSBwb3B1bGF0aW9uDQoNCjxicj4NCg0KIyMjIyMjICoqMy4gR2l2ZW4gdGhlIHR5cGUgb2YgdmFyaWFibGUgY21lZHYgaXMsIGlzIHRoaXMgYSByZWdyZXNzaW9uIG9yIGNsYXNzaWZpY2F0aW9uIHByb2JsZW0/KioNCi0gQXMgc3RhdGVkIGJlZm9yZSwgdGhpcyBpcyBhIFJlZ3Jlc3Npb24gcHJvYmxlbQ0KDQo8YnI+DQoNCiMjIyMjIyAqKjQuIEZpbGwgaW4gdGhlIGJsYW5rcyB0byBpbXBvcnQgdGhlIEJvc3RvbiBob3VzaW5nIGRhdGEgc2V0IChib3N0b24uY3N2KS4gQXJlIHRoZXJlIGFueSBtaXNzaW5nIHZhbHVlcz8gV2hhdCBpcyB0aGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXMgb2YgY21lZHY/IFdoYXQgaXMgdGhlIGF2ZXJhZ2UgY21lZHYgdmFsdWU/KioNCmBgYHtyIExvYWQgRGF0YSwgcmVzdWx0cyA9ICdoaWRlJ30NCnBhdGggPC0gaGVyZSgnRGF0YScsJ2Jvc3Rvbi5jc3YnKQ0KYm9zdG9uIDwtIHJlYWRyOjpyZWFkX2NzdihwYXRoKQ0KYGBgDQoNCmBgYHtyfQ0KaGVhZChib3N0b24pDQpgYGANCg0KPGJyPjxicj4NCg0KIyMjIyMjICoqNS4gRmlsbCBpbiB0aGUgYmxhbmtzIHRvIHNwbGl0IHRoZSBkYXRhIGludG8gYSB0cmFpbmluZyBzZXQgYW5kIHRlc3Qgc2V0IHVzaW5nIGEgNzAtMzAlIHNwbGl0LiBCZSBzdXJlIHRvIGluY2x1ZGUgdGhlIHNldC5zZWVkKDEyMykgc28gdGhhdCB5b3VyIHRyYWluIGFuZCB0ZXN0IHNldHMgYXJlIHRoZSBzYW1lIHNpemUgYXMgbWluZS4qKg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpzcGxpdCA8LSBpbml0aWFsX3NwbGl0KGJvc3RvbiwgcHJvcCA9IDAuNywgc3RyYXRhID0gY21lZHYpDQp0cmFpbiA8LSB0cmFpbmluZyhzcGxpdCkNCnRlc3QgPC0gdGVzdGluZyhzcGxpdCkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIyMgKio2LiBIb3cgbWFueSBvYnNlcnZhdGlvbnMgYXJlIGluIHRoZSB0cmFpbmluZyBzZXQgYW5kIHRlc3Qgc2V0PyoqDQpUaGVyZSBhcmUgKipgciBucm93KHRyYWluKWAqKiBvYnNlcnZhdGlvbnMgaW4gdGhlICJ0cmFpbiIgZGF0YSBzZXQgYW5kICoqYHIgbnJvdyh0ZXN0KWAqKiBvYnNlcnZhdGlvbnMgDQppbiB0aGUgInRlc3QiIGRhdGEgc2V0Lg0KPGJyPjxicj4NCg0KIyMjIyMjICoqNy4gQ29tcGFyZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGNtZWR2IGJldHdlZW4gdGhlIHRyYWluaW5nIHNldCBhbmQgdGVzdCBzZXQuIERvIHRoZXkgYXBwZWFyIHRvIGhhdmUgdGhlIHNhbWUgZGlzdHJpYnV0aW9uIG9yIGRvIHRoZXkgZGlmZmVyIHNpZ25pZmljYW50bHk/KioNCmBgYHtyfQ0KdHJhaW4gJT4lIA0KICBtdXRhdGUoaWQgPSAndHJhaW4nKSAlPiUgDQogIGJpbmRfcm93cyh0ZXN0ICU+JSBtdXRhdGUoaWQgPSAndGVzdCcpKSAlPiUNCiAgZ2dwbG90KGFlcyhjbWVkdiwgY29sb3IgPSBpZCkpICsNCiAgZ2VvbV9kZW5zaXR5KCkNCmBgYA0KDQo8YnI+PGJyPg0KDQojIyMjIyMgKio4LiBGaWxsIGluIHRoZSBibGFua3MgdG8gZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgdGhlIHJtIGZlYXR1cmUgdmFyaWFibGUgdG8gcHJlZGljdCBjbWVkdiBhbmQgY29tcHV0ZSB0aGUgUk1TRSBvbiB0aGUgdGVzdCBkYXRhLiBXaGF0IGlzIHRoZSB0ZXN0IHNldCBSTVNFPyoqDQpgYGB7cn0NCiMgZml0IG1vZGVsDQpsbTEgPC0gbGluZWFyX3JlZygpICU+JQ0KICBmaXQoIGNtZWR2IH4gcm0sIGRhdGEgPSB0cmFpbikNCg0KIyBjb21wdXRlIHRoZSBSTVNFIG9uIHRoZSB0ZXN0IGRhdGENCnByZDEgPC0gbG0xICU+JQ0KICBwcmVkaWN0KHRlc3QpICU+JQ0KICBiaW5kX2NvbHModGVzdCAlPiUgc2VsZWN0KGNtZWR2KSkgJT4lDQogIHJtc2UodHJ1dGggPSBjbWVkdiwgZXN0aW1hdGUgPSAucHJlZCkNCg0KcHJkMQ0KYGBgDQpUaGUgdGVzdCBzZXQgUk1TRSBpcyAqKiQ2LDgzMDEqKiB3aGVuIHVzaW5nIHJtIChhdmVyYWdlIG51bWJlciBvZiByb29tcykgdG8gZXN0aW1hdGUgY21lZHYNCg0KPGJyPjxicj4NCg0KIyMjIyMjICoqOS4gRmlsbCBpbiB0aGUgYmxhbmtzIHRvIGZpdCBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIGFsbCBhdmFpbGFibGUgZmVhdHVyZXMgdG8gcHJlZGljdCBjbWVkdiBhbmQgY29tcHV0ZSB0aGUgUk1TRSBvbiB0aGUgdGVzdCBkYXRhLiBXaGF0IGlzIHRoZSB0ZXN0IHNldCBSTVNFPyBJcyB0aGlzIGJldHRlciB0aGFuIHRoZSBwcmV2aW91cyBtb2RlbOKAmXMgcGVyZm9ybWFuY2U/KioNCmBgYHtyfQ0KIyBmaXQgbW9kZWwNCmZlYXR1cmVzIDwtIGNvbG5hbWVzKGJvc3RvbltuYW1lcyhib3N0b24pICVpbiUgJ2NtZWR2JyA9PSBGQUxTRV0pDQoNCmxtMiA8LSBsaW5lYXJfcmVnKCkgJT4lDQogIGZpdCggY21lZHYgfiAuLCBkYXRhID0gdHJhaW5bLGMoImNtZWR2IixmZWF0dXJlcyldKQ0KDQojIGNvbXB1dGUgdGhlIFJNU0Ugb24gdGhlIHRlc3QgZGF0YQ0KbG0yICU+JQ0KICBwcmVkaWN0KHRlc3QpICU+JQ0KICBiaW5kX2NvbHModGVzdCAlPiUgc2VsZWN0KGNtZWR2KSkgJT4lDQogIHJtc2UodHJ1dGggPSBjbWVkdiwgZXN0aW1hdGUgPSAucHJlZCkNCmBgYA0KVGhlIHRlc3Qgc2V0IFJNU0UgaXMgKiokNCw4MjkqKiB3aGVuIHVzaW5nIGFsbCBmZWF0dXJlcyB0byBlc3RpbWF0ZSBjbWVkdi4gVGhpcyByZXByZXNlbnRzIGEgbmVhcmx5ICokMiwwMDAqIGluY3JlYXNlIGluIHRoZSBtb2RlbCdzIGFjY3VyYWN5LiANCjxicj48YnI+DQoNCiMjIyMjIyAqKjEwLiBGaXQgYSBLLW5lYXJlc3QgbmVpZ2hib3IgbW9kZWwgdGhhdCB1c2VzIGFsbCBhdmFpbGFibGUgZmVhdHVyZXMgdG8gcHJlZGljdCBjbWVkdiBhbmQgY29tcHV0ZSB0aGUgUk1TRSBvbiB0aGUgdGVzdCBkYXRhLiBXaGF0IGlzIHRoZSB0ZXN0IHNldCBSTVNFPyBJcyB0aGlzIGJldHRlciB0aGFuIHRoZSBwcmV2aW91cyB0d28gbW9kZWxz4oCZIHBlcmZvcm1hbmNlcz8qKg0KYGBge3J9DQojIGZpdCBtb2RlbA0Ka25uIDwtIG5lYXJlc3RfbmVpZ2hib3IoKSAlPiUNCiAgc2V0X2VuZ2luZSgia2tubiIpICU+JQ0KICBzZXRfbW9kZSgicmVncmVzc2lvbiIpICU+JQ0KICBmaXQoIGNtZWR2IH4gLiwgZGF0YSA9IHRyYWluWyxjKCJjbWVkdiIsZmVhdHVyZXMpXSkNCg0KIyBjb21wdXRlIHRoZSBSTVNFIG9uIHRoZSB0ZXN0IGRhdGENCmtubiAlPiUNCiAgcHJlZGljdCh0ZXN0KSAlPiUNCiAgYmluZF9jb2xzKHRlc3QgJT4lIHNlbGVjdChjbWVkdikpICU+JQ0KICBybXNlKHRydXRoID0gY21lZHYsIGVzdGltYXRlID0gLnByZWQpDQpgYGANClVzaW5nIEstTmVhcmVzdC1OZWlnaGJvciwgdGhlIHRlc3Qgc2V0IFJNU0UgaXMgKiokMywzNTcqKiAod2l0aCBhbGwgZmVhdHVyZXMgaW5jbHVkZWQpLiBUaGUga2tubiBtb2RlbHMgbWFpbnRhaW5zIGEgKiokMSw1MDAqKiBpbmNyZWFzZSBpbiBhY2N1cmFjeSBjb21wYXJlZCB0byBsaW5lYXIgcmVncmVzc2lvbiB1c2luZyBhbGwgZmVhdHVyZXMsIGFuZCBhICoqJDMsNTAwKiogaW5jcmVhc2UgaW4gYWNjcnVhY3kgY29tcGFyZWQgdG8gbGluZWFyIHJlZ3Jlc3Npb24gdXNpbmcgb25seSB0aGUgcm0gZmFjdG9yLiAgIA0KDQoNCg0KDQoNCg==