First lets load the data into R:

com <- read.csv("communities.csv")

PART 1

(1) How many distinct states are represented in this dataset? How many distinct counties are represented?

length(unique(com$state))
[1] 46
length(unique(com$county))
[1] 109

There are a total of 46 distinct states, and 109 distinct counties (108 if you do not consider NA as a county). But there are many missing values in the counties column, so there actually might be many more.

(2) Produce a frequency table with the number of missing values per column.

freq = c()
for(i in names(com))
{
  j <- com[i]
  v <- sum(is.na(j))
  freq <- c(freq, v)
}
table(freq)
freq
   0    1 1174 1177 1675 
 103    1    1    1   22 

As can be seen in the table. 103 of the variables do not have any missing variables. Only 1 has 1 missing variable. One column has 1174 missing values, and another has 1177 missing values. And 22 variables has 1675 missing values.

(3) Discard all columns with more than 50% of the values missing. Reproduce the frequency table from 2 using the reduced dataset.

com_reduced = c()
for(i in names(com))
{
  j <- com[i]
  v <- sum(is.na(j))
  #print (v)
  if (v < 997)
  {
    com_reduced = c(com_reduced, com[i])
  }
}
freq_red = c()
for(i in names(com_reduced))
{
  j <- com_reduced[i]
  v <- length(grep("NA", j))
  freq_red <- c(freq_red, v)
}
table(freq_red)
freq_red
  0   1 
103   1 

The columns that had missing values, usually had most of the values missing. I discarded all the columns that had more than half of its values missing. This new reduced data set is now called com_reduced. And a new frequency table was created. In it we can see that all but one column have no data missing. And the column that has missing data, is only missing one value.

  1. Plot a histogram of the response variable ViolentCrimesPerPop.
hist(com_reduced$ViolentCrimesPerPop, main = "Histogram of Violent Crimes Per Population", xlab = "Violent Crimes per 100K")

The ViolentCrimesPerPop number is the number of violented crimes commited per 100K people. On average 0.24 crimes were commited. Most places did have a low number of violent crimes, and the frequency dicreases with the increase of the number of violent crimes.

PART 2

First lets remove the identifying variables. THe variables we will remove:

These variables that have been removed because they do not have any ordering to them.

com_relevant <- within(com_reduced, rm(state))
com_relevant <- within(com_relevant, rm(communityname))
com_relevant <- within(com_relevant, rm(fold))

(1) Run forward stepwise selection on your dataset.

Because I get an error because of the missing value, I will be remove the column that is causing the error. And afterwards we run forward stepwise selection.

com_relevant_2 <- within(com_relevant, rm(OtherPerCap))
m.full <- lm(ViolentCrimesPerPop ~ ., data=com_relevant_2)
m.empty <- lm(ViolentCrimesPerPop ~ 1, data=com_relevant_2)
m.forward <- step(m.empty, scope=list(upper=m.full),data=com_relevant_2, direction="forward",trace = FALSE)

Explain why you would have a warning message if you use any predictors with missing values in the stepwise selection process.

It causes an error because it is not possible to do linear regression on a missing value.

(2) Also run backward and bi-directional stepwise selection on your dataset.

#backward
m.full <- lm(ViolentCrimesPerPop ~ ., data=com_relevant_2)
m.empty <- lm(ViolentCrimesPerPop ~ 1, data=com_relevant_2)
m.backward <- step(m.full, scope=list(lower=m.empty),data=com_relevant_2, direction="backward",trace = FALSE)       
m.both <- step(m.empty, scope=list(upper=m.full),data=com_relevant_2, direction="both",trace = FALSE)

For each of the 3 models obtained via forward, backward, and bi-directional stepwise selection, report the model sizes (i.e. number of predictors) and the R squared values achieved.

sf <- summary(m.forward)
sba <- summary(m.backward)
sbo <- summary(m.both)
print ("forward:")
[1] "forward:"
sf$r.squared
[1] 0.6832967
AIC(m.forward)
[1] -2366.599
print("backward:")
[1] "backward:"
sba$r.squared
[1] 0.6908641
AIC(m.backward)
[1] -2382.823
print("both:")
[1] "both:"
sbo$r.squared
[1] 0.6832967
AIC(m.both)
[1] -2366.599

Both forward and bi-directional stepwise selection found 37 relevant predictors and had r-squared values of 0.683, and AIC of -2366.599. Backward selection found 53 predictors and had an r-squared value of 0.6910, and an AIC of -2382.823.

PART 3

The model which I consider the best is the one generated from forward stepwise selection. First we will extract the model, and then run regression on the same data.

f <- formula(m.forward)
f
ViolentCrimesPerPop ~ PctKids2Par + racePctWhite + HousVacant + 
    pctUrban + PctWorkMom + NumStreet + MalePctDivorce + PctIlleg + 
    numbUrban + PctPersDenseHous + racepctblack + agePct12t29 + 
    MedOwnCostPctIncNoMtg + PctPopUnderPov + pctWRetire + MedRentPctHousInc + 
    RentLowQ + MedRent + pctWWage + whitePerCap + MalePctNevMarr + 
    PctEmploy + PctEmplManu + TotalPctDiv + perCapInc + pctWInvInc + 
    LemasPctOfficDrugUn + MedOwnCostPctInc + PctVacMore6Mos + 
    PctVacantBoarded + HispPerCap + pctWFarmSelf + indianPerCap + 
    PctLess9thGrade + PctLargHouseFam + agePct12t21 + AsianPerCap
reg <- lm(f, data=com_relevant_2)
reg

Call:
lm(formula = f, data = com_relevant_2)

Coefficients:
          (Intercept)            PctKids2Par           racePctWhite             HousVacant  
              0.75437               -0.34470               -0.07903                0.26889  
             pctUrban             PctWorkMom              NumStreet         MalePctDivorce  
              0.04002               -0.13716                0.18639                0.34656  
             PctIlleg              numbUrban       PctPersDenseHous           racepctblack  
              0.14703               -0.21317                0.25001                0.17566  
          agePct12t29  MedOwnCostPctIncNoMtg         PctPopUnderPov             pctWRetire  
             -0.28410               -0.08087               -0.15525               -0.10541  
    MedRentPctHousInc               RentLowQ                MedRent               pctWWage  
              0.05484               -0.24271                0.26546               -0.22630  
          whitePerCap         MalePctNevMarr              PctEmploy            PctEmplManu  
             -0.32198                0.15148                0.19944               -0.03149  
          TotalPctDiv              perCapInc             pctWInvInc    LemasPctOfficDrugUn  
             -0.30508                0.21736               -0.16796                0.02951  
     MedOwnCostPctInc         PctVacMore6Mos       PctVacantBoarded             HispPerCap  
             -0.04733              -0.05978               0.04487               0.04240 
         pctWFarmSelf          indianPerCap       PctLess9thGrade       PctLargHouseFam 
              0.03912              -0.03551              -0.05776              -0.08847 
          agePct12t21           AsianPerCap 
              0.09153               0.02642 

** (1) Which model did you end up choosing? Justify your answer, show the regression output, and in a sentence or two, summarize what you learn from two or three of the significant coefficients. **

I chose forward stepwise selection. Forward and bi-directional gave the same results. And backward selection gave a similar r-squared but is a little lower. But it is only 1% better at fitting the data, which is most likely caused by overfitting. Another disadvantage of the backward selection is that it had a significant additional number of predictors. 16 more than forward selection. THerefore I thought it was better to choose a more simple model.

Above we can see the relevant predictors, and the weight of each. I will talk a bit more about the 3 predictors with the heighest weights.

(2) Run 10-fold cross-validation to estimate the test MSE. Use the fold column in the dataset for determining the folds.

fold = com$fold
mse = 0
for (i in 1:10)
{
  train <- com[fold != i,]
  valid <- com[fold == i,]
  m <- lm(f, data=train)
  p <- predict(m,newdata=valid)
  mse = mse + mean((p - valid$ViolentCrimesPerPop)^2)
}
print (mse / 10)
[1] 0.01793732

Report your estimated test MSE.

The Mean squared error for the model is 0.0179.

(3) Use the bootstrap to estimate a 90% confidence interval for multiple R2.

#confint(m.forward)
set.seed(222)
N <- 1000
r2 <- rep(NA, N)
n <- length(com_relevant_2[[1]])
com_r <- structure(com_relevant_2, row.names = c(NA, -n), class = "data.frame")
for (i in 1:N) {
  s <- sample(1:nrow(com_r), nrow(com_r), replace=TRUE)
  m1.s <- lm(f, data=com_r[s,])
  r2[i] <- summary(m1.s)$r.squared
}

1000 random samples were created, and from that extracted the confidence intervals. The confidence intervals for multiple R-squared are: 2.5% - 0.6597118 97.5% - 0.7188363

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpGaXJzdCBsZXRzIGxvYWQgdGhlIGRhdGEgaW50byBSOg0KDQpgYGB7cn0NCmNvbSA8LSByZWFkLmNzdigiY29tbXVuaXRpZXMuY3N2IikNCmBgYA0KDQojUEFSVCAxDQoNCioqKDEpIEhvdyBtYW55IGRpc3RpbmN0IHN0YXRlcyBhcmUgcmVwcmVzZW50ZWQgaW4gdGhpcyBkYXRhc2V0PyBIb3cgbWFueSBkaXN0aW5jdCBjb3VudGllcyBhcmUgcmVwcmVzZW50ZWQ/KioNCg0KYGBge3J9DQpsZW5ndGgodW5pcXVlKGNvbSRzdGF0ZSkpDQpsZW5ndGgodW5pcXVlKGNvbSRjb3VudHkpKQ0KYGBgDQoNClRoZXJlIGFyZSBhIHRvdGFsIG9mIDQ2IGRpc3RpbmN0IHN0YXRlcywgYW5kIDEwOSBkaXN0aW5jdCBjb3VudGllcyAoMTA4IGlmIHlvdSBkbyBub3QgY29uc2lkZXIgTkEgYXMgYSBjb3VudHkpLiBCdXQgdGhlcmUgYXJlIG1hbnkgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGNvdW50aWVzIGNvbHVtbiwgc28gdGhlcmUgYWN0dWFsbHkgbWlnaHQgYmUgbWFueSBtb3JlLg0KDQoqKigyKSBQcm9kdWNlIGEgZnJlcXVlbmN5IHRhYmxlIHdpdGggdGhlIG51bWJlciBvZiBtaXNzaW5nIHZhbHVlcyBwZXIgY29sdW1uLioqDQoNCmBgYHtyfQ0KZnJlcSA9IGMoKQ0KZm9yKGkgaW4gbmFtZXMoY29tKSkNCnsNCiAgaiA8LSBjb21baV0NCiAgdiA8LSBzdW0oaXMubmEoaikpDQogIGZyZXEgPC0gYyhmcmVxLCB2KQ0KfQ0KdGFibGUoZnJlcSkNCmBgYA0KDQpBcyBjYW4gYmUgc2VlbiBpbiB0aGUgdGFibGUuIDEwMyBvZiB0aGUgdmFyaWFibGVzIGRvIG5vdCBoYXZlIGFueSBtaXNzaW5nIHZhcmlhYmxlcy4gT25seSAxIGhhcyAxIG1pc3NpbmcgdmFyaWFibGUuIE9uZSBjb2x1bW4gaGFzIDExNzQgbWlzc2luZyB2YWx1ZXMsIGFuZCBhbm90aGVyIGhhcyAxMTc3IG1pc3NpbmcgdmFsdWVzLiBBbmQgMjIgdmFyaWFibGVzIGhhcyAxNjc1IG1pc3NpbmcgdmFsdWVzLg0KDQoqKigzKSBEaXNjYXJkIGFsbCBjb2x1bW5zIHdpdGggbW9yZSB0aGFuIDUwJSBvZiB0aGUgdmFsdWVzIG1pc3NpbmcuIFJlcHJvZHVjZSB0aGUgZnJlcXVlbmN5IHRhYmxlIGZyb20gMiB1c2luZyB0aGUgcmVkdWNlZCBkYXRhc2V0LioqDQoNCmBgYHtyfQ0KY29tX3JlZHVjZWQgPSBjKCkNCmZvcihpIGluIG5hbWVzKGNvbSkpDQp7DQogIGogPC0gY29tW2ldDQogIHYgPC0gc3VtKGlzLm5hKGopKQ0KICAjcHJpbnQgKHYpDQogIGlmICh2IDwgOTk3KQ0KICB7DQogICAgY29tX3JlZHVjZWQgPSBjKGNvbV9yZWR1Y2VkLCBjb21baV0pDQogIH0NCn0NCmZyZXFfcmVkID0gYygpDQpmb3IoaSBpbiBuYW1lcyhjb21fcmVkdWNlZCkpDQp7DQogIGogPC0gY29tX3JlZHVjZWRbaV0NCiAgdiA8LSBsZW5ndGgoZ3JlcCgiTkEiLCBqKSkNCiAgZnJlcV9yZWQgPC0gYyhmcmVxX3JlZCwgdikNCn0NCnRhYmxlKGZyZXFfcmVkKQ0KDQpgYGANCg0KVGhlIGNvbHVtbnMgdGhhdCBoYWQgbWlzc2luZyB2YWx1ZXMsIHVzdWFsbHkgaGFkIG1vc3Qgb2YgdGhlIHZhbHVlcyBtaXNzaW5nLiBJIGRpc2NhcmRlZCBhbGwgdGhlIGNvbHVtbnMgdGhhdCBoYWQgbW9yZSB0aGFuIGhhbGYgb2YgaXRzIHZhbHVlcyBtaXNzaW5nLiBUaGlzIG5ldyByZWR1Y2VkIGRhdGEgc2V0IGlzIG5vdyBjYWxsZWQgY29tX3JlZHVjZWQuIEFuZCBhIG5ldyBmcmVxdWVuY3kgdGFibGUgd2FzIGNyZWF0ZWQuIEluIGl0IHdlIGNhbiBzZWUgdGhhdCBhbGwgYnV0IG9uZSBjb2x1bW4gaGF2ZSBubyBkYXRhIG1pc3NpbmcuIEFuZCB0aGUgY29sdW1uIHRoYXQgaGFzIG1pc3NpbmcgZGF0YSwgaXMgb25seSBtaXNzaW5nIG9uZSB2YWx1ZS4NCg0KKDQpIFBsb3QgYSBoaXN0b2dyYW0gb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIFZpb2xlbnRDcmltZXNQZXJQb3AuDQoNCmBgYHtyfQ0KaGlzdChjb21fcmVkdWNlZCRWaW9sZW50Q3JpbWVzUGVyUG9wLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBWaW9sZW50IENyaW1lcyBQZXIgUG9wdWxhdGlvbiIsIHhsYWIgPSAiVmlvbGVudCBDcmltZXMgcGVyIDEwMEsiKQ0KYGBgDQoNClRoZSBWaW9sZW50Q3JpbWVzUGVyUG9wIG51bWJlciBpcyB0aGUgbnVtYmVyIG9mIHZpb2xlbnRlZCBjcmltZXMgY29tbWl0ZWQgcGVyIDEwMEsgcGVvcGxlLiBPbiBhdmVyYWdlIDAuMjQgY3JpbWVzIHdlcmUgY29tbWl0ZWQuIE1vc3QgcGxhY2VzIGRpZCBoYXZlIGEgbG93IG51bWJlciBvZiB2aW9sZW50IGNyaW1lcywgYW5kIHRoZSBmcmVxdWVuY3kgZGljcmVhc2VzIHdpdGggdGhlIGluY3JlYXNlIG9mIHRoZSBudW1iZXIgb2YgdmlvbGVudCBjcmltZXMuDQoNCiNQQVJUIDINCg0KRmlyc3QgbGV0cyByZW1vdmUgdGhlIGlkZW50aWZ5aW5nIHZhcmlhYmxlcy4gVEhlIHZhcmlhYmxlcyB3ZSB3aWxsIHJlbW92ZToNCg0KKiBjb21tdW5pdHkgbmFtZSANCg0KKiBjb21tdW5pdHkgKGhhcyBhbHJlYWR5IGJlZW4gcmVtb3ZlZCBiZWNhdXNlIHRvbyBtYW55IG1pc3NpbmcgdmFsdWVzKQ0KDQoqIGZvbGQNCg0KKiBzdGF0ZQ0KDQoqIGNvdW50eSAoaGFzIGFscmVhZHkgYmVlbiByZW1vdmVkIGJlY2F1c2UgdG9vIG1hbnkgbWlzc2luZyB2YWx1ZXMpDQoNClRoZXNlIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiByZW1vdmVkIGJlY2F1c2UgdGhleSBkbyBub3QgaGF2ZSBhbnkgb3JkZXJpbmcgdG8gdGhlbS4gDQoNCmBgYHtyfQ0KY29tX3JlbGV2YW50IDwtIHdpdGhpbihjb21fcmVkdWNlZCwgcm0oc3RhdGUpKQ0KY29tX3JlbGV2YW50IDwtIHdpdGhpbihjb21fcmVsZXZhbnQsIHJtKGNvbW11bml0eW5hbWUpKQ0KY29tX3JlbGV2YW50IDwtIHdpdGhpbihjb21fcmVsZXZhbnQsIHJtKGZvbGQpKQ0KYGBgDQoNCioqKDEpIFJ1biBmb3J3YXJkIHN0ZXB3aXNlIHNlbGVjdGlvbiBvbiB5b3VyIGRhdGFzZXQuKioNCg0KQmVjYXVzZSBJIGdldCBhbiBlcnJvciBiZWNhdXNlIG9mIHRoZSBtaXNzaW5nIHZhbHVlLCBJIHdpbGwgYmUgcmVtb3ZlIHRoZSBjb2x1bW4gdGhhdCBpcyBjYXVzaW5nIHRoZSBlcnJvci4gQW5kIGFmdGVyd2FyZHMgd2UgcnVuIGZvcndhcmQgc3RlcHdpc2Ugc2VsZWN0aW9uLg0KDQpgYGB7cn0NCmNvbV9yZWxldmFudF8yIDwtIHdpdGhpbihjb21fcmVsZXZhbnQsIHJtKE90aGVyUGVyQ2FwKSkNCg0KbS5mdWxsIDwtIGxtKFZpb2xlbnRDcmltZXNQZXJQb3AgfiAuLCBkYXRhPWNvbV9yZWxldmFudF8yKQ0KbS5lbXB0eSA8LSBsbShWaW9sZW50Q3JpbWVzUGVyUG9wIH4gMSwgZGF0YT1jb21fcmVsZXZhbnRfMikNCm0uZm9yd2FyZCA8LSBzdGVwKG0uZW1wdHksIHNjb3BlPWxpc3QodXBwZXI9bS5mdWxsKSxkYXRhPWNvbV9yZWxldmFudF8yLCBkaXJlY3Rpb249ImZvcndhcmQiLHRyYWNlID0gRkFMU0UpDQpgYGANCg0KDQpFeHBsYWluIHdoeSB5b3Ugd291bGQgaGF2ZSBhIHdhcm5pbmcgbWVzc2FnZSBpZiB5b3UgdXNlIGFueSBwcmVkaWN0b3JzIHdpdGggbWlzc2luZyB2YWx1ZXMgaW4gdGhlIHN0ZXB3aXNlIHNlbGVjdGlvbiBwcm9jZXNzLg0KDQpJdCBjYXVzZXMgYW4gZXJyb3IgYmVjYXVzZSBpdCBpcyBub3QgcG9zc2libGUgdG8gZG8gbGluZWFyIHJlZ3Jlc3Npb24gb24gYSBtaXNzaW5nIHZhbHVlLg0KDQoqKigyKSBBbHNvIHJ1biBiYWNrd2FyZCBhbmQgYmktZGlyZWN0aW9uYWwgc3RlcHdpc2Ugc2VsZWN0aW9uIG9uIHlvdXIgZGF0YXNldC4qKg0KDQpgYGB7cn0NCiNiYWNrd2FyZA0KbS5mdWxsIDwtIGxtKFZpb2xlbnRDcmltZXNQZXJQb3AgfiAuLCBkYXRhPWNvbV9yZWxldmFudF8yKQ0KbS5lbXB0eSA8LSBsbShWaW9sZW50Q3JpbWVzUGVyUG9wIH4gMSwgZGF0YT1jb21fcmVsZXZhbnRfMikNCm0uYmFja3dhcmQgPC0gc3RlcChtLmZ1bGwsIHNjb3BlPWxpc3QobG93ZXI9bS5lbXB0eSksZGF0YT1jb21fcmVsZXZhbnRfMiwgZGlyZWN0aW9uPSJiYWNrd2FyZCIsdHJhY2UgPSBGQUxTRSkgICAgICAgDQptLmJvdGggPC0gc3RlcChtLmVtcHR5LCBzY29wZT1saXN0KHVwcGVyPW0uZnVsbCksZGF0YT1jb21fcmVsZXZhbnRfMiwgZGlyZWN0aW9uPSJib3RoIix0cmFjZSA9IEZBTFNFKQ0KDQpgYGANCg0KRm9yIGVhY2ggb2YgdGhlIDMgbW9kZWxzIG9idGFpbmVkIHZpYSBmb3J3YXJkLCBiYWNrd2FyZCwgYW5kIGJpLWRpcmVjdGlvbmFsIHN0ZXB3aXNlIHNlbGVjdGlvbiwgcmVwb3J0IHRoZSBtb2RlbCBzaXplcyAoaS5lLiBudW1iZXIgb2YgcHJlZGljdG9ycykgYW5kIHRoZSBSIHNxdWFyZWQgdmFsdWVzIGFjaGlldmVkLg0KDQpgYGB7cn0NCnNmIDwtIHN1bW1hcnkobS5mb3J3YXJkKQ0Kc2JhIDwtIHN1bW1hcnkobS5iYWNrd2FyZCkNCnNibyA8LSBzdW1tYXJ5KG0uYm90aCkNCg0KcHJpbnQgKCJmb3J3YXJkOiIpDQpzZiRyLnNxdWFyZWQNCkFJQyhtLmZvcndhcmQpDQoNCnByaW50KCJiYWNrd2FyZDoiKQ0Kc2JhJHIuc3F1YXJlZA0KQUlDKG0uYmFja3dhcmQpDQoNCnByaW50KCJib3RoOiIpDQpzYm8kci5zcXVhcmVkDQpBSUMobS5ib3RoKQ0KDQpgYGANCg0KQm90aCBmb3J3YXJkIGFuZCBiaS1kaXJlY3Rpb25hbCBzdGVwd2lzZSBzZWxlY3Rpb24gZm91bmQgMzcgcmVsZXZhbnQgcHJlZGljdG9ycyBhbmQgaGFkIHItc3F1YXJlZCB2YWx1ZXMgb2YgMC42ODMsIGFuZCBBSUMgb2YgLTIzNjYuNTk5LiBCYWNrd2FyZCBzZWxlY3Rpb24gZm91bmQgNTMgcHJlZGljdG9ycyBhbmQgaGFkIGFuIHItc3F1YXJlZCB2YWx1ZSBvZiAwLjY5MTAsIGFuZCBhbiBBSUMgb2YgLTIzODIuODIzLg0KDQojUEFSVCAzDQoNClRoZSBtb2RlbCB3aGljaCBJIGNvbnNpZGVyIHRoZSBiZXN0IGlzIHRoZSBvbmUgZ2VuZXJhdGVkIGZyb20gZm9yd2FyZCBzdGVwd2lzZSBzZWxlY3Rpb24uIEZpcnN0IHdlIHdpbGwgZXh0cmFjdCB0aGUgbW9kZWwsIGFuZCB0aGVuIHJ1biByZWdyZXNzaW9uIG9uIHRoZSBzYW1lIGRhdGEuDQoNCmBgYHtyfQ0KZiA8LSBmb3JtdWxhKG0uZm9yd2FyZCkNCnJlZyA8LSBsbShmLCBkYXRhPWNvbV9yZWxldmFudF8yKQ0KcmVnDQpgYGANCg0KDQoqKiAoMSkgV2hpY2ggbW9kZWwgZGlkIHlvdSBlbmQgdXAgY2hvb3Npbmc/IEp1c3RpZnkgeW91ciBhbnN3ZXIsIHNob3cgdGhlIHJlZ3Jlc3Npb24gb3V0cHV0LCBhbmQgaW4gYQ0Kc2VudGVuY2Ugb3IgdHdvLCBzdW1tYXJpemUgd2hhdCB5b3UgbGVhcm4gZnJvbSB0d28gb3IgdGhyZWUgb2YgdGhlIHNpZ25pZmljYW50IGNvZWZmaWNpZW50cy4gKioNCg0KICBJIGNob3NlIGZvcndhcmQgc3RlcHdpc2Ugc2VsZWN0aW9uLiBGb3J3YXJkIGFuZCBiaS1kaXJlY3Rpb25hbCBnYXZlIHRoZSBzYW1lIHJlc3VsdHMuIEFuZCBiYWNrd2FyZCBzZWxlY3Rpb24gZ2F2ZSBhIHNpbWlsYXIgci1zcXVhcmVkIGJ1dCBpcyBhIGxpdHRsZSBsb3dlci4gQnV0IGl0IGlzIG9ubHkgMSUgYmV0dGVyIGF0IGZpdHRpbmcgdGhlIGRhdGEsIHdoaWNoIGlzIG1vc3QgbGlrZWx5IGNhdXNlZCBieSBvdmVyZml0dGluZy4gQW5vdGhlciBkaXNhZHZhbnRhZ2Ugb2YgdGhlIGJhY2t3YXJkIHNlbGVjdGlvbiBpcyB0aGF0IGl0IGhhZCBhIHNpZ25pZmljYW50IGFkZGl0aW9uYWwgbnVtYmVyIG9mIHByZWRpY3RvcnMuIDE2IG1vcmUgdGhhbiBmb3J3YXJkIHNlbGVjdGlvbi4gVEhlcmVmb3JlIEkgdGhvdWdodCBpdCB3YXMgYmV0dGVyIHRvIGNob29zZSBhIG1vcmUgc2ltcGxlIG1vZGVsLg0KICANCiAgQWJvdmUgd2UgY2FuIHNlZSB0aGUgcmVsZXZhbnQgcHJlZGljdG9ycywgYW5kIHRoZSB3ZWlnaHQgb2YgZWFjaC4gSSB3aWxsIHRhbGsgYSBiaXQgbW9yZSBhYm91dCB0aGUgMyBwcmVkaWN0b3JzIHdpdGggdGhlIGhlaWdoZXN0IHdlaWdodHMuDQogIA0KICAqIE1hbGVQZXJjZW50YWdlRGl2b3JjZSAtIEl0IHNlZW1zIHRoYXQgcmVnaW9ucyB3aXRoIGhpZ2ggZGl2b3JjZSByYXRlcyBhcmUgZGlyZWN0bHkgY29ycmVsYXRlZCB3aXRoIHZpb2xlbnQgY3JpbWUgcmF0ZXMuIA0KICANCiAgKiBQY3RLaWRzMlBhciAocGVyY2VudGFnZSB3aG8gaGF2ZSBraWRzIGluIGEgaG9tZSB3aXRoIHR3byBwYXJlbnRzKSAtIEl0IHNlZW1zIHRoYXQgcmVnaW9ucyB3aXRoIG1hbnkgc3RhYmxlIGZhbWlsaWVzIGNhdXNlIGxlc3MgdmlvbGVudCBjcmltZXMuDQogIA0KICAqIFdoaXRlUGVyQ2FwIChwZXIgY2FwaXRhIGluY29tZSBmb3IgY2F1Y2FzaWFucykgLSBJbiByZWdpb25zIHdoZXJlIGNhdWNhc2lhbnMgaGF2ZSBoaWdoZXIgaW5jb21lLCBpdCBpcyBsaWtlbHkgdGhhdCB0aGVyZSB3aWxsIGJlIGxlc3MgdmlvbGVudCBjcmltZXMuDQogIA0KKiooMikgUnVuIDEwLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiB0byBlc3RpbWF0ZSB0aGUgdGVzdCBNU0UuIFVzZSB0aGUgZm9sZCBjb2x1bW4gaW4gdGhlIGRhdGFzZXQgZm9yIGRldGVybWluaW5nIHRoZSBmb2xkcy4gKioNCg0KDQpgYGB7cn0NCmZvbGQgPSBjb20kZm9sZA0KbXNlID0gMA0KZm9yIChpIGluIDE6MTApDQp7DQogIHRyYWluIDwtIGNvbVtmb2xkICE9IGksXQ0KICB2YWxpZCA8LSBjb21bZm9sZCA9PSBpLF0NCiAgbSA8LSBsbShmLCBkYXRhPXRyYWluKQ0KICBwIDwtIHByZWRpY3QobSxuZXdkYXRhPXZhbGlkKQ0KICBtc2UgPSBtc2UgKyBtZWFuKChwIC0gdmFsaWQkVmlvbGVudENyaW1lc1BlclBvcCleMikNCn0NCnByaW50IChtc2UgLyAxMCkNCmBgYA0KDQpSZXBvcnQgeW91ciBlc3RpbWF0ZWQgdGVzdCBNU0UuDQogIA0KVGhlIE1lYW4gc3F1YXJlZCBlcnJvciBmb3IgdGhlIG1vZGVsIGlzIDAuMDE3OS4NCg0KKiooMykgVXNlIHRoZSBib290c3RyYXAgdG8gZXN0aW1hdGUgYSA5MCUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgbXVsdGlwbGUgUjIuICoqDQoNCg0KYGBge3J9DQojY29uZmludChtLmZvcndhcmQpDQpzZXQuc2VlZCgyMjIpDQpOIDwtIDEwMDANCnIyIDwtIHJlcChOQSwgTikNCg0KDQpuIDwtIGxlbmd0aChjb21fcmVsZXZhbnRfMltbMV1dKQ0KY29tX3IgPC0gc3RydWN0dXJlKGNvbV9yZWxldmFudF8yLCByb3cubmFtZXMgPSBjKE5BLCAtbiksIGNsYXNzID0gImRhdGEuZnJhbWUiKQ0KDQpmb3IgKGkgaW4gMTpOKSB7DQogIHMgPC0gc2FtcGxlKDE6bnJvdyhjb21fciksIG5yb3coY29tX3IpLCByZXBsYWNlPVRSVUUpDQogIG0xLnMgPC0gbG0oZiwgZGF0YT1jb21fcltzLF0pDQogIHIyW2ldIDwtIHN1bW1hcnkobTEucykkci5zcXVhcmVkDQp9DQpxIDwtIHF1YW50aWxlKHIyLCBjKDAuMDI1LCAwLjk3NSkpDQpxDQpgYGANCg0KMTAwMCByYW5kb20gc2FtcGxlcyB3ZXJlIGNyZWF0ZWQsIGFuZCBmcm9tIHRoYXQgZXh0cmFjdGVkIHRoZSBjb25maWRlbmNlIGludGVydmFscy4NClRoZSBjb25maWRlbmNlIGludGVydmFscyBmb3IgbXVsdGlwbGUgUi1zcXVhcmVkIGFyZToNCjIuNSUgLSAwLjY1OTcxMTggDQo5Ny41JSAtIDAuNzE4ODM2MyANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K