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)
package 'flexclust' was built under R version 3.4.4Loading required package: grid
Loading required package: modeltools
Loading required package: stats4

Attaching package: 'modeltools'

The following object is masked from 'package:igraph':

    clusters
library(FactoMineR)
package 'FactoMineR' was built under R version 3.4.4
library(factoextra)
package 'factoextra' was built under R version 3.4.4Welcome! Related Books: `Practical Guide To Cluster Analysis in R` at https://goo.gl/13EFCZ

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
plot(hc)
rect.hclust(hc, k=5, border="red")

  • 在做集群分析前,先將所有的區隔變數標準化,(使用scale函數),可以讓每個欄位平均值=0,標準差=1,使得在計算距離時不會受差值較大的區隔變數埋沒其他較小的變數。
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)對電影分類

學習重點:


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)
                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)

【問題討論】

從管理的角度來看,我們為甚麼要分群?

  • 集群分析還可以看出某群的一些特性,讓在預測模型之前可以先看出一些端倪。
  • 一般來說,將公司面對的客群做適當分群,可以在不同分群做出不同的商業決策。

我們為甚麼要做尺度縮減?

  • 可以將許多不同的區隔變數縮減至一個平面,較容易解讀不同分群跟區隔變數的關係。
  • 屬性太多的話,在做cluster計算資料點間的距離時,計算會太複雜
  • 我們要以資訊量損失最少的角度去做尺度縮減。

我們要如何把集群分析的結果轉化為策略呢?

  • 利用集群分析的結果看出不同分群的特性,並針對特性來做出相對策略的回應。
  • 還是要搭配決策者的背景知識去做最適當的策略。



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")



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?

  • 因為矩陣為566*646的大小,若要計算兩點距離來做集群分析,會有太多資料量,而R會負荷不了。
  • N=566*646
  • Dist的資料數=N(N-1)/2
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 將原圖形之分群規則套用到測試圖形
KMC.kcca = flexclust::as.kcca(KMC, healthyVector)        # 建立模型
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集群分析有什麼差異? 它們分別用在什麼狀況?

  • 層級式(hierarchical)可分為聚合式或分裂式
    • 聚合式是先將每個資料都視為一個cluster,計算cluster間的距離後,找出距離最近的兩者聚合成一個cluster,直到cluster數量符合設定。(由下往上)
    • 分列式則是先將整個資料視為一整個cluster(由上往下)
  • 群間距離有多種計算方法(min.max.average-linkage…)
  • 在使用上,利用點和點的距離做分群,不用先指定分K群
  • 可以做出dendrogram看出群與群之間的距離並做最恰當的切割
  • 通常適用於資料較少的情況,資料量過大R會不進行運算。
  • 可以利用參數設定,將noise排除

  • K-Means集群分析
  • 先指定分為K群,並隨機將資料點指派至某一群,將每一群的中心點計算出來,重新將資料點再分配到最近的中心點,不斷將這個過程重複直到沒有進展為止
  • 通常資料量過大時,會使用kmean來做集群分析 +但同筆資料分別使用層級式和kmean的結果並不會一致
  • 容易受noise影響(因為每個點一定都要屬於一個群)

集群分析模型和普通的集群分析有什麼差異?

  • 集群分析是將現有資料做分群,可以看出不同群的特性;
  • 但集群分析模型是將這個分群方法建立模型後,可以把額外新的資料投入模型,以同樣的演算法來把新的資料分群。 (利用原先的分群結果放在一個模型,在為第二個資料做分群。)

什麼時候需要建集群分析模型? 集群分析模型的用法?

  • 若需要比較變化兩種些微不同資料,利用模型可以將原本相同的部分得到一樣的結果,進而看出差異。

圖像處理和圖像辨識有什麼差異?

  • 圖像處理是將原有數值的資料型態,依照集群分析將各數值分類,並依照分群的結果及圖像應有的長寬呈現圖像,呈現方式可依參數設定灰階抑或是彩色。
  • 圖像辨識來自於不同數值下所分群的差異,在呈現時會因結果差異而有不同色階,透過這樣的方式可以判別一些特定的圖像,或是時間序列下不同的資料所呈現的圖像可做比較。
  • 通常要先做圖像處理才能進一步圖像辨識。








LS0tDQp0aXRsZTogIkFTNi0wIEdyb3VwNCAg6ZuG576k5YiG5p6QIg0KYXV0aG9yOiAi546L5qyjIE0wNjQxMTEwMzkiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8YnI+DQoNCmBgYHtyfQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwiQyIpDQpwYWNrYWdlcyA9IGMoDQogICJkcGx5ciIsImdncGxvdDIiLCJkM2hlYXRtYXAiLCJnb29nbGVWaXMiLCJkZXZ0b29scyIsInBsb3RseSIsICJ4Z2Jvb3N0IiwNCiAgIm1hZ3JpdHRyIiwiY2FUb29scyIsIlJPQ1IiLCJjb3JycGxvdCIsICJycGFydCIsICJycGFydC5wbG90IiwNCiAgImRvUGFyYWxsZWwiLCAiY2FyZXQiLCAiZ2xtbmV0IiwgIk1hdHJpeCIsICJlMTA3MSIsICJyYW5kb21Gb3Jlc3QiLA0KICAiZmxleGNsdXN0IiwgIkZhY3RvTWluZVIiLCAiZmFjdG9leHRyYSINCiAgKQ0KZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQ0KZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpDQpgYGANCg0KYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0NCnJtKGxpc3Q9bHMoYWxsPVQpKQ0Kb3B0aW9ucyhkaWdpdHM9NCwgc2NpcGVuPTEyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZmxleGNsdXN0KQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KYGBgDQoNCi0gLSAtDQoNCiMjIyBBLiDpm4bnvqTliIbmnpDoiIflsLrluqbnuK7muJsNCg0KIyMjIyMgQTEuIOaJueeZvOS6pOaYk+izh+aWmQ0KYGBge3J9DQpXID0gcmVhZC5jc3YoJ2RhdGEvd2hvbGVzYWxlcy5jc3YnKQ0KVyRDaGFubmVsID0gZmFjdG9yKCBwYXN0ZTAoIkNoIixXJENoYW5uZWwpICkNClckUmVnaW9uID0gZmFjdG9yKCBwYXN0ZTAoIlJlZyIsVyRSZWdpb24pICkNCldbMzo4XSA9IGxhcHBseShXWzM6Nl0sIGxvZywgYmFzZT0xMCkNCnN1bW1hcnkoVykNCmBgYA0KDQojIyMjIyBBMi4g5YWp5YCL5Y2A6ZqU6K6K5pW4DQpgYGB7cn0NCmhjID0gV1ssMzo0XSAlPiUgc2NhbGUgJT4lIGRpc3QgJT4lIGhjbHVzdA0KcGxvdChoYykNCnJlY3QuaGNsdXN0KGhjLCBrPTUsIGJvcmRlcj0icmVkIikNCmBgYA0KICsg5Zyo5YGa6ZuG576k5YiG5p6Q5YmN77yM5YWI5bCH5omA5pyJ55qE5Y2A6ZqU6K6K5pW45qiZ5rqW5YyW77yMKOS9v+eUqHNjYWxl5Ye95pW4Ke+8jOWPr+S7peiuk+avj+WAi+ashOS9jeW5s+Wdh+WAvD0wLOaomea6luW3rj0x77yM5L2/5b6X5Zyo6KiI566X6Led6Zui5pmC5LiN5pyD5Y+X5beu5YC86LyD5aSn55qE5Y2A6ZqU6K6K5pW45Z+L5rKS5YW25LuW6LyD5bCP55qE6K6K5pW444CCDQoNCmBgYHtyfQ0KVyRncm91cCA9IGN1dHJlZShoYywgaz01KSAlPiUgZmFjdG9yDQpnZ3Bsb3QoVywgYWVzKHg9RnJlc2gsIHk9TWlsaywgY29sPWdyb3VwKSkgKw0KICBnZW9tX3BvaW50KHNpemU9MywgYWxwaGE9MC41KSArIA0KICB0aGVtZV9saWdodCgpDQpgYGANCg0KIyMjIyMgQTMuIOWFreWAi+WNgOmalOiuiuaVuA0KYGBge3J9DQpoYyA9IFdbLDM6N10gJT4lIHNjYWxlICU+JSBkaXN0ICU+JSBoY2x1c3QNCnBsb3QoaGMpDQpXJGdyb3VwID0gZmFjdG9yKGN1dHJlZShoYywgaz04KSkNCnJlY3QuaGNsdXN0KGhjLCBrPTgsIGJvcmRlcj0icmVkIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmZ2aXpfZGVuZCgNCiAgaGMsIGs9OCwgc2hvd19sYWJlbHM9RiwgcmVjdD1ULCByZWN0X2ZpbGw9VCwNCiAgbGFiZWxzX3RyYWNrX2hlaWdodD0wLA0KICBwYWxldHRlPSJ1Y3NjZ2IiLCByZWN0X2JvcmRlcj0idWNzY2diIikNCmBgYA0KDQojIyMjIyBBNC4g5bC65bqm57iu5ribIA0KRGltZW5zaW9uIFJlZHVjdGlvbiB3aXRoIFBDQSAoUHJpbmNpcGxlIENvbXBvbmVudCBBbmFseXNpcywg5Li75oiQ5YiG5YiG5p6QKQ0KYGBge3IgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OX0NCldbLDM6OF0gJT4lIFBDQShncmFwaD1GKSAlPiUgZnZpel9wY2FfYmlwbG90KA0KICBsYWJlbD0idmFyIiwgY29sLmluZD1XJGdyb3VwLA0KICBwb2ludHNoYXBlPTE5LCBtZWFuLnBvaW50PUYsDQogIGFkZEVsbGlwc2VzPVQsIGVsbGlwc2UubGV2ZWw9MC43LA0KICBlbGxpcHNlLnR5cGUgPSAiY29udmV4IiwgcGFsZXR0ZT0idWNzY2diIiwNCiAgcmVwZWw9VA0KICApDQpgYGANCiAr5Zyo5L2O5bC65bqm56m66ZaT55yL5Yiw5YiG576k55qE57WQ5p6c77yb6YKE5pyJ5Y2A6ZqU6K6K5pW4KOWwuuW6pui3n+WwuuW6pinnmoTpl5zkv4LjgIINCiANCjxicj4NCg0KLSAtIC0NCg0KIyMjIDEuIENsdXN0ZXIgQW5hbHlzaXMgZm9yIE1vdmllcyAgDQoNCioq5Li76KaB6K2w6aGM77ya5L6d6aGe5Z6LKEdlbnJlKeWwjembu+W9seWIhumhnioqDQoNCioq5a2457+S6YeN6bue77yaKioNCg0KKyDpm4bnvqTliIbmnpDnmoTln7rmnKzop4Dlv7UNCisg6Led6Zui55+p6Zmj77yaRGlzdGFuY2UgTWF0cml4DQorIOWxpOe0muW8j+mbhue+pOWIhuaekO+8mkhpZXJhcmNoaWNhbCBDbHVzdGVyIEFuYWx5c2lzDQorIOaoueeLgOWclihEZW5kcm9ncmFtKeeahOWIpOiugA0KKyDkvp3mk5rmqLnni4DlnJbmsbrlrpropoHliIblpJrlsJHnvqQNCisg5Lul576k57WE5bmz5Z2H5YC85qqi6KaW5ZCE5peP576k55qE5bGs5oCnDQoNCjxicj4NCg0KIyMjIyMgMS4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQpNID0gcmVhZC50YWJsZSgiZGF0YS9tb3ZpZUxlbnMudHh0IiwgaGVhZGVyPUZBTFNFLCBzZXA9InwiLHF1b3RlPSJcIiIpDQoNCiMgQXNzaWduIGNvbHVtbiBuYW1lcw0KY29sbmFtZXMoTSkgPSBjKA0KICAiSUQiLCAiVGl0bGUiLCAiUmVsZWFzZURhdGUiLCAiVmlkZW9SZWxlYXNlRGF0ZSIsICJJTURCIiwgDQogICJVbmtub3duIiwgIkFjdGlvbiIsICJBZHZlbnR1cmUiLCAiQW5pbWF0aW9uIiwgIkNoaWxkcmVucyIsIA0KICAiQ29tZWR5IiwgIkNyaW1lIiwgIkRvY3VtZW50YXJ5IiwgIkRyYW1hIiwgIkZhbnRhc3kiLCAiRmlsbU5vaXIiLCANCiAgIkhvcnJvciIsICJNdXNpY2FsIiwgIk15c3RlcnkiLCAiUm9tYW5jZSIsICJTY2lGaSIsICJUaHJpbGxlciIsDQogICJXYXIiLCAiV2VzdGVybiIpDQoNCiMgUmVtb3ZlIHVubmVjZXNzYXJ5IHZhcmlhYmxlcw0KTSRJRCA9IE5VTEwNCk0kUmVsZWFzZURhdGUgPSBOVUxMDQpNJFZpZGVvUmVsZWFzZURhdGUgPSBOVUxMDQpNJElNREIgPSBOVUxMDQoNCiMgUmVtb3ZlIGR1cGxpY2F0ZXMNCk0gPSB1bmlxdWUoTSkNCmBgYA0KDQojIyMjIyAxLjIg5qqi6KaW6LOH5paZDQpgYGB7cn0NCmhlYWQoTSwgNSkNCmBgYA0KDQpgYGB7cn0NCnN1bShNJENvbWVkeSkgICAgICAgICAgICAgIyDllpzliofniYcNCnN1bShNJFdlc3Rlcm4pICAgICAgICAgICAgIyDopb/pg6jniYcNCnN1bShNJFJvbWFuY2UgfCBNJERyYW1hKSAgIyDmtarmvKvliofmg4XniYcNCmBgYA0KDQojIyMjIyAxLjMg6Led6Zui55+p6ZmjDQpgYGB7cn0NCmRteD0gZGlzdChNWzI6MjBdLCBtZXRob2Q9ImV1Y2xpZGVhbiIpDQpkbXggJT4lIGFzLm1hdHJpeCAlPiUgZGltDQpgYGANCg0KIyMjIyMgMS40IOWxpOe0muW8j+mbhue+pOWIhuaekA0KYGBge3J9DQpoY2x1c3QxID0gaGNsdXN0KGRteCwgbWV0aG9kID0gIndhcmQuRCIpIA0KYGBgDQoNCiMjIyMjIDEuNSDmqqLoppbmqLnni4DlnJYNCmBgYHtyfQ0KcGxvdChoY2x1c3QxKQ0KcmVjdC5oY2x1c3QoaGNsdXN0MSwgaz01LCBib3JkZXI9InJlZCIpDQpgYGANCg0KIyMjIyMgMS42IOWIh+WJsue+pOe1hA0KYGBge3J9DQpncnAgPSBjdXRyZWUoaGNsdXN0MSwgayA9IDUpDQp0YWJsZShncnApDQpgYGANCg0KIyMjIyMgMS43IOaqouafpee+pOe1hOWxrOaApw0KYGBge3J9DQp0YXBwbHkoTSRBY3Rpb24sIGdycCwgbWVhbikNCnRhcHBseShNJFJvbWFuY2UsIGdycCwgbWVhbikNCmBgYA0KDQojIyMjIyAxLjggVGhlIGBzYXBwbHlgLWBzcGxpdGAtYC4uLmAgQ29tYm/vvJoNCmBgYHtyfQ0Kc2FwcGx5KHNwbGl0KE1bLDI6MjBdLCBncnApLCBjb2xNZWFucykgJT4lIHJvdW5kKDMpDQpgYGANCg0KIyMjIyMgMS45IOizh+aWmeimluimuuWMlg0KYGBge3J9DQpsYXlvdXQobWF0cml4KGMoMSwyLDIpLCAzLCAxKSkNCnBhcihtYXI9YygyLDMsMSwxKSwgY2V4PTAuOCkNCnRhYmxlKGdycCkgJT4lIGJhcnBsb3QoY29sPTM6NywgbmFtZXMuYXJnPXBhc3RlMCgiR3JvdXAtIiwxOjUpKQ0KcGFyKG1hcj1jKDYsMywyLDEpKQ0Kc2FwcGx5KHNwbGl0KE1bLDI6MjBdLCBncnApLCBjb2xNZWFucykgJT4lIHQgJT4lIA0KICBiYXJwbG90KGJlc2lkZT1ULCBjb2w9Mzo3LCBsYXM9MikNCg0KYGBgDQoNCiMjIyMjIOOAkOWVj+mhjOiojuirluOAkQ0KDQrlvp7nrqHnkIbnmoTop5LluqbkvobnnIvvvIzmiJHlgJHngrrnlJrpurzopoHliIbnvqTvvJ8gDQoNCisg6ZuG576k5YiG5p6Q6YKE5Y+v5Lul55yL5Ye65p+Q576k55qE5LiA5Lqb54m55oCn77yM6K6T5Zyo6aCQ5ris5qih5Z6L5LmL5YmN5Y+v5Lul5YWI55yL5Ye65LiA5Lqb56uv5YCq44CCDQorIOS4gOiIrOS+huiqqu+8jOWwh+WFrOWPuOmdouWwjeeahOWuoue+pOWBmumBqeeVtuWIhue+pO+8jOWPr+S7peWcqOS4jeWQjOWIhue+pOWBmuWHuuS4jeWQjOeahOWVhualreaxuuetluOAgg0KDQoNCuaIkeWAkeeCuueUmum6vOimgeWBmuWwuuW6pue4rua4m++8nyANCg0KKyDlj6/ku6XlsIfoqLHlpJrkuI3lkIznmoTljYDpmpTorormlbjnuK7muJvoh7PkuIDlgIvlubPpnaLvvIzovIPlrrnmmJPop6PoroDkuI3lkIzliIbnvqTot5/ljYDpmpTorormlbjnmoTpl5zkv4LjgIINCisg5bGs5oCn5aSq5aSa55qE6Kmx77yM5Zyo5YGaY2x1c3RlcuioiOeul+izh+aWmem7numWk+eahOi3nembouaZgu+8jOioiOeul+acg+Wkquikh+mbnA0KKyDmiJHlgJHopoHku6Xos4foqIrph4/mkI3lpLHmnIDlsJHnmoTop5LluqbljrvlgZrlsLrluqbnuK7muJvjgIINCg0KDQrmiJHlgJHopoHlpoLkvZXmiorpm4bnvqTliIbmnpDnmoTntZDmnpzovYnljJbngrrnrZbnlaXlkaLvvJ8gDQoNCisg5Yip55So6ZuG576k5YiG5p6Q55qE57WQ5p6c55yL5Ye65LiN5ZCM5YiG576k55qE54m55oCn77yM5Lim6Yed5bCN54m55oCn5L6G5YGa5Ye655u45bCN562W55Wl55qE5Zue5oeJ44CCDQorIOmChOaYr+imgeaQremFjeaxuuetluiAheeahOiDjOaZr+efpeitmOWOu+WBmuacgOmBqeeVtueahOetlueVpeOAgg0KDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAyLiBGbG93ZXIgSW1hZ2UNCg0KIyMjIyMgMi4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQojIFJlYWQgZGF0YQ0KZmxvd2VyID0gcmVhZC5jc3YoImRhdGEvZmxvd2VyLmNzdiIsIGhlYWRlcj1GQUxTRSkNCg0KIyBDaGFuZ2UgdGhlIGRhdGEgdHlwZSB0byBtYXRyaXgNCmZsb3dlck1hdHJpeCA9IGFzLm1hdHJpeChmbG93ZXIpDQpkaW0oZmxvd2VyTWF0cml4KQ0KDQojIFR1cm4gbWF0cml4IGludG8gYSB2ZWN0b3INCmZsb3dlclZlY3RvciA9IGFzLnZlY3RvcihmbG93ZXJNYXRyaXgpDQpsZW5ndGgoZmxvd2VyVmVjdG9yKQ0KYGBgDQoNCiMjIyMjIDIuMiDot53pm6Lnn6npmaMNCmBgYHtyfQ0KIyBDb21wdXRlIGRpc3RhbmNlcw0KZGlzdGFuY2UgPSBkaXN0KGZsb3dlclZlY3RvciwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpgYGANCg0KIyMjIyMgMi4zIOWxpOe0muW8j+mbhue+pOWIhuaekA0KYGBge3J9DQojIEhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nDQpjbHVzdGVySW50ZW5zaXR5ID0gaGNsdXN0KGRpc3RhbmNlLCBtZXRob2Q9IndhcmQuRCIpDQpgYGANCg0KIyMjIyMgMi40IOaoueeLgOWclg0KYGBge3J9DQojIFBsb3QgdGhlIGRlbmRyb2dyYW0NCnBsb3QoY2x1c3RlckludGVuc2l0eSkNCiMgU2VsZWN0IDMgY2x1c3RlcnMNCnJlY3QuaGNsdXN0KGNsdXN0ZXJJbnRlbnNpdHksIGsgPSAzLCBib3JkZXIgPSAicmVkIikNCmBgYA0KDQojIyMjIyDliIflibLnvqTntYQNCmBgYHtyfQ0KZmxvd2VyQ2x1c3RlcnMgPSBjdXRyZWUoY2x1c3RlckludGVuc2l0eSwgayA9IDMpDQp0YWJsZShmbG93ZXJDbHVzdGVycykNCiMgZmxvd2VyQ2x1c3RlcnMNCmBgYA0KDQojIyMjIyDml4/nvqTlubPlnYco55Wr57Sg6aGP6Imy5rex5re65bqmKQ0KYGBge3J9DQojIEZpbmQgbWVhbiBpbnRlbnNpdHkgdmFsdWVzDQp0YXBwbHkoZmxvd2VyVmVjdG9yLCBmbG93ZXJDbHVzdGVycywgbWVhbikNCmBgYA0KDQojIyMjIyDlnJblg4/mr5TovIMNCmBgYHtyIGZpZy5oZWlnaHQ9My4yLCBmaWcud2lkdGg9Ni40fQ0KIyBQbG90IHRoZSBpbWFnZSBhbmQgdGhlIGNsdXN0ZXJzDQpkaW0oZmxvd2VyQ2x1c3RlcnMpID0gYyg1MCw1MCkNCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDIsMiwyLDIpKQ0KDQojIE9yaWdpbmFsIGltYWdlDQppbWFnZShmbG93ZXJNYXRyaXgsYXhlcz1GQUxTRSxjb2w9Z3JleShzZXEoMCwxLGxlbmd0aD0yNTYpKSxtYWluPSJPcmlnaW5hbCIpDQoNCiMgTmV3IGltYWdlDQppbWFnZShmbG93ZXJDbHVzdGVycywgYXhlcyA9IEZBTFNFLCBtYWluPSIzIENsdXN0ZXIiKQ0KYGBgDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyAzLiBNUkkgSW1hZ2UNCg0KIyMjIyMgMy4xIOaVtOeQhuizh+aWmQ0KYGBge3J9DQojIFJlYWQgZGF0YQ0KaGVhbHRoeSA9IHJlYWQuY3N2KCJkYXRhL2hlYWx0aHkuY3N2IiwgaGVhZGVyPUZBTFNFKQ0KaGVhbHRoeU1hdHJpeCA9IGFzLm1hdHJpeChoZWFsdGh5KQ0KZGltKGhlYWx0aHlNYXRyaXgpDQpgYGANCg0KIyMjIyMgMy4yIOeVq+WHuuWcluW9og0KYGBge3IgZmlnLndpZHRoPTIuODMsIGZpZy5oZWlnaHQ9My4yM30NCiMgUGxvdCBpbWFnZQ0KcGFyKG1hcj1jKDEsMSwxLDEpKQ0KaW1hZ2UoaGVhbHRoeU1hdHJpeCxheGVzPUZBTFNFLGNvbD1ncmV5KHNlcSgwLDEsbGVuZ3RoPTI1NikpKQ0KYGBgDQoNCiMjIyMjIDMuMyDot53pm6Lnn6npmaMNCmBgYHtyfQ0KIyBDb21wdXRlIGRpc3RhbmNlcw0KaGVhbHRoeVZlY3RvciA9IGFzLnZlY3RvcihoZWFsdGh5TWF0cml4KQ0KZGlzdGFuY2UgPSBkaXN0KGhlYWx0aHlWZWN0b3IsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KYGBgDQoNCioq44CQUeOAkSoqIFdoYXQgaXMgdGhlIHByb2JsZW0/DQoNCisg5Zug54K655+p6Zmj54K6NTY2KjY0NueahOWkp+Wwj++8jOiLpeimgeioiOeul+WFqem7nui3nembouS+huWBmumbhue+pOWIhuaekO+8jOacg+acieWkquWkmuizh+aWmemHj++8jOiAjFLmnIPosqDojbfkuI3kuobjgIINCisgTj01NjYqNjQ2DQorIERpc3TnmoTos4fmlpnmlbg9TihOLTEpLzINCg0KIyMjIyMgMy40IEtNZWFuc+mbhue+pOWIhuaekA0KYGBge3J9DQojIFJ1biBrLW1lYW5zDQprID0gNQ0Kc2V0LnNlZWQoMSkNCktNQyA9IGttZWFucyhoZWFsdGh5VmVjdG9yLCBjZW50ZXJzID0gaywgaXRlci5tYXggPSAxMDAwKQ0KDQpgYGANCg0KIyMjIyMgMy41IOaqouafpeWIhue+pOe1kOaenA0KYGBge3J9DQojIFZpZXcoS01DKQ0KdGFibGUoS01DJGNsdXN0ZXIpDQpLTUMkY2VudGVycw0KYGBgDQoNCiMjIyMjIDMuNiDnlavlh7rliIbnvqTntZDmnpwNCmBgYHtyIGZpZy53aWR0aD0yLjgzLCBmaWcuaGVpZ2h0PTMuMjN9DQojIEV4dHJhY3QgY2x1c3RlcnMNClggPSBLTUMkY2x1c3Rlcg0KDQojIFBsb3QgdGhlIGltYWdlIHdpdGggdGhlIGNsdXN0ZXJzDQpkaW0oWCkgPSBjKG5yb3coaGVhbHRoeU1hdHJpeCksIG5jb2woaGVhbHRoeU1hdHJpeCkpDQoNCiMgUGxvdCBpbWFnZQ0KcGFyKG1hcj1jKDEsMSwxLDEpKQ0KaW1hZ2UoWCwgYXhlcyA9IEZBTFNFLCBjb2w9cmFpbmJvdyhrKSkNCmBgYA0KDQojIyMjIyAzLjcg6K6A6YCy44CB6L2J5o+b5ris6Kmm5ZyW5b2iDQpgYGB7cn0NCnR1bW9yID0gcmVhZC5jc3YoImRhdGEvdHVtb3IuY3N2IiwgaGVhZGVyPUZBTFNFKQ0KdHVtb3JNYXRyaXggPSBhcy5tYXRyaXgodHVtb3IpDQpkaW0odHVtb3JNYXRyaXgpDQp0dW1vclZlY3RvciA9IGFzLnZlY3Rvcih0dW1vck1hdHJpeCkNCmxlbmd0aCh0dW1vclZlY3RvcikNCmBgYA0KDQojIyMjIyAzLjgg5bCH5Y6f5ZyW5b2i5LmL5YiG576k6KaP5YmH5aWX55So5Yiw5ris6Kmm5ZyW5b2iDQpgYGB7cn0NCiMgQXBwbHkgY2x1c3RlcnMgZnJvbSBiZWZvcmUgdG8gbmV3IGltYWdlLCB1c2luZyB0aGUgZmxleGNsdXN0IHBhY2thZ2UNCmxpYnJhcnkoZmxleGNsdXN0KQ0KdDAgPSBTeXMudGltZSgpDQpLTUMua2NjYSA9IGZsZXhjbHVzdDo6YXMua2NjYShLTUMsIGhlYWx0aHlWZWN0b3IpICAgICAgICAjIOW7uueri+aooeWeiw0KdHVtb3JDbHVzdGVycyA9IHByZWRpY3QoS01DLmtjY2EsIG5ld2RhdGEgPSB0dW1vclZlY3RvcikgIyDpgLLooYzpoJDmuKwo6L2J5o+bKQ0KU3lzLnRpbWUoKSAtIHQwDQpgYGANCg0KIyMjIyMgMy45IOWcluWDj+avlOi8gw0KYGBge3IgZmlnLmhlaWdodD0zLjIsIGZpZy53aWR0aD02fQ0KIyBWaXN1YWxpemUgdGhlIGNsdXN0ZXJzDQpkaW0odHVtb3JDbHVzdGVycykgPSBjKG5yb3codHVtb3JNYXRyaXgpLCBuY29sKHR1bW9yTWF0cml4KSkNCg0KcGFyKG1mcm93PWMoMSwyKSwgbWFyPWMoMSwxLDIsMSkpDQppbWFnZShYLCBheGVzID0gRkFMU0UsIGNvbD1yYWluYm93KGspLCBtYWluPSJIZWFsdGh5IikNCmltYWdlKHQodHVtb3JDbHVzdGVycylbLDU3MToxXSwgYXhlcyA9IEZBTFNFLCBjb2w9cmFpbmJvdyhrKSwgbWFpbj0iVHVtb3IiKQ0KYGBgDQoNCiMjIyMjIOOAkOWtuOe/kumHjem7nuOAkQ0KDQorIOmbhue+pOWIhuaekOWcqOWcluWDj+iZleeQhueahOaHieeUqA0KKyDllq7ljYDpmpTorormlbjnmoTpm4bnvqTliIbmnpANCisg6ZuG576k5YiG5p6Q5qih5Z6LDQoNCiMjIyMjIOOAkOWVj+mhjOiojuirluOAkQ0KDQrlsaTntJrlvI/lkoxLLU1lYW5z6ZuG576k5YiG5p6Q5pyJ5LuA6bq85beu55Ww77yfIOWug+WAkeWIhuWIpeeUqOWcqOS7gOm6vOeLgOazge+8nw0KDQorIOWxpOe0muW8jyhoaWVyYXJjaGljYWwp5Y+v5YiG54K66IGa5ZCI5byP5oiW5YiG6KOC5byPDQogICAgKyDogZrlkIjlvI/mmK/lhYjlsIfmr4/lgIvos4fmlpnpg73oppbngrrkuIDlgItjbHVzdGVy77yM6KiI566XY2x1c3RlcumWk+eahOi3nembouW+jO+8jOaJvuWHuui3nembouacgOi/keeahOWFqeiAheiBmuWQiOaIkOS4gOWAi2NsdXN0ZXLvvIznm7TliLBjbHVzdGVy5pW46YeP56ym5ZCI6Kit5a6a44CCKOeUseS4i+W+gOS4iikNCiAgICArIOWIhuWIl+W8j+WJh+aYr+WFiOWwh+aVtOWAi+izh+aWmeimlueCuuS4gOaVtOWAi2NsdXN0ZXIo55Sx5LiK5b6A5LiLKQ0KICArIOe+pOmWk+i3nembouacieWkmueoruioiOeul+aWueazlShtaW4ubWF4LmF2ZXJhZ2UtbGlua2FnZS4uLikNCiAgKyDlnKjkvb/nlKjkuIrvvIzliKnnlKjpu57lkozpu57nmoTot53pm6LlgZrliIbnvqTvvIzkuI3nlKjlhYjmjIflrprliIZL576kDQogICsg5Y+v5Lul5YGa5Ye6ZGVuZHJvZ3Jhbeeci+WHuue+pOiIh+e+pOS5i+mWk+eahOi3nembouS4puWBmuacgOaBsOeVtueahOWIh+WJsg0KICArIOmAmuW4uOmBqeeUqOaWvOizh+aWmei8g+WwkeeahOaDheazge+8jOizh+aWmemHj+mBjuWkp1LmnIPkuI3pgLLooYzpgYvnrpfjgIINCiAgKyDlj6/ku6XliKnnlKjlj4PmlbjoqK3lrprvvIzlsIdub2lzZeaOkumZpA0KDQorIEstTWVhbnPpm4bnvqTliIbmnpANCiAgKyDlhYjmjIflrprliIbngrpL576k77yM5Lim6Zqo5qmf5bCH6LOH5paZ6bue5oyH5rS+6Iez5p+Q5LiA576k77yM5bCH5q+P5LiA576k55qE5Lit5b+D6bue6KiI566X5Ye65L6G77yM6YeN5paw5bCH6LOH5paZ6bue5YaN5YiG6YWN5Yiw5pyA6L+R55qE5Lit5b+D6bue77yM5LiN5pa35bCH6YCZ5YCL6YGO56iL6YeN6KSH55u05Yiw5rKS5pyJ6YCy5bGV54K65q2iDQogICsg6YCa5bi46LOH5paZ6YeP6YGO5aSn5pmC77yM5pyD5L2/55Soa21lYW7kvoblgZrpm4bnvqTliIbmnpANCiAgK+S9huWQjOethuizh+aWmeWIhuWIpeS9v+eUqOWxpOe0muW8j+WSjGttZWFu55qE57WQ5p6c5Lim5LiN5pyD5LiA6Ie0DQogICsg5a655piT5Y+Xbm9pc2XlvbHpn78o5Zug54K65q+P5YCL6bue5LiA5a6a6YO96KaB5bGs5pa85LiA5YCL576kKQ0KDQoNCumbhue+pOWIhuaekOaooeWei+WSjOaZrumAmueahOmbhue+pOWIhuaekOacieS7gOm6vOW3rueVsO+8nyANCg0KKyDpm4bnvqTliIbmnpDmmK/lsIfnj77mnInos4fmlpnlgZrliIbnvqTvvIzlj6/ku6XnnIvlh7rkuI3lkIznvqTnmoTnibnmgKfvvJsNCisg5L2G6ZuG576k5YiG5p6Q5qih5Z6L5piv5bCH6YCZ5YCL5YiG576k5pa55rOV5bu656uL5qih5Z6L5b6M77yM5Y+v5Lul5oqK6aGN5aSW5paw55qE6LOH5paZ5oqV5YWl5qih5Z6L77yM5Lul5ZCM5qij55qE5ryU566X5rOV5L6G5oqK5paw55qE6LOH5paZ5YiG576k44CCDQogICjliKnnlKjljp/lhYjnmoTliIbnvqTntZDmnpzmlL7lnKjkuIDlgIvmqKHlnovvvIzlnKjngrrnrKzkuozlgIvos4fmlpnlgZrliIbnvqTjgIIpIA0KDQrku4DpurzmmYLlgJnpnIDopoHlu7rpm4bnvqTliIbmnpDmqKHlnovvvJ8g6ZuG576k5YiG5p6Q5qih5Z6L55qE55So5rOV77yfDQoNCisg6Iul6ZyA6KaB5q+U6LyD6K6K5YyW5YWp56iu5Lqb5b6u5LiN5ZCM6LOH5paZ77yM5Yip55So5qih5Z6L5Y+v5Lul5bCH5Y6f5pys55u45ZCM55qE6YOo5YiG5b6X5Yiw5LiA5qij55qE57WQ5p6c77yM6YCy6ICM55yL5Ye65beu55Ww44CCDQoNCg0K5ZyW5YOP6JmV55CG5ZKM5ZyW5YOP6L6o6K2Y5pyJ5LuA6bq85beu55Ww77yfDQoNCisg5ZyW5YOP6JmV55CG5piv5bCH5Y6f5pyJ5pW45YC855qE6LOH5paZ5Z6L5oWL77yM5L6d54Wn6ZuG576k5YiG5p6Q5bCH5ZCE5pW45YC85YiG6aGe77yM5Lim5L6d54Wn5YiG576k55qE57WQ5p6c5Y+K5ZyW5YOP5oeJ5pyJ55qE6ZW35a+s5ZGI54++5ZyW5YOP77yM5ZGI54++5pa55byP5Y+v5L6d5Y+D5pW46Kit5a6a54Gw6ZqO5oqR5oiW5piv5b2p6Imy44CCDQorIOWcluWDj+i+qOitmOS+huiHquaWvOS4jeWQjOaVuOWAvOS4i+aJgOWIhue+pOeahOW3rueVsO+8jOWcqOWRiOePvuaZguacg+WboOe1kOaenOW3rueVsOiAjOacieS4jeWQjOiJsumaju+8jOmAj+mBjumAmeaoo+eahOaWueW8j+WPr+S7peWIpOWIpeS4gOS6m+eJueWumueahOWcluWDj++8jOaIluaYr+aZgumWk+W6j+WIl+S4i+S4jeWQjOeahOizh+aWmeaJgOWRiOePvueahOWcluWDj+WPr+WBmuavlOi8g+OAgg0KKyDpgJrluLjopoHlhYjlgZrlnJblg4/omZXnkIbmiY3og73pgLLkuIDmraXlnJblg4/ovqjorZjjgIINCg0KPGJyPg0KDQotIC0gLQ0KDQo8YnI+PGJyPjxicj48YnI+PGJyPg0KDQo8c3R5bGU+DQouY2FwdGlvbiB7DQogIGNvbG9yOiAjNzc3Ow0KICBtYXJnaW4tdG9wOiAxMHB4Ow0KfQ0KcCBjb2RlIHsNCiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7DQp9DQpwcmUgew0KICB3b3JkLWJyZWFrOiBub3JtYWw7DQogIHdvcmQtd3JhcDogbm9ybWFsOw0KICBsaW5lLWhlaWdodDogMTsNCn0NCnByZSBjb2RlIHsNCiAgd2hpdGUtc3BhY2U6IGluaGVyaXQ7DQp9DQpwLGxpIHsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCi5yew0KICBsaW5lLWhlaWdodDogMS4yOw0KfQ0KDQp0aXRsZXsNCiAgY29sb3I6ICNjYzAwMDA7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpib2R5ew0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KaDEsaDIsaDMsaDQsaDV7DQogIGNvbG9yOiAjMDA4ODAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KaDN7DQogIGNvbG9yOiAjYjM2YjAwOw0KICBiYWNrZ3JvdW5kOiAjZmZlMGIzOw0KICBsaW5lLWhlaWdodDogMjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmg1ew0KICBjb2xvcjogIzAwNjAwMDsNCiAgYmFja2dyb3VuZDogI2ZmZmZlMDsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQplbXsNCiAgY29sb3I6ICMwMDAwYzA7DQogIGJhY2tncm91bmQ6ICNmMGYwZjA7DQogIH0NCjwvc3R5bGU+DQoNCg==