Notebook Instructions


Load Packages in R/RStudio

We are going to use tidyverse a collection of R packages designed for data science.


Task 1: Quantitative Analysis


1A) Read the csv file into R Studio and display the dataset.

  • Name your dataset ‘mydata’ so it easy to work with.

  • Commands: read_csv() head() max() min() var() sd()

Extract the assigned features (columns) to perform some analytics.

mydata <- read.csv("data/Advertising.csv")
head(mydata)

Change the variable name “X1” to case_number using the function rename()

  • mydata <- rename(mydata, “NEW_VAR_NAME” = “OLD_VAR_NAME”)
mydata <- rename(mydata, "case_number" = "X")

1B) Find the range ( difference between min and max ), min, max, standard deviation and variance for each assigned feature ( Use separate chunks for each feature ). Compare each feature and note any significant differences

CASE NUMBER

case_number_max <- max(mydata$case_number)
case_number_max
[1] 200
case_number_min <- min(mydata$case_number)
case_number_min
[1] 1
case_number_range <-range(case_number_max - case_number_min)
case_number_range
[1] 199 199
case_number_mean <- mean(mydata$case_number)
case_number_mean
[1] 100.5
case_number_sd <- sd(mydata$case_number)
case_number_sd
[1] 57.87918
case_number_variance <- var(mydata$case_number)
case_number_variance
[1] 3350

There is a large range for case_number at nearly 200. SALES

#variable_max
sales_max <- max(mydata$sales)
sales_max
[1] 27
#variable_min
sales_min <- min(mydata$sales)
sales_min
[1] 1.6
#variable_Range max-min
sales_range <- range(sales_max - sales_min)
sales_range
[1] 25.4 25.4
#variable_mean 
sales_mean <- mean(mydata$sales)
sales_mean
[1] 14.0225
#variable_sd Standard Deviation
sales_sd <- sd(mydata$sales)
sales_sd
[1] 5.217457
#variable_variance
sales_variance <- var(mydata$sales)
sales_variance
[1] 27.22185

Sales has a relatively smaller range in contrast to case_number and the smallest sd.

RADIO

#variable_max
radio_max <- max(mydata$radio)
radio_max
[1] 49.6
#variable_min
radio_min <- min(mydata$radio)
radio_min
[1] 0
#variable_Range max-min
radio_range <- range(radio_max - radio_min)
radio_range
[1] 49.6 49.6
#variable_mean 
radio_mean <- mean(mydata$radio)
radio_mean
[1] 23.264
#variable_sd Standard Deviation
radio_sd <- sd(mydata$radio)
radio_sd
[1] 14.84681
#variable_variance
radio_variance <- var(mydata$radio)
radio_variance
[1] 220.4277

Radio has a smaller variance in comparison to other variables.

TV

#variable_max
tv_max <- max(mydata$TV)
tv_max
[1] 296.4
#variable_min
tv_min <- min(mydata$TV)
tv_min
[1] 0.7
#variable_Range max-min
tv_range <- range(tv_max - tv_min)
tv_range
[1] 295.7 295.7
#variable_mean 
tv_mean <- mean(mydata$TV)
tv_mean
[1] 147.0425
#variable_sd Standard Deviation
tv_sd <- sd(mydata$TV)
tv_sd
[1] 85.85424
#variable_variance
tv_variance <- var(mydata$TV)
tv_variance
[1] 7370.95

NEWSPAPER

#variable_max
newspaper_max <- max(mydata$newspaper)
newspaper_max
[1] 114
#variable_min
newspaper_min <- min(mydata$newspaper)
newspaper_min
[1] 0.3
#variable_Range max-min
newspaper_range <- range(newspaper_max - newspaper_min)
newspaper_range
[1] 113.7 113.7
#variable_mean 
newspaper_mean <- mean(mydata$newspaper)
newspaper_mean
[1] 30.554
#variable_sd Standard Deviation
newspaper_sd <- sd(mydata$newspaper)
newspaper_sd
[1] 21.77862
#variable_variance
newspaper_variance <- var(mydata$newspaper)
newspaper_variance
[1] 474.3083

Newspaper is comaprable to the other variables and a small s.d. (close to sales’s s.d.)

1C) Use the summary() function on all the dataset to give you a general description of the data. Note any differences between features.

summary(mydata)
  case_number           TV             radio          newspaper          sales      
 Min.   :  1.00   Min.   :  0.70   Min.   : 0.000   Min.   :  0.30   Min.   : 1.60  
 1st Qu.: 50.75   1st Qu.: 74.38   1st Qu.: 9.975   1st Qu.: 12.75   1st Qu.:10.38  
 Median :100.50   Median :149.75   Median :22.900   Median : 25.75   Median :12.90  
 Mean   :100.50   Mean   :147.04   Mean   :23.264   Mean   : 30.55   Mean   :14.02  
 3rd Qu.:150.25   3rd Qu.:218.82   3rd Qu.:36.525   3rd Qu.: 45.10   3rd Qu.:17.40  
 Max.   :200.00   Max.   :296.40   Max.   :49.600   Max.   :114.00   Max.   :27.00  

Overall, there is a large range of values. For instance, maximum values range from 49.6 to 296.4, and mean values range from 23.3 to 147.75. On the other hand, miniumum values are more concentrated from 0

quantile(mydata$radio, na.rm= TRUE)
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
# lowerq = quantile(VARIABLE)[2]
# upperq = quantile(VARIABLE)[4]
lowerq = quantile(mydata$radio)
upperq = quantile(mydata$radio)
lowerq
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
upperq
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
# iqr = upperq - lowerq
iqr = upperq - lowerq
iqr
  0%  25%  50%  75% 100% 
   0    0    0    0    0 
# upper_threshold = (iqr * 1.5) + upperq 
upper_threshold = (iqr * 1.5) + upperq
# lower_threshold = lowerq - (iqr * 1.5)
lower_threshold = lowerq - (iqr * 1.5)
upper_threshold
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
lower_threshold
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
# VARIABLE[ VARIABLE > upper_threshold][1:10]
# VARIABLE[ VARIABLE > lower_threshold][1:10]
mydata$radio[mydata$radio > upper_threshold]
 [1] 37.8 39.3 45.9 41.3 48.9 32.8  5.8 24.0 35.1 47.7 36.6 39.6 27.7  3.5 29.3 28.3 17.4  4.1 43.8 49.4 22.3 33.4 27.7 22.5 41.5  3.1 41.7 46.2 49.4 28.1 49.6  2.0 42.7
[34]  9.3 24.6 30.6 14.3 33.0 43.7 28.5 26.7 44.5 18.4 27.5 40.6  4.9 33.5 31.6 42.3  4.3 36.3 46.4 11.0  8.2 38.0 35.0 14.3 36.9 26.8 21.7 11.8 38.9 49.0 39.6 27.2 47.0
[67] 39.0 28.9 17.0 35.4 33.2  1.9 49.0 40.3 13.9 23.3 39.7 11.6 43.5 36.9 18.1 35.8 36.8  3.4 37.6 11.6 20.9 48.9 30.2  2.6 43.0 45.1 28.7 41.1 10.8 42.0  3.7 42.0
mydata$radio[mydata$radio < lower_threshold]
  [1] 10.8 19.6  2.1  2.6  7.6 32.9 20.5 23.9  5.1 15.9 16.9 12.6 16.7 27.1 16.0  1.5 20.0  1.4 26.7 37.7  8.4 25.7  9.9 15.8 11.7  9.6 28.8 19.2 29.5 15.5 29.6 42.8 14.5
 [34] 27.5 43.9  5.7 24.6  1.6 29.9  7.7  4.1 20.3 43.0 25.5 47.8  1.5 36.5 14.0  3.5 21.0 41.7 10.1 17.2 34.3  0.3  0.4 26.9 15.4 20.6 46.8  0.8 16.0  2.4 34.6 32.3  0.0
 [67] 12.0  2.9 33.5 38.6 25.9 43.9  5.7 14.8  7.3 25.8  8.4 21.1  1.3 18.4 18.1 14.7  5.2 23.6 10.6 20.1  7.1  3.4  7.8  2.3 10.0  5.4  5.7 21.3  2.1 13.9 12.1  4.1 35.6
[100]  4.9  9.3  8.6
upper_threshold
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
lower_threshold
    0%    25%    50%    75%   100% 
 0.000  9.975 22.900 36.525 49.600 
# mydata[ VARIABLE > upper_threshold, ][1:10]
# mydata[ VARIABLE > lower_threshold, ][1:10]
mydata[mydata$radio > upper_threshold, ]
mydata[mydata$radio < lower_threshold, ]
count(mydata[ mydata$radio < lower_threshold, ])
count(mydata [ mydata$radio > upper_threshold, ])
#There are 200 outliers for radio

** OUTLIERS FOR TV**

quantile(mydata$tv)
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
# lowerq = quantile(VARIABLE)[2]
# upperq = quantile(VARIABLE)[4]
lowerq = quantile(mydata$tv)
upperq = quantile(mydata$tv)
lowerq
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
upperq
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
# iqr = upperq - lowerq
iqr = upperq - lowerq
iqr
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
# upper_threshold = (iqr * 1.5) + upperq 
upper_threshold = (iqr * 1.5) + upperq
# lower_threshold = lowerq - (iqr * 1.5)
lower_threshold = lowerq - (iqr * 1.5)
# VARIABLE[ VARIABLE > upper_threshold][1:10]
# VARIABLE[ VARIABLE > lower_threshold][1:10]
mydata$tv[mydata$tv > upper_threshold]
NULL
mydata$yv[mydata$tv < lower_threshold]
NULL
upper_threshold
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
lower_threshold
  0%  25%  50%  75% 100% 
  NA   NA   NA   NA   NA 
# mydata[ VARIABLE > upper_threshold, ][1:10]
# mydata[ VARIABLE > lower_threshold, ][1:10]
mydata[mydata$tv > upper_threshold, ]
mydata[mydata$tv < lower_threshold, ]
count(mydata[ mydata$tv < lower_threshold, ])
count(mydata[ mydata$tv > upper_threshold, ])
#There are no outliers for TV.

OUTLIERS FOR NEWSPAPER

quantile(mydata$newspaper)
    0%    25%    50%    75%   100% 
  0.30  12.75  25.75  45.10 114.00 
# lowerq = quantile(VARIABLE)[2]
# upperq = quantile(VARIABLE)[4]
lowerq = quantile(mydata$newspaper)
upperq = quantile(mydata$newspaper)
lowerq
    0%    25%    50%    75%   100% 
  0.30  12.75  25.75  45.10 114.00 
upperq
    0%    25%    50%    75%   100% 
  0.30  12.75  25.75  45.10 114.00 
# iqr = upperq - lowerq
iqr = upperq - lowerq
iqr
  0%  25%  50%  75% 100% 
   0    0    0    0    0 
# upper_threshold = (iqr * 1.5) + upperq 
upper_threshold = (iqr * 1.5) + upperq
# lower_threshold = lowerq - (iqr * 1.5)
lower_threshold = lowerq - (iqr * 1.5)
# VARIABLE[ VARIABLE > upper_threshold][1:10]
# VARIABLE[ VARIABLE > lower_threshold][1:10]
mydata$newspaper[mydata$newspaper > upper_threshold]
 [1]  69.2  45.1  69.3  58.5  75.0  23.5  24.2  65.9  52.9 114.0  55.8  53.4  23.5  49.6  19.5  43.2  38.6  30.0   8.5  45.7  31.6  38.7  31.5  35.7  49.9  34.6  39.6  58.7
[29]  60.0  41.4  21.4  54.7  27.3   0.9  38.7  31.7  89.4  20.7  22.3  36.9  32.5  65.7  16.0  63.2  73.4   9.3  33.0  59.0  72.3  52.9  51.2  49.8 100.9  59.0  29.7  56.5
[57]  23.2  52.7  25.6  79.2  46.2  50.4  25.9  50.6   8.7  43.0   8.5  59.7  12.9  75.6  37.9   9.0  44.3  37.0  48.7   5.7  50.5  45.2  30.7  49.3  84.8  21.6  57.6  18.4
[85]  47.4  41.8  20.3  35.2   8.3  27.4  29.7  71.8  19.6  26.6   5.8  31.6  13.8  66.2
mydata$newspaper[mydata$newspaper < lower_threshold]
  [1] 58.4 11.6  1.0 21.2  4.0  7.2 46.0 18.3 19.1 26.2 18.3 12.6 22.9 22.9 40.8  0.3  7.4  5.0 35.1 32.0  1.8 26.4 43.3 18.5 36.8  3.6 15.9 16.6 37.7  9.3  8.4 28.9  2.2
 [34] 10.2 11.0 27.2 19.3 31.3 13.1 14.2  9.4 23.1 35.6 33.8 51.4 10.9  5.9 22.0 45.9 21.4 17.9  5.3 23.2 25.6  5.5  2.4 10.7 34.5 14.8 22.3 15.6 12.4 74.2  9.2  3.2 43.1
 [67]  2.1 65.6  9.3 20.5  1.7 34.4 38.9  8.7 11.9 20.6 14.2 37.7  9.5 24.3 34.6 25.6  7.4  5.4 19.4  6.4 17.0 12.8 13.1 23.7 17.6 30.0 18.2  3.7 23.4  6.0  3.6  6.0  8.1
[100]  6.4  8.7
upper_threshold
    0%    25%    50%    75%   100% 
  0.30  12.75  25.75  45.10 114.00 
lower_threshold
    0%    25%    50%    75%   100% 
  0.30  12.75  25.75  45.10 114.00 
# mydata[ VARIABLE > upper_threshold, ][1:10]
# mydata[ VARIABLE > lower_threshold, ][1:10]
mydata[mydata$newspaper > upper_threshold, ]
mydata[mydata$newspaper < lower_threshold, ]
count(mydata[mydata$newspaper > upper_threshold, ])
count(mydata[mydata$newspaper < lower_threshold, ])
#There are 199 outliers for newspaper. 

OUTLIERS FOR SALES

quantile(mydata$sales)
    0%    25%    50%    75%   100% 
 1.600 10.375 12.900 17.400 27.000 
# lowerq = quantile(VARIABLE)[2]
# upperq = quantile(VARIABLE)[4]
lowerq = quantile(mydata$sales)
upperq = quantile(mydata$sales)
lowerq
    0%    25%    50%    75%   100% 
 1.600 10.375 12.900 17.400 27.000 
upperq
    0%    25%    50%    75%   100% 
 1.600 10.375 12.900 17.400 27.000 
# iqr = upperq - lowerq
iqr = upperq - lowerq
iqr
  0%  25%  50%  75% 100% 
   0    0    0    0    0 
# upper_threshold = (iqr * 1.5) + upperq 
upper_threshold = (iqr * 1.5) + upperq
# lower_threshold = lowerq - (iqr * 1.5)
lower_threshold = lowerq - (iqr * 1.5)
#VARIABLE[ VARIABLE > upper_threshold][1:10]
#VARIABLE[ VARIABLE > lower_threshold][1:10]
mydata$sales[mydata$sales > upper_threshold]
  [1] 22.1 10.4 18.5  7.2 11.8 13.2  8.6 17.4 22.4 12.5 24.4 18.0 12.5 12.0 15.0 15.9 18.9 21.4 11.9 12.8 25.4 14.7 16.6 17.1 20.7 14.9 10.6 23.2 11.4 10.7 22.6 21.2 23.7
 [34] 13.2 23.8  8.1 24.2 15.7  9.3 13.4 18.9 18.3 12.4  8.7 14.2 11.8 12.3 15.2 12.0 16.0 11.2 19.4 22.2 16.9 11.7 15.5 25.4 11.7 23.8 14.8 19.2 13.4 21.8 14.1 12.6 12.2
 [67] 15.5 10.6 24.7 12.7 19.6 11.6 20.8 10.9 19.2 20.1 10.3 13.2 25.4 16.1 11.6 16.6 19.0  3.2 15.3 14.4 13.3 14.9 18.0 11.9  8.4 14.5 27.0 20.2 10.5 12.2 26.2 22.6 17.3
[100] 10.8 19.6  7.6 25.5
mydata$sales[mydata$sales < lower_threshold]
 [1]  9.3 12.9  4.8 10.6  9.2  9.7 19.0 11.3 14.6  5.6 15.5  9.7 10.5  9.6  9.5 10.1 21.5 12.9  8.5 14.8  9.7 20.2  5.5 18.4 14.0 18.0  9.5 22.3  8.8 11.0 17.0  6.9  5.3
[34] 11.0 11.3 13.6 21.7 12.9 16.7  7.3 11.5 17.2 14.7 20.7  7.2  8.7  5.3 19.8 15.9 14.6  9.4 15.9  6.6  7.0 11.6 15.2 19.7  6.6  8.8  9.7  5.7 10.8  9.5  9.6 20.7 10.4
[67] 11.4 10.9 10.1 15.6 10.1  7.3 12.9 11.9  8.0 12.2 17.1 15.0  7.6 11.7 11.5 11.7 11.8 12.6  8.7 17.6 10.3 15.9  6.7  9.9  5.9 17.3  9.7 12.8 13.4
upper_threshold
    0%    25%    50%    75%   100% 
 1.600 10.375 12.900 17.400 27.000 
lower_threshold
    0%    25%    50%    75%   100% 
 1.600 10.375 12.900 17.400 27.000 
# mydata[ VARIABLE > upper_threshold, ][1:10]
# mydata[ VARIABLE > lower_threshold, ][1:10]
mydata[mydata$sales > upper_threshold, ]
mydata[mydata$sales < lower_threshold, ]
count(mydata[mydata$sales > upper_threshold, ])
count(mydata[mydata$sales < lower_threshold, ])
#There are 198 outliers for sales.

PLOTTING OUTLIERS

p <- ggplot(data = mydata, aes(x = "", y = mydata$radio)) + geom_boxplot() + coord_flip()
p

p <- ggplot(data = mydata, aes(x = "", y = mydata$newspaper)) + geom_boxplot() + coord_flip()
p

p <- ggplot(data = mydata, aes(x = "", y = mydata$sales)) + geom_boxplot() + coord_flip()
p

p <- ggplot(data = mydata, aes(x = "", y = mydata$TV)) + geom_boxplot() + coord_flip()
p

From these box plots, we can visualize which variables have outliers. They tend to be either on extremes as shown on newspaper’s box plot.

1D) Write a general description of the dataset using the statistics found in the steps above. Use the min,max range to compare the features, note any significant differences.

min(mydata$radio, na.rm = TRUE)
[1] 0
max(mydata$radio, na.rm = TRUE)
[1] 49.6
min(mydata$newspaper, na.rm = TRUE)
[1] 0.3
max(mydata$newspaper, na.rm = TRUE)
[1] 114
min(mydata$sales, na.rm = TRUE)
[1] 1.6
max(mydata$sales, na.rm = TRUE)
[1] 27
min(mydata$TV, na.rm = TRUE)
[1] 0.7
max(mydata$TV, na.rm = TRUE)
[1] 296.4
min(mydata$case_number, na.rm = TRUE)
[1] 1
max(mydata$case_number, na.rm = TRUE)
[1] 200

From this dataset, we can analyze how TV has the highest amount of 296.4 and the largest range of 295.7, while radio had the lowest value of 0.

Task 2: Qualitative Analysis


2A) Plot all the assigned features as y-axis for x-axis use case_number. Use the given commands to create each plot and create a grid to plot all features Note any trends/patters in the data

  • Commands: VARIABLE_plot <- ggplot(data = mydata, aes(x = VARIABLE, y = VARIABLE)) + geom_point()
  • Commands: grid.arrange(VARIABLE_plot1, VARIABLE_plot2, VARIABLE_plot3, VARIABLE_plot4, ncol=2)
library(ggplot2)
library(gridExtra)
#grid.arrange(VARIABLE_plot1, VARIABLE_plot2, VARIABLE_plot3, VARIABLE_plot4, ncol=2)
tv_plot <- ggplot(data = mydata, aes(x = case_number, y = TV)) + geom_point()
newspaper_plot <- ggplot(data = mydata, aes(x = case_number, y = newspaper)) + geom_point()
sales_plot <- ggplot(data = mydata, aes(x = case_number, y = sales)) + geom_point()
radio_plot <- ggplot(data = mydata, aes(x = case_number, y = radio)) + geom_point()
tv_plot

newspaper_plot

sales_plot

radio_plot

final <- grid.arrange(tv_plot, newspaper_plot, sales_plot, radio_plot, ncol=2)

Out of all these graphs, one cannot deduce strongly that there is a clear relationship between the two variables. In fact, there is no line of best fit for any of these graphs.

  • When looking at these plots it is hard to see a particular trend.
  • One way to observe any possible trend in the sales data would be to re-order the data from low to high.
  • The 200 months observations are in no particular chronological time sequence.
  • The case numbers are independent sequentially generated numbers. Since each case is independent, we can reorder them.

2B) Re-order sales from low to high, and save re-ordered data in a new set. As sales data is re-reorded associated other column fields follow.

  • Commands: newdata <- mydata[ order(mydata$VARIABLE), ]
# Extract case_number from the newdata
newdata <- mydata [ order(mydata$sales), ]
newdata

Extract the variables from the new data

# new_VARIABLE = newdata$VARIABLE
new_sales = newdata$sales
new_TV = newdata$TV
new_newspaper = newdata$newspaper
new_radio = newdata$radio

Task 3: Standardized Z-Value


3A) Create a histogram of the assigned feature z-scores. Describe the output note any relevant values.

  • Command: z_score = ( VARIABLE - mean(VARIABLE) ) / sd(VARIABLE)
  • Commands: qplot( x = VARIABLE ,geom=“histogram”, binwidth = 0.3)
z_scores = ( mydata$sales - mean(mydata$sales) ) / sd(mydata$sales)
qplot( x = z_scores ,geom="histogram", binwidth = 0.3)

This histogram has a normal distribution and is positively skewed, which means the mode is less than the mean and median.

3B) Given a sales value of $26700, calculate the corresponding z-value or z-score.

  • Command: z_score = ( VARIABLE - mean(VARIABLE) ) / sd(VARIABLE)
z_score = (26.7 - (mean(mydata$sales))) / sd(mydata$sales)
z_score
[1] 2.429824

3C) Based on the z-value, how would you rate a $26700 sales value: poor, average, good, or very good performance? Explain your logic.

Basd on the z-value, I would rate $26700 as a very good performance. Not only is it above the mean, but it exceeds the sales data’s upper threshold. Hence, one might conclude that this value is an outlier, and it might not be representative of the whole data and would require further investigation.

```

LS0tDQp0aXRsZTogIkRlc2NyaXB0aXZlIEFuYWx5dGljcyINCmF1dGhvcjogIkNoZXllbm5lIFBlbm55Ig0KZGF0ZTogIjIvMjIvMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCnN1YnRpdGxlOiBDTUUgR3JvdXAgRm91bmRhdGlvbiBCdXNpbmVzcyBBbmFseXRpY3MgTGFiDQotLS0NCg0KLS0tLS0tLS0tLS0tLQ0KDQojIyBOb3RlYm9vayBJbnN0cnVjdGlvbnMNCg0KLS0tLS0tLS0tLS0tLQ0KDQoqIEZvciB5b3VyIGFzc2lnbm1lbnQgeW91IG1heSBiZSB1c2luZyBkaWZmZXJlbnQgZGF0YXNldCB0aGFuIHdoYXQgaXMgaW5jbHVkZWQgaGVyZS4gDQoNCiogQWx3YXlzIHJlYWQgY2FyZWZ1bGx5IHRoZSBpbnN0cnVjdGlvbnMgb24gU2FrYWkuICANCg0KKiBUYXNrcy9xdWVzdGlvbnMgdG8gYmUgY29tcGxldGVkL2Fuc3dlcmVkIGFyZSBoaWdobGlnaHRlZCBpbiBsYXJnZXIgYm9sZGVkIGZvbnRzIGFuZCBudW1iZXJlZCBhY2NvcmRpbmcgdG8gdGhlaXIgc2VjdGlvbi4NCg0KIyMjIExvYWQgUGFja2FnZXMgaW4gUi9SU3R1ZGlvIA0KDQpXZSBhcmUgZ29pbmcgdG8gdXNlIHRpZHl2ZXJzZSBhIGNvbGxlY3Rpb24gb2YgUiBwYWNrYWdlcyBkZXNpZ25lZCBmb3IgZGF0YSBzY2llbmNlLiANCg0KKiBJbmZvOiBodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLw0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCg0KIyBIZXJlIHdlIGFyZSBjaGVja2luZyBpZiB0aGUgcGFja2FnZSBpcyBpbnN0YWxsZWQNCmlmKCFyZXF1aXJlKHRpZHl2ZXJzZSkpew0KICANCiAgIyBJZiB0aGUgcGFja2FnZSBpcyBub3QgaW4gdGhlIHN5c3RlbSB0aGVuIGl0IHdpbGwgYmUgaW5zdGFsbA0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICANCiAgIyBIZXJlIHdlIGFyZSBsb2FkaW5nIHRoZSBwYWNrYWdlDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZighcmVxdWlyZShncmlkRXh0cmEpKXsNCiAgDQogICMgSWYgdGhlIHBhY2thZ2UgaXMgbm90IGluIHRoZSBzeXN0ZW0gdGhlbiBpdCB3aWxsIGJlIGluc3RhbGwNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgDQogICMgSGVyZSB3ZSBhcmUgbG9hZGluZyB0aGUgcGFja2FnZQ0KICBsaWJyYXJ5KGdyaWRFeHRyYSkNCn0NCg0KYGBgDQoNCi0tLS0tLS0tLS0tLS0NCg0KIyMgVGFzayAxOiBRdWFudGl0YXRpdmUgQW5hbHlzaXMNCg0KLS0tLS0tLS0tLS0tLQ0KDQojIyMgMUEpIFJlYWQgdGhlIGNzdiBmaWxlIGludG8gUiBTdHVkaW8gYW5kIGRpc3BsYXkgdGhlIGRhdGFzZXQuIA0KDQoqIE5hbWUgeW91ciBkYXRhc2V0ICdteWRhdGEnIHNvIGl0IGVhc3kgdG8gd29yayB3aXRoLg0KDQoqIENvbW1hbmRzOiByZWFkX2NzdigpIGhlYWQoKSBtYXgoKSBtaW4oKSB2YXIoKSBzZCgpDQoNCiMjIyMgRXh0cmFjdCB0aGUgYXNzaWduZWQgZmVhdHVyZXMgKGNvbHVtbnMpIHRvIHBlcmZvcm0gc29tZSBhbmFseXRpY3MuIA0KDQpgYGB7cn0gDQoNCm15ZGF0YSA8LSByZWFkLmNzdigiZGF0YS9BZHZlcnRpc2luZy5jc3YiKQ0KaGVhZChteWRhdGEpDQoNCmBgYA0KDQojIyMjIENoYW5nZSB0aGUgdmFyaWFibGUgbmFtZSAiWDEiIHRvIGNhc2VfbnVtYmVyIHVzaW5nIHRoZSBmdW5jdGlvbiByZW5hbWUoKQ0KDQoqIG15ZGF0YSA8LSByZW5hbWUobXlkYXRhLCAiTkVXX1ZBUl9OQU1FIiA9ICJPTERfVkFSX05BTUUiKQ0KDQpgYGB7cn0gDQpteWRhdGEgPC0gcmVuYW1lKG15ZGF0YSwgImNhc2VfbnVtYmVyIiA9ICJYIikNCmBgYA0KDQojIyMgMUIpIEZpbmQgdGhlIHJhbmdlICggZGlmZmVyZW5jZSBiZXR3ZWVuIG1pbiBhbmQgbWF4ICksIG1pbiwgbWF4LCBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIHZhcmlhbmNlIGZvciBlYWNoIGFzc2lnbmVkIGZlYXR1cmUgKCBVc2Ugc2VwYXJhdGUgY2h1bmtzIGZvciBlYWNoIGZlYXR1cmUgKS4gQ29tcGFyZSBlYWNoIGZlYXR1cmUgYW5kIG5vdGUgYW55IHNpZ25pZmljYW50IGRpZmZlcmVuY2VzDQoqKkNBU0UgTlVNQkVSKioNCmBgYHtyfQ0KY2FzZV9udW1iZXJfbWF4IDwtIG1heChteWRhdGEkY2FzZV9udW1iZXIpDQpjYXNlX251bWJlcl9tYXgNCg0KY2FzZV9udW1iZXJfbWluIDwtIG1pbihteWRhdGEkY2FzZV9udW1iZXIpDQpjYXNlX251bWJlcl9taW4NCg0KY2FzZV9udW1iZXJfcmFuZ2UgPC1yYW5nZShjYXNlX251bWJlcl9tYXggLSBjYXNlX251bWJlcl9taW4pDQpjYXNlX251bWJlcl9yYW5nZQ0KDQpjYXNlX251bWJlcl9tZWFuIDwtIG1lYW4obXlkYXRhJGNhc2VfbnVtYmVyKQ0KY2FzZV9udW1iZXJfbWVhbg0KDQpjYXNlX251bWJlcl9zZCA8LSBzZChteWRhdGEkY2FzZV9udW1iZXIpDQpjYXNlX251bWJlcl9zZA0KDQpjYXNlX251bWJlcl92YXJpYW5jZSA8LSB2YXIobXlkYXRhJGNhc2VfbnVtYmVyKQ0KY2FzZV9udW1iZXJfdmFyaWFuY2UNCg0KDQpgYGANClRoZXJlIGlzIGEgbGFyZ2UgcmFuZ2UgZm9yIGNhc2VfbnVtYmVyIGF0IG5lYXJseSAyMDAuDQoqKlNBTEVTKioNCmBgYHtyfQ0KDQojdmFyaWFibGVfbWF4DQoNCnNhbGVzX21heCA8LSBtYXgobXlkYXRhJHNhbGVzKQ0Kc2FsZXNfbWF4DQoNCiN2YXJpYWJsZV9taW4NCnNhbGVzX21pbiA8LSBtaW4obXlkYXRhJHNhbGVzKQ0Kc2FsZXNfbWluDQoNCiN2YXJpYWJsZV9SYW5nZSBtYXgtbWluDQpzYWxlc19yYW5nZSA8LSByYW5nZShzYWxlc19tYXggLSBzYWxlc19taW4pDQpzYWxlc19yYW5nZQ0KI3ZhcmlhYmxlX21lYW4gDQoNCnNhbGVzX21lYW4gPC0gbWVhbihteWRhdGEkc2FsZXMpDQpzYWxlc19tZWFuDQojdmFyaWFibGVfc2QgU3RhbmRhcmQgRGV2aWF0aW9uDQpzYWxlc19zZCA8LSBzZChteWRhdGEkc2FsZXMpDQpzYWxlc19zZA0KI3ZhcmlhYmxlX3ZhcmlhbmNlDQpzYWxlc192YXJpYW5jZSA8LSB2YXIobXlkYXRhJHNhbGVzKQ0Kc2FsZXNfdmFyaWFuY2UNCmBgYA0KU2FsZXMgaGFzIGEgcmVsYXRpdmVseSBzbWFsbGVyIHJhbmdlIGluIGNvbnRyYXN0IHRvIGNhc2VfbnVtYmVyIGFuZCB0aGUgc21hbGxlc3Qgc2QuIA0KDQoqKlJBRElPKioNCmBgYHtyfQ0KDQojdmFyaWFibGVfbWF4DQpyYWRpb19tYXggPC0gbWF4KG15ZGF0YSRyYWRpbykNCg0KcmFkaW9fbWF4DQojdmFyaWFibGVfbWluDQoNCnJhZGlvX21pbiA8LSBtaW4obXlkYXRhJHJhZGlvKQ0KcmFkaW9fbWluDQojdmFyaWFibGVfUmFuZ2UgbWF4LW1pbg0KcmFkaW9fcmFuZ2UgPC0gcmFuZ2UocmFkaW9fbWF4IC0gcmFkaW9fbWluKQ0KcmFkaW9fcmFuZ2UNCiN2YXJpYWJsZV9tZWFuIA0KDQpyYWRpb19tZWFuIDwtIG1lYW4obXlkYXRhJHJhZGlvKQ0KcmFkaW9fbWVhbg0KI3ZhcmlhYmxlX3NkIFN0YW5kYXJkIERldmlhdGlvbg0KcmFkaW9fc2QgPC0gc2QobXlkYXRhJHJhZGlvKQ0KcmFkaW9fc2QNCiN2YXJpYWJsZV92YXJpYW5jZQ0KcmFkaW9fdmFyaWFuY2UgPC0gdmFyKG15ZGF0YSRyYWRpbykNCnJhZGlvX3ZhcmlhbmNlDQoNCg0KYGBgDQpSYWRpbyBoYXMgYSBzbWFsbGVyIHZhcmlhbmNlIGluIGNvbXBhcmlzb24gdG8gb3RoZXIgdmFyaWFibGVzLg0KDQoqKlRWKioNCmBgYHtyfQ0KDQojdmFyaWFibGVfbWF4DQp0dl9tYXggPC0gbWF4KG15ZGF0YSRUVikNCg0KdHZfbWF4DQojdmFyaWFibGVfbWluDQoNCnR2X21pbiA8LSBtaW4obXlkYXRhJFRWKQ0KdHZfbWluDQojdmFyaWFibGVfUmFuZ2UgbWF4LW1pbg0KdHZfcmFuZ2UgPC0gcmFuZ2UodHZfbWF4IC0gdHZfbWluKQ0KdHZfcmFuZ2UNCiN2YXJpYWJsZV9tZWFuIA0KDQp0dl9tZWFuIDwtIG1lYW4obXlkYXRhJFRWKQ0KdHZfbWVhbg0KI3ZhcmlhYmxlX3NkIFN0YW5kYXJkIERldmlhdGlvbg0KdHZfc2QgPC0gc2QobXlkYXRhJFRWKQ0KdHZfc2QNCiN2YXJpYWJsZV92YXJpYW5jZQ0KdHZfdmFyaWFuY2UgPC0gdmFyKG15ZGF0YSRUVikNCnR2X3ZhcmlhbmNlDQpgYGANCioqTkVXU1BBUEVSKioNCmBgYHtyfQ0KDQojdmFyaWFibGVfbWF4DQpuZXdzcGFwZXJfbWF4IDwtIG1heChteWRhdGEkbmV3c3BhcGVyKQ0KDQpuZXdzcGFwZXJfbWF4DQojdmFyaWFibGVfbWluDQoNCm5ld3NwYXBlcl9taW4gPC0gbWluKG15ZGF0YSRuZXdzcGFwZXIpDQpuZXdzcGFwZXJfbWluDQojdmFyaWFibGVfUmFuZ2UgbWF4LW1pbg0KbmV3c3BhcGVyX3JhbmdlIDwtIHJhbmdlKG5ld3NwYXBlcl9tYXggLSBuZXdzcGFwZXJfbWluKQ0KbmV3c3BhcGVyX3JhbmdlDQojdmFyaWFibGVfbWVhbiANCg0KbmV3c3BhcGVyX21lYW4gPC0gbWVhbihteWRhdGEkbmV3c3BhcGVyKQ0KbmV3c3BhcGVyX21lYW4NCiN2YXJpYWJsZV9zZCBTdGFuZGFyZCBEZXZpYXRpb24NCm5ld3NwYXBlcl9zZCA8LSBzZChteWRhdGEkbmV3c3BhcGVyKQ0KbmV3c3BhcGVyX3NkDQojdmFyaWFibGVfdmFyaWFuY2UNCm5ld3NwYXBlcl92YXJpYW5jZSA8LSB2YXIobXlkYXRhJG5ld3NwYXBlcikNCm5ld3NwYXBlcl92YXJpYW5jZQ0KDQpgYGANCg0KTmV3c3BhcGVyIGlzIGNvbWFwcmFibGUgdG8gdGhlIG90aGVyIHZhcmlhYmxlcyBhbmQgYSBzbWFsbCBzLmQuIChjbG9zZSB0byBzYWxlcydzIHMuZC4pDQoNCiMjIyAxQykgVXNlIHRoZSBzdW1tYXJ5KCkgZnVuY3Rpb24gb24gYWxsIHRoZSBkYXRhc2V0IHRvIGdpdmUgeW91IGEgZ2VuZXJhbCBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YS4gTm90ZSBhbnkgZGlmZmVyZW5jZXMgYmV0d2VlbiBmZWF0dXJlcy4NCg0KYGBge3J9DQoNCnN1bW1hcnkobXlkYXRhKQ0KDQpgYGANCg0KT3ZlcmFsbCwgdGhlcmUgaXMgYSBsYXJnZSByYW5nZSBvZiB2YWx1ZXMuIEZvciBpbnN0YW5jZSwgbWF4aW11bSB2YWx1ZXMgcmFuZ2UgZnJvbSA0OS42IHRvIDI5Ni40LCBhbmQgbWVhbiB2YWx1ZXMgcmFuZ2UgZnJvbSAyMy4zIHRvIDE0Ny43NS4gT24gdGhlIG90aGVyIGhhbmQsIG1pbml1bXVtIHZhbHVlcyBhcmUgbW9yZSBjb25jZW50cmF0ZWQgZnJvbSAwPHg8MSwgd2hpY2ggbWFrZXMgc2Vuc2UgYXMgdGhlc2UgdmFsdWVzIGNhbid0IGJlIG5lZ2F0aXZlLiBUaGVyZWZvcmUsIG9uZSBjYW4gZGVkdWNlIHRoYXQgdGhlcmUgaXNuJ3QgbXVjaCBzcHJlYWQgZm9yIG1pbmltdW0gdmFsdWVzIGFzIHRoZXJlIGFyZSBmb3IgbWF4aW11bSBhbmQgbWVhbiB2YWx1ZXMuIA0KDQoNCiMjIyMgQXJlIHRoZXJlIGFueSBvdXRsaWVycywgaWYgbm90IGV4cGxhaW4gdGhlIGxhY2sgb2Ygb3V0bGllcnM/IGlmIGFueSBleHBsYWluIHdoYXQgdGhlIG91dGxpZXJzIHJlcHJlc2VudCBhbmQgaG93IG1hbnkgcmVjb3JkcyBhcmUgb3V0bGllcnM/ICggVXNlIGNvZGUgZnJvbSBub3RlYm9vay0wMyB0byBmaW5kIG91dGxpZXJzKSANCg0KDQpgYA0KT3V0bGllcnMgcmVwcmVzZW50IHRoZSBkYXRhIHBvaW50cyB0aGF0IGxpZSBiZXlvbmQgdXBwZXIgdGhyZXNob2xkIGFuZCBiZWxvdyBsb3dlciB0aHJlc2hvbGQgbGltaXRzLiBUaGlzIG1lYW4gb3V0bGllcnMgY2FuIGRpc3RvcnQgZGF0YSBhbmQgc3RhdGlzdGljYWwgYW5hbHlzaXMsIHN1Y2ggYXMgbWVhbiBhbmQgbWVkaWFuLiBIZW5jZSwgdGhleSBzaG91bGQgYmUgZXhjbHVkZWQgZnJvbSBkYXRhIGFuYWx5c2lzLiANCg0KDQoNCg0KKiogT1VUTElFUlMgRk9SIFJBRElPKioNCg0KYGBge3J9DQpxdWFudGlsZShteWRhdGEkcmFkaW8sIG5hLnJtPSBUUlVFKQ0KDQpgYGANCg0KYGBge3J9DQojIGxvd2VycSA9IHF1YW50aWxlKFZBUklBQkxFKVsyXQ0KIyB1cHBlcnEgPSBxdWFudGlsZShWQVJJQUJMRSlbNF0NCg0KbG93ZXJxID0gcXVhbnRpbGUobXlkYXRhJHJhZGlvKQ0KdXBwZXJxID0gcXVhbnRpbGUobXlkYXRhJHJhZGlvKQ0KDQpsb3dlcnENCnVwcGVycQ0KDQoNCmBgYA0KYGBge3J9DQoNCg0KIyBpcXIgPSB1cHBlcnEgLSBsb3dlcnENCg0KaXFyID0gdXBwZXJxIC0gbG93ZXJxDQppcXINCmBgYA0KDQpgYGB7cn0NCg0KIyB1cHBlcl90aHJlc2hvbGQgPSAoaXFyICogMS41KSArIHVwcGVycSANCnVwcGVyX3RocmVzaG9sZCA9IChpcXIgKiAxLjUpICsgdXBwZXJxDQoNCiMgbG93ZXJfdGhyZXNob2xkID0gbG93ZXJxIC0gKGlxciAqIDEuNSkNCmxvd2VyX3RocmVzaG9sZCA9IGxvd2VycSAtIChpcXIgKiAxLjUpDQoNCnVwcGVyX3RocmVzaG9sZA0KbG93ZXJfdGhyZXNob2xkDQoNCmBgYA0KDQoNCg0KYGBge3J9DQojIFZBUklBQkxFWyBWQVJJQUJMRSA+IHVwcGVyX3RocmVzaG9sZF1bMToxMF0NCiMgVkFSSUFCTEVbIFZBUklBQkxFID4gbG93ZXJfdGhyZXNob2xkXVsxOjEwXQ0KbXlkYXRhJHJhZGlvW215ZGF0YSRyYWRpbyA+IHVwcGVyX3RocmVzaG9sZF0NCm15ZGF0YSRyYWRpb1tteWRhdGEkcmFkaW8gPCBsb3dlcl90aHJlc2hvbGRdDQp1cHBlcl90aHJlc2hvbGQNCmxvd2VyX3RocmVzaG9sZA0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBteWRhdGFbIFZBUklBQkxFID4gdXBwZXJfdGhyZXNob2xkLCBdWzE6MTBdDQojIG15ZGF0YVsgVkFSSUFCTEUgPiBsb3dlcl90aHJlc2hvbGQsIF1bMToxMF0NCg0KbXlkYXRhW215ZGF0YSRyYWRpbyA+IHVwcGVyX3RocmVzaG9sZCwgXQ0KbXlkYXRhW215ZGF0YSRyYWRpbyA8IGxvd2VyX3RocmVzaG9sZCwgXQ0KYGBgDQpgYGB7cn0NCmNvdW50KG15ZGF0YVsgbXlkYXRhJHJhZGlvIDwgbG93ZXJfdGhyZXNob2xkLCBdKQ0KY291bnQobXlkYXRhIFsgbXlkYXRhJHJhZGlvID4gdXBwZXJfdGhyZXNob2xkLCBdKQ0KDQojVGhlcmUgYXJlIDIwMCBvdXRsaWVycyBmb3IgcmFkaW8NCmBgYA0KDQoNCioqIE9VVExJRVJTIEZPUiBUVioqDQpgYGB7cn0NCnF1YW50aWxlKG15ZGF0YSR0dikNCg0KYGBgDQoNCmBgYHtyfQ0KIyBsb3dlcnEgPSBxdWFudGlsZShWQVJJQUJMRSlbMl0NCiMgdXBwZXJxID0gcXVhbnRpbGUoVkFSSUFCTEUpWzRdDQoNCmxvd2VycSA9IHF1YW50aWxlKG15ZGF0YSR0dikNCnVwcGVycSA9IHF1YW50aWxlKG15ZGF0YSR0dikNCg0KbG93ZXJxDQp1cHBlcnENCmBgYA0KDQpgYGB7cn0NCiMgaXFyID0gdXBwZXJxIC0gbG93ZXJxDQoNCmlxciA9IHVwcGVycSAtIGxvd2VycQ0KaXFyDQpgYGANCg0KYGBge3J9DQojIHVwcGVyX3RocmVzaG9sZCA9IChpcXIgKiAxLjUpICsgdXBwZXJxIA0KdXBwZXJfdGhyZXNob2xkID0gKGlxciAqIDEuNSkgKyB1cHBlcnENCg0KIyBsb3dlcl90aHJlc2hvbGQgPSBsb3dlcnEgLSAoaXFyICogMS41KQ0KbG93ZXJfdGhyZXNob2xkID0gbG93ZXJxIC0gKGlxciAqIDEuNSkNCmBgYA0KDQpgYGB7cn0NCg0KIyBWQVJJQUJMRVsgVkFSSUFCTEUgPiB1cHBlcl90aHJlc2hvbGRdWzE6MTBdDQojIFZBUklBQkxFWyBWQVJJQUJMRSA+IGxvd2VyX3RocmVzaG9sZF1bMToxMF0NCm15ZGF0YSR0dltteWRhdGEkdHYgPiB1cHBlcl90aHJlc2hvbGRdDQpteWRhdGEkeXZbbXlkYXRhJHR2IDwgbG93ZXJfdGhyZXNob2xkXQ0KdXBwZXJfdGhyZXNob2xkDQpsb3dlcl90aHJlc2hvbGQNCmBgYA0KDQpgYGB7cn0NCiMgbXlkYXRhWyBWQVJJQUJMRSA+IHVwcGVyX3RocmVzaG9sZCwgXVsxOjEwXQ0KIyBteWRhdGFbIFZBUklBQkxFID4gbG93ZXJfdGhyZXNob2xkLCBdWzE6MTBdDQoNCm15ZGF0YVtteWRhdGEkdHYgPiB1cHBlcl90aHJlc2hvbGQsIF0NCm15ZGF0YVtteWRhdGEkdHYgPCBsb3dlcl90aHJlc2hvbGQsIF0NCmBgYA0KDQpgYGB7cn0NCmNvdW50KG15ZGF0YVsgbXlkYXRhJHR2IDwgbG93ZXJfdGhyZXNob2xkLCBdKQ0KY291bnQobXlkYXRhWyBteWRhdGEkdHYgPiB1cHBlcl90aHJlc2hvbGQsIF0pDQoNCiNUaGVyZSBhcmUgbm8gb3V0bGllcnMgZm9yIFRWLg0KYGBgDQoNCg0KDQoNCg0KKipPVVRMSUVSUyBGT1IgTkVXU1BBUEVSKioNCmBgYHtyfQ0KcXVhbnRpbGUobXlkYXRhJG5ld3NwYXBlcikNCmBgYA0KDQpgYGB7cn0NCiMgbG93ZXJxID0gcXVhbnRpbGUoVkFSSUFCTEUpWzJdDQojIHVwcGVycSA9IHF1YW50aWxlKFZBUklBQkxFKVs0XQ0KDQpsb3dlcnEgPSBxdWFudGlsZShteWRhdGEkbmV3c3BhcGVyKQ0KdXBwZXJxID0gcXVhbnRpbGUobXlkYXRhJG5ld3NwYXBlcikNCg0KbG93ZXJxDQp1cHBlcnENCg0KYGBgDQoNCmBgYHtyfQ0KIyBpcXIgPSB1cHBlcnEgLSBsb3dlcnENCg0KaXFyID0gdXBwZXJxIC0gbG93ZXJxDQppcXINCmBgYA0KDQpgYGB7cn0NCg0KIyB1cHBlcl90aHJlc2hvbGQgPSAoaXFyICogMS41KSArIHVwcGVycSANCnVwcGVyX3RocmVzaG9sZCA9IChpcXIgKiAxLjUpICsgdXBwZXJxDQoNCiMgbG93ZXJfdGhyZXNob2xkID0gbG93ZXJxIC0gKGlxciAqIDEuNSkNCmxvd2VyX3RocmVzaG9sZCA9IGxvd2VycSAtIChpcXIgKiAxLjUpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBWQVJJQUJMRVsgVkFSSUFCTEUgPiB1cHBlcl90aHJlc2hvbGRdWzE6MTBdDQojIFZBUklBQkxFWyBWQVJJQUJMRSA+IGxvd2VyX3RocmVzaG9sZF1bMToxMF0NCm15ZGF0YSRuZXdzcGFwZXJbbXlkYXRhJG5ld3NwYXBlciA+IHVwcGVyX3RocmVzaG9sZF0NCm15ZGF0YSRuZXdzcGFwZXJbbXlkYXRhJG5ld3NwYXBlciA8IGxvd2VyX3RocmVzaG9sZF0NCnVwcGVyX3RocmVzaG9sZA0KbG93ZXJfdGhyZXNob2xkDQoNCmBgYA0KDQpgYGB7cn0NCiMgbXlkYXRhWyBWQVJJQUJMRSA+IHVwcGVyX3RocmVzaG9sZCwgXVsxOjEwXQ0KIyBteWRhdGFbIFZBUklBQkxFID4gbG93ZXJfdGhyZXNob2xkLCBdWzE6MTBdDQoNCm15ZGF0YVtteWRhdGEkbmV3c3BhcGVyID4gdXBwZXJfdGhyZXNob2xkLCBdDQpteWRhdGFbbXlkYXRhJG5ld3NwYXBlciA8IGxvd2VyX3RocmVzaG9sZCwgXQ0KDQpgYGANCg0KYGBge3J9DQpjb3VudChteWRhdGFbbXlkYXRhJG5ld3NwYXBlciA+IHVwcGVyX3RocmVzaG9sZCwgXSkNCmNvdW50KG15ZGF0YVtteWRhdGEkbmV3c3BhcGVyIDwgbG93ZXJfdGhyZXNob2xkLCBdKQ0KDQojVGhlcmUgYXJlIDE5OSBvdXRsaWVycyBmb3IgbmV3c3BhcGVyLiANCmBgYA0KDQoNCioqT1VUTElFUlMgRk9SIFNBTEVTKioNCmBgYHtyfQ0KDQpxdWFudGlsZShteWRhdGEkc2FsZXMpDQpgYGANCg0KYGBge3J9DQoNCiMgbG93ZXJxID0gcXVhbnRpbGUoVkFSSUFCTEUpWzJdDQojIHVwcGVycSA9IHF1YW50aWxlKFZBUklBQkxFKVs0XQ0KDQpsb3dlcnEgPSBxdWFudGlsZShteWRhdGEkc2FsZXMpDQp1cHBlcnEgPSBxdWFudGlsZShteWRhdGEkc2FsZXMpDQoNCmxvd2VycQ0KdXBwZXJxDQoNCmBgYA0KDQpgYGB7cn0NCiMgaXFyID0gdXBwZXJxIC0gbG93ZXJxDQoNCmlxciA9IHVwcGVycSAtIGxvd2VycQ0KaXFyDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyB1cHBlcl90aHJlc2hvbGQgPSAoaXFyICogMS41KSArIHVwcGVycSANCnVwcGVyX3RocmVzaG9sZCA9IChpcXIgKiAxLjUpICsgdXBwZXJxDQoNCiMgbG93ZXJfdGhyZXNob2xkID0gbG93ZXJxIC0gKGlxciAqIDEuNSkNCmxvd2VyX3RocmVzaG9sZCA9IGxvd2VycSAtIChpcXIgKiAxLjUpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI1ZBUklBQkxFWyBWQVJJQUJMRSA+IHVwcGVyX3RocmVzaG9sZF1bMToxMF0NCiNWQVJJQUJMRVsgVkFSSUFCTEUgPiBsb3dlcl90aHJlc2hvbGRdWzE6MTBdDQoNCm15ZGF0YSRzYWxlc1tteWRhdGEkc2FsZXMgPiB1cHBlcl90aHJlc2hvbGRdDQpteWRhdGEkc2FsZXNbbXlkYXRhJHNhbGVzIDwgbG93ZXJfdGhyZXNob2xkXQ0KdXBwZXJfdGhyZXNob2xkDQpsb3dlcl90aHJlc2hvbGQNCg0KYGBgDQoNCg0KYGBge3J9DQojIG15ZGF0YVsgVkFSSUFCTEUgPiB1cHBlcl90aHJlc2hvbGQsIF1bMToxMF0NCiMgbXlkYXRhWyBWQVJJQUJMRSA+IGxvd2VyX3RocmVzaG9sZCwgXVsxOjEwXQ0KDQpteWRhdGFbbXlkYXRhJHNhbGVzID4gdXBwZXJfdGhyZXNob2xkLCBdDQpteWRhdGFbbXlkYXRhJHNhbGVzIDwgbG93ZXJfdGhyZXNob2xkLCBdDQoNCmBgYA0KDQoNCmBgYHtyfQ0KY291bnQobXlkYXRhW215ZGF0YSRzYWxlcyA+IHVwcGVyX3RocmVzaG9sZCwgXSkNCmNvdW50KG15ZGF0YVtteWRhdGEkc2FsZXMgPCBsb3dlcl90aHJlc2hvbGQsIF0pDQoNCiNUaGVyZSBhcmUgMTk4IG91dGxpZXJzIGZvciBzYWxlcy4NCmBgYA0KDQoqKlBMT1RUSU5HIE9VVExJRVJTKioNCg0KYGBge3J9DQoNCnAgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gIiIsIHkgPSBteWRhdGEkcmFkaW8pKSArIGdlb21fYm94cGxvdCgpICsgY29vcmRfZmxpcCgpDQpwDQpwIDwtIGdncGxvdChkYXRhID0gbXlkYXRhLCBhZXMoeCA9ICIiLCB5ID0gbXlkYXRhJG5ld3NwYXBlcikpICsgZ2VvbV9ib3hwbG90KCkgKyBjb29yZF9mbGlwKCkNCnANCnAgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gIiIsIHkgPSBteWRhdGEkc2FsZXMpKSArIGdlb21fYm94cGxvdCgpICsgY29vcmRfZmxpcCgpDQpwDQpwIDwtIGdncGxvdChkYXRhID0gbXlkYXRhLCBhZXMoeCA9ICIiLCB5ID0gbXlkYXRhJFRWKSkgKyBnZW9tX2JveHBsb3QoKSArIGNvb3JkX2ZsaXAoKQ0KcA0KYGBgDQoNCg0KRnJvbSB0aGVzZSBib3ggcGxvdHMsIHdlIGNhbiB2aXN1YWxpemUgd2hpY2ggdmFyaWFibGVzIGhhdmUgb3V0bGllcnMuIFRoZXkgdGVuZCB0byBiZSBlaXRoZXIgb24gZXh0cmVtZXMgYXMgc2hvd24gb24gbmV3c3BhcGVyJ3MgYm94IHBsb3QuIA0KDQojIyMgMUQpIFdyaXRlIGEgZ2VuZXJhbCBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YXNldCB1c2luZyB0aGUgc3RhdGlzdGljcyBmb3VuZCBpbiB0aGUgc3RlcHMgYWJvdmUuIFVzZSB0aGUgbWluLG1heCByYW5nZSB0byBjb21wYXJlIHRoZSBmZWF0dXJlcywgbm90ZSBhbnkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMuDQoNCg0KDQpgYGB7cn0NCm1pbihteWRhdGEkcmFkaW8sIG5hLnJtID0gVFJVRSkNCm1heChteWRhdGEkcmFkaW8sIG5hLnJtID0gVFJVRSkNCg0KbWluKG15ZGF0YSRuZXdzcGFwZXIsIG5hLnJtID0gVFJVRSkNCm1heChteWRhdGEkbmV3c3BhcGVyLCBuYS5ybSA9IFRSVUUpDQoNCg0KbWluKG15ZGF0YSRzYWxlcywgbmEucm0gPSBUUlVFKQ0KbWF4KG15ZGF0YSRzYWxlcywgbmEucm0gPSBUUlVFKQ0KDQoNCm1pbihteWRhdGEkVFYsIG5hLnJtID0gVFJVRSkNCm1heChteWRhdGEkVFYsIG5hLnJtID0gVFJVRSkNCg0KDQptaW4obXlkYXRhJGNhc2VfbnVtYmVyLCBuYS5ybSA9IFRSVUUpDQptYXgobXlkYXRhJGNhc2VfbnVtYmVyLCBuYS5ybSA9IFRSVUUpDQoNCmBgYA0KDQoNCkZyb20gdGhpcyBkYXRhc2V0LCB3ZSBjYW4gYW5hbHl6ZSBob3cgVFYgaGFzIHRoZSBoaWdoZXN0IGFtb3VudCBvZiAyOTYuNCBhbmQgdGhlIGxhcmdlc3QgcmFuZ2Ugb2YgMjk1LjcsIHdoaWxlIHJhZGlvIGhhZCB0aGUgbG93ZXN0IHZhbHVlIG9mIDAuIA0KLS0tLS0tLS0tLS0tLQ0KDQoNCiMjIFRhc2sgMjogUXVhbGl0YXRpdmUgQW5hbHlzaXMNCg0KLS0tLS0tLS0tLS0tLQ0KDQoNCiMjIyAyQSkgUGxvdCBhbGwgdGhlIGFzc2lnbmVkIGZlYXR1cmVzIGFzIHktYXhpcyBmb3IgeC1heGlzIHVzZSBjYXNlX251bWJlci4gVXNlIHRoZSBnaXZlbiBjb21tYW5kcyB0byBjcmVhdGUgZWFjaCBwbG90IGFuZCBjcmVhdGUgYSBncmlkIHRvIHBsb3QgYWxsIGZlYXR1cmVzIE5vdGUgYW55IHRyZW5kcy9wYXR0ZXJzIGluIHRoZSBkYXRhDQoNCiogQ29tbWFuZHM6IFZBUklBQkxFX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gVkFSSUFCTEUsIHkgPSBWQVJJQUJMRSkpICsgZ2VvbV9wb2ludCgpDQoqIENvbW1hbmRzOiBncmlkLmFycmFuZ2UoVkFSSUFCTEVfcGxvdDEsIFZBUklBQkxFX3Bsb3QyLCBWQVJJQUJMRV9wbG90MywgVkFSSUFCTEVfcGxvdDQsIG5jb2w9MikNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCiNncmlkLmFycmFuZ2UoVkFSSUFCTEVfcGxvdDEsIFZBUklBQkxFX3Bsb3QyLCBWQVJJQUJMRV9wbG90MywgVkFSSUFCTEVfcGxvdDQsIG5jb2w9MikNCg0KdHZfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IG15ZGF0YSwgYWVzKHggPSBjYXNlX251bWJlciwgeSA9IFRWKSkgKyBnZW9tX3BvaW50KCkNCm5ld3NwYXBlcl9wbG90IDwtIGdncGxvdChkYXRhID0gbXlkYXRhLCBhZXMoeCA9IGNhc2VfbnVtYmVyLCB5ID0gbmV3c3BhcGVyKSkgKyBnZW9tX3BvaW50KCkNCnNhbGVzX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gY2FzZV9udW1iZXIsIHkgPSBzYWxlcykpICsgZ2VvbV9wb2ludCgpDQpyYWRpb19wbG90IDwtIGdncGxvdChkYXRhID0gbXlkYXRhLCBhZXMoeCA9IGNhc2VfbnVtYmVyLCB5ID0gcmFkaW8pKSArIGdlb21fcG9pbnQoKQ0KdHZfcGxvdA0KbmV3c3BhcGVyX3Bsb3QNCnNhbGVzX3Bsb3QNCnJhZGlvX3Bsb3QNCg0KZmluYWwgPC0gZ3JpZC5hcnJhbmdlKHR2X3Bsb3QsIG5ld3NwYXBlcl9wbG90LCBzYWxlc19wbG90LCByYWRpb19wbG90LCBuY29sPTIpDQpgYGANCg0KT3V0IG9mIGFsbCB0aGVzZSBncmFwaHMsIG9uZSBjYW5ub3QgZGVkdWNlIHN0cm9uZ2x5IHRoYXQgdGhlcmUgaXMgYSBjbGVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4gSW4gZmFjdCwgdGhlcmUgaXMgbm8gbGluZSBvZiBiZXN0IGZpdCBmb3IgYW55IG9mIHRoZXNlIGdyYXBocy4gDQoNCg0KKiBXaGVuIGxvb2tpbmcgYXQgdGhlc2UgcGxvdHMgaXQgaXMgaGFyZCB0byBzZWUgYSBwYXJ0aWN1bGFyIHRyZW5kLiANCiogT25lIHdheSB0byBvYnNlcnZlIGFueSBwb3NzaWJsZSB0cmVuZCBpbiB0aGUgc2FsZXMgZGF0YSB3b3VsZCBiZSB0byByZS1vcmRlciB0aGUgZGF0YSBmcm9tIGxvdyB0byBoaWdoLiANCiogVGhlIDIwMCBtb250aHMgb2JzZXJ2YXRpb25zIGFyZSBpbiBubyBwYXJ0aWN1bGFyIGNocm9ub2xvZ2ljYWwgdGltZSBzZXF1ZW5jZS4gDQoqIFRoZSBjYXNlIG51bWJlcnMgYXJlIGluZGVwZW5kZW50IHNlcXVlbnRpYWxseSBnZW5lcmF0ZWQgbnVtYmVycy4gU2luY2UgZWFjaCBjYXNlIGlzIGluZGVwZW5kZW50LCB3ZSBjYW4gcmVvcmRlciB0aGVtLiANCg0KDQojIyMgMkIpIFJlLW9yZGVyIHNhbGVzIGZyb20gbG93IHRvIGhpZ2gsIGFuZCBzYXZlIHJlLW9yZGVyZWQgZGF0YSBpbiBhIG5ldyBzZXQuIEFzIHNhbGVzIGRhdGEgaXMgcmUtcmVvcmRlZCBhc3NvY2lhdGVkIG90aGVyIGNvbHVtbiBmaWVsZHMgZm9sbG93Lg0KDQoqIENvbW1hbmRzOiBuZXdkYXRhIDwtIG15ZGF0YVsgb3JkZXIobXlkYXRhJFZBUklBQkxFKSwgXQ0KDQpgYGB7cn0NCg0KIyBFeHRyYWN0IGNhc2VfbnVtYmVyIGZyb20gdGhlIG5ld2RhdGENCg0KbmV3ZGF0YSA8LSBteWRhdGEgWyBvcmRlcihteWRhdGEkc2FsZXMpLCBdDQoNCg0KbmV3ZGF0YQ0KYGBgDQoNCg0KIyMjIyBFeHRyYWN0IHRoZSB2YXJpYWJsZXMgZnJvbSB0aGUgbmV3IGRhdGENCg0KYGBge3J9DQojIG5ld19WQVJJQUJMRSA9IG5ld2RhdGEkVkFSSUFCTEUNCg0KbmV3X3NhbGVzID0gbmV3ZGF0YSRzYWxlcw0KbmV3X1RWID0gbmV3ZGF0YSRUVg0KbmV3X25ld3NwYXBlciA9IG5ld2RhdGEkbmV3c3BhcGVyDQpuZXdfcmFkaW8gPSBuZXdkYXRhJHJhZGlvDQoNCmBgYA0KDQojIyMgMkMpIFJlcGVhdCB0aGUgNCBncmFwaHMgd2l0aCB0aGUgbmV3ZGF0YSB0byBzcG90IGFueSB0cmVuZHMuIE5vdGUgeW91ciBvYnNlcnZhdGlvbnMgb24gd2hhdCB0aGUgbmV3IHBsb3RzIGFyZSByZXZlYWxpbmcgaW4gdGVybXMgb2YgdHJlbmRpbmcgcmVsYXRpb25zaGlwLiANCg0KKiBDb21tYW5kczogVkFSSUFCTEVfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IG15ZGF0YSwgYWVzKHggPSBWQVJJQUJMRSwgeSA9IFZBUklBQkxFKSkgKyBnZW9tX3BvaW50KCkNCiogQ29tbWFuZHM6IEZvciB4IHZhcmlhYmxlIGluIHRoZSBwbG90IHVzZTogYWVzKHggPSBjYXNlX251bWJlcltvcmRlcihjYXNlX251bWJlcildKQ0KKiBDb21tYW5kczogZ3JpZC5hcnJhbmdlKFZBUklBQkxFX3Bsb3QxLCBWQVJJQUJMRV9wbG90MiwgVkFSSUFCTEVfcGxvdDMsIFZBUklBQkxFX3Bsb3Q0LCBuY29sPTIpDQoNCmBgYHtyfQ0KDQpuZXd0dl9wbG90IDwtIGdncGxvdChkYXRhID0gbXlkYXRhLCBhZXMoeCA9IGNhc2VfbnVtYmVyW29yZGVyKGNhc2VfbnVtYmVyKV0sIHkgPSBuZXdfVFYpKSArIGdlb21fcG9pbnQoKQ0KDQpuZXduZXdzcGFwZXJfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IG15ZGF0YSwgYWVzKHggPSBjYXNlX251bWJlcltvcmRlcihjYXNlX251bWJlcildLCB5ID0gbmV3X25ld3NwYXBlcikpICsgZ2VvbV9wb2ludCgpDQoNCm5ld3NhbGVzX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gY2FzZV9udW1iZXJbb3JkZXIoY2FzZV9udW1iZXIpXSwgeSA9IG5ld19zYWxlcykpICsgZ2VvbV9wb2ludCgpDQoNCm5ld3JhZGlvX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBteWRhdGEsIGFlcyh4ID0gY2FzZV9udW1iZXJbb3JkZXIoY2FzZV9udW1iZXIpXSwgeSA9IG5ld19yYWRpbykpICsgZ2VvbV9wb2ludCgpDQoNCg0KZmluYWwgPC0gZ3JpZC5hcnJhbmdlKG5ld3R2X3Bsb3QsIG5ld25ld3NwYXBlcl9wbG90LCBuZXdzYWxlc19wbG90LCBuZXdyYWRpb19wbG90LCBuY29sPTIpDQojZ3JpZC5hcnJhbmdlKG5ld3NhbGVzX3Bsb3QsIG5ld3R2X3Bsb3QsIG5ld3JhZGlvX3Bsb3QsIG5ld25ld3NfcGxvdCwgbmNvbD0yKQ0KYGBgDQpUaGVzZSBuZXcgZ3JhcGhzIHByZXNlbnQgIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBjZXJ0YWluIHZhcmlhYmxlcyBhbmQgY2FzZSBudW1iZXJzLg0KbmV3X1RWLCBuZXdfc2FsZXMsIGFuZCBuZXdfcmFkaW8gaGF2ZSBwb3NpdGl2ZSB0cmVuZGxpbmVzLCBpbGx1c3RyYXRpbmcgdGhhdCB0aGVyZSBoYXZlIHByb3BvcnRpb25hbCByZWxhdGlvbnNoaXBzIHdpdGggY2FzZSBudW1iZXJzLiBIb3dldmVyLCBuZXdfc2FsZXMgcGxvdCBhcHBlYXJzIHRvIGJlIGEgbGluZWFyIGxpbmUgb2YgYmVzdCBmaXQgd2l0aCB0aGUgbGVhc3QgYW1vdW50IG9mIHZhcmlhdGlvbiBmcm9tIHRoZSB0cmVuZGxpbmUsIHdoZXJlYXMgbmV3X3JhZGlvIGFuZCBuZXdfVFYgaGF2ZSBjdXJ2ZWQvZXhwb25lbnRpb25hbCByZWxhaW9uc2hpcHMuIE9uIHRoZSBvdGhlciBoYW5kLCBuZXdfbmV3c3BhcGVyIGRvZXNuJ3QgYXBwZWFyIHRvIGhhdmUgYW55IHByb21pbmVudCB0cmVuZGxpbmUuDQotLS0tLS0tLS0tDQoNCiMjIFRhc2sgMzogU3RhbmRhcmRpemVkIFotVmFsdWUNCg0KLS0tLS0tLS0tLQ0KDQoNCiMjIyAzQSkgQ3JlYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSBhc3NpZ25lZCBmZWF0dXJlIHotc2NvcmVzLiBEZXNjcmliZSB0aGUgb3V0cHV0IG5vdGUgYW55IHJlbGV2YW50IHZhbHVlcy4NCg0KKiBDb21tYW5kOiB6X3Njb3JlID0gKCBWQVJJQUJMRSAtIG1lYW4oVkFSSUFCTEUpICkgLyBzZChWQVJJQUJMRSkNCiogQ29tbWFuZHM6IHFwbG90KCB4ID0gVkFSSUFCTEUgLGdlb209Imhpc3RvZ3JhbSIsIGJpbndpZHRoID0gMC4zKQ0KDQpgYGB7cn0NCnpfc2NvcmVzID0gKCBteWRhdGEkc2FsZXMgLSBtZWFuKG15ZGF0YSRzYWxlcykgKSAvIHNkKG15ZGF0YSRzYWxlcykNCnFwbG90KCB4ID0gel9zY29yZXMgLGdlb209Imhpc3RvZ3JhbSIsIGJpbndpZHRoID0gMC4zKQ0KDQpgYGANClRoaXMgaGlzdG9ncmFtIGhhcyBhIG5vcm1hbCBkaXN0cmlidXRpb24gYW5kIGlzIHBvc2l0aXZlbHkgc2tld2VkLCB3aGljaCBtZWFucyB0aGUgbW9kZSBpcyBsZXNzIHRoYW4gdGhlIG1lYW4gYW5kIG1lZGlhbi4gDQoNCg0KIyMjIDNCKSBHaXZlbiBhIHNhbGVzIHZhbHVlIG9mICQyNjcwMCwgY2FsY3VsYXRlIHRoZSBjb3JyZXNwb25kaW5nIHotdmFsdWUgb3Igei1zY29yZS4gDQoNCiogQ29tbWFuZDogel9zY29yZSA9ICggVkFSSUFCTEUgLSBtZWFuKFZBUklBQkxFKSApIC8gc2QoVkFSSUFCTEUpDQoNCmBgYHtyfQ0Kel9zY29yZSA9ICgyNi43IC0gKG1lYW4obXlkYXRhJHNhbGVzKSkpIC8gc2QobXlkYXRhJHNhbGVzKQ0Kel9zY29yZQ0KDQpgYGANCg0KDQojIyMgM0MpIEJhc2VkIG9uIHRoZSB6LXZhbHVlLCBob3cgd291bGQgeW91IHJhdGUgYSAkMjY3MDAgc2FsZXMgdmFsdWU6IHBvb3IsIGF2ZXJhZ2UsIGdvb2QsIG9yIHZlcnkgZ29vZCBwZXJmb3JtYW5jZT8gRXhwbGFpbiB5b3VyIGxvZ2ljLiANCg0KDQpCYXNkIG9uIHRoZSB6LXZhbHVlLCBJIHdvdWxkIHJhdGUgJDI2NzAwIGFzIGEgdmVyeSBnb29kIHBlcmZvcm1hbmNlLiBOb3Qgb25seSBpcyBpdCBhYm92ZSB0aGUgbWVhbiwgYnV0IGl0IGV4Y2VlZHMgdGhlIHNhbGVzIGRhdGEncyB1cHBlciB0aHJlc2hvbGQuIEhlbmNlLCBvbmUgbWlnaHQgY29uY2x1ZGUgdGhhdCB0aGlzIHZhbHVlIGlzIGFuIG91dGxpZXIsIGFuZCBpdCBtaWdodCBub3QgYmUgcmVwcmVzZW50YXRpdmUgb2YgdGhlIHdob2xlIGRhdGEgYW5kIHdvdWxkIHJlcXVpcmUgZnVydGhlciBpbnZlc3RpZ2F0aW9uLg0KDQpgYGANCg0K