Sys.setlocale("LC_ALL","C")
packages = c(
"dplyr","ggplot2","d3heatmap","googleVis","devtools","plotly", "xgboost",
"magrittr","caTools","ROCR","corrplot", "rpart", "rpart.plot",
"doParallel", "caret", "glmnet", "Matrix", "e1071", "randomForest",
"flexclust", "FactoMineR", "factoextra"
)
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)
rm(list=ls(all=T))
options(digits=4, scipen=12)
library(dplyr)
library(ggplot2)
library(flexclust)
library(FactoMineR)
library(factoextra)
A. 集群分析與尺度縮減
A1. 批發交易資料
W = read.csv('data/wholesales.csv')
W$Channel = factor( paste0("Ch",W$Channel) )
W$Region = factor( paste0("Reg",W$Region) )
W[3:8] = lapply(W[3:6], log, base=10)
summary(W)
Channel Region Fresh Milk
Ch1:298 Reg1: 77 Min. :0.477 Min. :1.74
Ch2:142 Reg2: 47 1st Qu.:3.495 1st Qu.:3.19
Reg3:316 Median :3.930 Median :3.56
Mean :3.792 Mean :3.53
3rd Qu.:4.229 3rd Qu.:3.86
Max. :5.050 Max. :4.87
Grocery Frozen Detergents_Paper
Min. :0.477 Min. :1.40 Min. :0.477
1st Qu.:3.333 1st Qu.:2.87 1st Qu.:3.495
Median :3.677 Median :3.18 Median :3.930
Mean :3.666 Mean :3.17 Mean :3.792
3rd Qu.:4.028 3rd Qu.:3.55 3rd Qu.:4.229
Max. :4.967 Max. :4.78 Max. :5.050
Delicassen
Min. :1.74
1st Qu.:3.19
Median :3.56
Mean :3.53
3rd Qu.:3.86
Max. :4.87
A1.小組討論
學習使用apply系列操作資料,並且使用summary來看一下資料的平均值及四分位數
A2. 兩個區隔變數
hc = W[,3:4] %>% scale %>% dist %>% hclust
plot(hc)
rect.hclust(hc, k=5, border="red")

W$group = cutree(hc, k=5) %>% factor
ggplot(W, aes(x=Fresh, y=Milk, col=group)) +
geom_point(size=3, alpha=0.5) +
theme_light()

A3. 六個區隔變數
hc = W[,3:7] %>% scale %>% dist %>% hclust
plot(hc)
W$group = factor(cutree(hc, k=8))
rect.hclust(hc, k=8, border="red")

library(FactoMineR)
library(factoextra)
fviz_dend(
hc, k=8, show_labels=F, rect=T, rect_fill=T,
labels_track_height=0,
palette="ucscgb", rect_border="ucscgb")
A4. 尺度縮減
Dimension Reduction with PCA (Principle Component Analysis, 主成分分析)
W[,3:8] %>% PCA(graph=F) %>% fviz_pca_biplot(
label="var", col.ind=W$group,
pointshape=19, mean.point=F,
addEllipses=T, ellipse.level=0.7,
ellipse.type = "convex", palette="ucscgb",
repel=T
)
Warning messages:
1: In scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
EOF within quoted string
2: In scan(file = file, what = what, sep = sep, quote = quote, dec = dec, :
EOF within quoted string

小組討論A4.
- 在區隔變數很多的時候維度很大
- 超過3維以上的資料其實不好看
- 超過3維以上的資料學習使用PCA來分析
1. Cluster Analysis for Movies
主要議題:依類型(Genre)對電影分類
學習重點:
- 集群分析的基本觀念
- 距離矩陣:Distance Matrix
- 層級式集群分析:Hierarchical Cluster Analysis
- 樹狀圖(Dendrogram)的判讀
- 依據樹狀圖決定要分多少群
- 以群組平均值檢視各族群的屬性
1.1 整理資料
M = read.table("data/movieLens.txt", header=FALSE, sep="|",quote="\"")
# Assign column names
colnames(M) = c(
"ID", "Title", "ReleaseDate", "VideoReleaseDate", "IMDB",
"Unknown", "Action", "Adventure", "Animation", "Childrens",
"Comedy", "Crime", "Documentary", "Drama", "Fantasy", "FilmNoir",
"Horror", "Musical", "Mystery", "Romance", "SciFi", "Thriller",
"War", "Western")
# Remove unnecessary variables
M$ID = NULL
M$ReleaseDate = NULL
M$VideoReleaseDate = NULL
M$IMDB = NULL
# Remove duplicates
M = unique(M)
1.2 檢視資料
head(M, 5)
sum(M$Comedy) # 喜劇片
[1] 502
sum(M$Western) # 西部片
[1] 27
sum(M$Romance | M$Drama) # 浪漫劇情片
[1] 863
1.3 距離矩陣
dmx= dist(M[2:20], method="euclidean")
dmx %>% as.matrix %>% dim
[1] 1664 1664
1.4 層級式集群分析
hclust1 = hclust(dmx, method = "ward.D")
1.5 檢視樹狀圖
plot(hclust1)
rect.hclust(hclust1, k=5, border="red")

1.6 切割群組
grp = cutree(hclust1, k = 5)
table(grp)
grp
1 2 3 4 5
824 370 209 196 65
1.7 檢查群組屬性
tapply(M$Action, grp, mean)
1 2 3 4 5
0.28641 0.00000 0.00000 0.06633 0.00000
tapply(M$Romance, grp, mean)
1 2 3 4 5
0.05825 0.00000 0.00000 1.00000 0.00000
1.8 The sapply-split-... Combo:
#split(M[,2:20], grp):dataframe切成5個group
sapply(split(M[,2:20], grp), colMeans) %>% round(3)
1 2 3 4 5
Unknown 0.002 0 0 0.000 0
Action 0.286 0 0 0.066 0
Adventure 0.161 0 0 0.000 0
Animation 0.051 0 0 0.000 0
Childrens 0.146 0 0 0.000 0
Comedy 0.177 0 1 0.418 1
Crime 0.123 0 0 0.031 0
Documentary 0.061 0 0 0.000 0
Drama 0.238 1 0 0.434 1
Fantasy 0.027 0 0 0.000 0
FilmNoir 0.028 0 0 0.005 0
Horror 0.107 0 0 0.010 0
Musical 0.068 0 0 0.000 0
Mystery 0.073 0 0 0.000 0
Romance 0.058 0 0 1.000 0
SciFi 0.121 0 0 0.000 0
Thriller 0.279 0 0 0.092 0
War 0.086 0 0 0.000 0
Western 0.033 0 0 0.000 0
1.9 資料視覺化
layout(matrix(c(1,2,2), 3, 1))
par(mar=c(2,3,1,1), cex=0.8)
table(grp) %>% barplot(col=3:7, names.arg=paste0("Group-",1:5))
par(mar=c(6,3,2,1))
sapply(split(M[,2:20], grp), colMeans) %>% t %>%
barplot(beside=T, col=3:7, las=2)

【問題討論】
從管理的角度來看,我們為甚麼要分群?
我們為甚麼要做尺度縮減?
我們要如何把集群分析的結果轉化為策略呢?
- 首先我們要看我們分群後不同群有什麼不同的特色
- 例如我們今天分出來的一群可能是一些特別喜歡看恐怖片的顧客,那我們就可以推薦咒怨;如果今天分出來的一群是比較喜歡看愛情片的顧客,我們可以推薦鐵達尼號。
- 所以我們必須針對分出來的群去看他們有什麼特色,我們要投其所好,為他們量身打造一個策略。
小組討論1.Cluster Analysis for Movies
- 一個電影的種類有非常多,我們學習使用vector及boolean value來encode每個電影有哪些類別
- Encode的漂亮我們就可以用距離來衡量不同電影的相似情形
- Hierarchical分群完後使用tapply+mean來看群內的電影種類占比
- 使用sapply&split&combo來看不同群內電影種類占比
2. Flower Image
2.1 整理資料
# Read data
flower = read.csv("data/flower.csv", header=FALSE)
# Change the data type to matrix
flowerMatrix = as.matrix(flower)
dim(flowerMatrix)
[1] 50 50
# Turn matrix into a vector
flowerVector = as.vector(flowerMatrix)
length(flowerVector)
[1] 2500
2.2 距離矩陣
# Compute distances
distance = dist(flowerVector, method = "euclidean")
2.3 層級式集群分析
# Hierarchical clustering
clusterIntensity = hclust(distance, method="ward.D")
2.4 樹狀圖
# Plot the dendrogram
plot(clusterIntensity)
# Select 3 clusters
rect.hclust(clusterIntensity, k = 3, border = "red")

切割群組
flowerClusters = cutree(clusterIntensity, k = 3)
table(flowerClusters)
flowerClusters
1 2 3
1634 272 594
# flowerClusters
族群平均(畫素顏色深淺度)
# Find mean intensity values
tapply(flowerVector, flowerClusters, mean)
1 2 3
0.08574 0.50826 0.93148
圖像比較
# Plot the image and the clusters
dim(flowerClusters) = c(50,50)
par(mfrow=c(1,2), mar=c(2,2,2,2))
# Original image
image(flowerMatrix,axes=FALSE,col=grey(seq(0,1,length=256)),main="Original")
# New image
image(flowerClusters, axes = FALSE, main="3 Cluster")

小組討論 2. Flower Image
- 學習用分群技巧來做圖片處理
- 原來的圖片依照顏色暗淺來分成3群
3. MRI Image
3.1 整理資料
# Read data
healthy = read.csv("data/healthy.csv", header=FALSE)
healthyMatrix = as.matrix(healthy)
dim(healthyMatrix)
[1] 566 646
3.2 畫出圖形
# Plot image
par(mar=c(1,1,1,1))
image(healthyMatrix,axes=FALSE,col=grey(seq(0,1,length=256)))

3.3 距離矩陣
# Compute distances
healthyVector = as.vector(healthyMatrix)
distance = dist(healthyVector, method = "euclidean")
Error: cannot allocate vector of size 498.0 Gb
【Q】 What is the problem?
- Hierarchical用距離衡量相似度,需要計算n(n-1)/2=66844659430,占用極大的空間
- 所以當n很大時我們使用Kmeans
3.4 KMeans集群分析
# Run k-means
k = 5
set.seed(1)
KMC = kmeans(healthyVector, centers = k, iter.max = 1000)
3.5 檢查分群結果
# View(KMC)
table(KMC$cluster)
1 2 3 4 5
20556 101085 133162 31555 79278
KMC$centers
[,1]
1 0.48177
2 0.10619
3 0.01962
4 0.30943
5 0.18421
3.6 畫出分群結果
# Extract clusters
X = KMC$cluster
# Plot the image with the clusters
dim(X) = c(nrow(healthyMatrix), ncol(healthyMatrix))
# Plot image
par(mar=c(1,1,1,1))
image(X, axes = FALSE, col=rainbow(k))

3.7 讀進、轉換測試圖形
tumor = read.csv("data/tumor.csv", header=FALSE)
tumorMatrix = as.matrix(tumor)
dim(tumorMatrix)
[1] 571 512
tumorVector = as.vector(tumorMatrix)
length(tumorVector)
[1] 292352
3.8 將原圖形之分群規則套用到測試圖形
# Apply clusters from before to new image, using the flexclust package
library(flexclust)
t0 = Sys.time()
KMC.kcca = flexclust::as.kcca(KMC, healthyVector) # 建立模型
Found more than one class "kcca" in cache; using the first, from namespace 'kernlab'
Also defined by 'flexclust'
Found more than one class "kcca" in cache; using the first, from namespace 'kernlab'
Also defined by 'flexclust'
tumorClusters = predict(KMC.kcca, newdata = tumorVector) # 進行預測(轉換)
Found more than one class "kcca" in cache; using the first, from namespace 'kernlab'
Also defined by 'flexclust'
Sys.time() - t0
Time difference of 2.102 mins
3.9 圖像比較
# Visualize the clusters
dim(tumorClusters) = c(nrow(tumorMatrix), ncol(tumorMatrix))
par(mfrow=c(1,2), mar=c(1,1,2,1))
image(X, axes = FALSE, col=rainbow(k), main="Healthy")
image(t(tumorClusters)[,571:1], axes = FALSE, col=rainbow(k), main="Tumor")

【學習重點】
- 集群分析在圖像處理的應用
- 單區隔變數的集群分析
- 集群分析模型
【問題討論】
層級式和K-Means集群分析有什麼差異? 它們分別用在什麼狀況?
- 層級式不用事先指定群數,Kmeans要事先指定群數
- 層級式用距離分群,再依照情況看要分成幾群,Kmeans一開始隨機指定中心點,所以每次Kmeans結果可能都不同。
- 當資料小的時候我們用層級式,但是當資料大時層級式占用太大空間所以我們用Kmeans
|
kmeans
|
層級式
|
|
一開始必須先說要設幾群
|
把資料丟進去,直到長出樹才決定分多少群
|
|
適用於較大的資料
|
不適用於較大的資料
|
|
每次分群結果可能不同
|
距離不變的話樹狀圖不會變
|
集群分析模型和普通的集群分析有什麼差異?
- 普通集群分析在我們一開始對資料要分析什麼還不明確時,也因為沒有label可以做分類,屬於非監督式學習。我們可以先將資料做分群,待我們看到相似的資料被撿成一群時,可以看一下不同群有什麼不同特色,可能就會看到可以分析的內容了。
- 集群分析是在我們已經知道我們想分析什麼,所以我們將分群的規則提出來學習模型,這樣的好處在於套用此規則很快地便可以將資料依照我們想要分析的內容為資料分群,我們就去對相似資料做分析。這樣對於未知資料我們可以用這個規則快速的分群並且制定決策。
什麼時候需要建集群分析模型? 集群分析模型的用法?
- 如我們已經有想要利用分群來做圖片處理來找腫瘤,我們已經有這個分析的想法
- 我們就把Healthy的資料當成traing data拿去建立分群規則並且學習,之後有N張圖片我們便可以很快的利用此規則判別這N張照片是否有腫瘤。
- 簡單的說就是在我們找到我們想要分析的事情,並且有一套規則的時候,我們就可以建立集群分析模型。在我們還沒有想法時就做普通集群分析
圖像處理和圖像辨識有什麼差異?
小組總結
- 這單元學到如何使用非監督式學習分析資料,分群是一個很好的方法,將資料相似的分在一群,不相似的分在不同群,就可以看出不同群的特色,之後再近一步做分析。
- 我們拿到資料時學習用apply系列及summary來看資料分布
- 2種分群方式:階層式、Kmeans,各有不同的用途及使用時機
- 可以用距離來衡量資料的相似情形
- 我們希望群內距離小;群間距離大,如此可以區分資料,為不同族群制定決策
- 視覺化技巧
- 區隔變數多時使用尺度縮減
【Compare】
- - -
LS0tDQp0aXRsZTogIkFTNi0wIOmbhue+pOWIhuaekCINCmF1dGhvcjogIkdyb3VwMSwgMjAxOC8wNy8zMCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCisgPGEgaHJlZj0nI0ExJz5BMeWwj+e1hOiojuirljwvYT4NCisgPGEgaHJlZj0nI0EyJz5BMuWwj+e1hOiojuirljwvYT4NCisgPGEgaHJlZj0nI0E0Jz5BNOWwj+e1hOiojuirljwvYT4NCisgPGEgaHJlZj0nI0QxJz7lsI/ntYToqI7oq5YxLkNsdXN0ZXIgQW5hbHlzaXMgZm9yIE1vdmllczwvYT4NCisgPGEgaHJlZj0nI0QyJz7lsI/ntYToqI7oq5YyLkZsb3dlciBJbWFnZTwvYT4NCisgPGEgaHJlZj0nI0NMJz7lsI/ntYTnuL3ntZA8L2E+DQorIDxhIGhyZWY9JyNjb21wYXJlX2ltZyc+R3JvdXAx5pyA5by36YeN6bue5pW055CGPC9hPg0KDQo8YnI+DQoNCmBgYHtyfQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwiQyIpDQpwYWNrYWdlcyA9IGMoDQogICJkcGx5ciIsImdncGxvdDIiLCJkM2hlYXRtYXAiLCJnb29nbGVWaXMiLCJkZXZ0b29scyIsInBsb3RseSIsICJ4Z2Jvb3N0IiwNCiAgIm1hZ3JpdHRyIiwiY2FUb29scyIsIlJPQ1IiLCJjb3JycGxvdCIsICJycGFydCIsICJycGFydC5wbG90IiwNCiAgImRvUGFyYWxsZWwiLCAiY2FyZXQiLCAiZ2xtbmV0IiwgIk1hdHJpeCIsICJlMTA3MSIsICJyYW5kb21Gb3Jlc3QiLA0KICAiZmxleGNsdXN0IiwgIkZhY3RvTWluZVIiLCAiZmFjdG9leHRyYSINCiAgKQ0KZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQ0KZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpDQpgYGANCg0KYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0NCnJtKGxpc3Q9bHMoYWxsPVQpKQ0Kb3B0aW9ucyhkaWdpdHM9NCwgc2NpcGVuPTEyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZmxleGNsdXN0KQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KYGBgDQoNCi0gLSAtDQoNCiMjIyBBLiDpm4bnvqTliIbmnpDoiIflsLrluqbnuK7muJsNCg0KIyMjIyMgQTEuIOaJueeZvOS6pOaYk+izh+aWmQ0KYGBge3J9DQpXID0gcmVhZC5jc3YoJ2RhdGEvd2hvbGVzYWxlcy5jc3YnKQ0KVyRDaGFubmVsID0gZmFjdG9yKCBwYXN0ZTAoIkNoIixXJENoYW5uZWwpICkNClckUmVnaW9uID0gZmFjdG9yKCBwYXN0ZTAoIlJlZyIsVyRSZWdpb24pICkNCldbMzo4XSA9IGxhcHBseShXWzM6Nl0sIGxvZywgYmFzZT0xMCkNCnN1bW1hcnkoVykNCmBgYA0KIyMjIyMjICA8c3BhbiBpZD0nQTEnPkExLuWwj+e1hOiojuirljwvc3Bhbj4NCuWtuOe/kuS9v+eUqGFwcGx557O75YiX5pON5L2c6LOH5paZ77yM5Lim5LiU5L2/55Soc3VtbWFyeeS+hueci+S4gOS4i+izh+aWmeeahOW5s+Wdh+WAvOWPiuWbm+WIhuS9jeaVuA0KDQoNCiMjIyMjIEEyLiDlhanlgIvljYDpmpTorormlbgNCmBgYHtyfQ0KaGMgPSBXWywzOjRdICU+JSBzY2FsZSAlPiUgZGlzdCAlPiUgaGNsdXN0DQpwbG90KGhjKQ0KcmVjdC5oY2x1c3QoaGMsIGs9NSwgYm9yZGVyPSJyZWQiKQ0KYGBgDQoNCmBgYHtyfQ0KVyRncm91cCA9IGN1dHJlZShoYywgaz01KSAlPiUgZmFjdG9yDQpnZ3Bsb3QoVywgYWVzKHg9RnJlc2gsIHk9TWlsaywgY29sPWdyb3VwKSkgKw0KICBnZW9tX3BvaW50KHNpemU9MywgYWxwaGE9MC41KSArIA0KICB0aGVtZV9saWdodCgpDQpgYGANCiMjIyMjIyA8c3BhbiBpZD0nQTInPkEyLuWwj+e1hOiojuirljwvc3Bhbj4NCisg5oiR5YCR5bCN5pa86LOH5paZ5bCa5pyq5pyJ5oOz6KaB5YiG5p6Q55qE5YWn5a655oiW6ICF6LOH5paZ5rKS5pyJbGFiZWznmoTmmYLlgJnvvIzlj6/ku6Xkvp3nhafos4fmlpnkuYvplpPnmoTnm7jkvLznqIvluqblsIfos4fmlpnpgLLooYzliIbnvqTvvIzlsazmlrzpnZ7nm6PnnaPlvI/lrbjnv5INCg0KKyDlrbjnv5Lkvb/nlKhIaWVyYXJjaGljYWzliIbnvqTvvIzlnKjliIbnvqTnmoTmmYLlgJnkuI3nlKjlhYjmjIflrprnvqTmlbjjgIINCisgMS7kvb/nlKjot53pm6LooaHph4/os4fmlpnnm7jkvLzluqYgPGJyPjIu5YqD5Ye65YiG576k57WQ5p6c5LmL5b6M6YG45pOH5LiN5ZCM55qE576k5pW455yL5LiA5LiL57WQ5p6cIDxicj4zLkhlaWdodOeCuuizh+aWmeS4reW/g+m7nuiHs+WFtuS7lue+pOeahOi3nembou+8jOaIkeWAkeW4jOacm+e+pOmWk+i3nembouaEiOWkp+aEiOWlve+8jOaJgOS7peWPr+S7peeUqEhlaWdodOipleS8sOWIhue+pOeahOeLgOazge+8jEhlaWdodOaEiOWkp+aEiOiDvei3n+WFtuS7lue+pOWNgOWIhuWHuuS+huOAgg0KKyDlrbjnv5Lkvb/nlKjoppboprrljJbmioDlt6fnlavlh7ros4fmlpnpu57liIbnvqTnmoTmqKPosozvvIzpoY/oibLlj6/ku6Xkvp3nhadncm91cOWNgOWIhuOAgg0KDQoNCiMjIyMjIEEzLiDlha3lgIvljYDpmpTorormlbgNCmBgYHtyfQ0KaGMgPSBXWywzOjddICU+JSBzY2FsZSAlPiUgZGlzdCAlPiUgaGNsdXN0DQpwbG90KGhjKQ0KVyRncm91cCA9IGZhY3RvcihjdXRyZWUoaGMsIGs9OCkpDQpyZWN0LmhjbHVzdChoYywgaz04LCBib3JkZXI9InJlZCIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KEZhY3RvTWluZVIpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2RlbmQoDQogIGhjLCBrPTgsIHNob3dfbGFiZWxzPUYsIHJlY3Q9VCwgcmVjdF9maWxsPVQsDQogIGxhYmVsc190cmFja19oZWlnaHQ9MCwNCiAgcGFsZXR0ZT0idWNzY2diIiwgcmVjdF9ib3JkZXI9InVjc2NnYiIpDQpgYGANCg0KIyMjIyMgQTQuIOWwuuW6pue4rua4myANCkRpbWVuc2lvbiBSZWR1Y3Rpb24gd2l0aCBQQ0EgKFByaW5jaXBsZSBDb21wb25lbnQgQW5hbHlzaXMsIOS4u+aIkOWIhuWIhuaekCkNCg0KYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OX0NCldbLDM6OF0gJT4lIFBDQShncmFwaD1GKSAlPiUgZnZpel9wY2FfYmlwbG90KA0KICBsYWJlbD0idmFyIiwgY29sLmluZD1XJGdyb3VwLA0KICBwb2ludHNoYXBlPTE5LCBtZWFuLnBvaW50PUYsDQogIGFkZEVsbGlwc2VzPVQsIGVsbGlwc2UubGV2ZWw9MC43LA0KICBlbGxpcHNlLnR5cGUgPSAiY29udmV4IiwgcGFsZXR0ZT0idWNzY2diIiwNCiAgcmVwZWw9VA0KICApDQpgYGANCjxicj4NCg0KDQojIyMjIyMgPHNwYW4gaWQ9J0E0Jz7lsI/ntYToqI7oq5ZBNC48L3NwYW4+DQorIOWcqOWNgOmalOiuiuaVuOW+iOWkmueahOaZguWAmee2reW6puW+iOWkpw0KKyDotoXpgY4z57at5Lul5LiK55qE6LOH5paZ5YW25a+m5LiN5aW955yLDQorIOi2hemBjjPntq3ku6XkuIrnmoTos4fmlpnlrbjnv5Lkvb/nlKhQQ0HkvobliIbmnpANCg0KDQotIC0gLQ0KDQojIyMgMS4gQ2x1c3RlciBBbmFseXNpcyBmb3IgTW92aWVzICANCg0KKirkuLvopoHorbDpoYzvvJrkvp3poZ7lnosoR2VucmUp5bCN6Zu75b2x5YiG6aGeKioNCg0KKirlrbjnv5Lph43pu57vvJoqKg0KDQorIOmbhue+pOWIhuaekOeahOWfuuacrOingOW/tQ0KKyDot53pm6Lnn6npmaPvvJpEaXN0YW5jZSBNYXRyaXgNCisg5bGk57Sa5byP6ZuG576k5YiG5p6Q77yaSGllcmFyY2hpY2FsIENsdXN0ZXIgQW5hbHlzaXMNCisg5qi554uA5ZyWKERlbmRyb2dyYW0p55qE5Yik6K6ADQorIOS+neaTmuaoueeLgOWcluaxuuWumuimgeWIhuWkmuWwkee+pA0KKyDku6XnvqTntYTlubPlnYflgLzmqqLoppblkITml4/nvqTnmoTlsazmgKcNCg0KPGJyPg0KDQojIyMjIyAxLjEg5pW055CG6LOH5paZDQpgYGB7cn0NCk0gPSByZWFkLnRhYmxlKCJkYXRhL21vdmllTGVucy50eHQiLCBoZWFkZXI9RkFMU0UsIHNlcD0ifCIscXVvdGU9IlwiIikNCg0KIyBBc3NpZ24gY29sdW1uIG5hbWVzDQpjb2xuYW1lcyhNKSA9IGMoDQogICJJRCIsICJUaXRsZSIsICJSZWxlYXNlRGF0ZSIsICJWaWRlb1JlbGVhc2VEYXRlIiwgIklNREIiLCANCiAgIlVua25vd24iLCAiQWN0aW9uIiwgIkFkdmVudHVyZSIsICJBbmltYXRpb24iLCAiQ2hpbGRyZW5zIiwgDQogICJDb21lZHkiLCAiQ3JpbWUiLCAiRG9jdW1lbnRhcnkiLCAiRHJhbWEiLCAiRmFudGFzeSIsICJGaWxtTm9pciIsIA0KICAiSG9ycm9yIiwgIk11c2ljYWwiLCAiTXlzdGVyeSIsICJSb21hbmNlIiwgIlNjaUZpIiwgIlRocmlsbGVyIiwNCiAgIldhciIsICJXZXN0ZXJuIikNCg0KIyBSZW1vdmUgdW5uZWNlc3NhcnkgdmFyaWFibGVzDQpNJElEID0gTlVMTA0KTSRSZWxlYXNlRGF0ZSA9IE5VTEwNCk0kVmlkZW9SZWxlYXNlRGF0ZSA9IE5VTEwNCk0kSU1EQiA9IE5VTEwNCg0KIyBSZW1vdmUgZHVwbGljYXRlcw0KTSA9IHVuaXF1ZShNKQ0KYGBgDQoNCiMjIyMjIDEuMiDmqqLoppbos4fmlpkNCmBgYHtyfQ0KaGVhZChNLCA1KQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtKE0kQ29tZWR5KSAgICAgICAgICAgICAjIOWWnOWKh+eJhw0Kc3VtKE0kV2VzdGVybikgICAgICAgICAgICAjIOilv+mDqOeJhw0Kc3VtKE0kUm9tYW5jZSB8IE0kRHJhbWEpICAjIOa1qua8q+WKh+aDheeJhw0KYGBgDQoNCiMjIyMjIDEuMyDot53pm6Lnn6npmaMNCmBgYHtyfQ0KDQpkbXg9IGRpc3QoTVsyOjIwXSwgbWV0aG9kPSJldWNsaWRlYW4iKQ0KZG14ICU+JSBhcy5tYXRyaXggJT4lIGRpbQ0KYGBgDQoNCiMjIyMjIDEuNCDlsaTntJrlvI/pm4bnvqTliIbmnpANCmBgYHtyfQ0KaGNsdXN0MSA9IGhjbHVzdChkbXgsIG1ldGhvZCA9ICJ3YXJkLkQiKSANCmBgYA0KDQojIyMjIyAxLjUg5qqi6KaW5qi554uA5ZyWDQpgYGB7cn0NCnBsb3QoaGNsdXN0MSkNCnJlY3QuaGNsdXN0KGhjbHVzdDEsIGs9NSwgYm9yZGVyPSJyZWQiKQ0KYGBgDQoNCiMjIyMjIDEuNiDliIflibLnvqTntYQNCmBgYHtyfQ0KZ3JwID0gY3V0cmVlKGhjbHVzdDEsIGsgPSA1KQ0KdGFibGUoZ3JwKQ0KYGBgDQoNCiMjIyMjIDEuNyDmqqLmn6XnvqTntYTlsazmgKcNCmBgYHtyfQ0KdGFwcGx5KE0kQWN0aW9uLCBncnAsIG1lYW4pDQp0YXBwbHkoTSRSb21hbmNlLCBncnAsIG1lYW4pDQpgYGANCg0KIyMjIyMgMS44IFRoZSBgc2FwcGx5YC1gc3BsaXRgLWAuLi5gIENvbWJv77yaDQpgYGB7cn0NCiNzcGxpdChNWywyOjIwXSwgZ3JwKTpkYXRhZnJhbWXliIfmiJA15YCLZ3JvdXANCg0Kc2FwcGx5KHNwbGl0KE1bLDI6MjBdLCBncnApLCBjb2xNZWFucykgJT4lIHJvdW5kKDMpDQpgYGANCg0KIyMjIyMgMS45IOizh+aWmeimluimuuWMlg0KYGBge3J9DQpsYXlvdXQobWF0cml4KGMoMSwyLDIpLCAzLCAxKSkNCnBhcihtYXI9YygyLDMsMSwxKSwgY2V4PTAuOCkNCnRhYmxlKGdycCkgJT4lIGJhcnBsb3QoY29sPTM6NywgbmFtZXMuYXJnPXBhc3RlMCgiR3JvdXAtIiwxOjUpKQ0KcGFyKG1hcj1jKDYsMywyLDEpKQ0Kc2FwcGx5KHNwbGl0KE1bLDI6MjBdLCBncnApLCBjb2xNZWFucykgJT4lIHQgJT4lIA0KICBiYXJwbG90KGJlc2lkZT1ULCBjb2w9Mzo3LCBsYXM9MikNCg0KYGBgDQoNCiMjIyMjIOOAkOWVj+mhjOiojuirluOAkQ0KDQrlvp7nrqHnkIbnmoTop5LluqbkvobnnIvvvIzmiJHlgJHngrrnlJrpurzopoHliIbnvqTvvJ8gDQoNCisg566h55CG5a245Zyo5a2457+S5aaC5L2V5pyJ5pWI546H55qE566h55CG57WE57mU77yM6YCP6YGO57WE57mU6YGL55So5ZCE56iu5Lq65Yqb44CB6LOH5rqQ77yM5Zug5q2k5oiR5YCR5b+F6aCI6ICD6YeP5Yiw5LiN5ZCM57WE57mU6ZaT55qE5beu55Ww5oCn44CCDQorIOWIhue+pOWPr+S7peW5q+WKqeaIkeWAkeWwh+ebuOS8vOeahOizh+aWmeWIhuWcqOS4gOi1t++8jOmChOWPr+S7peWNgOWIhuavlOi8g+S4jeWQjOeahOizh+aWmQ0KDQorIOaJgOS7peS+i+WmguaIkeWAkeS7iuWkqeaDs+imgeaKiuebuOS8vOeahOS6uuWIhuWcqOWQjOS4gOWAi+e1hOe5lO+8jOaKiuS4jeWQjOeahOS6uuWIhuWcqOS4jeWQjOeahOe1hOe5lO+8jOaIkeWAkeWPr+S7peS9v+eUqOWIhue+pOacieaViOeahOWNgOWIhuS4lOeuoeeQhuS4jeWQjOeahOe1hOe5lO+8jOS4puS4lOWwjeS4jeWQjOeahOe1hOe5lOWItuioguS4jeWQjOeahOaxuuetluOAguWmguatpOacg+S9v+axuuetluabtOeCuuaYjueiuuS4lOaciemHneWwjeaAp+eahOeCuueJueWumueahOe1hOe5lOWItuWumueJueWumueahOaWueahiO+8jOacg+S9v+aViOeOh+Wkp+eCuuaPkOWNh+OAgg0KDQoNCuaIkeWAkeeCuueUmum6vOimgeWBmuWwuuW6pue4rua4m++8nyANCg0KKyAg5Zug54K6M+e2reS7peS4iueahOizh+aWmeS4puS4jemBqeWQiOS6uumhnuWIhuaekOiIh+eAj+imve+8jOS9huePvuWvpuS4reeahOizh+aWmeW+gOW+gOacieW+iOWkmueahOe2reW6pg0KKyAg5bC65bqm57iu5rib5oqK5aSa57at5bqm5omT5ZyoMue2reS4iu+8jOaIkeWAkeWWnOatoeecizLntq3vvIzmr5TovIPmuIXmpZrkuZ/mr5TovIPlrrnmmJPnnIvlh7rmg7PopoHliIbmnpDnmoTlhaflrrkNCg0KKyAg5omA5Lul55W257at5bqm6LaF6YGOM+e2reS7peS4iueahOizh+aWmeaIkeWAkeWPr+S7peWtuOe/kuWmguS9lemBi+eUqOWwuuW6pue4rua4m+S+huW5q+WKqeaIkeWAkeWIhuaekOizh+aWmQ0KDQoNCuaIkeWAkeimgeWmguS9leaKiumbhue+pOWIhuaekOeahOe1kOaenOi9ieWMlueCuuetlueVpeWRou+8nyANCg0KKyAg6aaW5YWI5oiR5YCR6KaB55yL5oiR5YCR5YiG576k5b6M5LiN5ZCM576k5pyJ5LuA6bq85LiN5ZCM55qE54m56ImyDQorICDkvovlpoLmiJHlgJHku4rlpKnliIblh7rkvobnmoTkuIDnvqTlj6/og73mmK/kuIDkupvnibnliKXllpzmraHnnIvmgZDmgJbniYfnmoTpoaflrqLvvIzpgqPmiJHlgJHlsLHlj6/ku6XmjqjolqblkpLmgKg75aaC5p6c5LuK5aSp5YiG5Ye65L6G55qE5LiA576k5piv5q+U6LyD5Zac5q2h55yL5oSb5oOF54mH55qE6aGn5a6i77yM5oiR5YCR5Y+v5Lul5o6o6Jam6ZC16YGU5bC86Jmf44CCDQorICDmiYDku6XmiJHlgJHlv4XpoIjph53lsI3liIblh7rkvobnmoTnvqTljrvnnIvku5blgJHmnInku4DpurznibnoibLvvIzmiJHlgJHopoHmipXlhbbmiYDlpb3vvIzngrrku5blgJHph4/ouqvmiZPpgKDkuIDlgIvnrZbnlaXjgIINCg0KPGJyPg0KDQojIyMjIyMgIDxzcGFuIGlkPSdEMSc+5bCP57WE6KiO6KuWMS5DbHVzdGVyIEFuYWx5c2lzIGZvciBNb3ZpZXM8L3NwYW4+DQorIOS4gOWAi+mbu+W9seeahOeorumhnuaciemdnuW4uOWkmu+8jOaIkeWAkeWtuOe/kuS9v+eUqHZlY3RvcuWPimJvb2xlYW4gdmFsdWXkvoZlbmNvZGXmr4/lgIvpm7vlvbHmnInlk6rkupvpoZ7liKUNCisgRW5jb2Rl55qE5ryC5Lqu5oiR5YCR5bCx5Y+v5Lul55So6Led6Zui5L6G6KGh6YeP5LiN5ZCM6Zu75b2x55qE55u45Ly85oOF5b2iDQorIEhpZXJhcmNoaWNhbOWIhue+pOWujOW+jOS9v+eUqHRhcHBseSttZWFu5L6G55yL576k5YWn55qE6Zu75b2x56iu6aGe5Y2g5q+UDQorIOS9v+eUqHNhcHBseSZzcGxpdCZjb21ib+S+hueci+S4jeWQjOe+pOWFp+mbu+W9seeorumhnuWNoOavlA0KDQotIC0gLQ0KDQojIyMgMi4gRmxvd2VyIEltYWdlDQoNCiMjIyMjIDIuMSDmlbTnkIbos4fmlpkNCmBgYHtyfQ0KIyBSZWFkIGRhdGENCmZsb3dlciA9IHJlYWQuY3N2KCJkYXRhL2Zsb3dlci5jc3YiLCBoZWFkZXI9RkFMU0UpDQoNCiMgQ2hhbmdlIHRoZSBkYXRhIHR5cGUgdG8gbWF0cml4DQpmbG93ZXJNYXRyaXggPSBhcy5tYXRyaXgoZmxvd2VyKQ0KZGltKGZsb3dlck1hdHJpeCkNCg0KIyBUdXJuIG1hdHJpeCBpbnRvIGEgdmVjdG9yDQpmbG93ZXJWZWN0b3IgPSBhcy52ZWN0b3IoZmxvd2VyTWF0cml4KQ0KbGVuZ3RoKGZsb3dlclZlY3RvcikNCmBgYA0KDQojIyMjIyAyLjIg6Led6Zui55+p6ZmjDQpgYGB7cn0NCiMgQ29tcHV0ZSBkaXN0YW5jZXMNCmRpc3RhbmNlID0gZGlzdChmbG93ZXJWZWN0b3IsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNCiMjIyMjIDIuMyDlsaTntJrlvI/pm4bnvqTliIbmnpANCmBgYHtyfQ0KIyBIaWVyYXJjaGljYWwgY2x1c3RlcmluZw0KY2x1c3RlckludGVuc2l0eSA9IGhjbHVzdChkaXN0YW5jZSwgbWV0aG9kPSJ3YXJkLkQiKQ0KYGBgDQoNCiMjIyMjIDIuNCDmqLnni4DlnJYNCmBgYHtyfQ0KIyBQbG90IHRoZSBkZW5kcm9ncmFtDQpwbG90KGNsdXN0ZXJJbnRlbnNpdHkpDQojIFNlbGVjdCAzIGNsdXN0ZXJzDQpyZWN0LmhjbHVzdChjbHVzdGVySW50ZW5zaXR5LCBrID0gMywgYm9yZGVyID0gInJlZCIpDQpgYGANCg0KIyMjIyMg5YiH5Ymy576k57WEDQpgYGB7cn0NCmZsb3dlckNsdXN0ZXJzID0gY3V0cmVlKGNsdXN0ZXJJbnRlbnNpdHksIGsgPSAzKQ0KdGFibGUoZmxvd2VyQ2x1c3RlcnMpDQojIGZsb3dlckNsdXN0ZXJzDQpgYGANCg0KIyMjIyMg5peP576k5bmz5Z2HKOeVq+e0oOmhj+iJsua3sea3uuW6pikNCmBgYHtyfQ0KIyBGaW5kIG1lYW4gaW50ZW5zaXR5IHZhbHVlcw0KdGFwcGx5KGZsb3dlclZlY3RvciwgZmxvd2VyQ2x1c3RlcnMsIG1lYW4pDQpgYGANCg0KIyMjIyMg5ZyW5YOP5q+U6LyDDQpgYGB7ciBmaWcuaGVpZ2h0PTMuMiwgZmlnLndpZHRoPTYuNH0NCiMgUGxvdCB0aGUgaW1hZ2UgYW5kIHRoZSBjbHVzdGVycw0KZGltKGZsb3dlckNsdXN0ZXJzKSA9IGMoNTAsNTApDQpwYXIobWZyb3c9YygxLDIpLCBtYXI9YygyLDIsMiwyKSkNCg0KIyBPcmlnaW5hbCBpbWFnZQ0KaW1hZ2UoZmxvd2VyTWF0cml4LGF4ZXM9RkFMU0UsY29sPWdyZXkoc2VxKDAsMSxsZW5ndGg9MjU2KSksbWFpbj0iT3JpZ2luYWwiKQ0KDQojIE5ldyBpbWFnZQ0KaW1hZ2UoZmxvd2VyQ2x1c3RlcnMsIGF4ZXMgPSBGQUxTRSwgbWFpbj0iMyBDbHVzdGVyIikNCmBgYA0KPGJyPg0KDQoNCiMjIyMjIyA8c3BhbiBpZD0nRDInPuWwj+e1hOiojuirliAyLiBGbG93ZXIgSW1hZ2U8L3NwYW4+DQorIOWtuOe/kueUqOWIhue+pOaKgOW3p+S+huWBmuWclueJh+iZleeQhg0KKyDljp/kvobnmoTlnJbniYfkvp3nhafpoY/oibLmmpfmt7rkvobliIbmiJAz576kDQoNCi0gLSAtDQoNCiMjIyAzLiBNUkkgSW1hZ2UNCg0KIyMjIyMgMy4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQojIFJlYWQgZGF0YQ0KaGVhbHRoeSA9IHJlYWQuY3N2KCJkYXRhL2hlYWx0aHkuY3N2IiwgaGVhZGVyPUZBTFNFKQ0KaGVhbHRoeU1hdHJpeCA9IGFzLm1hdHJpeChoZWFsdGh5KQ0KZGltKGhlYWx0aHlNYXRyaXgpDQpgYGANCg0KIyMjIyMgMy4yIOeVq+WHuuWcluW9og0KYGBge3IgZmlnLndpZHRoPTIuODMsIGZpZy5oZWlnaHQ9My4yM30NCiMgUGxvdCBpbWFnZQ0KcGFyKG1hcj1jKDEsMSwxLDEpKQ0KaW1hZ2UoaGVhbHRoeU1hdHJpeCxheGVzPUZBTFNFLGNvbD1ncmV5KHNlcSgwLDEsbGVuZ3RoPTI1NikpKQ0KYGBgDQoNCiMjIyMjIDMuMyDot53pm6Lnn6npmaMNCmBgYHtyfQ0KIyBDb21wdXRlIGRpc3RhbmNlcw0KaGVhbHRoeVZlY3RvciA9IGFzLnZlY3RvcihoZWFsdGh5TWF0cml4KQ0KZGlzdGFuY2UgPSBkaXN0KGhlYWx0aHlWZWN0b3IsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNCioq44CQUeOAkSoqIFdoYXQgaXMgdGhlIHByb2JsZW0/DQoNCisgIEhpZXJhcmNoaWNhbOeUqOi3nembouihoemHj+ebuOS8vOW6pu+8jOmcgOimgeioiOeul24obi0xKS8yPTY2ODQ0NjU5NDMw77yM5Y2g55So5qW15aSn55qE56m66ZaTDQorICDmiYDku6XnlbZu5b6I5aSn5pmC5oiR5YCR5L2/55SoS21lYW5zDQoNCg0KIyMjIyMgMy40IEtNZWFuc+mbhue+pOWIhuaekA0KYGBge3J9DQojIFJ1biBrLW1lYW5zDQprID0gNQ0Kc2V0LnNlZWQoMSkNCktNQyA9IGttZWFucyhoZWFsdGh5VmVjdG9yLCBjZW50ZXJzID0gaywgaXRlci5tYXggPSAxMDAwKQ0KYGBgDQoNCiMjIyMjIDMuNSDmqqLmn6XliIbnvqTntZDmnpwNCmBgYHtyfQ0KIyBWaWV3KEtNQykNCnRhYmxlKEtNQyRjbHVzdGVyKQ0KS01DJGNlbnRlcnMNCmBgYA0KDQojIyMjIyAzLjYg55Wr5Ye65YiG576k57WQ5p6cDQpgYGB7ciBmaWcud2lkdGg9Mi44MywgZmlnLmhlaWdodD0zLjIzfQ0KIyBFeHRyYWN0IGNsdXN0ZXJzDQpYID0gS01DJGNsdXN0ZXINCg0KIyBQbG90IHRoZSBpbWFnZSB3aXRoIHRoZSBjbHVzdGVycw0KZGltKFgpID0gYyhucm93KGhlYWx0aHlNYXRyaXgpLCBuY29sKGhlYWx0aHlNYXRyaXgpKQ0KDQojIFBsb3QgaW1hZ2UNCnBhcihtYXI9YygxLDEsMSwxKSkNCmltYWdlKFgsIGF4ZXMgPSBGQUxTRSwgY29sPXJhaW5ib3coaykpDQpgYGANCg0KIyMjIyMgMy43IOiugOmAsuOAgei9ieaPm+a4rOippuWcluW9og0KYGBge3J9DQp0dW1vciA9IHJlYWQuY3N2KCJkYXRhL3R1bW9yLmNzdiIsIGhlYWRlcj1GQUxTRSkNCnR1bW9yTWF0cml4ID0gYXMubWF0cml4KHR1bW9yKQ0KZGltKHR1bW9yTWF0cml4KQ0KdHVtb3JWZWN0b3IgPSBhcy52ZWN0b3IodHVtb3JNYXRyaXgpDQpsZW5ndGgodHVtb3JWZWN0b3IpDQpgYGANCg0KIyMjIyMgMy44IOWwh+WOn+WcluW9ouS5i+WIhue+pOimj+WJh+Wll+eUqOWIsOa4rOippuWcluW9og0KYGBge3J9DQojIEFwcGx5IGNsdXN0ZXJzIGZyb20gYmVmb3JlIHRvIG5ldyBpbWFnZSwgdXNpbmcgdGhlIGZsZXhjbHVzdCBwYWNrYWdlDQpsaWJyYXJ5KGZsZXhjbHVzdCkNCnQwID0gU3lzLnRpbWUoKQ0KS01DLmtjY2EgPSBmbGV4Y2x1c3Q6OmFzLmtjY2EoS01DLCBoZWFsdGh5VmVjdG9yKSAgICAgICAgIyDlu7rnq4vmqKHlnosNCnR1bW9yQ2x1c3RlcnMgPSBwcmVkaWN0KEtNQy5rY2NhLCBuZXdkYXRhID0gdHVtb3JWZWN0b3IpICMg6YCy6KGM6aCQ5risKOi9ieaPmykNClN5cy50aW1lKCkgLSB0MA0KYGBgDQoNCiMjIyMjIDMuOSDlnJblg4/mr5TovIMNCmBgYHtyIGZpZy5oZWlnaHQ9My4yLCBmaWcud2lkdGg9Nn0NCiMgVmlzdWFsaXplIHRoZSBjbHVzdGVycw0KZGltKHR1bW9yQ2x1c3RlcnMpID0gYyhucm93KHR1bW9yTWF0cml4KSwgbmNvbCh0dW1vck1hdHJpeCkpDQoNCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDEsMSwyLDEpKQ0KaW1hZ2UoWCwgYXhlcyA9IEZBTFNFLCBjb2w9cmFpbmJvdyhrKSwgbWFpbj0iSGVhbHRoeSIpDQppbWFnZSh0KHR1bW9yQ2x1c3RlcnMpWyw1NzE6MV0sIGF4ZXMgPSBGQUxTRSwgY29sPXJhaW5ib3coayksIG1haW49IlR1bW9yIikNCmBgYA0KDQojIyMjIyDjgJDlrbjnv5Lph43pu57jgJENCg0KKyDpm4bnvqTliIbmnpDlnKjlnJblg4/omZXnkIbnmoTmh4nnlKgNCisg5Zau5Y2A6ZqU6K6K5pW455qE6ZuG576k5YiG5p6QDQorIOmbhue+pOWIhuaekOaooeWeiw0KDQojIyMjIyDjgJDllY/poYzoqI7oq5bjgJENCg0K5bGk57Sa5byP5ZKMSy1NZWFuc+mbhue+pOWIhuaekOacieS7gOm6vOW3rueVsO+8nyDlroPlgJHliIbliKXnlKjlnKjku4Dpurzni4Dms4HvvJ8NCg0KKyDlsaTntJrlvI/kuI3nlKjkuovlhYjmjIflrprnvqTmlbjvvIxLbWVhbnPopoHkuovlhYjmjIflrprnvqTmlbgNCisg5bGk57Sa5byP55So6Led6Zui5YiG576k77yM5YaN5L6d54Wn5oOF5rOB55yL6KaB5YiG5oiQ5bm+576k77yMS21lYW5z5LiA6ZaL5aeL6Zqo5qmf5oyH5a6a5Lit5b+D6bue77yM5omA5Lul5q+P5qyhS21lYW5z57WQ5p6c5Y+v6IO96YO95LiN5ZCM44CCDQorIOeVtuizh+aWmeWwj+eahOaZguWAmeaIkeWAkeeUqOWxpOe0muW8j++8jOS9huaYr+eVtuizh+aWmeWkp+aZguWxpOe0muW8j+WNoOeUqOWkquWkp+epuumWk+aJgOS7peaIkeWAkeeUqEttZWFucw0KDQo8dGFibGUgd2lkdGg9IjQ1MCIgLGJvcmRlcj0iMSI+DQo8dGJvZHk+PHRyPg0KPHRkPg0Ka21lYW5zDQo8L3RkPg0KPHRkPg0K5bGk57Sa5byPDQo8L3RkPg0KPC90cj4NCjx0cj4NCjx0ZD4NCuS4gOmWi+Wni+W/hemgiOWFiOiqquimgeioreW5vue+pA0KPC90ZD4NCjx0ZD4NCuaKiuizh+aWmeS4n+mAsuWOu++8jOebtOWIsOmVt+WHuuaoueaJjeaxuuWumuWIhuWkmuWwkee+pA0KPC90ZD4NCjwvdHI+DQo8dHI+DQo8dGQ+DQrpgannlKjmlrzovIPlpKfnmoTos4fmlpkNCjwvdGQ+DQo8dGQ+DQrkuI3pgannlKjmlrzovIPlpKfnmoTos4fmlpkNCjwvdGQ+DQo8L3RyPg0KPHRyPg0KPHRkPg0K5q+P5qyh5YiG576k57WQ5p6c5Y+v6IO95LiN5ZCMDQo8L3RkPg0KPHRkPg0K6Led6Zui5LiN6K6K55qE6Kmx5qi554uA5ZyW5LiN5pyD6K6KDQo8L3RkPg0KPC90cj4NCjwvdGJvZHk+PC90YWJsZT4NCg0KDQoNCumbhue+pOWIhuaekOaooeWei+WSjOaZrumAmueahOmbhue+pOWIhuaekOacieS7gOm6vOW3rueVsO+8nyANCg0KKyAg5pmu6YCa6ZuG576k5YiG5p6Q5Zyo5oiR5YCR5LiA6ZaL5aeL5bCN6LOH5paZ6KaB5YiG5p6Q5LuA6bq86YKE5LiN5piO56K65pmC77yM5Lmf5Zug54K65rKS5pyJbGFiZWzlj6/ku6XlgZrliIbpoZ7vvIzlsazmlrzpnZ7nm6PnnaPlvI/lrbjnv5LjgILmiJHlgJHlj6/ku6XlhYjlsIfos4fmlpnlgZrliIbnvqTvvIzlvoXmiJHlgJHnnIvliLDnm7jkvLznmoTos4fmlpnooqvmkr/miJDkuIDnvqTmmYLvvIzlj6/ku6XnnIvkuIDkuIvkuI3lkIznvqTmnInku4DpurzkuI3lkIznibnoibLvvIzlj6/og73lsLHmnIPnnIvliLDlj6/ku6XliIbmnpDnmoTlhaflrrnkuobjgIINCisgIOmbhue+pOWIhuaekOaYr+WcqOaIkeWAkeW3sue2k+efpemBk+aIkeWAkeaDs+WIhuaekOS7gOm6vO+8jOaJgOS7peaIkeWAkeWwh+WIhue+pOeahOimj+WJh+aPkOWHuuS+huWtuOe/kuaooeWei++8jOmAmeaoo+eahOWlveiZleWcqOaWvOWll+eUqOatpOimj+WJh+W+iOW/q+WcsOS+v+WPr+S7peWwh+izh+aWmeS+neeFp+aIkeWAkeaDs+imgeWIhuaekOeahOWFp+WuueeCuuizh+aWmeWIhue+pO+8jOaIkeWAkeWwseWOu+WwjeebuOS8vOizh+aWmeWBmuWIhuaekOOAgumAmeaoo+WwjeaWvOacquefpeizh+aWmeaIkeWAkeWPr+S7peeUqOmAmeWAi+imj+WJh+W/q+mAn+eahOWIhue+pOS4puS4lOWItuWumuaxuuetluOAgg0KDQrku4DpurzmmYLlgJnpnIDopoHlu7rpm4bnvqTliIbmnpDmqKHlnovvvJ8g6ZuG576k5YiG5p6Q5qih5Z6L55qE55So5rOV77yfDQoNCisg5aaC5oiR5YCR5bey57aT5pyJ5oOz6KaB5Yip55So5YiG576k5L6G5YGa5ZyW54mH6JmV55CG5L6G5om+6IWr55ik77yM5oiR5YCR5bey57aT5pyJ6YCZ5YCL5YiG5p6Q55qE5oOz5rOVDQorIOaIkeWAkeWwseaKikhlYWx0aHnnmoTos4fmlpnnlbbmiJB0cmFpbmcgZGF0YeaLv+WOu+W7uueri+WIhue+pOimj+WJh+S4puS4lOWtuOe/ku+8jOS5i+W+jOaciU7lvLXlnJbniYfmiJHlgJHkvr/lj6/ku6Xlvojlv6vnmoTliKnnlKjmraTopo/liYfliKTliKXpgJlO5by154Wn54mH5piv5ZCm5pyJ6IWr55ik44CCDQorIOewoeWWrueahOiqquWwseaYr+WcqOaIkeWAkeaJvuWIsOaIkeWAkeaDs+imgeWIhuaekOeahOS6i+aDhe+8jOS4puS4lOacieS4gOWll+imj+WJh+eahOaZguWAme+8jOaIkeWAkeWwseWPr+S7peW7uueri+mbhue+pOWIhuaekOaooeWei+OAguWcqOaIkeWAkemChOaykuacieaDs+azleaZguWwseWBmuaZrumAmumbhue+pOWIhuaekA0KDQrlnJblg4/omZXnkIblkozlnJblg4/ovqjorZjmnInku4Dpurzlt67nlbDvvJ8NCg0KKyDlnJblg4/omZXnkIY65bCN5ZyW5YOP5oqK6aGP6Imy5L6d54Wn5rex5re65YiG576k77yM55So5LiN5ZCM55qE6aGP6Imy5L6G5L2/5ZyW54mH5ZGI54++5Ye65LiN5ZCM55qE5qij6LKM44CCDQoNCisg5ZyW5YOP6L6o6K2YOuiuk+apn+WZqOWwjeWcluWDj+mAsuihjOWIhuaekOOAgeiZleeQhuWSjOWtuOe/ku+8jOS9v+apn+WZqOWPr+S7pei+qOitmOWHuuS4jeWQjOWcluWDj+S5i+mWk+eahOW3rueVsOOAguWPr+S7peaNleaNieWclueJh+eahOi8quW7k+OAgee3muaineOAgeiJsua+pOetieetieeVtuaIkOWxrOaAp++8jOe1puapn+WZqOWtuOe/kuW+jOmAsuihjOi+qOitmOOAgg0KDQo8YnI+DQoNCg0KIyMjIyMjIDxzcGFuIGlkPSdDTCc+5bCP57WE57i957WQPC9zcGFuPg0KKyDpgJnllq7lhYPlrbjliLDlpoLkvZXkvb/nlKjpnZ7nm6PnnaPlvI/lrbjnv5LliIbmnpDos4fmlpnvvIzliIbnvqTmmK/kuIDlgIvlvojlpb3nmoTmlrnms5XvvIzlsIfos4fmlpnnm7jkvLznmoTliIblnKjkuIDnvqTvvIzkuI3nm7jkvLznmoTliIblnKjkuI3lkIznvqTvvIzlsLHlj6/ku6XnnIvlh7rkuI3lkIznvqTnmoTnibnoibLvvIzkuYvlvozlho3ov5HkuIDmraXlgZrliIbmnpDjgIINCisg5oiR5YCR5ou/5Yiw6LOH5paZ5pmC5a2457+S55SoYXBwbHnns7vliJflj4pzdW1tYXJ55L6G55yL6LOH5paZ5YiG5biDDQorIDLnqK7liIbnvqTmlrnlvI866ZqO5bGk5byP44CBS21lYW5z77yM5ZCE5pyJ5LiN5ZCM55qE55So6YCU5Y+K5L2/55So5pmC5qmfDQorIOWPr+S7peeUqOi3nembouS+huihoemHj+izh+aWmeeahOebuOS8vOaDheW9og0KKyDmiJHlgJHluIzmnJvnvqTlhafot53pm6LlsI87576k6ZaT6Led6Zui5aSn77yM5aaC5q2k5Y+v5Lul5Y2A5YiG6LOH5paZ77yM54K65LiN5ZCM5peP576k5Yi25a6a5rG6562WDQorIOimluimuuWMluaKgOW3pw0KKyDljYDpmpTorormlbjlpJrmmYLkvb/nlKjlsLrluqbnuK7muJsNCg0KDQoNCiMjIyMjIOOAkENvbXBhcmXjgJENCg0KPGltZyBpZD0nY29tcGFyZV9pbWcnIHNyYz0nZGF0YS9jb21wYXJlLmpwZyc+DQotIC0gLQ0KDQo8YnI+PGJyPjxicj48YnI+PGJyPg0KDQo8c3R5bGU+DQouY2FwdGlvbiB7DQogIGNvbG9yOiAjNzc3Ow0KICBtYXJnaW4tdG9wOiAxMHB4Ow0KfQ0KcCBjb2RlIHsNCiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7DQp9DQpwcmUgew0KICB3b3JkLWJyZWFrOiBub3JtYWw7DQogIHdvcmQtd3JhcDogbm9ybWFsOw0KICBsaW5lLWhlaWdodDogMTsNCn0NCnByZSBjb2RlIHsNCiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7DQp9DQpwLGxpIHsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCi5yew0KICBsaW5lLWhlaWdodDogMS4yOw0KfQ0KDQp0aXRsZXsNCiAgY29sb3I6ICNjYzAwMDA7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpib2R5ew0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KaDEsaDIsaDMsaDQsaDV7DQogIGNvbG9yOiAjMDA4ODAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KaDN7DQogIGNvbG9yOiAjYjM2YjAwOw0KICBiYWNrZ3JvdW5kOiAjZmZlMGIzOw0KICBsaW5lLWhlaWdodDogMjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmg1ew0KICBjb2xvcjogIzAwNjAwMDsNCiAgYmFja2dyb3VuZDogI2ZmZmZlMDsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KaDZ7DQogIGNvbG9yOiAjMDA2MDAwOw0KICBiYWNrZ3JvdW5kOiAjMDBmZmZmOw0KICBsaW5lLWhlaWdodDogMjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQoNCn0NCmVtew0KICBjb2xvcjogIzAwMDBjMDsNCiAgYmFja2dyb3VuZDogI2YwZjBmMDsNCiAgfQ0KICANCnRhYmxlLCB0aCwgdGQgew0KICAgIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOw0KfQ0KPC9zdHlsZT4NCg0K