主要議題:依字頻表對文章分群

學習重點:

rm(list=ls(all=T))
Sys.setlocale("LC_ALL","C")
[1] "C"
options(digits=4, scipen=12)
library(dplyr)



1. Hierarchical Clustering

1.1 字頻表、距離矩陣、階層式集群分析

Let’s start by building a hierarchical clustering model. First, read the data set into R. Then, compute the distances (using method=“euclidean”), and use hclust to build the model (using method=“ward.D”). You should cluster on all of the variables.

D = read.csv('data/dailykos.csv')
dim(D)
[1] 3430 1545
# 字頻表: Document Term Matrix
D[1:20, 1:10]
# 距離矩陣: Distance Matrix
t0 = Sys.time()
d = dist(D, method="euclidean")
Sys.time() - t0
Time difference of 2.474 mins

Running the dist function will probably take you a while. Why? Select all that apply.

  • 要計算每篇文章與其他文章的相似度 (3430 * 3429 / 2)
  • 每篇文章的詞彙多 => 計算花時間 (1545個差的和)
# 階層式集群分析: Hierarchical Clustering Analysis
t0 = Sys.time()
hc = hclust(d, method='ward.D')
Sys.time() - t0
Time difference of 0.5664 secs

Plot the dendrogram of your hierarchical clustering model.

plot(hc)

1.2 從樹狀圖判斷群數

Just looking at the dendrogram,

which of the following seem like good choices for the number of clusters? Select all that apply.

  • 2
  • 3 因為群間距離較大
1.3 從應用決定群數

In this problem, we are trying to cluster news articles or blog posts into groups. This can be used to show readers categories to choose from when trying to decide what to read. Just thinking about this application,

what are good choices for the number of clusters? Select all that apply.

  • 7
  • 8 在分類時,最好能夠多分幾類,讓讀者可以有較多種選項。
1.4 依群組分割資料

Let’s pick 7 clusters. This number is reasonable according to the dendrogram, and also seems reasonable for the application. Use the cutree function to split your data into 7 clusters.

kg = cutree(hc, k=7)
L = split(D, kg)

Now, we don’t really want to run tapply on every single variable when we have over 1,000 different variables. Let’s instead use the subset function to subset our data by cluster. Create 7 new datasets, each containing the observations from one of the clusters.

How many observations are in cluster 3?

nrow(L[[3]])
[1] 374
table(kg) %>% sort
kg
   4    7    2    3    5    6    1 
 139  209  321  374  407  714 1266 

Which cluster has the most observations?

  • 1

Which cluster has the fewest observations?

  • 4
1.5 找出第一族群中最常見的字辭

Instead of looking at the average value in each variable individually, we’ll just look at the top 6 words in each cluster. To do this for cluster 1, type the following in your R console (where “HierCluster1” should be replaced with the name of your first cluster subset):

tail(sort(colMeans(HierCluster1)))

This computes the mean frequency values of each of the words in cluster 1, and then outputs the 6 words that occur the most frequently. The colMeans function computes the column (word) means, the sort function orders the words in increasing order of the mean values, and the tail function outputs the last 6 words listed, which are the ones with the largest column means.

What is the most frequent word in this cluster, in terms of average value? Enter the word exactly how you see it in the output:

L[[1]] %>% colMeans %>% sort %>% tail #equals to tail(sort(colMeans(HierCluster1)))
     state republican       poll   democrat      kerry       bush 
    0.7575     0.7591     0.9036     0.9194     1.0624     1.7054 
#這邊計算得到的值是 "這個字在每篇文章中平均出現幾次!"
1.6 找出各族群中最常見的字辭

Now repeat the command given in the previous problem for each of the other clusters, and answer the following questions.

sapply(L, function(x) x %>% colMeans %>% sort %>% tail %>% names) %>% t
  [,1]       [,2]         [,3]             [,4]         [,5]       [,6]      
1 "state"    "republican" "poll"           "democrat"   "kerry"    "bush"    
2 "bush"     "democrat"   "challenge"      "vote"       "poll"     "november"
3 "elect"    "parties"    "state"          "republican" "democrat" "bush"    
4 "campaign" "voter"      "presided"       "poll"       "bush"     "kerry"   
5 "american" "presided"   "administration" "war"        "iraq"     "bush"    
6 "race"     "bush"       "kerry"          "elect"      "democrat" "poll"    
7 "democrat" "clark"      "edward"         "poll"       "kerry"    "dean"    
#把L中的每一個element當作x送入function中。

Which words best describe cluster 2?

  • november, poll, vote

Which cluster could best be described as the cluster related to the Iraq war?

  • 5

In 2004, one of the candidates for the Democratic nomination for the President of the United States was Howard Dean, John Kerry was the candidate who won the democratic nomination, and John Edwards with the running mate of John Kerry (the Vice President nominee). Given this information,

which cluster best corresponds to the democratic party?

  • 7



2 K-Means Clustering

2.1 K-Means集群分析

Now, run k-means clustering, setting the seed to 1000 right before you run the kmeans function. Again, pick the number of clusters equal to 7. You don’t need to add the iters.max argument.

set.seed(1000)
km = kmeans(D, 7)
kg2 = km$cluster
table(km$cluster) %>% sort

   2    1    5    3    7    6    4 
 144  146  163  277  308  329 2063 

Subset your data into the 7 clusters (7 new datasets) by using the “cluster” variable of your kmeans output.

cluster_1 = subset(D,kg2 == 1)
cluster_2 = subset(D,kg2 == 2)
cluster_3 = subset(D,kg2 == 3)
cluster_4 = subset(D,kg2 == 4)
cluster_5 = subset(D,kg2 == 5)
cluster_6 = subset(D,kg2 == 6)
cluster_7 = subset(D,kg2 == 7)

How many observations are in Cluster 3?

  • 277

Which cluster has the most observations?

  • 4

Which cluster has the fewest number of observations?

  • 2
2.2 找出各族群中最常見的字辭

Now, output the six most frequent words in each cluster, like we did in the previous problem, for each of the k-means clusters.

split(D, kg2) %>% sapply(function(x) 
  x %>% colMeans %>% sort %>% tail %>% names) %>% t
  [,1]             [,2]         [,3]        [,4]             [,5]         [,6]      
1 "state"          "iraq"       "kerry"     "administration" "presided"   "bush"    
2 "primaries"      "democrat"   "edward"    "clark"          "kerry"      "dean"    
3 "administration" "iraqi"      "american"  "bush"           "war"        "iraq"    
4 "elect"          "republican" "kerry"     "poll"           "democrat"   "bush"    
5 "race"           "senate"     "state"     "parties"        "republican" "democrat"
6 "democrat"       "bush"       "challenge" "vote"           "poll"       "november"
7 "presided"       "voter"      "campaign"  "poll"           "bush"       "kerry"   

Which k-means cluster best corresponds to the Iraq War?

  • 3

Which k-means cluster best corresponds to the democratic party? (Remember that we are looking for the names of the key democratic party leaders.)

  • 2
2.3 ~ 2.6 兩種分群結果之間的對應關係

For the rest of this problem, we’ll ask you to compare how observations were assigned to clusters in the two different methods. Use the table function to compare the cluster assignment of hierarchical clustering to the cluster assignment of k-means clustering.

table(Hierarchical=kg, KMeans=kg2)
            KMeans
Hierarchical    1    2    3    4    5    6    7
           1    3   11   64 1045   32    0  111
           2    0    0    0    0    0  320    1
           3   85   10   42   79  126    8   24
           4   10    5    0    0    1    0  123
           5   48    0  171  145    3    1   39
           6    0    2    0  712    0    0    0
           7    0  116    0   82    1    0   10

Which Hierarchical Cluster best corresponds to K-Means Cluster 2?

  • 7

Which Hierarchical Cluster best corresponds to K-Means Cluster 3?

  • 5

Which Hierarchical Cluster best corresponds to K-Means Cluster 7?

  • No Hierarchical Cluster contains at least half of the points in K-Means Cluster 7.

Which Hierarchical Cluster best corresponds to K-Means Cluster 6?

  • 2
【討論問題】

字頻表是什麼?它的資料格式?

  • 採用Bag of word的形式,先整理出所有文章中使用到的所有字,作為Column。
  • 在字頻表就是每篇文章中每一個字的數量,放到每個Column中。

使用字頻表作集群分析時,區隔變數是什麼?

  • 在分群時,是透過單詞的頻率來決定不同的群,所以我們認為是單詞的頻率。

從樹狀圖判斷群數和從應用需求決定群數有什麼差別?

  • 樹狀圖判斷群樹可以找到群間距離最大的群數,代表此時資料區分的最遠也最為理想。但這沒有明確的含義(每一類是什麼)。或許理想群樹相當少或相當多,難以應用。
  • 從應用需求決定,僅管資料分布的狀況未必會到最為理想,但是從應用面來看,這樣的分群數量是最適合拿來做進一步使用的。








LS0tDQp0aXRsZTogIkFTNi0xIERhaWx5IEtvc+aWh+eroOWIhue+pCINCmF1dGhvcjogIkdyb3VwIDIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8YnI+DQoNCioq5Li76KaB6K2w6aGM77ya5L6d5a2X6aC76KGo5bCN5paH56ug5YiG576kKioNCg0KKirlrbjnv5Lph43pu57vvJoqKg0KDQorIOS+neWtl+mgu+ihqOWwjeaWh+eroOWIhue+pA0KKyDlsaTntJrlvI/pm4bnvqTliIbmnpDvvJpIaWVyYXJjaGljYWwgQ2x1c3RlciBBbmFseXNpcw0KKyDkvp3mk5rmqLnni4DlnJbmsbrlrpropoHliIblpJrlsJHnvqQNCisg5L6d5pOa5oeJ55So5rG65a6a6KaB5YiG5aSa5bCR576kDQorIEstTWVhbnPpm4bnvqTliIbmnpDvvJpLLU1lYW5zIENsdXN0ZXIgQW5hbHlzaXMNCisg5b6e5bi46KaL5a2X6L6t5o6o6KuW5paH6ZuG55qE5Li76aGMDQoNCg0KYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0NCnJtKGxpc3Q9bHMoYWxsPVQpKQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwiQyIpDQpvcHRpb25zKGRpZ2l0cz00LCBzY2lwZW49MTIpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAxLiBIaWVyYXJjaGljYWwgQ2x1c3RlcmluZw0KDQojIyMjIyAxLjEg5a2X6aC76KGo44CB6Led6Zui55+p6Zmj44CB6ZqO5bGk5byP6ZuG576k5YiG5p6QDQpMZXQncyBzdGFydCBieSBidWlsZGluZyBhIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG1vZGVsLiBGaXJzdCwgcmVhZCB0aGUgZGF0YSBzZXQgaW50byBSLiBUaGVuLCBjb21wdXRlIHRoZSBkaXN0YW5jZXMgKHVzaW5nIG1ldGhvZD0iZXVjbGlkZWFuIiksIGFuZCB1c2UgaGNsdXN0IHRvIGJ1aWxkIHRoZSBtb2RlbCAodXNpbmcgbWV0aG9kPSJ3YXJkLkQiKS4gWW91IHNob3VsZCBjbHVzdGVyIG9uIGFsbCBvZiB0aGUgdmFyaWFibGVzLg0KDQpgYGB7cn0NCkQgPSByZWFkLmNzdignZGF0YS9kYWlseWtvcy5jc3YnKQ0KZGltKEQpDQpgYGANCg0KYGBge3J9DQojIOWtl+mgu+ihqDogRG9jdW1lbnQgVGVybSBNYXRyaXgNCkRbMToyMCwgMToxMF0NCmBgYA0KDQpgYGB7cn0NCiMg6Led6Zui55+p6ZmjOiBEaXN0YW5jZSBNYXRyaXgNCnQwID0gU3lzLnRpbWUoKQ0KZCA9IGRpc3QoRCwgbWV0aG9kPSJldWNsaWRlYW4iKQ0KU3lzLnRpbWUoKSAtIHQwDQpgYGANCl9SdW5uaW5nIHRoZSBkaXN0IGZ1bmN0aW9uIHdpbGwgcHJvYmFibHkgdGFrZSB5b3UgYSB3aGlsZS4gV2h5P18gU2VsZWN0IGFsbCB0aGF0IGFwcGx5Lg0KDQorIOimgeioiOeul+avj+evh+aWh+eroOiIh+WFtuS7luaWh+eroOeahOebuOS8vOW6piAoMzQzMCAqIDM0MjkgLyAyKSANCisg5q+P56+H5paH56ug55qE6Kme5b2Z5aSaID0+IOioiOeul+iKseaZgumWkyAoMTU0NeWAi+W3rueahOWSjCkNCg0KDQpgYGB7cn0NCiMg6ZqO5bGk5byP6ZuG576k5YiG5p6QOiBIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyBBbmFseXNpcw0KdDAgPSBTeXMudGltZSgpDQpoYyA9IGhjbHVzdChkLCBtZXRob2Q9J3dhcmQuRCcpDQpTeXMudGltZSgpIC0gdDANCmBgYA0KDQpQbG90IHRoZSBkZW5kcm9ncmFtIG9mIHlvdXIgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgbW9kZWwuIA0KYGBge3J9DQpwbG90KGhjKQ0KYGBgDQoNCiMjIyMjIDEuMiDlvp7mqLnni4DlnJbliKTmlrfnvqTmlbgNCkp1c3QgbG9va2luZyBhdCB0aGUgZGVuZHJvZ3JhbSwgDQoNCl93aGljaCBvZiB0aGUgZm9sbG93aW5nIHNlZW0gbGlrZSBnb29kIGNob2ljZXMgZm9yIHRoZSBudW1iZXIgb2YgY2x1c3RlcnM/XyBTZWxlY3QgYWxsIHRoYXQgYXBwbHkuDQoNCisgMg0KKyAzDQrlm6DngrrnvqTplpPot53pm6LovIPlpKcNCg0KIyMjIyMgMS4zIOW+nuaHieeUqOaxuuWumue+pOaVuA0KSW4gdGhpcyBwcm9ibGVtLCB3ZSBhcmUgdHJ5aW5nIHRvIGNsdXN0ZXIgbmV3cyBhcnRpY2xlcyBvciBibG9nIHBvc3RzIGludG8gZ3JvdXBzLiBUaGlzIGNhbiBiZSB1c2VkIHRvIHNob3cgcmVhZGVycyBjYXRlZ29yaWVzIHRvIGNob29zZSBmcm9tIHdoZW4gdHJ5aW5nIHRvIGRlY2lkZSB3aGF0IHRvIHJlYWQuIEp1c3QgdGhpbmtpbmcgYWJvdXQgdGhpcyBhcHBsaWNhdGlvbiwgDQoNCl93aGF0IGFyZSBnb29kIGNob2ljZXMgZm9yIHRoZSBudW1iZXIgb2YgY2x1c3RlcnM/XyBTZWxlY3QgYWxsIHRoYXQgYXBwbHkuDQoNCisgNw0KKyA4DQrlnKjliIbpoZ7mmYLvvIzmnIDlpb3og73lpKDlpJrliIblub7poZ7vvIzorpPoroDogIXlj6/ku6XmnInovIPlpJrnqK7pgbjpoIXjgIINCg0KIyMjIyMgMS40IOS+nee+pOe1hOWIhuWJsuizh+aWmQ0KTGV0J3MgcGljayA3IGNsdXN0ZXJzLiBUaGlzIG51bWJlciBpcyByZWFzb25hYmxlIGFjY29yZGluZyB0byB0aGUgZGVuZHJvZ3JhbSwgYW5kIGFsc28gc2VlbXMgcmVhc29uYWJsZSBmb3IgdGhlIGFwcGxpY2F0aW9uLiBVc2UgdGhlIGN1dHJlZSBmdW5jdGlvbiB0byBzcGxpdCB5b3VyIGRhdGEgaW50byA3IGNsdXN0ZXJzLg0KYGBge3J9DQprZyA9IGN1dHJlZShoYywgaz03KQ0KTCA9IHNwbGl0KEQsIGtnKQ0KYGBgDQpOb3csIHdlIGRvbid0IHJlYWxseSB3YW50IHRvIHJ1biB0YXBwbHkgb24gZXZlcnkgc2luZ2xlIHZhcmlhYmxlIHdoZW4gd2UgaGF2ZSBvdmVyIDEsMDAwIGRpZmZlcmVudCB2YXJpYWJsZXMuIExldCdzIGluc3RlYWQgdXNlIHRoZSBzdWJzZXQgZnVuY3Rpb24gdG8gc3Vic2V0IG91ciBkYXRhIGJ5IGNsdXN0ZXIuIENyZWF0ZSA3IG5ldyBkYXRhc2V0cywgZWFjaCBjb250YWluaW5nIHRoZSBvYnNlcnZhdGlvbnMgZnJvbSBvbmUgb2YgdGhlIGNsdXN0ZXJzLg0KDQpfSG93IG1hbnkgb2JzZXJ2YXRpb25zIGFyZSBpbiBjbHVzdGVyIDM/Xw0KYGBge3J9DQpucm93KExbWzNdXSkNCmBgYA0KDQpgYGB7cn0NCnRhYmxlKGtnKSAlPiUgc29ydA0KYGBgDQoNCl9XaGljaCBjbHVzdGVyIGhhcyB0aGUgbW9zdCBvYnNlcnZhdGlvbnM/Xw0KDQorIDENCisNCg0KX1doaWNoIGNsdXN0ZXIgaGFzIHRoZSBmZXdlc3Qgb2JzZXJ2YXRpb25zP18NCg0KKyA0DQorDQoNCiMjIyMjIDEuNSDmib7lh7rnrKzkuIDml4/nvqTkuK3mnIDluLjopovnmoTlrZfovq0NCkluc3RlYWQgb2YgbG9va2luZyBhdCB0aGUgYXZlcmFnZSB2YWx1ZSBpbiBlYWNoIHZhcmlhYmxlIGluZGl2aWR1YWxseSwgd2UnbGwganVzdCBsb29rIGF0IHRoZSB0b3AgNiB3b3JkcyBpbiBlYWNoIGNsdXN0ZXIuIFRvIGRvIHRoaXMgZm9yIGNsdXN0ZXIgMSwgdHlwZSB0aGUgZm9sbG93aW5nIGluIHlvdXIgUiBjb25zb2xlICh3aGVyZSAiSGllckNsdXN0ZXIxIiBzaG91bGQgYmUgcmVwbGFjZWQgd2l0aCB0aGUgbmFtZSBvZiB5b3VyIGZpcnN0IGNsdXN0ZXIgc3Vic2V0KToNCg0KdGFpbChzb3J0KGNvbE1lYW5zKEhpZXJDbHVzdGVyMSkpKQ0KDQpUaGlzIGNvbXB1dGVzIHRoZSBtZWFuIGZyZXF1ZW5jeSB2YWx1ZXMgb2YgZWFjaCBvZiB0aGUgd29yZHMgaW4gY2x1c3RlciAxLCBhbmQgdGhlbiBvdXRwdXRzIHRoZSA2IHdvcmRzIHRoYXQgb2NjdXIgdGhlIG1vc3QgZnJlcXVlbnRseS4gVGhlIGNvbE1lYW5zIGZ1bmN0aW9uIGNvbXB1dGVzIHRoZSBjb2x1bW4gKHdvcmQpIG1lYW5zLCB0aGUgc29ydCBmdW5jdGlvbiBvcmRlcnMgdGhlIHdvcmRzIGluIGluY3JlYXNpbmcgb3JkZXIgb2YgdGhlIG1lYW4gdmFsdWVzLCBhbmQgdGhlIHRhaWwgZnVuY3Rpb24gb3V0cHV0cyB0aGUgbGFzdCA2IHdvcmRzIGxpc3RlZCwgd2hpY2ggYXJlIHRoZSBvbmVzIHdpdGggdGhlIGxhcmdlc3QgY29sdW1uIG1lYW5zLg0KDQpfV2hhdCBpcyB0aGUgbW9zdCBmcmVxdWVudCB3b3JkIGluIHRoaXMgY2x1c3RlciwgaW4gdGVybXMgb2YgYXZlcmFnZSB2YWx1ZT9fIEVudGVyIHRoZSB3b3JkIGV4YWN0bHkgaG93IHlvdSBzZWUgaXQgaW4gdGhlIG91dHB1dDoNCmBgYHtyfQ0KTFtbMV1dICU+JSBjb2xNZWFucyAlPiUgc29ydCAlPiUgdGFpbCAjZXF1YWxzIHRvIHRhaWwoc29ydChjb2xNZWFucyhIaWVyQ2x1c3RlcjEpKSkNCiPpgJnpgoroqIjnrpflvpfliLDnmoTlgLzmmK8gIumAmeWAi+Wtl+WcqOavj+evh+aWh+eroOS4reW5s+Wdh+WHuuePvuW5vuasoe+8gSINCmBgYA0KDQoNCiMjIyMjIDEuNiDmib7lh7rlkITml4/nvqTkuK3mnIDluLjopovnmoTlrZfovq0NCk5vdyByZXBlYXQgdGhlIGNvbW1hbmQgZ2l2ZW4gaW4gdGhlIHByZXZpb3VzIHByb2JsZW0gZm9yIGVhY2ggb2YgdGhlIG90aGVyIGNsdXN0ZXJzLCBhbmQgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zLg0KYGBge3J9DQpzYXBwbHkoTCwgZnVuY3Rpb24oeCkgeCAlPiUgY29sTWVhbnMgJT4lIHNvcnQgJT4lIHRhaWwgJT4lIG5hbWVzKSAlPiUgdA0KI+aKikzkuK3nmoTmr4/kuIDlgItlbGVtZW5055W25L2ceOmAgeWFpWZ1bmN0aW9u5Lit44CCDQpgYGANCg0KX1doaWNoIHdvcmRzIGJlc3QgZGVzY3JpYmUgY2x1c3RlciAyP18NCg0KKyBub3ZlbWJlciwgcG9sbCwgdm90ZQ0KKw0KDQpfV2hpY2ggY2x1c3RlciBjb3VsZCBiZXN0IGJlIGRlc2NyaWJlZCBhcyB0aGUgY2x1c3RlciByZWxhdGVkIHRvIHRoZSBJcmFxIHdhcj9fDQoNCisgNQ0KKw0KDQpJbiAyMDA0LCBvbmUgb2YgdGhlIGNhbmRpZGF0ZXMgZm9yIHRoZSBEZW1vY3JhdGljIG5vbWluYXRpb24gZm9yIHRoZSBQcmVzaWRlbnQgb2YgdGhlIFVuaXRlZCBTdGF0ZXMgd2FzIEhvd2FyZCBEZWFuLCBKb2huIEtlcnJ5IHdhcyB0aGUgY2FuZGlkYXRlIHdobyB3b24gdGhlIGRlbW9jcmF0aWMgbm9taW5hdGlvbiwgYW5kIEpvaG4gRWR3YXJkcyB3aXRoIHRoZSBydW5uaW5nIG1hdGUgb2YgSm9obiBLZXJyeSAodGhlIFZpY2UgUHJlc2lkZW50IG5vbWluZWUpLiBHaXZlbiB0aGlzIGluZm9ybWF0aW9uLCANCg0KX3doaWNoIGNsdXN0ZXIgYmVzdCBjb3JyZXNwb25kcyB0byB0aGUgZGVtb2NyYXRpYyBwYXJ0eT9fDQoNCisgNw0KKw0KDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAyIEstTWVhbnMgQ2x1c3RlcmluZw0KDQojIyMjIyAyLjEgSy1NZWFuc+mbhue+pOWIhuaekA0KTm93LCBydW4gay1tZWFucyBjbHVzdGVyaW5nLCBzZXR0aW5nIHRoZSBzZWVkIHRvIDEwMDAgcmlnaHQgYmVmb3JlIHlvdSBydW4gdGhlIGttZWFucyBmdW5jdGlvbi4gQWdhaW4sIHBpY2sgdGhlIG51bWJlciBvZiBjbHVzdGVycyBlcXVhbCB0byA3LiBZb3UgZG9uJ3QgbmVlZCB0byBhZGQgdGhlIGl0ZXJzLm1heCBhcmd1bWVudC4NCmBgYHtyfQ0Kc2V0LnNlZWQoMTAwMCkNCmttID0ga21lYW5zKEQsIDcpDQprZzIgPSBrbSRjbHVzdGVyDQp0YWJsZShrbSRjbHVzdGVyKSAlPiUgc29ydA0KYGBgDQoNClN1YnNldCB5b3VyIGRhdGEgaW50byB0aGUgNyBjbHVzdGVycyAoNyBuZXcgZGF0YXNldHMpIGJ5IHVzaW5nIHRoZSAiY2x1c3RlciIgdmFyaWFibGUgb2YgeW91ciBrbWVhbnMgb3V0cHV0Lg0KDQpgYGB7cn0NCmNsdXN0ZXJfMSA9IHN1YnNldChELGtnMiA9PSAxKQ0KY2x1c3Rlcl8yID0gc3Vic2V0KEQsa2cyID09IDIpDQpjbHVzdGVyXzMgPSBzdWJzZXQoRCxrZzIgPT0gMykNCmNsdXN0ZXJfNCA9IHN1YnNldChELGtnMiA9PSA0KQ0KY2x1c3Rlcl81ID0gc3Vic2V0KEQsa2cyID09IDUpDQpjbHVzdGVyXzYgPSBzdWJzZXQoRCxrZzIgPT0gNikNCmNsdXN0ZXJfNyA9IHN1YnNldChELGtnMiA9PSA3KQ0KYGBgDQoNCg0KX0hvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgaW4gQ2x1c3RlciAzP18NCg0KKyAyNzcNCisgDQoNCl9XaGljaCBjbHVzdGVyIGhhcyB0aGUgbW9zdCBvYnNlcnZhdGlvbnM/Xw0KDQorIDQNCisNCg0KX1doaWNoIGNsdXN0ZXIgaGFzIHRoZSBmZXdlc3QgbnVtYmVyIG9mIG9ic2VydmF0aW9ucz9fDQoNCisgMg0KKw0KDQojIyMjIyAyLjIg5om+5Ye65ZCE5peP576k5Lit5pyA5bi46KaL55qE5a2X6L6tDQpOb3csIG91dHB1dCB0aGUgc2l4IG1vc3QgZnJlcXVlbnQgd29yZHMgaW4gZWFjaCBjbHVzdGVyLCBsaWtlIHdlIGRpZCBpbiB0aGUgcHJldmlvdXMgcHJvYmxlbSwgZm9yIGVhY2ggb2YgdGhlIGstbWVhbnMgY2x1c3RlcnMuDQpgYGB7cn0NCnNwbGl0KEQsIGtnMikgJT4lIHNhcHBseShmdW5jdGlvbih4KSANCiAgeCAlPiUgY29sTWVhbnMgJT4lIHNvcnQgJT4lIHRhaWwgJT4lIG5hbWVzKSAlPiUgdA0KYGBgDQoNCl9XaGljaCBrLW1lYW5zIGNsdXN0ZXIgYmVzdCBjb3JyZXNwb25kcyB0byB0aGUgSXJhcSBXYXI/Xw0KDQorIDMNCisgDQoNCl9XaGljaCBrLW1lYW5zIGNsdXN0ZXIgYmVzdCBjb3JyZXNwb25kcyB0byB0aGUgZGVtb2NyYXRpYyBwYXJ0eT9fIChSZW1lbWJlciB0aGF0IHdlIGFyZSBsb29raW5nIGZvciB0aGUgbmFtZXMgb2YgdGhlIGtleSBkZW1vY3JhdGljIHBhcnR5IGxlYWRlcnMuKQ0KDQorIDINCisgDQoNCiMjIyMjIDIuMyB+IDIuNiDlhannqK7liIbnvqTntZDmnpzkuYvplpPnmoTlsI3mh4npl5zkv4INCkZvciB0aGUgcmVzdCBvZiB0aGlzIHByb2JsZW0sIHdlJ2xsIGFzayB5b3UgdG8gY29tcGFyZSBob3cgb2JzZXJ2YXRpb25zIHdlcmUgYXNzaWduZWQgdG8gY2x1c3RlcnMgaW4gdGhlIHR3byBkaWZmZXJlbnQgbWV0aG9kcy4gVXNlIHRoZSB0YWJsZSBmdW5jdGlvbiB0byBjb21wYXJlIHRoZSBjbHVzdGVyIGFzc2lnbm1lbnQgb2YgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgdG8gdGhlIGNsdXN0ZXIgYXNzaWdubWVudCBvZiBrLW1lYW5zIGNsdXN0ZXJpbmcuDQpgYGB7cn0NCnRhYmxlKEhpZXJhcmNoaWNhbD1rZywgS01lYW5zPWtnMikNCmBgYA0KX1doaWNoIEhpZXJhcmNoaWNhbCBDbHVzdGVyIGJlc3QgY29ycmVzcG9uZHMgdG8gSy1NZWFucyBDbHVzdGVyIDI/Xw0KDQorIDcNCisNCg0KX1doaWNoIEhpZXJhcmNoaWNhbCBDbHVzdGVyIGJlc3QgY29ycmVzcG9uZHMgdG8gSy1NZWFucyBDbHVzdGVyIDM/Xw0KDQorIDUNCisNCg0KX1doaWNoIEhpZXJhcmNoaWNhbCBDbHVzdGVyIGJlc3QgY29ycmVzcG9uZHMgdG8gSy1NZWFucyBDbHVzdGVyIDc/Xw0KDQorIE5vIEhpZXJhcmNoaWNhbCBDbHVzdGVyIGNvbnRhaW5zIGF0IGxlYXN0IGhhbGYgb2YgdGhlIHBvaW50cyBpbiBLLU1lYW5zIENsdXN0ZXIgNy4NCisgDQoNCl9XaGljaCBIaWVyYXJjaGljYWwgQ2x1c3RlciBiZXN0IGNvcnJlc3BvbmRzIHRvIEstTWVhbnMgQ2x1c3RlciA2P18NCg0KKyAyDQorIA0KDQoNCiMjIyMjIOOAkOiojuirluWVj+mhjOOAkQ0KDQrlrZfpoLvooajmmK/ku4DpurzvvJ/lroPnmoTos4fmlpnmoLzlvI/vvJ8NCg0KKyDmjqHnlKhCYWcgb2Ygd29yZOeahOW9ouW8j++8jOWFiOaVtOeQhuWHuuaJgOacieaWh+eroOS4reS9v+eUqOWIsOeahOaJgOacieWtl++8jOS9nOeCukNvbHVtbuOAgg0KKyDlnKjlrZfpoLvooajlsLHmmK/mr4/nr4fmlofnq6DkuK3mr4/kuIDlgIvlrZfnmoTmlbjph4/vvIzmlL7liLDmr4/lgItDb2x1bW7kuK3jgIINCg0K5L2/55So5a2X6aC76KGo5L2c6ZuG576k5YiG5p6Q5pmC77yM5Y2A6ZqU6K6K5pW45piv5LuA6bq877yfDQoNCisg5Zyo5YiG576k5pmC77yM5piv6YCP6YGO5Zau6Kme55qE6aC7546H5L6G5rG65a6a5LiN5ZCM55qE576k77yM5omA5Lul5oiR5YCR6KqN54K65piv5Zau6Kme55qE6aC7546H44CCDQorIA0KDQrlvp7mqLnni4DlnJbliKTmlrfnvqTmlbjlkozlvp7mh4nnlKjpnIDmsYLmsbrlrprnvqTmlbjmnInku4Dpurzlt67liKXvvJ8NCg0KKyDmqLnni4DlnJbliKTmlrfnvqTmqLnlj6/ku6Xmib7liLDnvqTplpPot53pm6LmnIDlpKfnmoTnvqTmlbjvvIzku6PooajmraTmmYLos4fmlpnljYDliIbnmoTmnIDpgaDkuZ/mnIDngrrnkIbmg7PjgILkvYbpgJnmspLmnInmmI7norrnmoTlkKvnvqko5q+P5LiA6aGe5piv5LuA6bq8KeOAguaIluioseeQhuaDs+e+pOaoueebuOeVtuWwkeaIluebuOeVtuWkmu+8jOmbo+S7peaHieeUqOOAgg0KKyDlvp7mh4nnlKjpnIDmsYLmsbrlrprvvIzlg4XnrqHos4fmlpnliIbluIPnmoTni4Dms4HmnKrlv4XmnIPliLDmnIDngrrnkIbmg7PvvIzkvYbmmK/lvp7mh4nnlKjpnaLkvobnnIvvvIzpgJnmqKPnmoTliIbnvqTmlbjph4/mmK/mnIDpganlkIjmi7/kvoblgZrpgLLkuIDmraXkvb/nlKjnmoTjgIINCg0KDQoNCjxicj4NCg0KLSAtIC0NCg0KPGJyPjxicj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogI2IzNmIwMDsNCiAgYmFja2dyb3VuZDogI2ZmZTBiMzsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmZmZmZTA7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KZW17DQogIGNvbG9yOiAjMDAwMGMwOw0KICBiYWNrZ3JvdW5kOiAjZjBmMGYwOw0KICB9DQoNCjwvc3R5bGU+DQoNCg==