TODO:
- Winsorize departure_delay_in_minutes and arrival_delay_in_minutes to handle outliers (done)
- Create scatter plots for variables, w/ abline
- Get correlation coefficints for all variables
import data from cleaning step
df <- read.csv("Cheapseats.csv", stringsAsFactors = T)
summary of analysis
- The independent variables: airline_status + age + gender + type_of_travel + arrival_delay_greater_5_mins + num_flights product a linear model that can explain 44% of the variance around the mean of the dependent variable “satisfaction”"
- “Silver” status customers have the highest satisfaction ratings
- “Business” travelors have the highest satisfaction ratings
- “Males” have higher ratings than females
- Customers with delays less than five minutes have higher satisfaction ratings
- All interpretations have the condition of keeping all other independent variables constant
Refined business quesitons
- Why are Silver status customers more satisfied than the higher Platinum and Gold counterparts?
- Why are Males more satisfied than females?
Winsorize departure_delay_in_minutes and arrival_delay_in_minutes
- see how many rows fall above the 95th percentile
departure_delay_95 <- quantile(df$departure_delay_in_minutes, .95)
sprintf("%d rows will be changed to the 95th percentile of departure_delay_in_minutes", length(which(df$departure_delay_in_minutes > departure_delay_95)))
[1] "1290 rows will be changed to the 95th percentile of departure_delay_in_minutes"
df[which(df$departure_delay_in_minutes > departure_delay_95), "departure_delay_in_minutes"] = departure_delay_95
arrival_delay_95 <- quantile(df$arrival_delay_in_minutes, .95)
sprintf("%d rows will be changed to the 95th percentile of arrival_delay_in_minutes", length(which(df$arrival_delay_in_minutes > arrival_delay_95)))
[1] "1289 rows will be changed to the 95th percentile of arrival_delay_in_minutes"
df[which(df$arrival_delay_in_minutes > arrival_delay_95),"arrival_delay_in_minutes"] = arrival_delay_95
get the r-squared values for all the variables as predictors of satisfaction
createLM <- function(mydf) {
r_squares <- list()
for(i in 2:ncol(mydf)) {
model <- lm(formula=satisfaction~mydf[[i]], data=mydf)
r_squares[[i]] <- summary(model)
}
model_names <- c('satisfaction','airline_status', 'age', 'gender', 'price_sensitivity', 'year_first_flight','num_flights', 'percent_flight_other_airlines', 'type_of_travel','num_loyalty_cards', 'airport_shopping', 'airport_dining','class', 'day_of_month', 'flight_date','origin_city', 'origin_state', 'destination_city','destination_state', 'scheduled_departure_hour', 'departure_delay_in_minutes', 'arrival_delay_in_minutes', 'flight_cancelled','flight_time_in_minutes', 'flight_distance', 'arrival_delay_greater_5_mins')
names(r_squares) <- model_names # name lists
return(r_squares)
}
df <- df[,-which(colnames(df)=="airline_code")]
df <- df[,-which(colnames(df)=="airline_name")]
r_squares <- createLM(df)
for(i in 2:length(r_squares)) {
v_name <- names(r_squares)[i]
print(sprintf("The r-squared value for %s: %f", v_name, r_squares[[i]]$r.squared))
}
[1] "The r-squared value for airline_status: 0.123284"
[1] "The r-squared value for age: 0.049398"
[1] "The r-squared value for gender: 0.018651"
[1] "The r-squared value for price_sensitivity: 0.009431"
[1] "The r-squared value for year_first_flight: 0.000059"
[1] "The r-squared value for num_flights: 0.055542"
[1] "The r-squared value for percent_flight_other_airlines: 0.004124"
[1] "The r-squared value for type_of_travel: 0.335375"
[1] "The r-squared value for num_loyalty_cards: 0.007634"
[1] "The r-squared value for airport_shopping: 0.000169"
[1] "The r-squared value for airport_dining: 0.000049"
[1] "The r-squared value for class: 0.002290"
[1] "The r-squared value for day_of_month: 0.000017"
[1] "The r-squared value for flight_date: 0.003585"
[1] "The r-squared value for origin_city: 0.002952"
[1] "The r-squared value for origin_state: 0.001570"
[1] "The r-squared value for destination_city: 0.003460"
[1] "The r-squared value for destination_state: 0.001681"
[1] "The r-squared value for scheduled_departure_hour: 0.000588"
[1] "The r-squared value for departure_delay_in_minutes: 0.009210"
[1] "The r-squared value for arrival_delay_in_minutes: 0.011927"
[1] "The r-squared value for flight_cancelled: 0.000671"
[1] "The r-squared value for flight_time_in_minutes: 0.000013"
[1] "The r-squared value for flight_distance: 0.000005"
[1] "The r-squared value for arrival_delay_greater_5_mins: 0.026848"
- winsorizing the departure/arrival delays changed the coefficients from .005 and .007 to .010 and .014 respectively
Interpretation of Adj R-squared and coefficients
- This model explains 44% (Adj. R-squared value) of the variance around the mean of the dependent variable satisfaction
- Customers who are either Gold, Platinum, or Silver have satisfaction ratings of (.44, .25, and .62) higher than customers that don’t have a flight_status
- The “Silver” status has the strongest positive correlation with customer satisfaction amongst the airline status categories. Its’ coefficient is interpreted as, “for Silver status, and holding all other variables constant, the satisfaction score is .62 higher for Silver flyers than for all other airline_status categories”
- Holding all other variables constant, male customers’ satisfaction scores are .13 higher than female customers
- Holdling all other variables constant, customers traveling for “Mileage” have satisfaction scores -.15 less than customers traveling for “Business”
- Holding all other variables constant, customers traveling for “Personal” have satisfaction scores -1.1 less than customers traveling for “Business”
- Holding all other variables constant, customers with flights delays greater than 5 minutes have satisfaction scores -.33 less than customers with flight delays less than 5 minutes
reorder the factors for airline_status and type_of_travel to see what the coefficients are for the current reference variables “Blue”,“Business”
df$airline_status <- factor(df$airline_status, levels=c("Silver","Gold","Platinum", "Blue"))
df$type_of_travel <- factor(df$type_of_travel, levels=c("Personal","Business","Mileage"))
# create the model again
model <- lm(satisfaction~airline_status+age+gender+type_of_travel+arrival_delay_greater_5_mins+num_flights+arrival_delay_in_minutes+departure_delay_in_minutes+num_loyalty_cards, data=df)
selected_model <- stepAIC(model, direction="backward", trace=TRUE)
Start: AIC=-16894.93
satisfaction ~ airline_status + age + gender + type_of_travel +
arrival_delay_greater_5_mins + num_flights + arrival_delay_in_minutes +
departure_delay_in_minutes + num_loyalty_cards
Df Sum of Sq RSS AIC
- num_loyalty_cards 1 0.1 13537 -16896.7
- arrival_delay_in_minutes 1 0.5 13538 -16896.0
<none> 13537 -16894.9
- departure_delay_in_minutes 1 1.7 13539 -16893.6
- age 1 27.8 13565 -16843.7
- num_flights 1 39.5 13577 -16821.3
- gender 1 94.9 13632 -16715.5
- arrival_delay_greater_5_mins 1 375.9 13913 -16185.5
- airline_status 3 1820.4 15358 -13624.2
- type_of_travel 2 5208.8 18746 -8444.4
Step: AIC=-16896.7
satisfaction ~ airline_status + age + gender + type_of_travel +
arrival_delay_greater_5_mins + num_flights + arrival_delay_in_minutes +
departure_delay_in_minutes
Df Sum of Sq RSS AIC
- arrival_delay_in_minutes 1 0.5 13538 -16897.8
<none> 13537 -16896.7
- departure_delay_in_minutes 1 1.7 13539 -16895.4
- age 1 31.7 13569 -16838.0
- num_flights 1 39.6 13577 -16822.9
- gender 1 95.2 13633 -16716.6
- arrival_delay_greater_5_mins 1 375.9 13913 -16187.5
- airline_status 3 1820.3 15358 -13626.2
- type_of_travel 2 5234.5 18772 -8410.7
Step: AIC=-16897.8
satisfaction ~ airline_status + age + gender + type_of_travel +
arrival_delay_greater_5_mins + num_flights + departure_delay_in_minutes
Df Sum of Sq RSS AIC
<none> 13538 -16897.8
- departure_delay_in_minutes 1 2.2 13540 -16895.6
- age 1 31.6 13570 -16839.2
- num_flights 1 39.7 13578 -16823.8
- gender 1 95.3 13633 -16717.7
- arrival_delay_greater_5_mins 1 440.1 13978 -16068.9
- airline_status 3 1820.2 15358 -13627.6
- type_of_travel 2 5235.1 18773 -8411.2
summary(selected_model)
Call:
lm(formula = satisfaction ~ airline_status + age + gender + type_of_travel +
arrival_delay_greater_5_mins + num_flights + departure_delay_in_minutes,
data = df)
Residuals:
Min 1Q Median 3Q Max
-3.08100 -0.40458 0.02695 0.49302 2.76463
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.3314730 0.0208838 159.525 < 2e-16 ***
airline_statusGold -0.2047314 0.0186525 -10.976 < 2e-16 ***
airline_statusPlatinum -0.3590109 0.0272312 -13.184 < 2e-16 ***
airline_statusBlue -0.6496885 0.0115067 -56.462 < 2e-16 ***
age -0.0021793 0.0002799 -7.786 7.19e-15 ***
genderMale 0.1243370 0.0091996 13.515 < 2e-16 ***
type_of_travelBusiness 1.0909831 0.0109545 99.592 < 2e-16 ***
type_of_travelMileage 0.9337062 0.0185542 50.323 < 2e-16 ***
arrival_delay_greater_5_minsyes -0.3496571 0.0120358 -29.052 < 2e-16 ***
num_flights -0.0029503 0.0003382 -8.723 < 2e-16 ***
departure_delay_in_minutes 0.0005591 0.0002716 2.058 0.0396 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.7221 on 25960 degrees of freedom
Multiple R-squared: 0.4487, Adjusted R-squared: 0.4485
F-statistic: 2113 on 10 and 25960 DF, p-value: < 2.2e-16
According to google :), a lower AIC is better, so the last “Step” is the best model:
- satisfaction ~ airline_status + age + gender + type_of_travel + arrival_delay_greater_5_mins + num_flights (best linear model)
- this model explains 44% of the variance around the mean of the dependent variable satisfaction
LS0tCnRpdGxlOiAiQ2hlYXBzZWF0c19saW5lYXJfbW9kZWxpbmcuUm1kIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIyMgVE9ETzoKKiBXaW5zb3JpemUgZGVwYXJ0dXJlX2RlbGF5X2luX21pbnV0ZXMgYW5kIGFycml2YWxfZGVsYXlfaW5fbWludXRlcyB0byBoYW5kbGUgb3V0bGllcnMgKGRvbmUpCiogQ3JlYXRlIHNjYXR0ZXIgcGxvdHMgZm9yIHZhcmlhYmxlcywgdy8gYWJsaW5lCiogR2V0IGNvcnJlbGF0aW9uIGNvZWZmaWNpbnRzIGZvciBhbGwgdmFyaWFibGVzCgojIyMjIGltcG9ydCBkYXRhIGZyb20gY2xlYW5pbmcgc3RlcAoKYGBge3J9CmRmIDwtIHJlYWQuY3N2KCJDaGVhcHNlYXRzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKQpgYGAKCiMjIyMgc3VtbWFyeSBvZiBhbmFseXNpcwoqIFRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXM6IGFpcmxpbmVfc3RhdHVzICsgYWdlICsgZ2VuZGVyICsgdHlwZV9vZl90cmF2ZWwgKyBhcnJpdmFsX2RlbGF5X2dyZWF0ZXJfNV9taW5zICsgbnVtX2ZsaWdodHMgcHJvZHVjdCBhIGxpbmVhciBtb2RlbCB0aGF0IGNhbiBleHBsYWluIDQ0JSBvZiB0aGUgdmFyaWFuY2UgYXJvdW5kIHRoZSBtZWFuIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgInNhdGlzZmFjdGlvbiIiCiogIlNpbHZlciIgc3RhdHVzIGN1c3RvbWVycyBoYXZlIHRoZSBoaWdoZXN0IHNhdGlzZmFjdGlvbiByYXRpbmdzCiogIkJ1c2luZXNzIiB0cmF2ZWxvcnMgaGF2ZSB0aGUgaGlnaGVzdCBzYXRpc2ZhY3Rpb24gcmF0aW5ncyAKKiAiTWFsZXMiIGhhdmUgaGlnaGVyIHJhdGluZ3MgdGhhbiBmZW1hbGVzIAoqIEN1c3RvbWVycyB3aXRoIGRlbGF5cyBsZXNzIHRoYW4gZml2ZSBtaW51dGVzIGhhdmUgaGlnaGVyIHNhdGlzZmFjdGlvbiByYXRpbmdzCiogKkFsbCBpbnRlcnByZXRhdGlvbnMgaGF2ZSB0aGUgY29uZGl0aW9uIG9mIGtlZXBpbmcgYWxsIG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlcyBjb25zdGFudCoKCiMjIyMgUmVmaW5lZCBidXNpbmVzcyBxdWVzaXRvbnMKKiBXaHkgYXJlIFNpbHZlciBzdGF0dXMgY3VzdG9tZXJzIG1vcmUgc2F0aXNmaWVkIHRoYW4gdGhlIGhpZ2hlciBQbGF0aW51bSBhbmQgR29sZCBjb3VudGVycGFydHM/CiogV2h5IGFyZSBNYWxlcyBtb3JlIHNhdGlzZmllZCB0aGFuIGZlbWFsZXM/CgojIyMjIFdpbnNvcml6ZSBkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcyBhbmQgYXJyaXZhbF9kZWxheV9pbl9taW51dGVzCisgc2VlIGhvdyBtYW55IHJvd3MgZmFsbCBhYm92ZSB0aGUgOTV0aCBwZXJjZW50aWxlCmBgYHtyfQpkZXBhcnR1cmVfZGVsYXlfOTUgPC0gcXVhbnRpbGUoZGYkZGVwYXJ0dXJlX2RlbGF5X2luX21pbnV0ZXMsIC45NSkKc3ByaW50ZigiJWQgcm93cyB3aWxsIGJlIGNoYW5nZWQgdG8gdGhlIDk1dGggcGVyY2VudGlsZSBvZiBkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcyIsIGxlbmd0aCh3aGljaChkZiRkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcyA+IGRlcGFydHVyZV9kZWxheV85NSkpKQpkZlt3aGljaChkZiRkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcyA+IGRlcGFydHVyZV9kZWxheV85NSksICJkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcyJdID0gZGVwYXJ0dXJlX2RlbGF5Xzk1CgphcnJpdmFsX2RlbGF5Xzk1IDwtIHF1YW50aWxlKGRmJGFycml2YWxfZGVsYXlfaW5fbWludXRlcywgLjk1KQpzcHJpbnRmKCIlZCByb3dzIHdpbGwgYmUgY2hhbmdlZCB0byB0aGUgOTV0aCBwZXJjZW50aWxlIG9mIGFycml2YWxfZGVsYXlfaW5fbWludXRlcyIsIGxlbmd0aCh3aGljaChkZiRhcnJpdmFsX2RlbGF5X2luX21pbnV0ZXMgPiBhcnJpdmFsX2RlbGF5Xzk1KSkpCmRmW3doaWNoKGRmJGFycml2YWxfZGVsYXlfaW5fbWludXRlcyA+IGFycml2YWxfZGVsYXlfOTUpLCJhcnJpdmFsX2RlbGF5X2luX21pbnV0ZXMiXSA9IGFycml2YWxfZGVsYXlfOTUKCmBgYAoKIyMjIyBnZXQgdGhlIHItc3F1YXJlZCB2YWx1ZXMgZm9yIGFsbCB0aGUgdmFyaWFibGVzIGFzIHByZWRpY3RvcnMgb2Ygc2F0aXNmYWN0aW9uCmBgYHtyfQpjcmVhdGVMTSA8LSBmdW5jdGlvbihteWRmKSB7CiAgcl9zcXVhcmVzIDwtIGxpc3QoKQogIGZvcihpIGluIDI6bmNvbChteWRmKSkgewogICAgbW9kZWwgPC0gbG0oZm9ybXVsYT1zYXRpc2ZhY3Rpb25+bXlkZltbaV1dLCBkYXRhPW15ZGYpCiAgICByX3NxdWFyZXNbW2ldXSA8LSBzdW1tYXJ5KG1vZGVsKQogIH0KICAKICBtb2RlbF9uYW1lcyA8LSBjKCdzYXRpc2ZhY3Rpb24nLCdhaXJsaW5lX3N0YXR1cycsICdhZ2UnLCAnZ2VuZGVyJywgJ3ByaWNlX3NlbnNpdGl2aXR5JywgJ3llYXJfZmlyc3RfZmxpZ2h0JywnbnVtX2ZsaWdodHMnLCAncGVyY2VudF9mbGlnaHRfb3RoZXJfYWlybGluZXMnLCAndHlwZV9vZl90cmF2ZWwnLCdudW1fbG95YWx0eV9jYXJkcycsICdhaXJwb3J0X3Nob3BwaW5nJywgJ2FpcnBvcnRfZGluaW5nJywnY2xhc3MnLCAnZGF5X29mX21vbnRoJywgJ2ZsaWdodF9kYXRlJywnb3JpZ2luX2NpdHknLCAnb3JpZ2luX3N0YXRlJywgJ2Rlc3RpbmF0aW9uX2NpdHknLCdkZXN0aW5hdGlvbl9zdGF0ZScsICdzY2hlZHVsZWRfZGVwYXJ0dXJlX2hvdXInLCAnZGVwYXJ0dXJlX2RlbGF5X2luX21pbnV0ZXMnLCAnYXJyaXZhbF9kZWxheV9pbl9taW51dGVzJywgJ2ZsaWdodF9jYW5jZWxsZWQnLCdmbGlnaHRfdGltZV9pbl9taW51dGVzJywgJ2ZsaWdodF9kaXN0YW5jZScsICdhcnJpdmFsX2RlbGF5X2dyZWF0ZXJfNV9taW5zJykKICAKICBuYW1lcyhyX3NxdWFyZXMpIDwtIG1vZGVsX25hbWVzICAjIG5hbWUgbGlzdHMgCgogIHJldHVybihyX3NxdWFyZXMpCn0KCmRmIDwtIGRmWywtd2hpY2goY29sbmFtZXMoZGYpPT0iYWlybGluZV9jb2RlIildCmRmIDwtIGRmWywtd2hpY2goY29sbmFtZXMoZGYpPT0iYWlybGluZV9uYW1lIildCnJfc3F1YXJlcyA8LSBjcmVhdGVMTShkZikKZm9yKGkgaW4gMjpsZW5ndGgocl9zcXVhcmVzKSkgewogIHZfbmFtZSA8LSBuYW1lcyhyX3NxdWFyZXMpW2ldCiAgcHJpbnQoc3ByaW50ZigiVGhlIHItc3F1YXJlZCB2YWx1ZSBmb3IgJXM6ICVmIiwgdl9uYW1lLCByX3NxdWFyZXNbW2ldXSRyLnNxdWFyZWQpKQp9CmBgYAogICsgd2luc29yaXppbmcgdGhlIGRlcGFydHVyZS9hcnJpdmFsIGRlbGF5cyBjaGFuZ2VkIHRoZSBjb2VmZmljaWVudHMgZnJvbSAqLjAwNSBhbmQgLjAwNyogdG8gKi4wMTAgYW5kIC4wMTQqIHJlc3BlY3RpdmVseQoKCiMjIyMgcGVyZm9ybSBzdGVwd2lzZSByZWdyZXNzaW9uIChiYWNrd2FyZHMpIHRvIGZpbmQgYmVzdCBwcmVkaWN0b3JzCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoTUFTUykKbW9kZWwgPC0gbG0oc2F0aXNmYWN0aW9ufmFpcmxpbmVfc3RhdHVzK2FnZStnZW5kZXIrdHlwZV9vZl90cmF2ZWwrYXJyaXZhbF9kZWxheV9ncmVhdGVyXzVfbWlucytudW1fZmxpZ2h0cythcnJpdmFsX2RlbGF5X2luX21pbnV0ZXMrZGVwYXJ0dXJlX2RlbGF5X2luX21pbnV0ZXMrbnVtX2xveWFsdHlfY2FyZHMsIGRhdGE9ZGYpCnNlbGVjdGVkX21vZGVsIDwtIHN0ZXBBSUMobW9kZWwsIGRpcmVjdGlvbj0iYmFja3dhcmQiLCB0cmFjZT1UUlVFKQpzdW1tYXJ5KHNlbGVjdGVkX21vZGVsKQpgYGAKCiMjIyMgSW50ZXJwcmV0YXRpb24gb2YgQWRqIFItc3F1YXJlZCBhbmQgY29lZmZpY2llbnRzCiAgKyBUaGlzIG1vZGVsIGV4cGxhaW5zIDQ0JSAoQWRqLiBSLXNxdWFyZWQgdmFsdWUpIG9mIHRoZSB2YXJpYW5jZSBhcm91bmQgdGhlIG1lYW4gb2YgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBzYXRpc2ZhY3Rpb24KICArIEN1c3RvbWVycyB3aG8gYXJlIGVpdGhlciBHb2xkLCBQbGF0aW51bSwgb3IgU2lsdmVyIGhhdmUgc2F0aXNmYWN0aW9uIHJhdGluZ3Mgb2YgKC40NCwgLjI1LCBhbmQgLjYyKSBoaWdoZXIgdGhhbiBjdXN0b21lcnMgdGhhdCBkb24ndCBoYXZlIGEgZmxpZ2h0X3N0YXR1cwogICsgVGhlICJTaWx2ZXIiIHN0YXR1cyBoYXMgdGhlIHN0cm9uZ2VzdCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiB3aXRoIGN1c3RvbWVyIHNhdGlzZmFjdGlvbiBhbW9uZ3N0IHRoZSBhaXJsaW5lIHN0YXR1cyBjYXRlZ29yaWVzLiAgSXRzJyBjb2VmZmljaWVudCBpcyBpbnRlcnByZXRlZCBhcywgImZvciBTaWx2ZXIgc3RhdHVzLCBhbmQgaG9sZGluZyBhbGwgb3RoZXIgdmFyaWFibGVzIGNvbnN0YW50LCB0aGUgc2F0aXNmYWN0aW9uIHNjb3JlIGlzIC42MiBoaWdoZXIgZm9yIFNpbHZlciBmbHllcnMgdGhhbiBmb3IgYWxsIG90aGVyIGFpcmxpbmVfc3RhdHVzIGNhdGVnb3JpZXMiCiAgKyBIb2xkaW5nIGFsbCBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQsIG1hbGUgY3VzdG9tZXJzJyBzYXRpc2ZhY3Rpb24gc2NvcmVzIGFyZSAuMTMgaGlnaGVyIHRoYW4gZmVtYWxlIGN1c3RvbWVycwogICsgSG9sZGxpbmcgYWxsIG90aGVyIHZhcmlhYmxlcyBjb25zdGFudCwgY3VzdG9tZXJzIHRyYXZlbGluZyBmb3IgIk1pbGVhZ2UiIGhhdmUgc2F0aXNmYWN0aW9uIHNjb3JlcyAtLjE1IGxlc3MgdGhhbiBjdXN0b21lcnMgdHJhdmVsaW5nIGZvciAiQnVzaW5lc3MiCiAgKyBIb2xkaW5nIGFsbCBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQsIGN1c3RvbWVycyB0cmF2ZWxpbmcgZm9yICJQZXJzb25hbCIgaGF2ZSBzYXRpc2ZhY3Rpb24gc2NvcmVzIC0xLjEgbGVzcyB0aGFuIGN1c3RvbWVycyB0cmF2ZWxpbmcgZm9yICJCdXNpbmVzcyIKICArIEhvbGRpbmcgYWxsIG90aGVyIHZhcmlhYmxlcyBjb25zdGFudCwgY3VzdG9tZXJzIHdpdGggZmxpZ2h0cyBkZWxheXMgZ3JlYXRlciB0aGFuIDUgbWludXRlcyBoYXZlIHNhdGlzZmFjdGlvbiBzY29yZXMgIC0uMzMgbGVzcyB0aGFuIGN1c3RvbWVycyB3aXRoIGZsaWdodCBkZWxheXMgbGVzcyB0aGFuIDUgbWludXRlcwogIAogIAojIyMjIHJlb3JkZXIgdGhlIGZhY3RvcnMgZm9yIGFpcmxpbmVfc3RhdHVzIGFuZCB0eXBlX29mX3RyYXZlbCB0byBzZWUgd2hhdCB0aGUgY29lZmZpY2llbnRzIGFyZSBmb3IgdGhlIGN1cnJlbnQgcmVmZXJlbmNlIHZhcmlhYmxlcyAiQmx1ZSIsIkJ1c2luZXNzIgpgYGB7cn0KZGYkYWlybGluZV9zdGF0dXMgPC0gZmFjdG9yKGRmJGFpcmxpbmVfc3RhdHVzLCBsZXZlbHM9YygiU2lsdmVyIiwiR29sZCIsIlBsYXRpbnVtIiwgIkJsdWUiKSkKZGYkdHlwZV9vZl90cmF2ZWwgPC0gZmFjdG9yKGRmJHR5cGVfb2ZfdHJhdmVsLCBsZXZlbHM9YygiUGVyc29uYWwiLCJCdXNpbmVzcyIsIk1pbGVhZ2UiKSkKIyBjcmVhdGUgdGhlIG1vZGVsIGFnYWluIAptb2RlbCA8LSBsbShzYXRpc2ZhY3Rpb25+YWlybGluZV9zdGF0dXMrYWdlK2dlbmRlcit0eXBlX29mX3RyYXZlbCthcnJpdmFsX2RlbGF5X2dyZWF0ZXJfNV9taW5zK251bV9mbGlnaHRzK2Fycml2YWxfZGVsYXlfaW5fbWludXRlcytkZXBhcnR1cmVfZGVsYXlfaW5fbWludXRlcytudW1fbG95YWx0eV9jYXJkcywgZGF0YT1kZikKc2VsZWN0ZWRfbW9kZWwgPC0gc3RlcEFJQyhtb2RlbCwgZGlyZWN0aW9uPSJiYWNrd2FyZCIsIHRyYWNlPVRSVUUpCnN1bW1hcnkoc2VsZWN0ZWRfbW9kZWwpCmBgYAoKIyMjIyBBY2NvcmRpbmcgdG8gZ29vZ2xlIDopLCBhIGxvd2VyIEFJQyBpcyBiZXR0ZXIsIHNvIHRoZSBsYXN0ICJTdGVwIiBpcyB0aGUgYmVzdCBtb2RlbDoKKiBzYXRpc2ZhY3Rpb24gfiBhaXJsaW5lX3N0YXR1cyArIGFnZSArIGdlbmRlciArIHR5cGVfb2ZfdHJhdmVsICsgYXJyaXZhbF9kZWxheV9ncmVhdGVyXzVfbWlucyArIG51bV9mbGlnaHRzIChiZXN0IGxpbmVhciBtb2RlbCkKICAgICsgdGhpcyBtb2RlbCBleHBsYWlucyA0NCUgb2YgdGhlIHZhcmlhbmNlIGFyb3VuZCB0aGUgbWVhbiBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHNhdGlzZmFjdGlvbgogICAgCgoKCgoKCg==