Setup

# Load the necessary packages required to reproduce the report. For example:

library(kableExtra)
library(magrittr)
library(dplyr)  
library(readr)
library(readxl)

Student names, numbers and percentage of contributions

Group information
Student name Student number Percentage of contribution
Hrishika Shrestha s4192201 100

Data Description

The datasets used here is taken from Kaggle. The dataset is titled “Stroke Prediction Dataset” in Kaggle. The link to the dataset: https://www.kaggle.com/datasets/fedesoriano/stroke-prediction-dataset

The dataset contains 11 clinical features that are used for predicting stroke. It contains the following variables:

Categorical Variables:

gender: “Male”, “Female” or “Other”
ever_married: “No” or “Yes”
work_type: “children”, “Govt_jov”, “Never_worked”, “Private” or “Self-employed”
Residence_type: “Rural” or “Urban”
smoking_status: “formerly smoked”, “never smoked”, “smokes” or “Unknown”

Numerical Variables:

id: unique identifier
age: Age of the patient
avg_glucose_level: average glucose level in blood
bmi: body mass index

Boolean Variables:

hypertension: 0 if the patient doesn’t have hypertension, 1 if the patient has hypertension
heart_disease: 0 if the patient doesn’t have any heart diseases, 1 if the patient has a heart disease
stroke: 1 if the patient had a stroke or 0 if not

Read/Import Data

# Read the dataset


stroke_data <- read.csv("C:\\Users\\Predator\\Downloads\\healthcare-dataset-stroke-data.csv")


# First 10 rows
head(stroke_data,10)

Inspect and Understand

Check the dimensions of the data frame.

Here at first the dimensions of the dataset is checked to know the total rows and columns present in the dataset used.

# Check the dimensions of the dataset
dim_result <- dim(stroke_data)
cat("Dimensions of the data frame: ", dim_result[1], "rows and", dim_result[2], "columns.\n")
Dimensions of the data frame:  5110 rows and 12 columns.

Check column names.

By using colnames(), we extracted the name of the columns of our dataset.

# check column names
col_names <- colnames(stroke_data)
print("Column names in the data frame: ")
[1] "Column names in the data frame: "
print(col_names)
 [1] "id"                "gender"            "age"               "hypertension"      "heart_disease"     "ever_married"      "work_type"        
 [8] "Residence_type"    "avg_glucose_level" "bmi"               "smoking_status"    "stroke"           

Check data types of variables

By using glimpse() the datatypes of each variables present in the dataset is checked, this gives data in a readable and compact format. Similarly, capture.output() function is used to capture the output of data and writelines() function to write the output in lines.

# check data types

cat("Structure of the data frame:\n")
Structure of the data frame:
output <- capture.output(glimpse(stroke_data))
writeLines(output)
Rows: 5,110
Columns: 12
$ id                <int> 9046, 51676, 31112, 60182, 1665, 56669, 53882, 10434, 27419, 60491, 12109, 12095, 12175, 8213, 5317, 58202, 56112, 34120, 274…
$ gender            <chr> "Male", "Female", "Male", "Female", "Female", "Male", "Male", "Female", "Female", "Female", "Female", "Female", "Female", "Ma…
$ age               <dbl> 67, 61, 80, 49, 79, 81, 74, 69, 59, 78, 81, 61, 54, 78, 79, 50, 64, 75, 60, 57, 71, 52, 79, 82, 71, 80, 65, 58, 69, 59, 57, 4…
$ hypertension      <int> 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0,…
$ heart_disease     <int> 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0,…
$ ever_married      <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "No", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", …
$ work_type         <chr> "Private", "Self-employed", "Private", "Private", "Self-employed", "Private", "Private", "Private", "Private", "Private", "Pr…
$ Residence_type    <chr> "Urban", "Rural", "Rural", "Urban", "Rural", "Urban", "Rural", "Urban", "Rural", "Urban", "Rural", "Rural", "Urban", "Urban",…
$ avg_glucose_level <dbl> 228.69, 202.21, 105.92, 171.23, 174.12, 186.21, 70.09, 94.39, 76.15, 58.57, 80.43, 120.46, 104.51, 219.84, 214.09, 167.41, 19…
$ bmi               <chr> "36.6", "N/A", "32.5", "34.4", "24", "29", "27.4", "22.8", "N/A", "24.2", "29.7", "36.8", "27.3", "N/A", "28.2", "30.9", "37.…
$ smoking_status    <chr> "formerly smoked", "never smoked", "never smoked", "smokes", "never smoked", "formerly smoked", "never smoked", "never smoked…
$ stroke            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…

Data Summary

# check data summary

summary_result <- summary(stroke_data)
print("Summary of the data:")
[1] "Summary of the data:"
print(summary_result)
       id           gender               age         hypertension     heart_disease     ever_married        work_type         Residence_type    
 Min.   :   67   Length:5110        Min.   : 0.08   Min.   :0.00000   Min.   :0.00000   Length:5110        Length:5110        Length:5110       
 1st Qu.:17741   Class :character   1st Qu.:25.00   1st Qu.:0.00000   1st Qu.:0.00000   Class :character   Class :character   Class :character  
 Median :36932   Mode  :character   Median :45.00   Median :0.00000   Median :0.00000   Mode  :character   Mode  :character   Mode  :character  
 Mean   :36518                      Mean   :43.23   Mean   :0.09746   Mean   :0.05401                                                           
 3rd Qu.:54682                      3rd Qu.:61.00   3rd Qu.:0.00000   3rd Qu.:0.00000                                                           
 Max.   :72940                      Max.   :82.00   Max.   :1.00000   Max.   :1.00000                                                           
 avg_glucose_level     bmi            smoking_status         stroke       
 Min.   : 55.12    Length:5110        Length:5110        Min.   :0.00000  
 1st Qu.: 77.25    Class :character   Class :character   1st Qu.:0.00000  
 Median : 91.89    Mode  :character   Mode  :character   Median :0.00000  
 Mean   :106.15                                          Mean   :0.04873  
 3rd Qu.:114.09                                          3rd Qu.:0.00000  
 Max.   :271.74                                          Max.   :1.00000  

Data Cleaning and Type Conversion

There are both categorical and numerical variables in the dataset. As an identifier (factor/character), id ought to be handled accordingly. While gender, ever_married, work_type, residence_type, and smoking_status should be factors, age, avg_glucose_level, and bmi are numerical. Heart disease, stroke, and hypertension should be classified as “No” and “Yes” variables since they are binary (0/1).


# Convert 'id' to factor since it's an identifier, not for numeric analysis
stroke_data$id <- as.factor(stroke_data$id)

# Convert 'gender' to factor (categorical variable)
stroke_data$gender <- as.factor(stroke_data$gender)

# Convert 'ever_married' to factor (categorical variable: Yes/No)
stroke_data$ever_married <- as.factor(stroke_data$ever_married)

# Convert 'work_type' to factor (categorical variable: Govt_job, Private, etc.)
stroke_data$work_type <- as.factor(stroke_data$work_type)

# Convert 'Residence_type' to factor (categorical variable: Rural/Urban)
stroke_data$Residence_type <- as.factor(stroke_data$Residence_type)

# Convert 'bmi' to numeric (continuous variable; may contain missing values)
stroke_data$bmi <- as.numeric(stroke_data$bmi)
G2;H2;Warningh: NAs introduced by coerciong
# Convert 'smoking_status' to factor (categorical variable: never smoked, formerly smoked, etc.)
stroke_data$smoking_status <- as.factor(stroke_data$smoking_status)

# Convert 'hypertension' from numeric 0/1 into factor with labels No/Yes
stroke_data$hypertension <- factor(as.numeric(as.character(stroke_data$hypertension)), 
                                   levels = c(0,1), labels = c("No","Yes"))

# Convert 'heart_disease' from numeric 0/1 into factor with labels No/Yes
stroke_data$heart_disease <- factor(as.numeric(as.character(stroke_data$heart_disease)), 
                                    levels = c(0,1), labels = c("No","Yes"))

# Convert 'stroke' from numeric 0/1 into factor with labels No/Yes
stroke_data$stroke <- factor(as.numeric(as.character(stroke_data$stroke)), 
                             levels = c(0,1), labels = c("No","Yes"))

# Check the structure of the dataset after type conversions
str(stroke_data)
'data.frame':   5110 obs. of  12 variables:
 $ id               : Factor w/ 5110 levels "67","77","84",..: 672 3611 2152 4227 115 3971 3767 749 1895 4244 ...
 $ gender           : Factor w/ 3 levels "Female","Male",..: 2 1 2 1 1 2 2 1 1 1 ...
 $ age              : num  67 61 80 49 79 81 74 69 59 78 ...
 $ hypertension     : Factor w/ 2 levels "No","Yes": 1 1 1 1 2 1 2 1 1 1 ...
 $ heart_disease    : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 1 2 1 1 1 ...
 $ ever_married     : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 1 2 2 ...
 $ work_type        : Factor w/ 5 levels "children","Govt_job",..: 4 5 4 4 5 4 4 4 4 4 ...
 $ Residence_type   : Factor w/ 2 levels "Rural","Urban": 2 1 1 2 1 2 1 2 1 2 ...
 $ avg_glucose_level: num  229 202 106 171 174 ...
 $ bmi              : num  36.6 NA 32.5 34.4 24 29 27.4 22.8 NA 24.2 ...
 $ smoking_status   : Factor w/ 4 levels "formerly smoked",..: 1 2 2 3 2 1 2 2 4 4 ...
 $ stroke           : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 2 2 2 2 2 ...

Subsetting

Using indexing, we retrieved the first ten rows and every column, then we transformed the subset into a matrix. All values were forced to character class in order to preserve consistency because data frames can have mixed types whereas matrices cannot.


# Subset your data and convert it to a matrix, provide R codes here.

# Subset first 10 rows
 subset_df <- stroke_data[1:10, ]
 # Convert to matrix
 matrix_data <- as.matrix(subset_df)
 # Check matrix structure
 str(matrix_data)
 chr [1:10, 1:12] "9046" "51676" "31112" "60182" "1665" "56669" "53882" "10434" "27419" "60491" "Male" "Female" "Male" "Female" "Female" "Male" ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:10] "1" "2" "3" "4" ...
  ..$ : chr [1:12] "id" "gender" "age" "hypertension" ...
print("First few rows of the matrix:")
[1] "First few rows of the matrix:"
print(head(matrix_data, 3))
  id      gender   age  hypertension heart_disease ever_married work_type       Residence_type avg_glucose_level bmi    smoking_status    stroke
1 "9046"  "Male"   "67" "No"         "Yes"         "Yes"        "Private"       "Urban"        "228.69"          "36.6" "formerly smoked" "Yes" 
2 "51676" "Female" "61" "No"         "No"          "Yes"        "Self-employed" "Rural"        "202.21"          NA     "never smoked"    "Yes" 
3 "31112" "Male"   "80" "No"         "Yes"         "Yes"        "Private"       "Rural"        "105.92"          "32.5" "never smoked"    "Yes" 

The structure changes to character once the first ten rows are selected and converted to a matrix since matrices can only hold one type of data and R automatically converts all variables to character because categorical variables are present.

Create a new Data Frame

We started by creating a tiny data frame with variables related to the risk of stroke. While the ordinal variable risk_level appropriately factorizes and orders stroke risk as Low, Medium, or High, the integer variable years_smoking reflects the number of years a patient has smoked. Next, we used cbind() to add a third numerical variable, bmi. Three variables with the proper kinds are included in the final data frame: an integer, an ordered factor, and a numeric variable.


# Integer variable: years the patient has smoked
years_smoking <- c(0, 5, 10, 2, 0, 15, 3, 1, 20, 8)

# Ordinal variable: stroke risk levels
risk_level <- c("Low", "Medium", "High", "Medium", "Low", 
                "High", "Medium", "Low", "High", "Medium")

# Convert risk_level to an ordered factor
risk_level <- factor(risk_level, 
                     levels = c("Low", "Medium", "High"), 
                     ordered = TRUE)

# Combine into a data frame
df <- data.frame(years_smoking, risk_level)

# Check structure
str(df)
'data.frame':   10 obs. of  2 variables:
 $ years_smoking: num  0 5 10 2 0 15 3 1 20 8
 $ risk_level   : Ord.factor w/ 3 levels "Low"<"Medium"<..: 1 2 3 2 1 3 2 1 3 2
# Check levels of the ordinal variable
levels(df$risk_level)
[1] "Low"    "Medium" "High"  

# Numeric variable: BMI values
bmi <- c(22.5, 27.8, 31.2, 24.7, 29.1, 26.3, 28.4, 23.9, 32.0, 25.5)

# Add BMI to the data frame
df <- cbind(df, bmi)

# Check structure
str(df)
'data.frame':   10 obs. of  3 variables:
 $ years_smoking: num  0 5 10 2 0 15 3 1 20 8
 $ risk_level   : Ord.factor w/ 3 levels "Low"<"Medium"<..: 1 2 3 2 1 3 2 1 3 2
 $ bmi          : num  22.5 27.8 31.2 24.7 29.1 26.3 28.4 23.9 32 25.5

Summary

Presentation

Presentation

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nIChEYXRhIFByZXByb2Nlc3NpbmcpIiANCmF1dGhvcjogIkhyaXNoaWthIFNocmVzdGhhIg0Kc3VidGl0bGU6IFByYWN0aWNhbCBhc3Nlc3NtZW50IDENCmRhdGU6ICIiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQgDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KLS0tDQoNCg0KIyMgKipTZXR1cCoqDQoNCmBgYHtyfQ0KIyBMb2FkIHRoZSBuZWNlc3NhcnkgcGFja2FnZXMgcmVxdWlyZWQgdG8gcmVwcm9kdWNlIHRoZSByZXBvcnQuIEZvciBleGFtcGxlOg0KDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShkcGx5cikgIA0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkocmVhZHhsKQ0KDQpgYGANCg0KDQojIyAqKlN0dWRlbnQgbmFtZXMsIG51bWJlcnMgYW5kIHBlcmNlbnRhZ2Ugb2YgY29udHJpYnV0aW9ucyoqDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KIyBBZGQgeW91ciBuYW1lcywgbnVtYmVycyBhbmQgcGVyY2VudGFnZSBvZiB5b3VyIGNvbnRyaWJ1dGlvbiBoZXJlLg0KDQpuYTwtIGMoIkhyaXNoaWthIFNocmVzdGhhIikNCm5vPC0gYygiczQxOTIyMDEiKQ0KcGM8LSBjKCIxMDAiKQ0KDQpzPC0gZGF0YS5mcmFtZShjYmluZChuYSxubyxwYykpDQpjb2xuYW1lcyhzKTwtIGMoIlN0dWRlbnQgbmFtZSIsICJTdHVkZW50IG51bWJlciIsICJQZXJjZW50YWdlIG9mIGNvbnRyaWJ1dGlvbiIpDQoNCnMgJT4lIGtibChjYXB0aW9uID0gIkdyb3VwIGluZm9ybWF0aW9uIikgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCg0KDQoNCmBgYA0KDQojIyAqKkRhdGEgRGVzY3JpcHRpb24qKg0KDQpUaGUgZGF0YXNldHMgdXNlZCBoZXJlIGlzIHRha2VuIGZyb20gS2FnZ2xlLiBUaGUgZGF0YXNldCBpcyB0aXRsZWQgIlN0cm9rZSBQcmVkaWN0aW9uIERhdGFzZXQiIGluIEthZ2dsZS4NClRoZSBsaW5rIHRvIHRoZSBkYXRhc2V0OiBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2ZlZGVzb3JpYW5vL3N0cm9rZS1wcmVkaWN0aW9uLWRhdGFzZXQNCg0KVGhlIGRhdGFzZXQgY29udGFpbnMgMTEgY2xpbmljYWwgZmVhdHVyZXMgdGhhdCBhcmUgdXNlZCBmb3IgcHJlZGljdGluZyBzdHJva2UuDQpJdCBjb250YWlucyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoNCg0KIyMjIENhdGVnb3JpY2FsIFZhcmlhYmxlczoNCg0KKipnZW5kZXIqKjogIk1hbGUiLCAiRmVtYWxlIiBvciAiT3RoZXIiPGJyPg0KKipldmVyX21hcnJpZWQqKjogIk5vIiBvciAiWWVzIjxicj4NCioqd29ya190eXBlKio6ICJjaGlsZHJlbiIsICJHb3Z0X2pvdiIsICJOZXZlcl93b3JrZWQiLCAiUHJpdmF0ZSIgb3IgIlNlbGYtZW1wbG95ZWQiPGJyPg0KKipSZXNpZGVuY2VfdHlwZSoqOiAiUnVyYWwiIG9yICJVcmJhbiI8YnI+DQoqKnNtb2tpbmdfc3RhdHVzKio6ICJmb3JtZXJseSBzbW9rZWQiLCAibmV2ZXIgc21va2VkIiwgInNtb2tlcyIgb3IgIlVua25vd24iPGJyPg0KDQojIyMgTnVtZXJpY2FsIFZhcmlhYmxlczoNCioqaWQqKjogdW5pcXVlIGlkZW50aWZpZXI8YnI+DQoqKmFnZSoqOiBBZ2Ugb2YgdGhlIHBhdGllbnQ8YnI+DQoqKmF2Z19nbHVjb3NlX2xldmVsKio6IGF2ZXJhZ2UgZ2x1Y29zZSBsZXZlbCBpbiBibG9vZDxicj4NCioqYm1pKio6IGJvZHkgbWFzcyBpbmRleDxicj4NCg0KDQojIyMgQm9vbGVhbiBWYXJpYWJsZXM6DQoNCioqaHlwZXJ0ZW5zaW9uKio6IDAgaWYgdGhlIHBhdGllbnQgZG9lc24ndCBoYXZlIGh5cGVydGVuc2lvbiwgMSBpZiB0aGUgcGF0aWVudCBoYXMgaHlwZXJ0ZW5zaW9uPGJyPg0KKipoZWFydF9kaXNlYXNlKio6IDAgaWYgdGhlIHBhdGllbnQgZG9lc24ndCBoYXZlIGFueSBoZWFydCBkaXNlYXNlcywgMSBpZiB0aGUgcGF0aWVudCBoYXMgYSBoZWFydCBkaXNlYXNlPGJyPg0KKipzdHJva2UqKjogMSBpZiB0aGUgcGF0aWVudCBoYWQgYSBzdHJva2Ugb3IgMCBpZiBub3Q8YnI+DQoNCiMjICoqUmVhZC9JbXBvcnQgRGF0YSoqDQoNCg0KYGBge3J9DQojIFJlYWQgdGhlIGRhdGFzZXQNCg0KZGYgPSAiQzpcXFVzZXJzXFxQcmVkYXRvclxcRG93bmxvYWRzXFxoZWFsdGhjYXJlLWRhdGFzZXQtc3Ryb2tlLWRhdGEuY3N2Ig0Kc3Ryb2tlX2RhdGEgPC0gcmVhZC5jc3YoZGYpDQoNCiMgRmlyc3QgMTAgcm93cw0KaGVhZChzdHJva2VfZGF0YSwxMCkNCmBgYA0KDQoNCiMjICoqSW5zcGVjdCBhbmQgVW5kZXJzdGFuZCoqDQoNCiMjIyBDaGVjayB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZGF0YSBmcmFtZS4gDQoNCkhlcmUgYXQgZmlyc3QgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIGRhdGFzZXQgaXMgY2hlY2tlZCB0byBrbm93IHRoZSB0b3RhbCByb3dzIGFuZCBjb2x1bW5zIHByZXNlbnQgaW4gdGhlIGRhdGFzZXQgdXNlZC4NCmBgYHtyfQ0KIyBDaGVjayB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZGF0YXNldA0KZGltX3Jlc3VsdCA8LSBkaW0oc3Ryb2tlX2RhdGEpDQpjYXQoIkRpbWVuc2lvbnMgb2YgdGhlIGRhdGEgZnJhbWU6ICIsIGRpbV9yZXN1bHRbMV0sICJyb3dzIGFuZCIsIGRpbV9yZXN1bHRbMl0sICJjb2x1bW5zLlxuIikNCmBgYA0KIyMjIENoZWNrIGNvbHVtbiBuYW1lcy4gDQoNCkJ5IHVzaW5nIGBjb2xuYW1lcygpYCwgd2UgZXh0cmFjdGVkIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW5zIG9mIG91ciBkYXRhc2V0Lg0KYGBge3J9DQojIGNoZWNrIGNvbHVtbiBuYW1lcw0KY29sX25hbWVzIDwtIGNvbG5hbWVzKHN0cm9rZV9kYXRhKQ0KcHJpbnQoIkNvbHVtbiBuYW1lcyBpbiB0aGUgZGF0YSBmcmFtZTogIikNCnByaW50KGNvbF9uYW1lcykNCmBgYA0KIyMjIENoZWNrIGRhdGEgdHlwZXMgb2YgdmFyaWFibGVzDQoNCkJ5IHVzaW5nIGBnbGltcHNlKClgIHRoZSBkYXRhdHlwZXMgb2YgZWFjaCB2YXJpYWJsZXMgcHJlc2VudCBpbiB0aGUgZGF0YXNldCBpcyBjaGVja2VkLCB0aGlzIGdpdmVzIGRhdGEgaW4gYSByZWFkYWJsZSBhbmQgY29tcGFjdCBmb3JtYXQuIFNpbWlsYXJseSwgYGNhcHR1cmUub3V0cHV0KClgIGZ1bmN0aW9uIGlzIHVzZWQgdG8gY2FwdHVyZSB0aGUgb3V0cHV0IG9mIGRhdGEgYW5kIGB3cml0ZWxpbmVzKClgIGZ1bmN0aW9uIHRvIHdyaXRlIHRoZSBvdXRwdXQgaW4gbGluZXMuIA0KDQoNCmBgYHtyfQ0KIyBjaGVjayBkYXRhIHR5cGVzDQoNCmNhdCgiU3RydWN0dXJlIG9mIHRoZSBkYXRhIGZyYW1lOlxuIikNCm91dHB1dCA8LSBjYXB0dXJlLm91dHB1dChnbGltcHNlKHN0cm9rZV9kYXRhKSkNCndyaXRlTGluZXMob3V0cHV0KQ0KYGBgDQojIyMgRGF0YSBTdW1tYXJ5DQoNCmBgYHtyfQ0KIyBjaGVjayBkYXRhIHN1bW1hcnkNCg0Kc3VtbWFyeV9yZXN1bHQgPC0gc3VtbWFyeShzdHJva2VfZGF0YSkNCnByaW50KCJTdW1tYXJ5IG9mIHRoZSBkYXRhOiIpDQpwcmludChzdW1tYXJ5X3Jlc3VsdCkNCmBgYA0KDQojIyBEYXRhIENsZWFuaW5nIGFuZCBUeXBlIENvbnZlcnNpb24NCg0KVGhlcmUgYXJlIGJvdGggY2F0ZWdvcmljYWwgYW5kIG51bWVyaWNhbCB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQuIEFzIGFuIGlkZW50aWZpZXIgKGZhY3Rvci9jaGFyYWN0ZXIpLCBpZCBvdWdodCB0byBiZSBoYW5kbGVkIGFjY29yZGluZ2x5LiBXaGlsZSBnZW5kZXIsIGV2ZXJfbWFycmllZCwgd29ya190eXBlLCByZXNpZGVuY2VfdHlwZSwgYW5kIHNtb2tpbmdfc3RhdHVzIHNob3VsZCBiZSBmYWN0b3JzLCBhZ2UsIGF2Z19nbHVjb3NlX2xldmVsLCBhbmQgYm1pIGFyZSBudW1lcmljYWwuIEhlYXJ0IGRpc2Vhc2UsIHN0cm9rZSwgYW5kIGh5cGVydGVuc2lvbiBzaG91bGQgYmUgY2xhc3NpZmllZCBhcyAiTm8iIGFuZCAiWWVzIiB2YXJpYWJsZXMgc2luY2UgdGhleSBhcmUgYmluYXJ5ICgwLzEpLg0KDQoNCmBgYHtyfQ0KDQojIENvbnZlcnQgJ2lkJyB0byBmYWN0b3Igc2luY2UgaXQncyBhbiBpZGVudGlmaWVyLCBub3QgZm9yIG51bWVyaWMgYW5hbHlzaXMNCnN0cm9rZV9kYXRhJGlkIDwtIGFzLmZhY3RvcihzdHJva2VfZGF0YSRpZCkNCg0KIyBDb252ZXJ0ICdnZW5kZXInIHRvIGZhY3RvciAoY2F0ZWdvcmljYWwgdmFyaWFibGUpDQpzdHJva2VfZGF0YSRnZW5kZXIgPC0gYXMuZmFjdG9yKHN0cm9rZV9kYXRhJGdlbmRlcikNCg0KIyBDb252ZXJ0ICdldmVyX21hcnJpZWQnIHRvIGZhY3RvciAoY2F0ZWdvcmljYWwgdmFyaWFibGU6IFllcy9ObykNCnN0cm9rZV9kYXRhJGV2ZXJfbWFycmllZCA8LSBhcy5mYWN0b3Ioc3Ryb2tlX2RhdGEkZXZlcl9tYXJyaWVkKQ0KDQojIENvbnZlcnQgJ3dvcmtfdHlwZScgdG8gZmFjdG9yIChjYXRlZ29yaWNhbCB2YXJpYWJsZTogR292dF9qb2IsIFByaXZhdGUsIGV0Yy4pDQpzdHJva2VfZGF0YSR3b3JrX3R5cGUgPC0gYXMuZmFjdG9yKHN0cm9rZV9kYXRhJHdvcmtfdHlwZSkNCg0KIyBDb252ZXJ0ICdSZXNpZGVuY2VfdHlwZScgdG8gZmFjdG9yIChjYXRlZ29yaWNhbCB2YXJpYWJsZTogUnVyYWwvVXJiYW4pDQpzdHJva2VfZGF0YSRSZXNpZGVuY2VfdHlwZSA8LSBhcy5mYWN0b3Ioc3Ryb2tlX2RhdGEkUmVzaWRlbmNlX3R5cGUpDQoNCiMgQ29udmVydCAnYm1pJyB0byBudW1lcmljIChjb250aW51b3VzIHZhcmlhYmxlOyBtYXkgY29udGFpbiBtaXNzaW5nIHZhbHVlcykNCnN0cm9rZV9kYXRhJGJtaSA8LSBhcy5udW1lcmljKHN0cm9rZV9kYXRhJGJtaSkNCg0KIyBDb252ZXJ0ICdzbW9raW5nX3N0YXR1cycgdG8gZmFjdG9yIChjYXRlZ29yaWNhbCB2YXJpYWJsZTogbmV2ZXIgc21va2VkLCBmb3JtZXJseSBzbW9rZWQsIGV0Yy4pDQpzdHJva2VfZGF0YSRzbW9raW5nX3N0YXR1cyA8LSBhcy5mYWN0b3Ioc3Ryb2tlX2RhdGEkc21va2luZ19zdGF0dXMpDQoNCiMgQ29udmVydCAnaHlwZXJ0ZW5zaW9uJyBmcm9tIG51bWVyaWMgMC8xIGludG8gZmFjdG9yIHdpdGggbGFiZWxzIE5vL1llcw0Kc3Ryb2tlX2RhdGEkaHlwZXJ0ZW5zaW9uIDwtIGZhY3Rvcihhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzdHJva2VfZGF0YSRoeXBlcnRlbnNpb24pKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoMCwxKSwgbGFiZWxzID0gYygiTm8iLCJZZXMiKSkNCg0KIyBDb252ZXJ0ICdoZWFydF9kaXNlYXNlJyBmcm9tIG51bWVyaWMgMC8xIGludG8gZmFjdG9yIHdpdGggbGFiZWxzIE5vL1llcw0Kc3Ryb2tlX2RhdGEkaGVhcnRfZGlzZWFzZSA8LSBmYWN0b3IoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3Ryb2tlX2RhdGEkaGVhcnRfZGlzZWFzZSkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoMCwxKSwgbGFiZWxzID0gYygiTm8iLCJZZXMiKSkNCg0KIyBDb252ZXJ0ICdzdHJva2UnIGZyb20gbnVtZXJpYyAwLzEgaW50byBmYWN0b3Igd2l0aCBsYWJlbHMgTm8vWWVzDQpzdHJva2VfZGF0YSRzdHJva2UgPC0gZmFjdG9yKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHN0cm9rZV9kYXRhJHN0cm9rZSkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygwLDEpLCBsYWJlbHMgPSBjKCJObyIsIlllcyIpKQ0KDQojIENoZWNrIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQgYWZ0ZXIgdHlwZSBjb252ZXJzaW9ucw0Kc3RyKHN0cm9rZV9kYXRhKQ0KDQpgYGANCg0KIyMgKipTdWJzZXR0aW5nKiogDQoNClVzaW5nIGluZGV4aW5nLCB3ZSByZXRyaWV2ZWQgdGhlIGZpcnN0IHRlbiByb3dzIGFuZCBldmVyeSBjb2x1bW4sIHRoZW4gd2UgdHJhbnNmb3JtZWQgdGhlIHN1YnNldCBpbnRvIGEgbWF0cml4LiBBbGwgdmFsdWVzIHdlcmUgZm9yY2VkIHRvIGNoYXJhY3RlciBjbGFzcyBpbiBvcmRlciB0byBwcmVzZXJ2ZSBjb25zaXN0ZW5jeSBiZWNhdXNlIGRhdGEgZnJhbWVzIGNhbiBoYXZlIG1peGVkIHR5cGVzIHdoZXJlYXMgbWF0cmljZXMgY2Fubm90Lg0KDQpgYGB7cn0NCg0KIyBTdWJzZXQgeW91ciBkYXRhIGFuZCBjb252ZXJ0IGl0IHRvIGEgbWF0cml4LCBwcm92aWRlIFIgY29kZXMgaGVyZS4NCg0KIyBTdWJzZXQgZmlyc3QgMTAgcm93cw0KIHN1YnNldF9kZiA8LSBzdHJva2VfZGF0YVsxOjEwLCBdDQogIyBDb252ZXJ0IHRvIG1hdHJpeA0KIG1hdHJpeF9kYXRhIDwtIGFzLm1hdHJpeChzdWJzZXRfZGYpDQogIyBDaGVjayBtYXRyaXggc3RydWN0dXJlDQogc3RyKG1hdHJpeF9kYXRhKQ0KDQpgYGANCg0KYGBge3J9DQpwcmludCgiRmlyc3QgZmV3IHJvd3Mgb2YgdGhlIG1hdHJpeDoiKQ0KcHJpbnQoaGVhZChtYXRyaXhfZGF0YSwgMykpDQpgYGANClRoZSBzdHJ1Y3R1cmUgY2hhbmdlcyB0byBjaGFyYWN0ZXIgb25jZSB0aGUgZmlyc3QgdGVuIHJvd3MgYXJlIHNlbGVjdGVkIGFuZCBjb252ZXJ0ZWQgdG8gYSBtYXRyaXggc2luY2UgbWF0cmljZXMgY2FuIG9ubHkgaG9sZCBvbmUgdHlwZSBvZiBkYXRhIGFuZCBSIGF1dG9tYXRpY2FsbHkgY29udmVydHMgYWxsIHZhcmlhYmxlcyB0byBjaGFyYWN0ZXIgYmVjYXVzZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYXJlIHByZXNlbnQuDQoNCiMjICoqQ3JlYXRlIGEgbmV3IERhdGEgRnJhbWUqKg0KDQpXZSBzdGFydGVkIGJ5IGNyZWF0aW5nIGEgdGlueSBkYXRhIGZyYW1lIHdpdGggdmFyaWFibGVzIHJlbGF0ZWQgdG8gdGhlIHJpc2sgb2Ygc3Ryb2tlLiAgV2hpbGUgdGhlIG9yZGluYWwgdmFyaWFibGUgYHJpc2tfbGV2ZWxgIGFwcHJvcHJpYXRlbHkgZmFjdG9yaXplcyBhbmQgb3JkZXJzIHN0cm9rZSByaXNrIGFzIExvdywgTWVkaXVtLCBvciBIaWdoLCB0aGUgaW50ZWdlciB2YXJpYWJsZSBgeWVhcnNfc21va2luZ2AgcmVmbGVjdHMgdGhlIG51bWJlciBvZiB5ZWFycyBhIHBhdGllbnQgaGFzIHNtb2tlZC4gIE5leHQsIHdlIHVzZWQgYGNiaW5kKClgIHRvIGFkZCBhIHRoaXJkIG51bWVyaWNhbCB2YXJpYWJsZSwgYGJtaWAuICBUaHJlZSB2YXJpYWJsZXMgd2l0aCB0aGUgcHJvcGVyIGtpbmRzIGFyZSBpbmNsdWRlZCBpbiB0aGUgZmluYWwgZGF0YSBmcmFtZTogYW4gaW50ZWdlciwgYW4gb3JkZXJlZCBmYWN0b3IsIGFuZCBhIG51bWVyaWMgdmFyaWFibGUuDQoNCmBgYHtyfQ0KDQojIEludGVnZXIgdmFyaWFibGU6IHllYXJzIHRoZSBwYXRpZW50IGhhcyBzbW9rZWQNCnllYXJzX3Ntb2tpbmcgPC0gYygwLCA1LCAxMCwgMiwgMCwgMTUsIDMsIDEsIDIwLCA4KQ0KDQojIE9yZGluYWwgdmFyaWFibGU6IHN0cm9rZSByaXNrIGxldmVscw0Kcmlza19sZXZlbCA8LSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giLCAiTWVkaXVtIiwgIkxvdyIsIA0KICAgICAgICAgICAgICAgICJIaWdoIiwgIk1lZGl1bSIsICJMb3ciLCAiSGlnaCIsICJNZWRpdW0iKQ0KDQojIENvbnZlcnQgcmlza19sZXZlbCB0byBhbiBvcmRlcmVkIGZhY3Rvcg0Kcmlza19sZXZlbCA8LSBmYWN0b3Iocmlza19sZXZlbCwgDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwgDQogICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkNCg0KIyBDb21iaW5lIGludG8gYSBkYXRhIGZyYW1lDQpkZiA8LSBkYXRhLmZyYW1lKHllYXJzX3Ntb2tpbmcsIHJpc2tfbGV2ZWwpDQoNCiMgQ2hlY2sgc3RydWN0dXJlDQpzdHIoZGYpDQoNCiMgQ2hlY2sgbGV2ZWxzIG9mIHRoZSBvcmRpbmFsIHZhcmlhYmxlDQpsZXZlbHMoZGYkcmlza19sZXZlbCkNCg0KYGBgDQpgYGB7cn0NCg0KIyBOdW1lcmljIHZhcmlhYmxlOiBCTUkgdmFsdWVzDQpibWkgPC0gYygyMi41LCAyNy44LCAzMS4yLCAyNC43LCAyOS4xLCAyNi4zLCAyOC40LCAyMy45LCAzMi4wLCAyNS41KQ0KDQojIEFkZCBCTUkgdG8gdGhlIGRhdGEgZnJhbWUNCmRmIDwtIGNiaW5kKGRmLCBibWkpDQoNCiMgQ2hlY2sgc3RydWN0dXJlDQpzdHIoZGYpDQpgYGANCiMjCSoqU3VtbWFyeSAqKg0KDQoNCg0KIyMJKipQcmVzZW50YXRpb24gKioNCg0KW1ByZXNlbnRhdGlvbl0oKQ0KDQoNCg==