STAT 452 Homework1 Ulziibat Tserenbat February 2, 2019

Machine learning is a method of data analysis that automates analytical model building. It is a branch of artificial intelligence based on the idea that systems can learn from data, identify patterns and make decisions with minimal human intervention.

Statistical learning theory is a framework for machine learning drawing from the fields of statistics and functional analysis.

Predictive analytics is the practice of extracting information from existing data sets in order to determine patterns and predict future outcomes and trends. Predictive analytics does not tell you what will happen in the future.

In the field of computer science, artificial intelligence (AI), sometimes called machine intelligence, is intelligence demonstrated by machines, in contrast to the natural intelligence displayed by humans and other animals.

Deep learning (also known as deep structured learning or hierarchical learning) is part of a broader family of machine learning methods based on learning data representations, as opposed to task-specific algorithms.

This book provides clear and intuitive guidance on how to implement cutting edge statistical and machine learning methods.

Chapter 2

This is an R Notebook with the code from Machine Learning with R, Lantz.

Blog post about Projects and Notebooks

Prime Hings for Running A Data Project in R

Good website for learning about R.

Quick-R

Chapter 2: Managing and Understanding Data

Libraries

library(here)
library(lattice)
library(corrgram)
library(gmodels)
here::here()
[1] "C:/Users/Harold.KCG-HAROLD/Downloads/Chap02/Chap02"

R data structures

Vectors

create vectors of data for three medical patients

subject_name <- c("John Doe", "Jane Doe", "Steve Graves")
temperature <- c(98.1, 98.6, 101.4)
flu_status <- c(FALSE, FALSE, TRUE)

access the second element in body temperature vector

temperature[2]
[1] 98.6

examples of accessing items in vector

include items in the range 2 to 3

temperature[2:3]
[1]  98.6 101.4

exclude item 2 using the minus sign

rr temperature[-2]

[1]  98.1 101.4

use a vector to indicate whether to include item

temperature[c(TRUE, TRUE, FALSE)]
[1] 98.1 98.6

Factors

add gender factor

gender <- factor(c("MALE", "FEMALE", "MALE"))
gender
[1] MALE   FEMALE MALE  
Levels: FEMALE MALE

add blood type factor

blood <- factor(c("O", "AB", "A"),
                levels = c("A", "B", "AB", "O"))
blood
[1] O  AB A 
Levels: A B AB O

add ordered factor

symptoms <- factor(c("SEVERE", "MILD", "MODERATE"),
                   levels = c("MILD", "MODERATE", "SEVERE"),
                   ordered = TRUE)
symptoms
[1] SEVERE   MILD     MODERATE
Levels: MILD < MODERATE < SEVERE

check for symptoms greater than moderate

symptoms > "MODERATE"
[1]  TRUE FALSE FALSE

Lists

display information for a patient

subject_name[1]
[1] "John Doe"
temperature[1]
[1] 98.1
flu_status[1]
[1] FALSE
gender[1]
[1] MALE
Levels: FEMALE MALE
blood[1]
[1] O
Levels: A B AB O
symptoms[1]
[1] SEVERE
3 Levels: MILD < ... < SEVERE

create list for a patient and display the patient

subject1 <- list(fullname = subject_name[1], 
                 temperature = temperature[1],
                 flu_status = flu_status[1],
                 gender = gender[1],
                 blood = blood[1],
                 symptoms = symptoms[1])
subject1
$`fullname`
[1] "John Doe"

$temperature
[1] 98.1

$flu_status
[1] FALSE

$gender
[1] MALE
Levels: FEMALE MALE

$blood
[1] O
Levels: A B AB O

$symptoms
[1] SEVERE
Levels: MILD < MODERATE < SEVERE

methods for accessing a list

get a single list value by position (returns a sub-list)

subject1[2]
$`temperature`
[1] 98.1

get a single list value by position (returns a numeric vector)

subject1[[2]]
[1] 98.1

get a single list value by name

subject1$temperature
[1] 98.1

get several list items by specifying a vector of names

subject1[c("temperature", "flu_status")]
$`temperature`
[1] 98.1

$flu_status
[1] FALSE

access a list like a vector get values 2 and 3

rr subject1[2:3]

$temperature
[1] 98.1

$flu_status
[1] FALSE

Data frames

create a data frame from medical patient data and display the data frame

pt_data <- data.frame(subject_name, temperature, flu_status, gender,
                      blood, symptoms, stringsAsFactors = FALSE)
pt_data

accessing a data frame

get a single column

pt_data$subject_name
[1] "John Doe"     "Jane Doe"     "Steve Graves"

get several columns by specifying a vector of names

pt_data[c("temperature", "flu_status")]

this is the same as above, extracting temperature and flu_status

pt_data[2:3]

accessing by row and column

pt_data[1, 2]
[1] 98.1

accessing several rows and several columns using vectors

pt_data[c(1, 3), c(2, 4)]

Leave a row or column blank to extract all rows or columns

rr # column 1, all rows pt_data[, 1]

[1] \John Doe\     \Jane Doe\     \Steve Graves\

rr # row 1, all columns pt_data[1, ] r # all rows and all columns pt_data[ , ]

the following are equivalent

rr pt_data[c(1, 3), c(, )] r pt_data[-2, c(-1, -3, -5, -6)]

Matrixes

create a 2x2 matrix

rr m <- matrix(c(1, 2, 3, 4), nrow = 2) m

     [,1] [,2]
[1,]    1    3
[2,]    2    4

equivalent to the above

rr m <- matrix(c(1, 2, 3, 4), ncol = 2) m

     [,1] [,2]
[1,]    1    3
[2,]    2    4

create a 2x3 matrix

rr m <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 2) m

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

create a 3x2 matrix

m <- matrix(c(1, 2, 3, 4, 5, 6), ncol = 2)
m
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

extract values from matrixes

m[1, 1]
[1] 1
m[3, 2]
[1] 6

extract rows

m[1, ]
[1] 1 4

extract columns

m[, 1]
[1] 1 2 3

Managing data with R

saving, loading, and removing R data structures

show all data structures in memory

ls()
 [1] "blood"        "flu_status"  
 [3] "gender"       "m"           
 [5] "model_table"  "pt_data"     
 [7] "subject_name" "symptoms"    
 [9] "temperature"  "usedcars"    

remove the m and subject1 objects

rm(m, subject1)
object 'subject1' not found
ls()
[1] "blood"        "flu_status"  
[3] "gender"       "model_table" 
[5] "pt_data"      "subject_name"
[7] "symptoms"     "temperature" 
[9] "usedcars"    
rm(list=ls())

Exploring and understanding data

data exploration example using used car data

usedcars <- read.csv("usedcars.csv", stringsAsFactors = FALSE)

get structure of used car data

str(usedcars)
'data.frame':   150 obs. of  6 variables:
 $ year        : int  2011 2011 2011 2011 2012 2010 2011 2010 2011 2010 ...
 $ model       : chr  "SEL" "SEL" "SEL" "SEL" ...
 $ price       : int  21992 20995 19995 17809 17500 17495 17000 16995 16995 16995 ...
 $ mileage     : int  7413 10926 7351 11613 8367 25125 27393 21026 32655 36116 ...
 $ color       : chr  "Yellow" "Gray" "Silver" "Gray" ...
 $ transmission: chr  "AUTO" "AUTO" "AUTO" "AUTO" ...

Exploring numeric variables

summarize numeric variables

rr summary(usedcars$year)

   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   2000    2008    2009    2009    2010    2012 

rr summary(usedcars[c(, )])

     price          mileage      
 Min.   : 3800   Min.   :  4867  
 1st Qu.:10995   1st Qu.: 27200  
 Median :13592   Median : 36385  
 Mean   :12962   Mean   : 44261  
 3rd Qu.:14904   3rd Qu.: 55124  
 Max.   :21992   Max.   :151479  

calculate the mean income

rr (36000 + 44000 + 56000) / 3

[1] 45333.33

rr mean(c(36000, 44000, 56000))

[1] 45333.33

the median income

rr median(c(36000, 44000, 56000))

[1] 44000

the min/max of used car prices

rr range(usedcars$price)

[1]  3800 21992

the difference of the range

rr diff(range(usedcars$price))

[1] 18192

IQR for used car prices

rr IQR(usedcars$price)

[1] 3909.5

use quantile to calculate five-number summary

rr quantile(usedcars$price)

     0%     25%     50%     75%    100% 
 3800.0 10995.0 13591.5 14904.5 21992.0 

the 99th percentile

rr quantile(usedcars$price, probs = c(0.01, 0.99))

      1%      99% 
 5428.69 20505.00 

quintiles

rr quantile(usedcars$price, seq(from = 0, to = 1, by = 0.20))

     0%     20%     40%     60%     80%    100% 
 3800.0 10759.4 12993.8 13992.0 14999.0 21992.0 

boxplot of used car prices and mileage

boxplot(usedcars$price, main="Boxplot of Used Car Prices",
      ylab="Price ($)")

boxplot(usedcars$price ~ usedcars$transmission, main="Boxplot of Used Car Prices by Transmission",
      ylab="Price ($)")

using the lattice package

rr lattice::bwplot(usedcars\(price~usedcars\)transmission, ylab=, xlab=, main=by Transmission)

rr usedcars\(year <- as.character(usedcars\)year) lattice::bwplot(usedcars\(price~usedcars\)transmission|usedcars$year, ylab=, xlab=, main=by Transmission and Year, layout=(c(5,3)))

rr boxplot(usedcars$mileage, main=of Used Car Mileage, ylab=(mi.))

rr boxplot(usedcars\(mileage ~ usedcars\)transmission, main=of Used Car Mileage by Transmission, ylab=(mi.))

histograms of used car prices and mileage

rr hist(usedcars\(price, main = \Histogram of Used Car Prices\, xlab = \Price (\)))

rr hist(usedcars$mileage, main = of Used Car Mileage, xlab = (mi.))

rr lattice::histogram(~ usedcars$price, xlab=, main=of Price)

rr usedcars\(year <- as.character(usedcars\)year) lattice::histogram(~ usedcars\(price | usedcars\)year, ylab=, xlab=, main=of Price by Year, layout=(c(5,3)))

rr lattice::histogram(~ usedcars$mileage, xlab=, main=of Mileage)

rr usedcars\(year <- as.character(usedcars\)year) lattice::histogram(~ usedcars\(mileage | usedcars\)year, xlab=, main=of Mileage by Year, layout=(c(5,3)))

variance and standard deviation of the used car data

rr var(usedcars$price)

[1] 9749892

rr sd(usedcars$price)

[1] 3122.482

rr var(usedcars$mileage)

[1] 728033954

rr sd(usedcars$mileage)

[1] 26982.1

Exploring numeric variables

one-way tables for the used car data

table(usedcars$year)

2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 
   3    1    1    1    3    2    6   11   14   42   49   16    1 
table(usedcars$model)

 SE SEL SES 
 78  23  49 
table(usedcars$color)

 Black   Blue   Gold   Gray  Green    Red Silver  White Yellow 
    35     17      1     16      5     25     32     16      3 

compute table proportions

model_table <- table(usedcars$model)
prop.table(model_table)

       SE       SEL       SES 
0.5200000 0.1533333 0.3266667 

round the data

rr color_table <- table(usedcars$color) color_pct <- prop.table(color_table) * 100 round(color_pct, digits = 1)


 Black   Blue   Gold   Gray  Green    Red Silver  White Yellow 
  23.3   11.3    0.7   10.7    3.3   16.7   21.3   10.7    2.0 

Exploring relationships between variables

correlation

rr cor(x = usedcars\(mileage, y = usedcars\)price)

[1] -0.8061494

scatterplot of price vs. mileage

rr plot(x = usedcars\(mileage, y = usedcars\)price, main = of Price vs. Mileage, xlab = Car Odometer (mi.), ylab = Car Price ($))

The corrgram package has the corrgram function that is nice for looking at relationships between numeric variable.

rr corrgram::corrgram(usedcars,lower.panel=panel.ellipse, upper.panel=panel.pts)

new variable indicating conservative colors

rr usedcars\(conservative <- usedcars\)color %in% c(, , , )

checking our variable

rr table(usedcars$conservative)


FALSE  TRUE 
   51    99 

Crosstab of conservative by model

rr gmodels::CrossTable(x = usedcars\(model, y = usedcars\)conservative)


 
   Cell Contents
|-------------------------|
|                       N |
| Chi-square contribution |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  150 

 
               | usedcars$conservative 
usedcars$model |     FALSE |      TRUE | Row Total | 
---------------|-----------|-----------|-----------|
            SE |        27 |        51 |        78 | 
               |     0.009 |     0.004 |           | 
               |     0.346 |     0.654 |     0.520 | 
               |     0.529 |     0.515 |           | 
               |     0.180 |     0.340 |           | 
---------------|-----------|-----------|-----------|
           SEL |         7 |        16 |        23 | 
               |     0.086 |     0.044 |           | 
               |     0.304 |     0.696 |     0.153 | 
               |     0.137 |     0.162 |           | 
               |     0.047 |     0.107 |           | 
---------------|-----------|-----------|-----------|
           SES |        17 |        32 |        49 | 
               |     0.007 |     0.004 |           | 
               |     0.347 |     0.653 |     0.327 | 
               |     0.333 |     0.323 |           | 
               |     0.113 |     0.213 |           | 
---------------|-----------|-----------|-----------|
  Column Total |        51 |        99 |       150 | 
               |     0.340 |     0.660 |           | 
---------------|-----------|-----------|-----------|

 
LS0tDQp0aXRsZTogIkhvbWV3b3JrIDEiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KU1RBVCA0NTIgSG9tZXdvcmsxDQpVbHppaWJhdCBUc2VyZW5iYXQNCkZlYnJ1YXJ5IDIsIDIwMTkgDQoNCg0KTWFjaGluZSBsZWFybmluZyBpcyBhIG1ldGhvZCBvZiBkYXRhIGFuYWx5c2lzIHRoYXQgYXV0b21hdGVzIGFuYWx5dGljYWwgbW9kZWwgYnVpbGRpbmcuIEl0IGlzIGEgYnJhbmNoIG9mIGFydGlmaWNpYWwgaW50ZWxsaWdlbmNlIGJhc2VkIG9uIHRoZSBpZGVhIHRoYXQgc3lzdGVtcyBjYW4gbGVhcm4gZnJvbSBkYXRhLCBpZGVudGlmeSBwYXR0ZXJucyBhbmQgbWFrZSBkZWNpc2lvbnMgd2l0aCBtaW5pbWFsIGh1bWFuIGludGVydmVudGlvbi4NCg0KU3RhdGlzdGljYWwgbGVhcm5pbmcgdGhlb3J5IGlzIGEgZnJhbWV3b3JrIGZvciBtYWNoaW5lIGxlYXJuaW5nIGRyYXdpbmcgZnJvbSB0aGUgZmllbGRzIG9mIHN0YXRpc3RpY3MgYW5kIGZ1bmN0aW9uYWwgYW5hbHlzaXMuDQoNClByZWRpY3RpdmUgYW5hbHl0aWNzIGlzIHRoZSBwcmFjdGljZSBvZiBleHRyYWN0aW5nIGluZm9ybWF0aW9uIGZyb20gZXhpc3RpbmcgZGF0YSBzZXRzIGluIG9yZGVyIHRvIGRldGVybWluZSBwYXR0ZXJucyBhbmQgcHJlZGljdCBmdXR1cmUgb3V0Y29tZXMgYW5kIHRyZW5kcy4gUHJlZGljdGl2ZSBhbmFseXRpY3MgZG9lcyBub3QgdGVsbCB5b3Ugd2hhdCB3aWxsIGhhcHBlbiBpbiB0aGUgZnV0dXJlLg0KDQpJbiB0aGUgZmllbGQgb2YgY29tcHV0ZXIgc2NpZW5jZSwgYXJ0aWZpY2lhbCBpbnRlbGxpZ2VuY2UgKEFJKSwgc29tZXRpbWVzIGNhbGxlZCBtYWNoaW5lIGludGVsbGlnZW5jZSwgaXMgaW50ZWxsaWdlbmNlIGRlbW9uc3RyYXRlZCBieSBtYWNoaW5lcywgaW4gY29udHJhc3QgdG8gdGhlIG5hdHVyYWwgaW50ZWxsaWdlbmNlIGRpc3BsYXllZCBieSBodW1hbnMgYW5kIG90aGVyIGFuaW1hbHMuDQoNCkRlZXAgbGVhcm5pbmcgKGFsc28ga25vd24gYXMgZGVlcCBzdHJ1Y3R1cmVkIGxlYXJuaW5nIG9yIGhpZXJhcmNoaWNhbCBsZWFybmluZykgaXMgcGFydCBvZiBhIGJyb2FkZXIgZmFtaWx5IG9mIG1hY2hpbmUgbGVhcm5pbmcgbWV0aG9kcyBiYXNlZCBvbiBsZWFybmluZyBkYXRhIHJlcHJlc2VudGF0aW9ucywgYXMgb3Bwb3NlZCB0byB0YXNrLXNwZWNpZmljIGFsZ29yaXRobXMuDQoNClRoaXMgYm9vayBwcm92aWRlcyBjbGVhciBhbmQgaW50dWl0aXZlIGd1aWRhbmNlIG9uIGhvdyB0byBpbXBsZW1lbnQgY3V0dGluZyBlZGdlIHN0YXRpc3RpY2FsIGFuZCBtYWNoaW5lIGxlYXJuaW5nIG1ldGhvZHMuDQoNCiMgQ2hhcHRlciAyDQoNClRoaXMgaXMgYW4gUiBOb3RlYm9vayB3aXRoIHRoZSBjb2RlIGZyb20gTWFjaGluZSBMZWFybmluZyB3aXRoIFIsIExhbnR6Lg0KDQoNCiMjIEJsb2cgcG9zdCBhYm91dCBQcm9qZWN0cyBhbmQgTm90ZWJvb2tzIA0KDQpbUHJpbWUgSGluZ3MgZm9yIFJ1bm5pbmcgQSBEYXRhIFByb2plY3QgaW4gUl0oaHR0cHM6Ly9ra3VsbWEuZ2l0aHViLmlvLzIwMTgtMDMtMTgtUHJpbWUtSGludHMtZm9yLVJ1bm5pbmctYS1kYXRhLXByb2plY3QtaW4tUi8pDQoNCiMjIEdvb2Qgd2Vic2l0ZSBmb3IgbGVhcm5pbmcgYWJvdXQgUi4NCg0KW1F1aWNrLVJdKGh0dHBzOi8vd3d3LnN0YXRtZXRob2RzLm5ldC8pDQoNCiMgQ2hhcHRlciAyOiBNYW5hZ2luZyBhbmQgVW5kZXJzdGFuZGluZyBEYXRhDQoNCioqTGlicmFyaWVzKioNCg0KYGBge3J9DQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGxhdHRpY2UpDQpsaWJyYXJ5KGNvcnJncmFtKQ0KbGlicmFyeShnbW9kZWxzKQ0KYGBgDQoNCmBgYHtyfQ0KaGVyZTo6aGVyZSgpDQpgYGANCg0KDQojIyBSIGRhdGEgc3RydWN0dXJlcyANCg0KKipWZWN0b3JzKioNCg0KY3JlYXRlIHZlY3RvcnMgb2YgZGF0YSBmb3IgdGhyZWUgbWVkaWNhbCBwYXRpZW50cw0KDQpgYGB7cn0NCnN1YmplY3RfbmFtZSA8LSBjKCJKb2huIERvZSIsICJKYW5lIERvZSIsICJTdGV2ZSBHcmF2ZXMiKQ0KdGVtcGVyYXR1cmUgPC0gYyg5OC4xLCA5OC42LCAxMDEuNCkNCmZsdV9zdGF0dXMgPC0gYyhGQUxTRSwgRkFMU0UsIFRSVUUpDQpgYGANCg0KYWNjZXNzIHRoZSBzZWNvbmQgZWxlbWVudCBpbiBib2R5IHRlbXBlcmF0dXJlIHZlY3Rvcg0KDQpgYGB7cn0NCnRlbXBlcmF0dXJlWzJdDQpgYGANCg0KZXhhbXBsZXMgb2YgYWNjZXNzaW5nIGl0ZW1zIGluIHZlY3Rvcg0KDQppbmNsdWRlIGl0ZW1zIGluIHRoZSByYW5nZSAyIHRvIDMNCg0KYGBge3J9DQp0ZW1wZXJhdHVyZVsyOjNdDQpgYGANCg0KZXhjbHVkZSBpdGVtIDIgdXNpbmcgdGhlIG1pbnVzIHNpZ24NCg0KYGBge3J9DQp0ZW1wZXJhdHVyZVstMl0NCmBgYA0KDQp1c2UgYSB2ZWN0b3IgdG8gaW5kaWNhdGUgd2hldGhlciB0byBpbmNsdWRlIGl0ZW0NCg0KYGBge3J9DQp0ZW1wZXJhdHVyZVtjKFRSVUUsIFRSVUUsIEZBTFNFKV0NCmBgYA0KDQojIyBGYWN0b3JzIA0KDQphZGQgZ2VuZGVyIGZhY3Rvcg0KDQpgYGB7cn0NCmdlbmRlciA8LSBmYWN0b3IoYygiTUFMRSIsICJGRU1BTEUiLCAiTUFMRSIpKQ0KZ2VuZGVyDQpgYGANCg0KYWRkIGJsb29kIHR5cGUgZmFjdG9yDQoNCmBgYHtyfQ0KDQpibG9vZCA8LSBmYWN0b3IoYygiTyIsICJBQiIsICJBIiksDQogICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQSIsICJCIiwgIkFCIiwgIk8iKSkNCmJsb29kDQpgYGANCg0KYWRkIG9yZGVyZWQgZmFjdG9yDQoNCmBgYHtyfQ0Kc3ltcHRvbXMgPC0gZmFjdG9yKGMoIlNFVkVSRSIsICJNSUxEIiwgIk1PREVSQVRFIiksDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTUlMRCIsICJNT0RFUkFURSIsICJTRVZFUkUiKSwNCiAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkNCnN5bXB0b21zDQpgYGANCg0KY2hlY2sgZm9yIHN5bXB0b21zIGdyZWF0ZXIgdGhhbiBtb2RlcmF0ZQ0KDQpgYGB7cn0NCnN5bXB0b21zID4gIk1PREVSQVRFIg0KYGBgDQoNCiMjIExpc3RzIA0KDQpkaXNwbGF5IGluZm9ybWF0aW9uIGZvciBhIHBhdGllbnQNCg0KYGBge3J9DQpzdWJqZWN0X25hbWVbMV0NCnRlbXBlcmF0dXJlWzFdDQpmbHVfc3RhdHVzWzFdDQpnZW5kZXJbMV0NCmJsb29kWzFdDQpzeW1wdG9tc1sxXQ0KDQpgYGANCg0KY3JlYXRlIGxpc3QgZm9yIGEgcGF0aWVudCBhbmQgZGlzcGxheSB0aGUgcGF0aWVudA0KDQpgYGB7cn0NCg0Kc3ViamVjdDEgPC0gbGlzdChmdWxsbmFtZSA9IHN1YmplY3RfbmFtZVsxXSwgDQogICAgICAgICAgICAgICAgIHRlbXBlcmF0dXJlID0gdGVtcGVyYXR1cmVbMV0sDQogICAgICAgICAgICAgICAgIGZsdV9zdGF0dXMgPSBmbHVfc3RhdHVzWzFdLA0KICAgICAgICAgICAgICAgICBnZW5kZXIgPSBnZW5kZXJbMV0sDQogICAgICAgICAgICAgICAgIGJsb29kID0gYmxvb2RbMV0sDQogICAgICAgICAgICAgICAgIHN5bXB0b21zID0gc3ltcHRvbXNbMV0pDQpzdWJqZWN0MQ0KDQpgYGANCg0KbWV0aG9kcyBmb3IgYWNjZXNzaW5nIGEgbGlzdA0KDQpnZXQgYSBzaW5nbGUgbGlzdCB2YWx1ZSBieSBwb3NpdGlvbiAocmV0dXJucyBhIHN1Yi1saXN0KQ0KDQpgYGB7cn0NCnN1YmplY3QxWzJdDQoNCmBgYA0KDQpnZXQgYSBzaW5nbGUgbGlzdCB2YWx1ZSBieSBwb3NpdGlvbiAocmV0dXJucyBhIG51bWVyaWMgdmVjdG9yKQ0KDQpgYGB7cn0NCnN1YmplY3QxW1syXV0NCmBgYA0KDQpnZXQgYSBzaW5nbGUgbGlzdCB2YWx1ZSBieSBuYW1lDQoNCmBgYHtyfQ0Kc3ViamVjdDEkdGVtcGVyYXR1cmUNCmBgYA0KDQpnZXQgc2V2ZXJhbCBsaXN0IGl0ZW1zIGJ5IHNwZWNpZnlpbmcgYSB2ZWN0b3Igb2YgbmFtZXMNCg0KYGBge3J9DQpzdWJqZWN0MVtjKCJ0ZW1wZXJhdHVyZSIsICJmbHVfc3RhdHVzIildDQpgYGANCg0KYWNjZXNzIGEgbGlzdCBsaWtlIGEgdmVjdG9yDQpnZXQgdmFsdWVzIDIgYW5kIDMNCg0KYGBge3J9DQpzdWJqZWN0MVsyOjNdDQpgYGANCg0KIyMgRGF0YSBmcmFtZXMgDQoNCmNyZWF0ZSBhIGRhdGEgZnJhbWUgZnJvbSBtZWRpY2FsIHBhdGllbnQgZGF0YSBhbmQgZGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KDQpgYGB7cn0NCnB0X2RhdGEgPC0gZGF0YS5mcmFtZShzdWJqZWN0X25hbWUsIHRlbXBlcmF0dXJlLCBmbHVfc3RhdHVzLCBnZW5kZXIsDQogICAgICAgICAgICAgICAgICAgICAgYmxvb2QsIHN5bXB0b21zLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpwdF9kYXRhDQpgYGANCg0KYWNjZXNzaW5nIGEgZGF0YSBmcmFtZQ0KDQpnZXQgYSBzaW5nbGUgY29sdW1uDQoNCmBgYHtyfQ0KcHRfZGF0YSRzdWJqZWN0X25hbWUNCg0KYGBgDQoNCmdldCBzZXZlcmFsIGNvbHVtbnMgYnkgc3BlY2lmeWluZyBhIHZlY3RvciBvZiBuYW1lcw0KDQpgYGB7cn0NCnB0X2RhdGFbYygidGVtcGVyYXR1cmUiLCAiZmx1X3N0YXR1cyIpXQ0KYGBgDQoNCnRoaXMgaXMgdGhlIHNhbWUgYXMgYWJvdmUsIGV4dHJhY3RpbmcgdGVtcGVyYXR1cmUgYW5kIGZsdV9zdGF0dXMNCg0KYGBge3J9DQpwdF9kYXRhWzI6M10NCmBgYA0KDQphY2Nlc3NpbmcgYnkgcm93IGFuZCBjb2x1bW4NCg0KYGBge3J9DQpwdF9kYXRhWzEsIDJdDQpgYGANCg0KYWNjZXNzaW5nIHNldmVyYWwgcm93cyBhbmQgc2V2ZXJhbCBjb2x1bW5zIHVzaW5nIHZlY3RvcnMNCg0KYGBge3J9DQpwdF9kYXRhW2MoMSwgMyksIGMoMiwgNCldDQpgYGANCg0KTGVhdmUgYSByb3cgb3IgY29sdW1uIGJsYW5rIHRvIGV4dHJhY3QgYWxsIHJvd3Mgb3IgY29sdW1ucw0KDQpgYGB7cn0NCiMgY29sdW1uIDEsIGFsbCByb3dzDQpwdF9kYXRhWywgMV0NCiMgcm93IDEsIGFsbCBjb2x1bW5zDQpwdF9kYXRhWzEsIF0NCiMgYWxsIHJvd3MgYW5kIGFsbCBjb2x1bW5zDQpwdF9kYXRhWyAsIF0NCmBgYA0KDQp0aGUgZm9sbG93aW5nIGFyZSBlcXVpdmFsZW50DQoNCmBgYHtyfQ0KcHRfZGF0YVtjKDEsIDMpLCBjKCJ0ZW1wZXJhdHVyZSIsICJnZW5kZXIiKV0NCnB0X2RhdGFbLTIsIGMoLTEsIC0zLCAtNSwgLTYpXQ0KYGBgDQoNCiMjIE1hdHJpeGVzIA0KDQpjcmVhdGUgYSAyeDIgbWF0cml4DQoNCmBgYHtyfQ0KbSA8LSBtYXRyaXgoYygxLCAyLCAzLCA0KSwgbnJvdyA9IDIpDQptDQpgYGANCg0KZXF1aXZhbGVudCB0byB0aGUgYWJvdmUNCg0KYGBge3J9DQptIDwtIG1hdHJpeChjKDEsIDIsIDMsIDQpLCBuY29sID0gMikNCm0NCmBgYA0KDQpjcmVhdGUgYSAyeDMgbWF0cml4DQoNCmBgYHtyfQ0KbSA8LSBtYXRyaXgoYygxLCAyLCAzLCA0LCA1LCA2KSwgbnJvdyA9IDIpDQptDQpgYGANCg0KY3JlYXRlIGEgM3gyIG1hdHJpeA0KDQpgYGB7cn0NCm0gPC0gbWF0cml4KGMoMSwgMiwgMywgNCwgNSwgNiksIG5jb2wgPSAyKQ0KbQ0KYGBgDQoNCmV4dHJhY3QgdmFsdWVzIGZyb20gbWF0cml4ZXMNCg0KYGBge3J9DQptWzEsIDFdDQptWzMsIDJdDQpgYGANCg0KZXh0cmFjdCByb3dzDQoNCmBgYHtyfQ0KbVsxLCBdDQpgYGANCg0KZXh0cmFjdCBjb2x1bW5zDQoNCmBgYHtyfQ0KbVssIDFdDQpgYGANCg0KIyMgTWFuYWdpbmcgZGF0YSB3aXRoIFIgDQoNCnNhdmluZywgbG9hZGluZywgYW5kIHJlbW92aW5nIFIgZGF0YSBzdHJ1Y3R1cmVzDQoNCnNob3cgYWxsIGRhdGEgc3RydWN0dXJlcyBpbiBtZW1vcnkNCg0KYGBge3J9DQpscygpDQpgYGANCg0KcmVtb3ZlIHRoZSBtIGFuZCBzdWJqZWN0MSBvYmplY3RzDQoNCmBgYHtyfQ0Kcm0obSwgc3ViamVjdDEpDQpscygpDQpgYGANCg0KYGBge3J9DQpybShsaXN0PWxzKCkpDQpgYGANCg0KIyMgRXhwbG9yaW5nIGFuZCB1bmRlcnN0YW5kaW5nIGRhdGEgDQoNCmRhdGEgZXhwbG9yYXRpb24gZXhhbXBsZSB1c2luZyB1c2VkIGNhciBkYXRhDQoNCmBgYHtyfQ0KdXNlZGNhcnMgPC0gcmVhZC5jc3YoInVzZWRjYXJzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCmBgYA0KDQpnZXQgc3RydWN0dXJlIG9mIHVzZWQgY2FyIGRhdGENCg0KYGBge3J9DQpzdHIodXNlZGNhcnMpDQpgYGANCg0KIyMgRXhwbG9yaW5nIG51bWVyaWMgdmFyaWFibGVzIA0KDQpzdW1tYXJpemUgbnVtZXJpYyB2YXJpYWJsZXMNCg0KYGBge3J9DQpzdW1tYXJ5KHVzZWRjYXJzJHllYXIpDQpzdW1tYXJ5KHVzZWRjYXJzW2MoInByaWNlIiwgIm1pbGVhZ2UiKV0pDQpgYGANCg0KY2FsY3VsYXRlIHRoZSBtZWFuIGluY29tZQ0KDQpgYGB7cn0NCigzNjAwMCArIDQ0MDAwICsgNTYwMDApIC8gMw0KbWVhbihjKDM2MDAwLCA0NDAwMCwgNTYwMDApKQ0KYGBgDQoNCnRoZSBtZWRpYW4gaW5jb21lDQoNCmBgYHtyfQ0KbWVkaWFuKGMoMzYwMDAsIDQ0MDAwLCA1NjAwMCkpDQpgYGANCg0KdGhlIG1pbi9tYXggb2YgdXNlZCBjYXIgcHJpY2VzDQoNCmBgYHtyfQ0KcmFuZ2UodXNlZGNhcnMkcHJpY2UpDQpgYGANCg0KdGhlIGRpZmZlcmVuY2Ugb2YgdGhlIHJhbmdlDQoNCmBgYHtyfQ0KZGlmZihyYW5nZSh1c2VkY2FycyRwcmljZSkpDQpgYGANCg0KSVFSIGZvciB1c2VkIGNhciBwcmljZXMNCg0KYGBge3J9DQpJUVIodXNlZGNhcnMkcHJpY2UpDQpgYGANCg0KdXNlIHF1YW50aWxlIHRvIGNhbGN1bGF0ZSBmaXZlLW51bWJlciBzdW1tYXJ5DQoNCmBgYHtyfQ0KcXVhbnRpbGUodXNlZGNhcnMkcHJpY2UpDQoNCmBgYA0KDQp0aGUgOTl0aCBwZXJjZW50aWxlDQoNCmBgYHtyfQ0KcXVhbnRpbGUodXNlZGNhcnMkcHJpY2UsIHByb2JzID0gYygwLjAxLCAwLjk5KSkNCmBgYA0KDQpxdWludGlsZXMNCmBgYHtyfQ0KcXVhbnRpbGUodXNlZGNhcnMkcHJpY2UsIHNlcShmcm9tID0gMCwgdG8gPSAxLCBieSA9IDAuMjApKQ0KYGBgDQoNCmJveHBsb3Qgb2YgdXNlZCBjYXIgcHJpY2VzIGFuZCBtaWxlYWdlDQoNCmBgYHtyfQ0KYm94cGxvdCh1c2VkY2FycyRwcmljZSwgbWFpbj0iQm94cGxvdCBvZiBVc2VkIENhciBQcmljZXMiLA0KICAgICAgeWxhYj0iUHJpY2UgKCQpIikNCmJveHBsb3QodXNlZGNhcnMkcHJpY2UgfiB1c2VkY2FycyR0cmFuc21pc3Npb24sIG1haW49IkJveHBsb3Qgb2YgVXNlZCBDYXIgUHJpY2VzIGJ5IFRyYW5zbWlzc2lvbiIsDQogICAgICB5bGFiPSJQcmljZSAoJCkiKQ0KDQpgYGANCg0KdXNpbmcgdGhlIGxhdHRpY2UgcGFja2FnZQ0KDQpgYGB7cn0NCmxhdHRpY2U6OmJ3cGxvdCh1c2VkY2FycyRwcmljZX51c2VkY2FycyR0cmFuc21pc3Npb24sDQogICB5bGFiPSJQcmljZSIsIHhsYWI9IlRyYW5zbWlzc2lvbiIsDQogICBtYWluPSJQcmljZSBieSBUcmFuc21pc3Npb24iKQ0KYGBgDQoNCg0KYGBge3J9DQp1c2VkY2FycyR5ZWFyIDwtIGFzLmNoYXJhY3Rlcih1c2VkY2FycyR5ZWFyKQ0KDQpsYXR0aWNlOjpid3Bsb3QodXNlZGNhcnMkcHJpY2V+dXNlZGNhcnMkdHJhbnNtaXNzaW9ufHVzZWRjYXJzJHllYXIsDQogICB5bGFiPSJQcmljZSIsIHhsYWI9IlRyYW5zbWlzc2lvbiIsDQogICBtYWluPSJQcmljZSBieSBUcmFuc21pc3Npb24gYW5kIFllYXIiLCBsYXlvdXQ9KGMoNSwzKSkpDQpgYGANCg0KDQpgYGB7cn0NCmJveHBsb3QodXNlZGNhcnMkbWlsZWFnZSwgbWFpbj0iQm94cGxvdCBvZiBVc2VkIENhciBNaWxlYWdlIiwNCiAgICAgIHlsYWI9Ik9kb21ldGVyIChtaS4pIikNCg0KYm94cGxvdCh1c2VkY2FycyRtaWxlYWdlIH4gdXNlZGNhcnMkdHJhbnNtaXNzaW9uLCBtYWluPSJCb3hwbG90IG9mIFVzZWQgQ2FyIE1pbGVhZ2UgYnkgVHJhbnNtaXNzaW9uIiwgeWxhYj0iT2RvbWV0ZXIgKG1pLikiKQ0KYGBgDQoNCg0KDQpoaXN0b2dyYW1zIG9mIHVzZWQgY2FyIHByaWNlcyBhbmQgbWlsZWFnZQ0KDQpgYGB7cn0NCg0KaGlzdCh1c2VkY2FycyRwcmljZSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgVXNlZCBDYXIgUHJpY2VzIiwNCiAgICAgeGxhYiA9ICJQcmljZSAoJCkiKQ0KDQpoaXN0KHVzZWRjYXJzJG1pbGVhZ2UsIG1haW4gPSAiSGlzdG9ncmFtIG9mIFVzZWQgQ2FyIE1pbGVhZ2UiLA0KICAgICB4bGFiID0gIk9kb21ldGVyIChtaS4pIikNCmBgYA0KDQpgYGB7cn0NCmxhdHRpY2U6Omhpc3RvZ3JhbSh+IHVzZWRjYXJzJHByaWNlLA0KICAgeGxhYj0iUHJpY2UiLA0KICAgbWFpbj0iRGlzdHJpYnV0aW9uIG9mIFByaWNlIikNCmBgYA0KDQoNCmBgYHtyfQ0KDQp1c2VkY2FycyR5ZWFyIDwtIGFzLmNoYXJhY3Rlcih1c2VkY2FycyR5ZWFyKQ0KDQpsYXR0aWNlOjpoaXN0b2dyYW0ofiB1c2VkY2FycyRwcmljZSB8IHVzZWRjYXJzJHllYXIsDQogICB5bGFiPSJQcmljZSIsIHhsYWI9IlByaWNlIiwNCiAgIG1haW49IkRpc3RyaWJ1dGlvbiBvZiBQcmljZSBieSBZZWFyIiwgbGF5b3V0PShjKDUsMykpKQ0KYGBgDQoNCmBgYHtyfQ0KbGF0dGljZTo6aGlzdG9ncmFtKH4gdXNlZGNhcnMkbWlsZWFnZSwNCiAgIHhsYWI9Ik1pbGVhZ2FnZSIsDQogICBtYWluPSJEaXN0cmlidXRpb24gb2YgTWlsZWFnZSIpDQpgYGANCg0KDQpgYGB7cn0NCg0KdXNlZGNhcnMkeWVhciA8LSBhcy5jaGFyYWN0ZXIodXNlZGNhcnMkeWVhcikNCg0KbGF0dGljZTo6aGlzdG9ncmFtKH4gdXNlZGNhcnMkbWlsZWFnZSB8IHVzZWRjYXJzJHllYXIsDQogICB4bGFiPSJNaWxlYWdlIiwNCiAgIG1haW49IkRpc3RyaWJ1dGlvbiBvZiBNaWxlYWdlIGJ5IFllYXIiLCBsYXlvdXQ9KGMoNSwzKSkpDQpgYGANCg0KdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgdXNlZCBjYXIgZGF0YQ0KDQpgYGB7cn0NCnZhcih1c2VkY2FycyRwcmljZSkNCnNkKHVzZWRjYXJzJHByaWNlKQ0KdmFyKHVzZWRjYXJzJG1pbGVhZ2UpDQpzZCh1c2VkY2FycyRtaWxlYWdlKQ0KYGBgDQoNCiMjIEV4cGxvcmluZyBudW1lcmljIHZhcmlhYmxlcw0KDQpvbmUtd2F5IHRhYmxlcyBmb3IgdGhlIHVzZWQgY2FyIGRhdGENCg0KYGBge3J9DQoNCnRhYmxlKHVzZWRjYXJzJHllYXIpDQp0YWJsZSh1c2VkY2FycyRtb2RlbCkNCnRhYmxlKHVzZWRjYXJzJGNvbG9yKQ0KYGBgDQoNCmNvbXB1dGUgdGFibGUgcHJvcG9ydGlvbnMNCg0KYGBge3J9DQptb2RlbF90YWJsZSA8LSB0YWJsZSh1c2VkY2FycyRtb2RlbCkNCnByb3AudGFibGUobW9kZWxfdGFibGUpDQpgYGANCg0Kcm91bmQgdGhlIGRhdGENCg0KYGBge3J9DQpjb2xvcl90YWJsZSA8LSB0YWJsZSh1c2VkY2FycyRjb2xvcikNCmNvbG9yX3BjdCA8LSBwcm9wLnRhYmxlKGNvbG9yX3RhYmxlKSAqIDEwMA0Kcm91bmQoY29sb3JfcGN0LCBkaWdpdHMgPSAxKQ0KYGBgDQoNCiMjIEV4cGxvcmluZyByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzDQoNCmNvcnJlbGF0aW9uDQoNCmBgYHtyfQ0KY29yKHggPSB1c2VkY2FycyRtaWxlYWdlLCB5ID0gdXNlZGNhcnMkcHJpY2UpDQpgYGANCg0KDQoNCnNjYXR0ZXJwbG90IG9mIHByaWNlIHZzLiBtaWxlYWdlDQoNCmBgYHtyfQ0KcGxvdCh4ID0gdXNlZGNhcnMkbWlsZWFnZSwgeSA9IHVzZWRjYXJzJHByaWNlLA0KICAgICBtYWluID0gIlNjYXR0ZXJwbG90IG9mIFByaWNlIHZzLiBNaWxlYWdlIiwNCiAgICAgeGxhYiA9ICJVc2VkIENhciBPZG9tZXRlciAobWkuKSIsDQogICAgIHlsYWIgPSAiVXNlZCBDYXIgUHJpY2UgKCQpIikNCmBgYA0KDQpUaGUgY29ycmdyYW0gcGFja2FnZSBoYXMgdGhlIGNvcnJncmFtIGZ1bmN0aW9uIHRoYXQgaXMgbmljZSBmb3IgbG9va2luZyBhdCByZWxhdGlvbnNoaXBzIGJldHdlZW4gbnVtZXJpYyB2YXJpYWJsZS4NCg0KYGBge3J9DQpjb3JyZ3JhbTo6Y29ycmdyYW0odXNlZGNhcnMsbG93ZXIucGFuZWw9cGFuZWwuZWxsaXBzZSwNCiAgdXBwZXIucGFuZWw9cGFuZWwucHRzKQ0KYGBgDQoNCg0KbmV3IHZhcmlhYmxlIGluZGljYXRpbmcgY29uc2VydmF0aXZlIGNvbG9ycw0KDQpgYGB7cn0NCnVzZWRjYXJzJGNvbnNlcnZhdGl2ZSA8LQ0KICB1c2VkY2FycyRjb2xvciAlaW4lIGMoIkJsYWNrIiwgIkdyYXkiLCAiU2lsdmVyIiwgIldoaXRlIikNCmBgYA0KDQpjaGVja2luZyBvdXIgdmFyaWFibGUNCmBgYHtyfQ0KdGFibGUodXNlZGNhcnMkY29uc2VydmF0aXZlKQ0KYGBgDQoNCkNyb3NzdGFiIG9mIGNvbnNlcnZhdGl2ZSBieSBtb2RlbA0KDQpgYGB7cn0NCmdtb2RlbHM6OkNyb3NzVGFibGUoeCA9IHVzZWRjYXJzJG1vZGVsLCB5ID0gdXNlZGNhcnMkY29uc2VydmF0aXZlKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==