主要議題:行政區界套圖

Sys.setlocale('LC_ALL','C')
[1] "C"
library(dplyr)
library(ggplot2)
library(maps)
library(ggmap)
library(caTools)


1. Drawing a Map of the US

1.1

If you look at the structure of the statesMap data frame using the str function, you should see that there are 6 variables. One of the variables, group, defines the different shapes or polygons on the map. Sometimes a state may have multiple groups, for example, if it includes islands. How many different groups are there?

# 1.1
#美國地圖
statesMap = map_data('state')
table(statesMap$group)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15 
 202  149  312  516   79   91   94   10  872  381  233  329  257  256  113 
  16   17   18   19   20   21   22   23   24   25   26   27   28   29   30 
 397  650  399  566   36  220   30  460  370  373  382  315  238  208   70 
  31   32   33   34   35   36   37   38   39   40   41   42   43   44   45 
 125  205   78   16  290   21  168   37  733   12  105  238  284  236  172 
  46   47   48   49   50   51   52   53   54   55   56   57   58   59   60 
  66  304  166  289 1088   59  129   96   15  623   17   17   19   44  448 
  61   62   63 
 373  388   68 
table(statesMap$group) %>% length
[1] 63
1.2

You can draw a map of the United States by typing the following in your R console:

ggplot(statesMap, aes(x=long, y=lat, group=group)) + 
  geom_polygon(fill="white", color="black")

We specified two colors in geom_polygon – fill and color. Which one defined the color of the outline of the states?

  • color
  • color=‘black’ 用黑色畫states輪廓


2 Coloring the States by Predictions

2.1 Predictive Model

Now, let’s color the map of the US according to our 2012 US presidential election predictions from the Unit 3 Recitation. We’ll rebuild the model here, using the dataset PollingImputed.csv. Be sure to use this file so that you don’t have to redo the imputation to fill in the missing values, like we did in the Unit 3 Recitation.

Load the data using the read.csv function, and call it “polling”. Then split the data using the subset function into a training set called “Train” that has observations from 2004 and 2008, and a testing set called “Test” that has observations from 2012.

Note that we only have 45 states in our testing set, since we are missing observations for Alaska, Delaware, Alabama, Wyoming, and Vermont, so these states will not appear colored in our map.

Then, create a logistic regression model and make predictions on the test set using the following commands:

polling = read.csv('data/PollingImputed.csv')
#2012年作為test data
trn = subset(polling, Year != 2012)
tst = subset(polling, Year == 2012)
#Republican:是否為共和黨
mod2 = glm(Republican~SurveyUSA+DiffCount, trn, family=binomial)
pred = predict(mod2,tst,type='response')
repub = as.numeric(pred > 0.5)
df = data.frame(pred, repub, state=tst$State)
head(df)

For how many states is our binary prediction 1 (for 2012), corresponding to Republican?

#repub:predict出來機率>0.5估為是Republican
sum(repub)
[1] 22

What is the average predicted probability of our model (on the Test set, for 2012)?

mean(pred) 
[1] 0.4852626
2.2 Merge Data into Map

Now, we need to merge “predictionDataFrame” with the map data “statesMap”, like we did in lecture. Before doing so, we need to convert the Test.State variable to lowercase, so that it matches the region variable in statesMap. Do this by typing the following in your R console:

df$region = tolower(df$state)
pmap = merge(statesMap, df, by='region') 

How many observations are there in predictionMap?

nrow(pmap)       # 15034
[1] 15034

How many observations are there in stateMap?

nrow(statesMap)  # 15537
[1] 15537
2.3 The Rule of merge()

When we merged the data in the previous problem, it caused the number of observations to change. Why? Check out the help page for merge by typing ?merge to help you answer this question.

  • Because we only make predictions for 45 states, we no longer have observations for some of the states. These observations were removed in the merging process.
2.4 Plot the color map

Now we are ready to color the US map with our predictions! You can color the states according to our binary predictions by typing the following in your R console:

# fill=repub:顏色區分是否為共和黨
pmap = pmap[order(pmap$group, pmap$order) , ]
ggplot(pmap, aes(x=long, y=lat, group=group, fill=repub)) +
  geom_polygon(color='black')

The states appear light blue and dark blue in this map. Which color represents a Republican prediction?

  • Light blue
  • repub=1預測是共和黨,從圖上看是淺藍色
2.5

We see that the legend displays a blue gradient for outcomes between 0 and 1. However, when plotting the binary predictions there are only two possible outcomes: 0 or 1. Let’s replot the map with discrete outcomes. We can also change the color scheme to blue and red, to match the blue color associated with the Democratic Party in the US and the red color associated with the Republican Party in the US. This can be done with the following command:

Alternatively, we could plot the probabilities instead of the binary predictions. Change the plot command above to instead color the states by the variable TestPrediction.

#改用Prediction機率區分顏色
ggplot(pmap, aes(x=long, y=lat, group=group, fill=pred)) +
  geom_polygon(color='black') +
  scale_fill_gradient(
    low="blue", high="red", 
    guide="legend", breaks= c(0,1), 
    labels=c("Democrat", "Republican"), name="Prediction 2012")

You should see a gradient of colors ranging from red to blue. Do the colors of the states in the map for TestPrediction look different from the colors of the states in the map with TestPredictionBinary? Why or why not?

  • TestPredictionBinary只有0、1兩個factor,顏色只有兩種

  • TestPrediction用機率區分顏色,會有一個連續區間,顏色種類會比較多



3. Understanding the Predictions

3.1

In the 2012 election, the state of Florida ended up being a very close race. It was ultimately won by the Democratic party.

df$pred[ df$state == 'Florida'] # 0.96404
[1] 0.9640395

Did we predict this state correctly or incorrectly?

  • We incorrectly predicted this state by predicting that it would be won by the Republican party.
  • Florida在2012年選舉最終是由Democratic party獲選
3.2

What was our predicted probability for the state of Florida?

df$pred[ df$state == 'Florida'] # 0.96404
[1] 0.9640395

What does this imply?

  • Our prediction model did not do a very good job of correctly predicting the state of Florida, and we were very confident in our incorrect prediction.


4. Parameter Settings

In this part, we’ll explore what the different parameter settings of geom_polygon do. Throughout the problem, use the help page for geom_polygon, which can be accessed by ?geom_polygon. To see more information about a certain parameter, just type a question mark and then the parameter name to get the help page for that parameter. Experiment with different parameter settings to try and replicate the plots!

We’ll be asking questions about the following three plots:

grad = scale_fill_gradient(
  low="blue", high="red", 
  guide="legend", breaks= c(0,1), 
  labels=c("Democrat", "Republican"), name="Prediction 2012")
ggplot(pmap, aes(x=long, y=lat, group=group, fill=repub)) + grad +
  geom_polygon(color='black',linetype=3,size=1) + ggtitle("Plot(1)")

ggplot(pmap, aes(x=long, y=lat, group=group, fill=repub)) + grad +
  geom_polygon(color='black',linetype=1,size=3) + ggtitle("Plot(2)")

ggplot(pmap, aes(x=long, y=lat, group=group, fill=repub)) + grad +
  geom_polygon(color='black',linetype=1,size=1,alpha=0.3) + ggtitle("Plot(3)")

4.1

Plots (1) and (2) were created by changing different parameters of geom_polygon from their default values.

What is the name of the parameter we changed to create plot (1)?

  • linetype
  • linetype=3會用虛線畫

What is the name of the parameter we changed to create plot (2)?

  • size
4.2

Plot (3) was created by changing the value of a different geom_polygon parameter to have value 0.3. Which parameter did we use?

  • alpha







LS0tDQp0aXRsZTogIkFTNy0xIOe+juWci+e4vee1seWkp+mBuOWcsOWcliINCmF1dGhvcjogIuWKieiCsumKmCwgTTA2NDAyMDAyNSwgMjAxOC8wNy8yNSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCjxicj4NCg0KKirkuLvopoHorbDpoYzvvJrooYzmlL/ljYDnlYzlpZflnJYqKg0KDQoNCmBgYHtyIGVjaG89VCwgbWVzc2FnZT1GLCBjYWNoZT1GLCB3YXJuaW5nPUZ9DQpTeXMuc2V0bG9jYWxlKCdMQ19BTEwnLCdDJykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KG1hcHMpDQpsaWJyYXJ5KGdnbWFwKQ0KbGlicmFyeShjYVRvb2xzKQ0KYGBgDQoNCjxicj48aHI+DQoNCiMjIyAxLiBEcmF3aW5nIGEgTWFwIG9mIHRoZSBVUw0KDQojIyMjIyAxLjEgDQpJZiB5b3UgbG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSBzdGF0ZXNNYXAgZGF0YSBmcmFtZSB1c2luZyB0aGUgc3RyIGZ1bmN0aW9uLCB5b3Ugc2hvdWxkIHNlZSB0aGF0IHRoZXJlIGFyZSA2IHZhcmlhYmxlcy4gT25lIG9mIHRoZSB2YXJpYWJsZXMsIGdyb3VwLCBkZWZpbmVzIHRoZSBkaWZmZXJlbnQgc2hhcGVzIG9yIHBvbHlnb25zIG9uIHRoZSBtYXAuIFNvbWV0aW1lcyBhIHN0YXRlIG1heSBoYXZlIG11bHRpcGxlIGdyb3VwcywgZm9yIGV4YW1wbGUsIGlmIGl0IGluY2x1ZGVzIGlzbGFuZHMuIF9Ib3cgbWFueSBkaWZmZXJlbnQgZ3JvdXBzIGFyZSB0aGVyZT9fDQoNCmBgYHtyfQ0KIyAxLjENCg0KI+e+juWci+WcsOWclg0Kc3RhdGVzTWFwID0gbWFwX2RhdGEoJ3N0YXRlJykNCnRhYmxlKHN0YXRlc01hcCRncm91cCkNCnRhYmxlKHN0YXRlc01hcCRncm91cCkgJT4lIGxlbmd0aA0KYGBgDQoNCiMjIyMjIDEuMg0KWW91IGNhbiBkcmF3IGEgbWFwIG9mIHRoZSBVbml0ZWQgU3RhdGVzIGJ5IHR5cGluZyB0aGUgZm9sbG93aW5nIGluIHlvdXIgUiBjb25zb2xlOg0KYGBge3J9DQpnZ3Bsb3Qoc3RhdGVzTWFwLCBhZXMoeD1sb25nLCB5PWxhdCwgZ3JvdXA9Z3JvdXApKSArIA0KICBnZW9tX3BvbHlnb24oZmlsbD0id2hpdGUiLCBjb2xvcj0iYmxhY2siKQ0KYGBgDQpXZSBzcGVjaWZpZWQgdHdvIGNvbG9ycyBpbiBnZW9tX3BvbHlnb24gLS0gYGZpbGxgIGFuZCBgY29sb3JgLiBfV2hpY2ggb25lIGRlZmluZWQgdGhlIGNvbG9yIG9mIHRoZSBvdXRsaW5lIG9mIHRoZSBzdGF0ZXM/Xw0KDQorIGNvbG9yDQorIGNvbG9yPSdibGFjaycg55So6buR6Imy55Wrc3RhdGVz6Lyq5buTDQoNCjxicj48aHI+DQoNCiMjIyAyIENvbG9yaW5nIHRoZSBTdGF0ZXMgYnkgUHJlZGljdGlvbnMNCg0KIyMjIyMgMi4xIFByZWRpY3RpdmUgTW9kZWwNCg0KTm93LCBsZXQncyBjb2xvciB0aGUgbWFwIG9mIHRoZSBVUyBhY2NvcmRpbmcgdG8gb3VyIDIwMTIgVVMgcHJlc2lkZW50aWFsIGVsZWN0aW9uIHByZWRpY3Rpb25zIGZyb20gdGhlIFVuaXQgMyBSZWNpdGF0aW9uLiBXZSdsbCByZWJ1aWxkIHRoZSBtb2RlbCBoZXJlLCB1c2luZyB0aGUgZGF0YXNldCBQb2xsaW5nSW1wdXRlZC5jc3YuIEJlIHN1cmUgdG8gdXNlIHRoaXMgZmlsZSBzbyB0aGF0IHlvdSBkb24ndCBoYXZlIHRvIHJlZG8gdGhlIGltcHV0YXRpb24gdG8gZmlsbCBpbiB0aGUgbWlzc2luZyB2YWx1ZXMsIGxpa2Ugd2UgZGlkIGluIHRoZSBVbml0IDMgUmVjaXRhdGlvbi4NCg0KTG9hZCB0aGUgZGF0YSB1c2luZyB0aGUgcmVhZC5jc3YgZnVuY3Rpb24sIGFuZCBjYWxsIGl0ICJwb2xsaW5nIi4gVGhlbiBzcGxpdCB0aGUgZGF0YSB1c2luZyB0aGUgc3Vic2V0IGZ1bmN0aW9uIGludG8gYSB0cmFpbmluZyBzZXQgY2FsbGVkICJUcmFpbiIgdGhhdCBoYXMgb2JzZXJ2YXRpb25zIGZyb20gMjAwNCBhbmQgMjAwOCwgYW5kIGEgdGVzdGluZyBzZXQgY2FsbGVkICJUZXN0IiB0aGF0IGhhcyBvYnNlcnZhdGlvbnMgZnJvbSAyMDEyLg0KDQpOb3RlIHRoYXQgd2Ugb25seSBoYXZlIDQ1IHN0YXRlcyBpbiBvdXIgdGVzdGluZyBzZXQsIHNpbmNlIHdlIGFyZSBtaXNzaW5nIG9ic2VydmF0aW9ucyBmb3IgQWxhc2thLCBEZWxhd2FyZSwgQWxhYmFtYSwgV3lvbWluZywgYW5kIFZlcm1vbnQsIHNvIHRoZXNlIHN0YXRlcyB3aWxsIG5vdCBhcHBlYXIgY29sb3JlZCBpbiBvdXIgbWFwLg0KDQpUaGVuLCBjcmVhdGUgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIGFuZCBtYWtlIHByZWRpY3Rpb25zIG9uIHRoZSB0ZXN0IHNldCB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmRzOg0KDQoNCmBgYHtyfQ0KcG9sbGluZyA9IHJlYWQuY3N2KCdkYXRhL1BvbGxpbmdJbXB1dGVkLmNzdicpDQoNCiMyMDEy5bm05L2c54K6dGVzdCBkYXRhDQp0cm4gPSBzdWJzZXQocG9sbGluZywgWWVhciAhPSAyMDEyKQ0KdHN0ID0gc3Vic2V0KHBvbGxpbmcsIFllYXIgPT0gMjAxMikNCg0KI1JlcHVibGljYW465piv5ZCm54K65YWx5ZKM6buoDQptb2QyID0gZ2xtKFJlcHVibGljYW5+U3VydmV5VVNBK0RpZmZDb3VudCwgdHJuLCBmYW1pbHk9Ymlub21pYWwpDQpwcmVkID0gcHJlZGljdChtb2QyLHRzdCx0eXBlPSdyZXNwb25zZScpDQpyZXB1YiA9IGFzLm51bWVyaWMocHJlZCA+IDAuNSkNCmRmID0gZGF0YS5mcmFtZShwcmVkLCByZXB1Yiwgc3RhdGU9dHN0JFN0YXRlKQ0KaGVhZChkZikNCmBgYA0KDQpfRm9yIGhvdyBtYW55IHN0YXRlcyBpcyBvdXIgYmluYXJ5IHByZWRpY3Rpb24gMSAoZm9yIDIwMTIpLCBjb3JyZXNwb25kaW5nIHRvIFJlcHVibGljYW4/Xw0KYGBge3J9DQojcmVwdWI6cHJlZGljdOWHuuS+huapn+eOhz4wLjXkvLDngrrmmK9SZXB1YmxpY2FuDQpzdW0ocmVwdWIpDQpgYGANCg0KX1doYXQgaXMgdGhlIGF2ZXJhZ2UgcHJlZGljdGVkIHByb2JhYmlsaXR5IG9mIG91ciBtb2RlbCAob24gdGhlIFRlc3Qgc2V0LCBmb3IgMjAxMik/Xw0KYGBge3J9DQptZWFuKHByZWQpIA0KYGBgDQoNCiMjIyMjIDIuMiBNZXJnZSBEYXRhIGludG8gTWFwDQpOb3csIHdlIG5lZWQgdG8gbWVyZ2UgInByZWRpY3Rpb25EYXRhRnJhbWUiIHdpdGggdGhlIG1hcCBkYXRhICJzdGF0ZXNNYXAiLCBsaWtlIHdlIGRpZCBpbiBsZWN0dXJlLiBCZWZvcmUgZG9pbmcgc28sIHdlIG5lZWQgdG8gY29udmVydCB0aGUgVGVzdC5TdGF0ZSB2YXJpYWJsZSB0byBsb3dlcmNhc2UsIHNvIHRoYXQgaXQgbWF0Y2hlcyB0aGUgcmVnaW9uIHZhcmlhYmxlIGluIHN0YXRlc01hcC4gRG8gdGhpcyBieSB0eXBpbmcgdGhlIGZvbGxvd2luZyBpbiB5b3VyIFIgY29uc29sZToNCg0KYGBge3J9DQpkZiRyZWdpb24gPSB0b2xvd2VyKGRmJHN0YXRlKQ0KcG1hcCA9IG1lcmdlKHN0YXRlc01hcCwgZGYsIGJ5PSdyZWdpb24nKSANCmBgYA0KDQpfSG93IG1hbnkgb2JzZXJ2YXRpb25zIGFyZSB0aGVyZSBpbiBwcmVkaWN0aW9uTWFwP18NCmBgYHtyfQ0KbnJvdyhwbWFwKSAgICAgICAjIDE1MDM0DQpgYGANCg0KX0hvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gc3RhdGVNYXA/Xw0KYGBge3J9DQpucm93KHN0YXRlc01hcCkgICMgMTU1MzcNCmBgYA0KDQojIyMjIyAyLjMgVGhlIFJ1bGUgb2YgYG1lcmdlKClgDQpfV2hlbiB3ZSBtZXJnZWQgdGhlIGRhdGEgaW4gdGhlIHByZXZpb3VzIHByb2JsZW0sIGl0IGNhdXNlZCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB0byBjaGFuZ2UuIFdoeT9fIENoZWNrIG91dCB0aGUgaGVscCBwYWdlIGZvciBtZXJnZSBieSB0eXBpbmcgP21lcmdlIHRvIGhlbHAgeW91IGFuc3dlciB0aGlzIHF1ZXN0aW9uLg0KDQorIEJlY2F1c2Ugd2Ugb25seSBtYWtlIHByZWRpY3Rpb25zIGZvciA0NSBzdGF0ZXMsIHdlIG5vIGxvbmdlciBoYXZlIG9ic2VydmF0aW9ucyBmb3Igc29tZSBvZiB0aGUgc3RhdGVzLiBUaGVzZSBvYnNlcnZhdGlvbnMgd2VyZSByZW1vdmVkIGluIHRoZSBtZXJnaW5nIHByb2Nlc3MuDQorDQoNCiMjIyMjIDIuNCBQbG90IHRoZSBjb2xvciBtYXANCk5vdyB3ZSBhcmUgcmVhZHkgdG8gY29sb3IgdGhlIFVTIG1hcCB3aXRoIG91ciBwcmVkaWN0aW9ucyEgWW91IGNhbiBjb2xvciB0aGUgc3RhdGVzIGFjY29yZGluZyB0byBvdXIgYmluYXJ5IHByZWRpY3Rpb25zIGJ5IHR5cGluZyB0aGUgZm9sbG93aW5nIGluIHlvdXIgUiBjb25zb2xlOg0KYGBge3J9DQojIGZpbGw9cmVwdWI66aGP6Imy5Y2A5YiG5piv5ZCm54K65YWx5ZKM6buoDQpwbWFwID0gcG1hcFtvcmRlcihwbWFwJGdyb3VwLCBwbWFwJG9yZGVyKSAsIF0NCmdncGxvdChwbWFwLCBhZXMoeD1sb25nLCB5PWxhdCwgZ3JvdXA9Z3JvdXAsIGZpbGw9cmVwdWIpKSArDQogIGdlb21fcG9seWdvbihjb2xvcj0nYmxhY2snKQ0KYGBgDQpUaGUgc3RhdGVzIGFwcGVhciBsaWdodCBibHVlIGFuZCBkYXJrIGJsdWUgaW4gdGhpcyBtYXAuIF9XaGljaCBjb2xvciByZXByZXNlbnRzIGEgUmVwdWJsaWNhbiBwcmVkaWN0aW9uP18NCg0KKyBMaWdodCBibHVlDQorIHJlcHViPTHpoJDmuKzmmK/lhbHlkozpu6jvvIzlvp7lnJbkuIrnnIvmmK/mt7rol43oibINCg0KIyMjIyMgMi41DQpXZSBzZWUgdGhhdCB0aGUgbGVnZW5kIGRpc3BsYXlzIGEgYmx1ZSBncmFkaWVudCBmb3Igb3V0Y29tZXMgYmV0d2VlbiAwIGFuZCAxLiBIb3dldmVyLCB3aGVuIHBsb3R0aW5nIHRoZSBiaW5hcnkgcHJlZGljdGlvbnMgdGhlcmUgYXJlIG9ubHkgdHdvIHBvc3NpYmxlIG91dGNvbWVzOiAwIG9yIDEuIExldCdzIHJlcGxvdCB0aGUgbWFwIHdpdGggZGlzY3JldGUgb3V0Y29tZXMuIFdlIGNhbiBhbHNvIGNoYW5nZSB0aGUgY29sb3Igc2NoZW1lIHRvIGJsdWUgYW5kIHJlZCwgdG8gbWF0Y2ggdGhlIGJsdWUgY29sb3IgYXNzb2NpYXRlZCB3aXRoIHRoZSBEZW1vY3JhdGljIFBhcnR5IGluIHRoZSBVUyBhbmQgdGhlIHJlZCBjb2xvciBhc3NvY2lhdGVkIHdpdGggdGhlIFJlcHVibGljYW4gUGFydHkgaW4gdGhlIFVTLiBUaGlzIGNhbiBiZSBkb25lIHdpdGggdGhlIGZvbGxvd2luZyBjb21tYW5kOg0KDQpBbHRlcm5hdGl2ZWx5LCB3ZSBjb3VsZCBwbG90IHRoZSBwcm9iYWJpbGl0aWVzIGluc3RlYWQgb2YgdGhlIGJpbmFyeSBwcmVkaWN0aW9ucy4gQ2hhbmdlIHRoZSBwbG90IGNvbW1hbmQgYWJvdmUgdG8gaW5zdGVhZCBjb2xvciB0aGUgc3RhdGVzIGJ5IHRoZSB2YXJpYWJsZSBUZXN0UHJlZGljdGlvbi4gDQoNCmBgYHtyfQ0KI+aUueeUqFByZWRpY3Rpb27mqZ/njofljYDliIbpoY/oibINCg0KZ2dwbG90KHBtYXAsIGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCwgZmlsbD1wcmVkKSkgKw0KICBnZW9tX3BvbHlnb24oY29sb3I9J2JsYWNrJykgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KA0KICAgIGxvdz0iYmx1ZSIsIGhpZ2g9InJlZCIsIA0KICAgIGd1aWRlPSJsZWdlbmQiLCBicmVha3M9IGMoMCwxKSwgDQogICAgbGFiZWxzPWMoIkRlbW9jcmF0IiwgIlJlcHVibGljYW4iKSwgbmFtZT0iUHJlZGljdGlvbiAyMDEyIikNCmBgYA0KWW91IHNob3VsZCBzZWUgYSBncmFkaWVudCBvZiBjb2xvcnMgcmFuZ2luZyBmcm9tIHJlZCB0byBibHVlLiBfRG8gdGhlIGNvbG9ycyBvZiB0aGUgc3RhdGVzIGluIHRoZSBtYXAgZm9yIFRlc3RQcmVkaWN0aW9uIGxvb2sgZGlmZmVyZW50IGZyb20gdGhlIGNvbG9ycyBvZiB0aGUgc3RhdGVzIGluIHRoZSBtYXAgd2l0aCBUZXN0UHJlZGljdGlvbkJpbmFyeT8gV2h5IG9yIHdoeSBub3Q/Xw0KDQorIFRlc3RQcmVkaWN0aW9uQmluYXJ55Y+q5pyJMOOAgTHlhanlgItmYWN0b3LvvIzpoY/oibLlj6rmnInlhannqK4NCg0KKyBUZXN0UHJlZGljdGlvbueUqOapn+eOh+WNgOWIhumhj+iJsu+8jOacg+acieS4gOWAi+mAo+e6jOWNgOmWk++8jOmhj+iJsueorumhnuacg+avlOi8g+Wkmg0KDQo8YnI+PGhyPg0KDQojIyMgMy4gVW5kZXJzdGFuZGluZyB0aGUgUHJlZGljdGlvbnMNCg0KIyMjIyMgMy4xIA0KSW4gdGhlIDIwMTIgZWxlY3Rpb24sIHRoZSBzdGF0ZSBvZiBGbG9yaWRhIGVuZGVkIHVwIGJlaW5nIGEgdmVyeSBjbG9zZSByYWNlLiBJdCB3YXMgdWx0aW1hdGVseSB3b24gYnkgdGhlIERlbW9jcmF0aWMgcGFydHkuIA0KYGBge3J9DQpkZiRwcmVkWyBkZiRzdGF0ZSA9PSAnRmxvcmlkYSddICMgMC45NjQwNA0KYGBgDQpfRGlkIHdlIHByZWRpY3QgdGhpcyBzdGF0ZSBjb3JyZWN0bHkgb3IgaW5jb3JyZWN0bHk/IF8NCg0KKyBXZSBpbmNvcnJlY3RseSBwcmVkaWN0ZWQgdGhpcyBzdGF0ZSBieSBwcmVkaWN0aW5nIHRoYXQgaXQgd291bGQgYmUgd29uIGJ5IHRoZSBSZXB1YmxpY2FuIHBhcnR5LiANCisgRmxvcmlkYeWcqDIwMTLlubTpgbjoiInmnIDntYLmmK/nlLFEZW1vY3JhdGljIHBhcnR5542y6YG4DQoNCiMjIyMjIDMuMg0KX1doYXQgd2FzIG91ciBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgZm9yIHRoZSBzdGF0ZSBvZiBGbG9yaWRhP18NCmBgYHtyfQ0KZGYkcHJlZFsgZGYkc3RhdGUgPT0gJ0Zsb3JpZGEnXSAjIDAuOTY0MDQNCmBgYA0KDQpfV2hhdCBkb2VzIHRoaXMgaW1wbHk/Xw0KDQorIE91ciBwcmVkaWN0aW9uIG1vZGVsIGRpZCBub3QgZG8gYSB2ZXJ5IGdvb2Qgam9iIG9mIGNvcnJlY3RseSBwcmVkaWN0aW5nIHRoZSBzdGF0ZSBvZiBGbG9yaWRhLCBhbmQgd2Ugd2VyZSB2ZXJ5IGNvbmZpZGVudCBpbiBvdXIgaW5jb3JyZWN0IHByZWRpY3Rpb24uDQorDQoNCjxicj48aHI+DQoNCiMjIyMjIDQuIFBhcmFtZXRlciBTZXR0aW5ncw0KSW4gdGhpcyBwYXJ0LCB3ZSdsbCBleHBsb3JlIHdoYXQgdGhlIGRpZmZlcmVudCBwYXJhbWV0ZXIgc2V0dGluZ3Mgb2YgZ2VvbV9wb2x5Z29uIGRvLiBUaHJvdWdob3V0IHRoZSBwcm9ibGVtLCB1c2UgdGhlIGhlbHAgcGFnZSBmb3IgZ2VvbV9wb2x5Z29uLCB3aGljaCBjYW4gYmUgYWNjZXNzZWQgYnkgP2dlb21fcG9seWdvbi4gVG8gc2VlIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgYSBjZXJ0YWluIHBhcmFtZXRlciwganVzdCB0eXBlIGEgcXVlc3Rpb24gbWFyayBhbmQgdGhlbiB0aGUgcGFyYW1ldGVyIG5hbWUgdG8gZ2V0IHRoZSBoZWxwIHBhZ2UgZm9yIHRoYXQgcGFyYW1ldGVyLiBFeHBlcmltZW50IHdpdGggZGlmZmVyZW50IHBhcmFtZXRlciBzZXR0aW5ncyB0byB0cnkgYW5kIHJlcGxpY2F0ZSB0aGUgcGxvdHMhDQoNCldlJ2xsIGJlIGFza2luZyBxdWVzdGlvbnMgYWJvdXQgdGhlIGZvbGxvd2luZyB0aHJlZSBwbG90czoNCmBgYHtyfQ0KZ3JhZCA9IHNjYWxlX2ZpbGxfZ3JhZGllbnQoDQogIGxvdz0iYmx1ZSIsIGhpZ2g9InJlZCIsIA0KICBndWlkZT0ibGVnZW5kIiwgYnJlYWtzPSBjKDAsMSksIA0KICBsYWJlbHM9YygiRGVtb2NyYXQiLCAiUmVwdWJsaWNhbiIpLCBuYW1lPSJQcmVkaWN0aW9uIDIwMTIiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHBtYXAsIGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCwgZmlsbD1yZXB1YikpICsgZ3JhZCArDQogIGdlb21fcG9seWdvbihjb2xvcj0nYmxhY2snLGxpbmV0eXBlPTMsc2l6ZT0xKSArIGdndGl0bGUoIlBsb3QoMSkiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHBtYXAsIGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCwgZmlsbD1yZXB1YikpICsgZ3JhZCArDQogIGdlb21fcG9seWdvbihjb2xvcj0nYmxhY2snLGxpbmV0eXBlPTEsc2l6ZT0zKSArIGdndGl0bGUoIlBsb3QoMikiKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3QocG1hcCwgYWVzKHg9bG9uZywgeT1sYXQsIGdyb3VwPWdyb3VwLCBmaWxsPXJlcHViKSkgKyBncmFkICsNCiAgZ2VvbV9wb2x5Z29uKGNvbG9yPSdibGFjaycsbGluZXR5cGU9MSxzaXplPTEsYWxwaGE9MC4zKSArIGdndGl0bGUoIlBsb3QoMykiKQ0KYGBgDQoNCiMjIyMjIDQuMSANClBsb3RzICgxKSBhbmQgKDIpIHdlcmUgY3JlYXRlZCBieSBjaGFuZ2luZyBkaWZmZXJlbnQgcGFyYW1ldGVycyBvZiBnZW9tX3BvbHlnb24gZnJvbSB0aGVpciBkZWZhdWx0IHZhbHVlcy4NCg0KX1doYXQgaXMgdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlciB3ZSBjaGFuZ2VkIHRvIGNyZWF0ZSBwbG90ICgxKT9fDQoNCisgbGluZXR5cGUNCisgbGluZXR5cGU9M+acg+eUqOiZm+e3mueVqw0KDQpfV2hhdCBpcyB0aGUgbmFtZSBvZiB0aGUgcGFyYW1ldGVyIHdlIGNoYW5nZWQgdG8gY3JlYXRlIHBsb3QgKDIpP18NCg0KKyBzaXplDQorDQoNCg0KIyMjIyMgNC4yIA0KUGxvdCAoMykgd2FzIGNyZWF0ZWQgYnkgY2hhbmdpbmcgdGhlIHZhbHVlIG9mIGEgZGlmZmVyZW50IGdlb21fcG9seWdvbiBwYXJhbWV0ZXIgdG8gaGF2ZSB2YWx1ZSAwLjMuIF9XaGljaCBwYXJhbWV0ZXIgZGlkIHdlIHVzZT9fDQoNCisgYWxwaGENCisNCg0KPGJyPjxocj4NCg0KPGJyPjxicj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogI2IzNmIwMDsNCiAgYmFja2dyb3VuZDogI2ZmZTBiMzsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmZmZmZTA7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KZW17DQogIGNvbG9yOiAjMDAwMGMwOw0KICBiYWNrZ3JvdW5kOiAjZjBmMGYwOw0KICB9DQoNCjwvc3R5bGU+DQoNCg==