Sys.setlocale("LC_ALL","C")
[1] "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 Grocery Frozen Detergents_Paper
Ch1:298 Reg1: 77 Min. :0.477 Min. :1.74 Min. :0.477 Min. :1.40 Min. :0.477
Ch2:142 Reg2: 47 1st Qu.:3.495 1st Qu.:3.19 1st Qu.:3.333 1st Qu.:2.87 1st Qu.:3.495
Reg3:316 Median :3.930 Median :3.56 Median :3.677 Median :3.18 Median :3.930
Mean :3.792 Mean :3.53 Mean :3.666 Mean :3.17 Mean :3.792
3rd Qu.:4.229 3rd Qu.:3.86 3rd Qu.:4.028 3rd Qu.:3.55 3rd Qu.:4.229
Max. :5.050 Max. :4.87 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
A2. 兩個區隔變數
hc = W[,3:4] %>% scale %>% dist %>% hclust #先標準化scale,將平均值、標準差=0
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
)

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:
sapply(split(M[,2:20], grp), colMeans) %>% round(3) #grp是群集之後的結果,是整數的向量
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
#round 取到小數點第幾位
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)

【問題討論】
從管理的角度來看,我們為甚麼要分群?
- 透過分群,方便我們針對個種不同的狀況,做最好的決策。
- 例如在行銷上,透過分群可以讓我們更了解顧客的消費、喜好,進而投其所好,做出對顧客最有利的策略。
我們為甚麼要做尺度縮減?
- 在機器學習分類問題中,通常有太多因素在最終分類的基礎上完成。 這些因素基本上是稱為特徵的變量。 功能數量越多,就越難以可視化訓練集然後對其進行處理。 有時,大多數這些功能是相關的,因此是多餘的。 這就是降維算法發揮作用的地方。 降維是通過獲得一組主要變量來減少所考慮的隨機變量數量的過程。 它可以分為特徵選擇和特徵提取。
- In machine learning classification problems, there are often too many factors on the basis of which the final classification is done. These factors are basically variables called features. The higher the number of features, the harder it gets to visualize the training set and then work on it. Sometimes, most of these features are correlated, and hence redundant. This is wherve dimensionality reduction algorithms come into play. Dimensionality reduction is the process of reducing the number of random variables under consideration, by obtaining a set of principal variables. It can be divided into feature selection and feature extraction.
我們要如何把集群分析的結果轉化為策略呢?
- 以產品面來說,將每一個集群的特徵做分析,進而知道目前趨勢與狀況為何,針對弱項進行改進,對於強項則持續加強,以降低失誤率、增加顧客對產品的滿意度、保持產品競爭力。
- 以顧客面來說,將每一個集群的特徵作分析,進而得知每一個群集顧客的消費型態,並針對其消費型態做出適合且有效的行銷方式,增加行銷成功率,也可以提高公司整體的競爭力與市場佔有率。
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) #切成2500個點
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")

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?
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 33.71 secs
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集群分析有什麼差異? 它們分別用在什麼狀況?
- 階層式集群是以階層架構的方式反覆進行分裂或聚合,以產生最後的樹狀架構,可從樹狀圖取得任何想要的集群數,缺點是只適合小量資料。
- k-means集群,分割式分群法,分群方式是先將原始事物分為k個群體,計算某一資料點到集群中心之距離(或相適度),將其分配到最接近的群體,重新計算增加及減少資料點的集群中心,重複計算直至各資料點不必重新分配至其他集群為止。
- 層級式集群常用在群數未知且適用在小樣本上,目的為想知道資料能夠被分成幾群。
- k-means集群常用於群數已知且適用於大數量樣本上,主要是想知道觀察個體會分到哪一群。
集群分析模型和普通的集群分析有什麼差異?
- 集群分析的目的則是將觀察個體分類,個體間的相似性或相異性,主要是用個體間的距離來判斷,若個體間的距離越大,表示相異性越大,換句話說相似性越小。
- 集群分析模型則是將集群分析形式化,讓使用者更好觀察集群變化。
- 集群分析與集群分析模型的差異就在於是否能做後續的預測。
什麼時候需要建集群分析模型? 集群分析模型的用法?
- 其主要用法就是將複雜的資料區分為較小部分,讓每部分更容易解釋與簡化。在行銷上時常用於市場區隔!
圖像處理和圖像辨識有什麼差異?
LS0tDQp0aXRsZTogIkFTNi0wIOmbhue+pOWIhuaekCINCmF1dGhvcjogIkdyb3VwIDIiIA0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KPGJyPg0KDQpgYGB7cn0NClN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsIkMiKQ0KcGFja2FnZXMgPSBjKA0KICAiZHBseXIiLCJnZ3Bsb3QyIiwiZDNoZWF0bWFwIiwiZ29vZ2xlVmlzIiwiZGV2dG9vbHMiLCJwbG90bHkiLCAieGdib29zdCIsDQogICJtYWdyaXR0ciIsImNhVG9vbHMiLCJST0NSIiwiY29ycnBsb3QiLCAicnBhcnQiLCAicnBhcnQucGxvdCIsDQogICJkb1BhcmFsbGVsIiwgImNhcmV0IiwgImdsbW5ldCIsICJNYXRyaXgiLCAiZTEwNzEiLCAicmFuZG9tRm9yZXN0IiwNCiAgImZsZXhjbHVzdCIsICJGYWN0b01pbmVSIiwgImZhY3RvZXh0cmEiDQogICkNCmV4aXN0aW5nID0gYXMuY2hhcmFjdGVyKGluc3RhbGxlZC5wYWNrYWdlcygpWywxXSkNCmZvcihwa2cgaW4gcGFja2FnZXNbIShwYWNrYWdlcyAlaW4lIGV4aXN0aW5nKV0pIGluc3RhbGwucGFja2FnZXMocGtnKQ0KYGBgDQoNCmBgYHtyIGVjaG89VCwgbWVzc2FnZT1GLCBjYWNoZT1GLCB3YXJuaW5nPUZ9DQpybShsaXN0PWxzKGFsbD1UKSkNCm9wdGlvbnMoZGlnaXRzPTQsIHNjaXBlbj0xMikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGZsZXhjbHVzdCkNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmBgYA0KDQotIC0gLQ0KDQojIyMgQS4g6ZuG576k5YiG5p6Q6IiH5bC65bqm57iu5ribDQoNCiMjIyMjIEExLiDmibnnmbzkuqTmmJPos4fmlpkNCmBgYHtyfQ0KVyA9IHJlYWQuY3N2KCdkYXRhL3dob2xlc2FsZXMuY3N2JykNClckQ2hhbm5lbCA9IGZhY3RvciggcGFzdGUwKCJDaCIsVyRDaGFubmVsKSApDQpXJFJlZ2lvbiA9IGZhY3RvciggcGFzdGUwKCJSZWciLFckUmVnaW9uKSApDQpXWzM6OF0gPSBsYXBwbHkoV1szOjZdLCBsb2csIGJhc2U9MTApDQpzdW1tYXJ5KFcpDQpgYGANCg0KIyMjIyMgQTIuIOWFqeWAi+WNgOmalOiuiuaVuA0KYGBge3J9DQpoYyA9IFdbLDM6NF0gJT4lIHNjYWxlICU+JSBkaXN0ICU+JSBoY2x1c3QgI+WFiOaomea6luWMlnNjYWxl77yM5bCH5bmz5Z2H5YC844CB5qiZ5rqW5beuPTANCnBsb3QoaGMpDQpyZWN0LmhjbHVzdChoYywgaz01LCBib3JkZXI9InJlZCIpDQpgYGANCg0KYGBge3J9DQpXJGdyb3VwID0gY3V0cmVlKGhjLCBrPTUpICU+JSBmYWN0b3INCmdncGxvdChXLCBhZXMoeD1GcmVzaCwgeT1NaWxrLCBjb2w9Z3JvdXApKSArDQogIGdlb21fcG9pbnQoc2l6ZT0zLCBhbHBoYT0wLjUpICsgDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KDQojIyMjIyBBMy4g5YWt5YCL5Y2A6ZqU6K6K5pW4DQpgYGB7cn0NCmhjID0gV1ssMzo3XSAlPiUgc2NhbGUgJT4lIGRpc3QgJT4lIGhjbHVzdA0KcGxvdChoYykNClckZ3JvdXAgPSBmYWN0b3IoY3V0cmVlKGhjLCBrPTgpKQ0KcmVjdC5oY2x1c3QoaGMsIGs9OCwgYm9yZGVyPSJyZWQiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KZnZpel9kZW5kKA0KICBoYywgaz04LCBzaG93X2xhYmVscz1GLCByZWN0PVQsIHJlY3RfZmlsbD1ULA0KICBsYWJlbHNfdHJhY2tfaGVpZ2h0PTAsDQogIHBhbGV0dGU9InVjc2NnYiIsIHJlY3RfYm9yZGVyPSJ1Y3NjZ2IiKQ0KYGBgDQoNCiMjIyMjIEE0LiDlsLrluqbnuK7muJsgDQpEaW1lbnNpb24gUmVkdWN0aW9uIHdpdGggUENBIChQcmluY2lwbGUgQ29tcG9uZW50IEFuYWx5c2lzLCDkuLvmiJDliIbliIbmnpApDQpgYGB7ciBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD05fQ0KV1ssMzo4XSAlPiUgUENBKGdyYXBoPUYpICU+JSBmdml6X3BjYV9iaXBsb3QoDQogIGxhYmVsPSJ2YXIiLCBjb2wuaW5kPVckZ3JvdXAsDQogIHBvaW50c2hhcGU9MTksIG1lYW4ucG9pbnQ9RiwNCiAgYWRkRWxsaXBzZXM9VCwgZWxsaXBzZS5sZXZlbD0wLjcsDQogIGVsbGlwc2UudHlwZSA9ICJjb252ZXgiLCBwYWxldHRlPSJ1Y3NjZ2IiLA0KICByZXBlbD1UDQogICkNCmBgYA0KPGJyPg0KDQotIC0gLQ0KDQojIyMgMS4gQ2x1c3RlciBBbmFseXNpcyBmb3IgTW92aWVzICANCg0KKirkuLvopoHorbDpoYzvvJrkvp3poZ7lnosoR2VucmUp5bCN6Zu75b2x5YiG6aGeKioNCg0KKirlrbjnv5Lph43pu57vvJoqKg0KDQorIOmbhue+pOWIhuaekOeahOWfuuacrOingOW/tQ0KKyDot53pm6Lnn6npmaPvvJpEaXN0YW5jZSBNYXRyaXgNCisg5bGk57Sa5byP6ZuG576k5YiG5p6Q77yaSGllcmFyY2hpY2FsIENsdXN0ZXIgQW5hbHlzaXMNCisg5qi554uA5ZyWKERlbmRyb2dyYW0p55qE5Yik6K6ADQorIOS+neaTmuaoueeLgOWcluaxuuWumuimgeWIhuWkmuWwkee+pA0KKyDku6XnvqTntYTlubPlnYflgLzmqqLoppblkITml4/nvqTnmoTlsazmgKcNCg0KPGJyPg0KDQojIyMjIyAxLjEg5pW055CG6LOH5paZDQpgYGB7cn0NCk0gPSByZWFkLnRhYmxlKCJkYXRhL21vdmllTGVucy50eHQiLCBoZWFkZXI9RkFMU0UsIHNlcD0ifCIscXVvdGU9IlwiIikNCg0KIyBBc3NpZ24gY29sdW1uIG5hbWVzDQpjb2xuYW1lcyhNKSA9IGMoDQogICJJRCIsICJUaXRsZSIsICJSZWxlYXNlRGF0ZSIsICJWaWRlb1JlbGVhc2VEYXRlIiwgIklNREIiLCANCiAgIlVua25vd24iLCAiQWN0aW9uIiwgIkFkdmVudHVyZSIsICJBbmltYXRpb24iLCAiQ2hpbGRyZW5zIiwgDQogICJDb21lZHkiLCAiQ3JpbWUiLCAiRG9jdW1lbnRhcnkiLCAiRHJhbWEiLCAiRmFudGFzeSIsICJGaWxtTm9pciIsIA0KICAiSG9ycm9yIiwgIk11c2ljYWwiLCAiTXlzdGVyeSIsICJSb21hbmNlIiwgIlNjaUZpIiwgIlRocmlsbGVyIiwNCiAgIldhciIsICJXZXN0ZXJuIikNCg0KIyBSZW1vdmUgdW5uZWNlc3NhcnkgdmFyaWFibGVzDQpNJElEID0gTlVMTA0KTSRSZWxlYXNlRGF0ZSA9IE5VTEwNCk0kVmlkZW9SZWxlYXNlRGF0ZSA9IE5VTEwNCk0kSU1EQiA9IE5VTEwNCg0KIyBSZW1vdmUgZHVwbGljYXRlcw0KTSA9IHVuaXF1ZShNKQ0KYGBgDQoNCiMjIyMjIDEuMiDmqqLoppbos4fmlpkNCmBgYHtyfQ0KaGVhZChNLCA1KQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtKE0kQ29tZWR5KSAgICAgICAgICAgICAjIOWWnOWKh+eJhw0Kc3VtKE0kV2VzdGVybikgICAgICAgICAgICAjIOilv+mDqOeJhw0Kc3VtKE0kUm9tYW5jZSB8IE0kRHJhbWEpICAjIOa1qua8q+WKh+aDheeJhw0KYGBgDQoNCiMjIyMjIDEuMyDot53pm6Lnn6npmaMNCmBgYHtyfQ0KZG14PSBkaXN0KE1bMjoyMF0sIG1ldGhvZD0iZXVjbGlkZWFuIikNCmRteCAlPiUgYXMubWF0cml4ICU+JSBkaW0NCmBgYA0KDQojIyMjIyAxLjQg5bGk57Sa5byP6ZuG576k5YiG5p6QDQpgYGB7cn0NCmhjbHVzdDEgPSBoY2x1c3QoZG14LCBtZXRob2QgPSAid2FyZC5EIikgDQpgYGANCg0KIyMjIyMgMS41IOaqouimluaoueeLgOWclg0KYGBge3J9DQpwbG90KGhjbHVzdDEpDQpyZWN0LmhjbHVzdChoY2x1c3QxLCBrPTUsIGJvcmRlcj0icmVkIikNCmBgYA0KDQojIyMjIyAxLjYg5YiH5Ymy576k57WEDQpgYGB7cn0NCmdycCA9IGN1dHJlZShoY2x1c3QxLCBrID0gNSkNCnRhYmxlKGdycCkNCmBgYA0KDQojIyMjIyAxLjcg5qqi5p+l576k57WE5bGs5oCnDQpgYGB7cn0NCnRhcHBseShNJEFjdGlvbiwgZ3JwLCBtZWFuKQ0KdGFwcGx5KE0kUm9tYW5jZSwgZ3JwLCBtZWFuKQ0KYGBgDQoNCiMjIyMjIDEuOCBUaGUgYHNhcHBseWAtYHNwbGl0YC1gLi4uYCBDb21ib++8mg0KYGBge3J9DQpzYXBwbHkoc3BsaXQoTVssMjoyMF0sIGdycCksIGNvbE1lYW5zKSAlPiUgcm91bmQoMykgI2dycOaYr+e+pOmbhuS5i+W+jOeahOe1kOaenO+8jOaYr+aVtOaVuOeahOWQkemHjw0KI3JvdW5kIOWPluWIsOWwj+aVuOm7nuesrOW5vuS9jQ0KYGBgDQoNCiMjIyMjIDEuOSDos4fmlpnoppboprrljJbvvIjnnIvmr4/kuIDnvqTnmoTlpKflsI/vvIkNCmBgYHtyfQ0KbGF5b3V0KG1hdHJpeChjKDEsMiwyKSwgMywgMSkpDQpwYXIobWFyPWMoMiwzLDEsMSksIGNleD0wLjgpDQp0YWJsZShncnApICU+JSBiYXJwbG90KGNvbD0zOjcsIG5hbWVzLmFyZz1wYXN0ZTAoIkdyb3VwLSIsMTo1KSkNCnBhcihtYXI9Yyg2LDMsMiwxKSkNCnNhcHBseShzcGxpdChNWywyOjIwXSwgZ3JwKSwgY29sTWVhbnMpICU+JSB0ICU+JSANCiAgYmFycGxvdChiZXNpZGU9VCwgY29sPTM6NywgbGFzPTIpDQoNCmBgYA0KDQojIyMjIyDjgJDllY/poYzoqI7oq5bjgJENCg0K5b6e566h55CG55qE6KeS5bqm5L6G55yL77yM5oiR5YCR54K655Sa6bq86KaB5YiG576k77yfIA0KDQorIOmAj+mBjuWIhue+pO+8jOaWueS+v+aIkeWAkemHneWwjeWAi+eoruS4jeWQjOeahOeLgOazge+8jOWBmuacgOWlveeahOaxuuetluOAgg0KKyDkvovlpoLlnKjooYzpirfkuIrvvIzpgI/pgY7liIbnvqTlj6/ku6XorpPmiJHlgJHmm7Tkuobop6PpoaflrqLnmoTmtojosrvjgIHllpzlpb3vvIzpgLLogIzmipXlhbbmiYDlpb3vvIzlgZrlh7rlsI3poaflrqLmnIDmnInliKnnmoTnrZbnlaXjgIINCg0KDQrmiJHlgJHngrrnlJrpurzopoHlgZrlsLrluqbnuK7muJvvvJ8gDQoNCisg5Zyo5qmf5Zmo5a2457+S5YiG6aGe5ZWP6aGM5Lit77yM6YCa5bi45pyJ5aSq5aSa5Zug57Sg5Zyo5pyA57WC5YiG6aGe55qE5Z+656SO5LiK5a6M5oiQ44CCIOmAmeS6m+WboOe0oOWfuuacrOS4iuaYr+eoseeCuueJueW+teeahOiuiumHj+OAgiDlip/og73mlbjph4/otorlpJrvvIzlsLHotorpm6Pku6Xlj6/oppbljJboqJPnt7Tpm4bnhLblvozlsI3lhbbpgLLooYzomZXnkIbjgIIg5pyJ5pmC77yM5aSn5aSa5pW46YCZ5Lqb5Yqf6IO95piv55u46Zec55qE77yM5Zug5q2k5piv5aSa6aSY55qE44CCIOmAmeWwseaYr+mZjee2reeul+azleeZvOaPruS9nOeUqOeahOWcsOaWueOAgiDpmY3ntq3mmK/pgJrpgY7njbLlvpfkuIDntYTkuLvopoHororph4/kvobmuJvlsJHmiYDogIPmha7nmoTpmqjmqZ/ororph4/mlbjph4/nmoTpgY7nqIvjgIIg5a6D5Y+v5Lul5YiG54K654m55b616YG45pOH5ZKM54m55b615o+Q5Y+W44CCDQorIEluIG1hY2hpbmUgbGVhcm5pbmcgY2xhc3NpZmljYXRpb24gcHJvYmxlbXMsIHRoZXJlIGFyZSBvZnRlbiB0b28gbWFueSBmYWN0b3JzIG9uIHRoZSBiYXNpcyBvZiB3aGljaCB0aGUgZmluYWwgY2xhc3NpZmljYXRpb24gaXMgZG9uZS4gVGhlc2UgZmFjdG9ycyBhcmUgYmFzaWNhbGx5IHZhcmlhYmxlcyBjYWxsZWQgZmVhdHVyZXMuIFRoZSBoaWdoZXIgdGhlIG51bWJlciBvZiBmZWF0dXJlcywgdGhlIGhhcmRlciBpdCBnZXRzIHRvIHZpc3VhbGl6ZSB0aGUgdHJhaW5pbmcgc2V0IGFuZCB0aGVuIHdvcmsgb24gaXQuIFNvbWV0aW1lcywgbW9zdCBvZiB0aGVzZSBmZWF0dXJlcyBhcmUgY29ycmVsYXRlZCwgYW5kIGhlbmNlIHJlZHVuZGFudC4gVGhpcyBpcyB3aGVydmUgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIGFsZ29yaXRobXMgY29tZSBpbnRvIHBsYXkuIERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBpcyB0aGUgcHJvY2VzcyBvZiByZWR1Y2luZyB0aGUgbnVtYmVyIG9mIHJhbmRvbSB2YXJpYWJsZXMgdW5kZXIgY29uc2lkZXJhdGlvbiwgYnkgb2J0YWluaW5nIGEgc2V0IG9mIHByaW5jaXBhbCB2YXJpYWJsZXMuIEl0IGNhbiBiZSBkaXZpZGVkIGludG8gZmVhdHVyZSBzZWxlY3Rpb24gYW5kIGZlYXR1cmUgZXh0cmFjdGlvbi4NCg0KDQrmiJHlgJHopoHlpoLkvZXmiorpm4bnvqTliIbmnpDnmoTntZDmnpzovYnljJbngrrnrZbnlaXlkaLvvJ8gDQoNCisg5Lul55Si5ZOB6Z2i5L6G6Kqq77yM5bCH5q+P5LiA5YCL6ZuG576k55qE54m55b615YGa5YiG5p6Q77yM6YCy6ICM55+l6YGT55uu5YmN6Lao5Yui6IiH54uA5rOB54K65L2V77yM6Yed5bCN5byx6aCF6YCy6KGM5pS56YCy77yM5bCN5pa85by36aCF5YmH5oyB57qM5Yqg5by377yM5Lul6ZmN5L2O5aSx6Kqk546H44CB5aKe5Yqg6aGn5a6i5bCN55Si5ZOB55qE5ru/5oSP5bqm44CB5L+d5oyB55Si5ZOB56u254it5Yqb44CCDQorIOS7pemhp+WuoumdouS+huiqqu+8jOWwh+avj+S4gOWAi+mbhue+pOeahOeJueW+teS9nOWIhuaekO+8jOmAsuiAjOW+l+efpeavj+S4gOWAi+e+pOmbhumhp+WuoueahOa2iOiyu+Wei+aFi++8jOS4pumHneWwjeWFtua2iOiyu+Wei+aFi+WBmuWHuumBqeWQiOS4lOacieaViOeahOihjOmKt+aWueW8j++8jOWinuWKoOihjOmKt+aIkOWKn+eOh++8jOS5n+WPr+S7peaPkOmrmOWFrOWPuOaVtOmrlOeahOertueIreWKm+iIh+W4guWgtOS9lOacieeOh+OAgg0KDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAyLiBGbG93ZXIgSW1hZ2UNCg0KIyMjIyMgMi4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQojIFJlYWQgZGF0YQ0KZmxvd2VyID0gcmVhZC5jc3YoImRhdGEvZmxvd2VyLmNzdiIsIGhlYWRlcj1GQUxTRSkNCg0KIyBDaGFuZ2UgdGhlIGRhdGEgdHlwZSB0byBtYXRyaXgNCmZsb3dlck1hdHJpeCA9IGFzLm1hdHJpeChmbG93ZXIpDQpkaW0oZmxvd2VyTWF0cml4KQ0KDQojIFR1cm4gbWF0cml4IGludG8gYSB2ZWN0b3INCmZsb3dlclZlY3RvciA9IGFzLnZlY3RvcihmbG93ZXJNYXRyaXgpDQpsZW5ndGgoZmxvd2VyVmVjdG9yKQ0KYGBgDQoNCiMjIyMjIDIuMiDot53pm6Lnn6npmaMNCmBgYHtyfQ0KIyBDb21wdXRlIGRpc3RhbmNlcw0KZGlzdGFuY2UgPSBkaXN0KGZsb3dlclZlY3RvciwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpgYGANCg0KIyMjIyMgMi4zIOWxpOe0muW8j+mbhue+pOWIhuaekA0KYGBge3J9DQojIEhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nDQpjbHVzdGVySW50ZW5zaXR5ID0gaGNsdXN0KGRpc3RhbmNlLCBtZXRob2Q9IndhcmQuRCIpDQpgYGANCg0KIyMjIyMgMi40IOaoueeLgOWclg0KYGBge3J9DQojIFBsb3QgdGhlIGRlbmRyb2dyYW0NCnBsb3QoY2x1c3RlckludGVuc2l0eSkNCiMgU2VsZWN0IDMgY2x1c3RlcnMNCnJlY3QuaGNsdXN0KGNsdXN0ZXJJbnRlbnNpdHksIGsgPSAzLCBib3JkZXIgPSAicmVkIikNCmBgYA0KDQojIyMjIyDliIflibLnvqTntYQNCmBgYHtyfQ0KZmxvd2VyQ2x1c3RlcnMgPSBjdXRyZWUoY2x1c3RlckludGVuc2l0eSwgayA9IDMpDQp0YWJsZShmbG93ZXJDbHVzdGVycykNCiMgZmxvd2VyQ2x1c3RlcnMNCmBgYA0KDQojIyMjIyDml4/nvqTlubPlnYco55Wr57Sg6aGP6Imy5rex5re65bqmKQ0KYGBge3J9DQojIEZpbmQgbWVhbiBpbnRlbnNpdHkgdmFsdWVzDQp0YXBwbHkoZmxvd2VyVmVjdG9yLCBmbG93ZXJDbHVzdGVycywgbWVhbikNCmBgYA0KDQojIyMjIyDlnJblg4/mr5TovIMNCmBgYHtyIGZpZy5oZWlnaHQ9My4yLCBmaWcud2lkdGg9Ni40fQ0KIyBQbG90IHRoZSBpbWFnZSBhbmQgdGhlIGNsdXN0ZXJzDQpkaW0oZmxvd2VyQ2x1c3RlcnMpID0gYyg1MCw1MCkgI+WIh+aIkDI1MDDlgIvpu54NCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDIsMiwyLDIpKQ0KDQojIE9yaWdpbmFsIGltYWdlDQppbWFnZShmbG93ZXJNYXRyaXgsYXhlcz1GQUxTRSxjb2w9Z3JleShzZXEoMCwxLGxlbmd0aD0yNTYpKSxtYWluPSJPcmlnaW5hbCIpDQoNCiMgTmV3IGltYWdlDQppbWFnZShmbG93ZXJDbHVzdGVycywgYXhlcyA9IEZBTFNFLCBtYWluPSIzIENsdXN0ZXIiKQ0KYGBgDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAzLiBNUkkgSW1hZ2UNCg0KIyMjIyMgMy4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQojIFJlYWQgZGF0YQ0KaGVhbHRoeSA9IHJlYWQuY3N2KCJkYXRhL2hlYWx0aHkuY3N2IiwgaGVhZGVyPUZBTFNFKQ0KaGVhbHRoeU1hdHJpeCA9IGFzLm1hdHJpeChoZWFsdGh5KQ0KZGltKGhlYWx0aHlNYXRyaXgpDQpgYGANCg0KIyMjIyMgMy4yIOeVq+WHuuWcluW9og0KYGBge3IgZmlnLndpZHRoPTIuODMsIGZpZy5oZWlnaHQ9My4yM30NCiMgUGxvdCBpbWFnZQ0KcGFyKG1hcj1jKDEsMSwxLDEpKQ0KaW1hZ2UoaGVhbHRoeU1hdHJpeCxheGVzPUZBTFNFLGNvbD1ncmV5KHNlcSgwLDEsbGVuZ3RoPTI1NikpKQ0KYGBgDQoNCiMjIyMjIDMuMyDot53pm6Lnn6npmaMNCmBgYHtyfQ0KIyBDb21wdXRlIGRpc3RhbmNlcw0KaGVhbHRoeVZlY3RvciA9IGFzLnZlY3RvcihoZWFsdGh5TWF0cml4KQ0KZGlzdGFuY2UgPSBkaXN0KGhlYWx0aHlWZWN0b3IsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNCioq44CQUeOAkSoqIFdoYXQgaXMgdGhlIHByb2JsZW0/DQoNCisg5ZCR6YeP6YGO5aSa44CB6YGO5aSn5bCO6Ie05YWn5a2Y6ICX55uh44CCDQoNCg0KIyMjIyMgMy40IEtNZWFuc+mbhue+pOWIhuaekA0KYGBge3J9DQojIFJ1biBrLW1lYW5zDQprID0gNQ0Kc2V0LnNlZWQoMSkNCktNQyA9IGttZWFucyhoZWFsdGh5VmVjdG9yLCBjZW50ZXJzID0gaywgaXRlci5tYXggPSAxMDAwKQ0KYGBgDQoNCiMjIyMjIDMuNSDmqqLmn6XliIbnvqTntZDmnpwNCmBgYHtyfQ0KIyBWaWV3KEtNQykNCnRhYmxlKEtNQyRjbHVzdGVyKQ0KS01DJGNlbnRlcnMNCmBgYA0KDQojIyMjIyAzLjYg55Wr5Ye65YiG576k57WQ5p6cDQpgYGB7ciBmaWcud2lkdGg9Mi44MywgZmlnLmhlaWdodD0zLjIzfQ0KIyBFeHRyYWN0IGNsdXN0ZXJzDQpYID0gS01DJGNsdXN0ZXINCg0KIyBQbG90IHRoZSBpbWFnZSB3aXRoIHRoZSBjbHVzdGVycw0KZGltKFgpID0gYyhucm93KGhlYWx0aHlNYXRyaXgpLCBuY29sKGhlYWx0aHlNYXRyaXgpKQ0KDQojIFBsb3QgaW1hZ2UNCnBhcihtYXI9YygxLDEsMSwxKSkNCmltYWdlKFgsIGF4ZXMgPSBGQUxTRSwgY29sPXJhaW5ib3coaykpDQpgYGANCg0KIyMjIyMgMy43IOiugOmAsuOAgei9ieaPm+a4rOippuWcluW9og0KYGBge3J9DQp0dW1vciA9IHJlYWQuY3N2KCJkYXRhL3R1bW9yLmNzdiIsIGhlYWRlcj1GQUxTRSkNCnR1bW9yTWF0cml4ID0gYXMubWF0cml4KHR1bW9yKQ0KZGltKHR1bW9yTWF0cml4KQ0KdHVtb3JWZWN0b3IgPSBhcy52ZWN0b3IodHVtb3JNYXRyaXgpDQpsZW5ndGgodHVtb3JWZWN0b3IpDQpgYGANCg0KIyMjIyMgMy44IOWwh+WOn+WcluW9ouS5i+WIhue+pOimj+WJh+Wll+eUqOWIsOa4rOippuWcluW9og0KYGBge3J9DQojIEFwcGx5IGNsdXN0ZXJzIGZyb20gYmVmb3JlIHRvIG5ldyBpbWFnZSwgdXNpbmcgdGhlIGZsZXhjbHVzdCBwYWNrYWdlDQpsaWJyYXJ5KGZsZXhjbHVzdCkNCnQwID0gU3lzLnRpbWUoKQ0KS01DLmtjY2EgPSBmbGV4Y2x1c3Q6OmFzLmtjY2EoS01DLCBoZWFsdGh5VmVjdG9yKSAgICAgICAgIyDlu7rnq4vmqKHlnosNCnR1bW9yQ2x1c3RlcnMgPSBwcmVkaWN0KEtNQy5rY2NhLCBuZXdkYXRhID0gdHVtb3JWZWN0b3IpICMg6YCy6KGM6aCQ5risKOi9ieaPmykNClN5cy50aW1lKCkgLSB0MA0KYGBgDQoNCiMjIyMjIDMuOSDlnJblg4/mr5TovIMNCmBgYHtyIGZpZy5oZWlnaHQ9My4yLCBmaWcud2lkdGg9Nn0NCiMgVmlzdWFsaXplIHRoZSBjbHVzdGVycw0KZGltKHR1bW9yQ2x1c3RlcnMpID0gYyhucm93KHR1bW9yTWF0cml4KSwgbmNvbCh0dW1vck1hdHJpeCkpDQoNCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDEsMSwyLDEpKQ0KaW1hZ2UoWCwgYXhlcyA9IEZBTFNFLCBjb2w9cmFpbmJvdyhrKSwgbWFpbj0iSGVhbHRoeSIpDQppbWFnZSh0KHR1bW9yQ2x1c3RlcnMpWyw1NzE6MV0sIGF4ZXMgPSBGQUxTRSwgY29sPXJhaW5ib3coayksIG1haW49IlR1bW9yIikNCmBgYA0KDQojIyMjIyDjgJDlrbjnv5Lph43pu57jgJENCg0KKyDpm4bnvqTliIbmnpDlnKjlnJblg4/omZXnkIbnmoTmh4nnlKgNCisg5Zau5Y2A6ZqU6K6K5pW455qE6ZuG576k5YiG5p6QDQorIOmbhue+pOWIhuaekOaooeWeiw0KIyMjIyMg44CQ5ZWP6aGM6KiO6KuW44CRDQoNCuWxpOe0muW8j+WSjEstTWVhbnPpm4bnvqTliIbmnpDmnInku4Dpurzlt67nlbDvvJ8g5a6D5YCR5YiG5Yil55So5Zyo5LuA6bq854uA5rOB77yfDQoNCisg6ZqO5bGk5byP6ZuG576k5piv5Lul6ZqO5bGk5p625qeL55qE5pa55byP5Y+N6KaG6YCy6KGM5YiG6KOC5oiW6IGa5ZCI77yM5Lul55Si55Sf5pyA5b6M55qE5qi554uA5p625qeL77yM5Y+v5b6e5qi554uA5ZyW5Y+W5b6X5Lu75L2V5oOz6KaB55qE6ZuG576k5pW477yM57y66bue5piv5Y+q6YGp5ZCI5bCP6YeP6LOH5paZ44CCDQorIGstbWVhbnPpm4bnvqTvvIzliIblibLlvI/liIbnvqTms5XvvIzliIbnvqTmlrnlvI/mmK/lhYjlsIfljp/lp4vkuovnianliIbngrpr5YCL576k6auU77yM6KiI566X5p+Q5LiA6LOH5paZ6bue5Yiw6ZuG576k5Lit5b+D5LmL6Led6Zui77yI5oiW55u46YGp5bqm77yJ77yM5bCH5YW25YiG6YWN5Yiw5pyA5o6l6L+R55qE576k6auU77yM6YeN5paw6KiI566X5aKe5Yqg5Y+K5rib5bCR6LOH5paZ6bue55qE6ZuG576k5Lit5b+D77yM6YeN6KSH6KiI566X55u06Iez5ZCE6LOH5paZ6bue5LiN5b+F6YeN5paw5YiG6YWN6Iez5YW25LuW6ZuG576k54K65q2i44CCDQorIOWxpOe0muW8j+mbhue+pOW4uOeUqOWcqOe+pOaVuOacquefpeS4lOmBqeeUqOWcqOWwj+aoo+acrOS4iu+8jOebrueahOeCuuaDs+efpemBk+izh+aWmeiDveWkoOiiq+WIhuaIkOW5vue+pOOAgg0KKyBrLW1lYW5z6ZuG576k5bi455So5pa8576k5pW45bey55+l5LiU6YGp55So5pa85aSn5pW46YeP5qij5pys5LiK77yM5Li76KaB5piv5oOz55+l6YGT6KeA5a+f5YCL6auU5pyD5YiG5Yiw5ZOq5LiA576k44CCDQoNCumbhue+pOWIhuaekOaooeWei+WSjOaZrumAmueahOmbhue+pOWIhuaekOacieS7gOm6vOW3rueVsO+8nyANCg0KKyDpm4bnvqTliIbmnpDnmoTnm67nmoTliYfmmK/lsIfop4Dlr5/lgIvpq5TliIbpoZ7vvIzlgIvpq5TplpPnmoTnm7jkvLzmgKfmiJbnm7jnlbDmgKfvvIzkuLvopoHmmK/nlKjlgIvpq5TplpPnmoTot53pm6LkvobliKTmlrfvvIzoi6XlgIvpq5TplpPnmoTot53pm6LotorlpKfvvIzooajnpLrnm7jnlbDmgKfotorlpKfvvIzmj5vlj6XoqbHoqqrnm7jkvLzmgKfotorlsI/jgIINCisg6ZuG576k5YiG5p6Q5qih5Z6L5YmH5piv5bCH6ZuG576k5YiG5p6Q5b2i5byP5YyW77yM6K6T5L2/55So6ICF5pu05aW96KeA5a+f6ZuG576k6K6K5YyW44CCDQorIOmbhue+pOWIhuaekOiIh+mbhue+pOWIhuaekOaooeWei+eahOW3rueVsOWwseWcqOaWvOaYr+WQpuiDveWBmuW+jOe6jOeahOmgkOa4rOOAgg0KDQrku4DpurzmmYLlgJnpnIDopoHlu7rpm4bnvqTliIbmnpDmqKHlnovvvJ8g6ZuG576k5YiG5p6Q5qih5Z6L55qE55So5rOV77yfDQoNCisg5YW25Li76KaB55So5rOV5bCx5piv5bCH6KSH6Zuc55qE6LOH5paZ5Y2A5YiG54K66LyD5bCP6YOo5YiG77yM6K6T5q+P6YOo5YiG5pu05a655piT6Kej6YeL6IiH57Ch5YyW44CC5Zyo6KGM6Yq35LiK5pmC5bi455So5pa85biC5aC05Y2A6ZqU77yBDQoNCuWcluWDj+iZleeQhuWSjOWcluWDj+i+qOitmOacieS7gOm6vOW3rueVsO+8nw0KDQorIOWcluWDj+iZleeQhueCuuWwh+WcluWDj+iZleeQhuaIkOaVuOaTmu+8jOagueaTmumcgOaxguWwjeaVuOaTmuWBmuiZleeQhu+8jOS/ruaUueWclueJh+mhj+iJsuOAgemVt+W6pu+8jOiuk+WIhuaekOiAheabtOWlvei+qOitmOOAgeWIhuaekOWcluW9ouOAgg0KDQorIOWcluWDj+i+qOitmOeCuuWwh+WclueJh+aUvumAsuW3sue2k+iok+e3tOmBjueahOaooeWei+S4re+8jOeUseaooeWei+mAsuihjOi+qOitmO+8jOS+i+WmguS6uuiHiei+qOitmOOAgg0KDQo8YnI+DQoNCi0gLSAtDQoNCjxicj48YnI+PGJyPjxicj48YnI+DQoNCjxzdHlsZT4NCi5jYXB0aW9uIHsNCiAgY29sb3I6ICM3Nzc7DQogIG1hcmdpbi10b3A6IDEwcHg7DQp9DQpwIGNvZGUgew0KICB3aGl0ZS1zcGFjZTogaW5oZXJpdDsNCn0NCnByZSB7DQogIHdvcmQtYnJlYWs6IG5vcm1hbDsNCiAgd29yZC13cmFwOiBub3JtYWw7DQogIGxpbmUtaGVpZ2h0OiAxOw0KfQ0KcHJlIGNvZGUgew0KICB3aGl0ZS1zcGFjZTogaW5oZXJpdDsNCn0NCnAsbGkgew0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KLnJ7DQogIGxpbmUtaGVpZ2h0OiAxLjI7DQp9DQoNCnRpdGxlew0KICBjb2xvcjogI2NjMDAwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmJvZHl7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpoMSxoMixoMyxoNCxoNXsNCiAgY29sb3I6ICMwMDg4MDA7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpoM3sNCiAgY29sb3I6ICNiMzZiMDA7DQogIGJhY2tncm91bmQ6ICNmZmUwYjM7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KaDV7DQogIGNvbG9yOiAjMDA2MDAwOw0KICBiYWNrZ3JvdW5kOiAjZmZmZmUwOw0KICBsaW5lLWhlaWdodDogMjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmVtew0KICBjb2xvcjogIzAwMDBjMDsNCiAgYmFja2dyb3VuZDogI2YwZjBmMDsNCiAgfQ0KPC9zdHlsZT4NCg0K