PCA - Iris

Species - 범주

나머지 - 연속형

##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
  1. 결측치 확인
## Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
##            0            0            0            0            0
  1. 변수별 기술 통계 및 분포 확인

중위수와 평균의 차이가 크면, 이상치가 많다는 의미로 볼 수 있다. (중요)

##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 

## Importance of components:
##                           PC1    PC2     PC3     PC4
## Standard deviation     1.7084 0.9560 0.38309 0.14393
## Proportion of Variance 0.7296 0.2285 0.03669 0.00518
## Cumulative Proportion  0.7296 0.9581 0.99482 1.00000
   Standard Deviation : 제곱 = 분산 = eigenvalue 
   Proportaion of Variance : 전체 분산에서 차지하는 비율 
   Cumlative Proportion : 누적 비율 
   
   
   PC 1은 72.9% 전체 변동량을 설명한다 
   PC 1 + PC 2 는 95.81%를 설명한다. 

Rotation

각 주성분들의 eigenvector (= 각 변수들의 가중치)

##                     PC1         PC2        PC3        PC4
## Sepal.Length  0.5210659 -0.37741762  0.7195664  0.2612863
## Sepal.Width  -0.2693474 -0.92329566 -0.2443818 -0.1235096
## Petal.Length  0.5804131 -0.02449161 -0.1421264 -0.8014492
## Petal.Width   0.5648565 -0.06694199 -0.6342727  0.5235971

X

##            PC1        PC2         PC3          PC4
## [1,] -2.257141 -0.4784238  0.12727962  0.024087508
## [2,] -2.074013  0.6718827  0.23382552  0.102662845
## [3,] -2.356335  0.3407664 -0.04405390  0.028282305
## [4,] -2.291707  0.5953999 -0.09098530 -0.065735340
## [5,] -2.381863 -0.6446757 -0.01568565 -0.035802870
## [6,] -2.068701 -1.4842053 -0.02687825  0.006586116

Scree Plot

  1. 시각화 기준 2 or 3 개
  2. Eigenvalue > 1 기준으로
  3. Scree plot 에서의 elbow point 를 설정한다.

3 번쨰 주성분까지 선택하면 안되는 이유 -> Variance 는 eigenvalue 인데 1 이하 임으로, 2개의 주성분이 적당하다.

  1. 차원 축소

2 개의 차원으로 축소

##             PC1         PC2
##  [1,] -2.257141 -0.47842383
##  [2,] -2.074013  0.67188269
##  [3,] -2.356335  0.34076642
##  [4,] -2.291707  0.59539986
##  [5,] -2.381863 -0.64467566
##  [6,] -2.068701 -1.48420530
##  [7,] -2.435868 -0.04748512
##  [8,] -2.225392 -0.22240300
##  [9,] -2.326845  1.11160370
## [10,] -2.177035  0.46744757
  1. 2 차원 시각화

  1. 고급 시각화 -1

고급 시각화-2

V 가까운 거리/방향성 = 상관성 증가 PC1 (DIM1) 기준 좌우 / PC2(DIM2) 기준 상하

PCA - AirBnB

2008년 이후, 게스트와 호스트는 여행이나, 좀 더 색다르고, 개별적인 여행 경험을 얻고자 에어비엔비를 사용하였다.

Column Books

idlisting: ID name: name of the listing host_id: host ID host_name: name of the host neighbourhood_grouplocation: neighbourhoodarea latitude: latitude coordinates longitude: longitude coordinates room_typelisting: space type price: price in dollars minimum_night: samount of nights minimum number_of_reviews: number of reviews last_review: latest review reviews_per_month: number of reviews per month calculated_host_listings_count: amount of listing per host availability_365: number of days when listing is available for booking

Data Pre Processing

## 'data.frame':    48895 obs. of  16 variables:
##  $ id                            : int  2539 2595 3647 3831 5022 5099 5121 5178 5203 5238 ...
##  $ name                          : chr  "Clean & quiet apt home by the park" "Skylit Midtown Castle" "THE VILLAGE OF HARLEM....NEW YORK !" "Cozy Entire Floor of Brownstone" ...
##  $ host_id                       : int  2787 2845 4632 4869 7192 7322 7356 8967 7490 7549 ...
##  $ host_name                     : chr  "John" "Jennifer" "Elisabeth" "LisaRoxanne" ...
##  $ neighbourhood_group           : chr  "Brooklyn" "Manhattan" "Manhattan" "Brooklyn" ...
##  $ neighbourhood                 : chr  "Kensington" "Midtown" "Harlem" "Clinton Hill" ...
##  $ latitude                      : num  40.6 40.8 40.8 40.7 40.8 ...
##  $ longitude                     : num  -74 -74 -73.9 -74 -73.9 ...
##  $ room_type                     : chr  "Private room" "Entire home/apt" "Private room" "Entire home/apt" ...
##  $ price                         : int  149 225 150 89 80 200 60 79 79 150 ...
##  $ minimum_nights                : int  1 1 3 1 10 3 45 2 2 1 ...
##  $ number_of_reviews             : int  9 45 0 270 9 74 49 430 118 160 ...
##  $ last_review                   : chr  "2018-10-19" "2019-05-21" "" "2019-07-05" ...
##  $ reviews_per_month             : num  0.21 0.38 NA 4.64 0.1 0.59 0.4 3.47 0.99 1.33 ...
##  $ calculated_host_listings_count: int  6 2 1 1 1 1 1 1 1 4 ...
##  $ availability_365              : int  365 355 365 194 0 129 0 220 0 188 ...

Numeric 만 추출

Descriptive Statistics

Correlation

##                                      price minimum_nights number_of_reviews
## price                           1.00000000     0.04279933       -0.04795423
## minimum_nights                  0.04279933     1.00000000       -0.08011607
## number_of_reviews              -0.04795423    -0.08011607        1.00000000
## calculated_host_listings_count  0.05747169     0.12795963       -0.07237606
## availability_365                0.08182883     0.14430306        0.17202758
##                                calculated_host_listings_count availability_365
## price                                              0.05747169       0.08182883
## minimum_nights                                     0.12795963       0.14430306
## number_of_reviews                                 -0.07237606       0.17202758
## calculated_host_listings_count                     1.00000000       0.22570137
## availability_365                                   0.22570137       1.00000000

PCA Analysis

## Importance of components:
##                           PC1    PC2    PC3    PC4    PC5
## Standard deviation     1.1695 1.0646 0.9845 0.9334 0.8115
## Proportion of Variance 0.2735 0.2267 0.1938 0.1742 0.1317
## Cumulative Proportion  0.2735 0.5002 0.6940 0.8683 1.0000

PC 4가 86.83%의 변동률을 설명하는 것으로 4개가 적당해보인다.

X

##             PC1        PC2         PC3         PC4        PC5
## [1,]  1.0032784  0.5813873  0.07919756  0.30552371 -1.5550835
## [2,]  1.0039239  1.1772506  0.45957024  0.03989221 -1.1041550
## [3,]  0.9551646  0.4063914  0.06127306  0.17283789 -1.7050652
## [4,]  0.2656214  5.0369605  0.35645301 -0.85687593  2.2226285
## [5,] -0.6608942 -0.5561055 -0.32651731 -0.15276554  0.3290961

Rotation - eigenvectors

##                                       PC1        PC2          PC3         PC4
## price                          0.27569841 -0.2114304  0.920046259 -0.12497146
## minimum_nights                 0.46486745 -0.2822177 -0.335773478 -0.73645904
## number_of_reviews              0.03681049  0.8354198  0.083556017 -0.18126643
## calculated_host_listings_count 0.57439556 -0.1461332 -0.183649326  0.63909258
## availability_365               0.61368019  0.3954354  0.007897413  0.02670907
##                                       PC5
## price                           0.1310900
## minimum_nights                  0.2216658
## number_of_reviews               0.5107637
## calculated_host_listings_count  0.4544760
## availability_365               -0.6828263
    해석) PC1 365일 중, 가용 가능 날짜가 positive correlation 
          PC2 리뷰의 숫자가 가장 positve correlation 하다. 
          PC3 가격
          PC4 최소 숙박일이 낮아지면, listing_count 은 증가한다. 

sdev

## [1] 1.1694633 1.0645600 0.9845079 0.9334173 0.8115071

숫자형 변수만 추출하여, PCA 분석 결과, 전체 변동 중 50%의 변동은 PC1 (27.35%) 와 PC2 (22.67%)를 차지하고 있다. PC1 에서 listing_count 와 availability_365가 가장 많은 변동량을 설명하고 있고, PC2에서는 review의 갯수이다. 그 외 다른 숫자형 변수 들은 약간의 다중 공선성이 서로간 있어보인다.

## Importance of components:
##                           PC1    PC2    PC3    PC4    PC5
## Standard deviation     1.1695 1.0646 0.9845 0.9334 0.8115
## Proportion of Variance 0.2735 0.2267 0.1938 0.1742 0.1317
## Cumulative Proportion  0.2735 0.5002 0.6940 0.8683 1.0000

###(1) 각 PC축에 가깝게 평행을 이루는 변수가 해당 PC에 영향을 가장 많이 주는 변수.

: PC 1에 가장 영향을 많이 주는 변수는 host_listing 

###(2) 각 빨간선의 길이는 원변수의 분산을 표현, 길이가 길수록 분산이 길다.

: 그 다음으로 PC1 에 영향을 주는 변수는 mimum_nights 로 볼수 있다. 

###(3) 각 빨간선이 가까울수록 서로 상관관계가 있다. (반대로 서로 거리가 멀수록 상관관계가 적다.)

: listing_count, price, mimum_night는 상관관계가 높다고 판단됨 

PCA - Crime

범죄에 가장 연관성이 있는 변수들을 파악해보기

USArrest 데이터 세트 활용

## Importance of components:
##                           PC1    PC2     PC3     PC4
## Standard deviation     1.5749 0.9949 0.59713 0.41645
## Proportion of Variance 0.6201 0.2474 0.08914 0.04336
## Cumulative Proportion  0.6201 0.8675 0.95664 1.00000

Variance 가 1 이하로 넘어가지 않는걸 생각하면 2개의 주성분이 유효함

## [1] 1.5748783 0.9948694 0.5971291 0.4164494
##                 PC1        PC2        PC3         PC4
## Murder   -0.5358995  0.4181809 -0.3412327  0.64922780
## Assault  -0.5831836  0.1879856 -0.2681484 -0.74340748
## UrbanPop -0.2781909 -0.8728062 -0.3780158  0.13387773
## Rape     -0.5434321 -0.1673186  0.8177779  0.08902432

K-Means

K-mean 두가지 예제

Wholesale customers

##   Channel Region Fresh Milk Grocery Frozen Detergents_Paper Delicassen
## 1       2      3 12669 9656    7561    214             2674       1338
## 2       2      3  7057 9810    9568   1762             3293       1776
## 3       2      3  6353 8808    7684   2405             3516       7844
## 4       1      3 13265 1196    4221   6404              507       1788
## 5       2      3 22615 5410    7198   3915             1777       5185
## 6       2      3  9413 8259    5126    666             1795       1451

Channel 과 Region 변수를 바꿔주기

결측치 확인

##          Channel           Region            Fresh             Milk 
##                0                0                0                0 
##          Grocery           Frozen Detergents_Paper       Delicassen 
##                0                0                0                0

기술통계와 분포

##          Channel Region        Fresh         Milk      Grocery       Frozen
## median        NA     NA 8.504000e+03 3.627000e+03 4.755500e+03 1.526000e+03
## mean          NA     NA 1.200030e+04 5.796266e+03 7.951277e+03 3.071932e+03
## SE.mean       NA     NA 6.029377e+02 3.518457e+02 4.530455e+02 2.314375e+02
## CI.mean       NA     NA 1.185003e+03 6.915113e+02 8.904077e+02 4.548631e+02
## var           NA     NA 1.599549e+08 5.446997e+07 9.031010e+07 2.356785e+07
## std.dev       NA     NA 1.264733e+04 7.380377e+03 9.503163e+03 4.854673e+03
## coef.var      NA     NA 1.053918e+00 1.273299e+00 1.195174e+00 1.580332e+00
##          Detergents_Paper   Delicassen
## median       8.165000e+02 9.655000e+02
## mean         2.881493e+03 1.524870e+03
## SE.mean      2.272985e+02 1.344433e+02
## CI.mean      4.467286e+02 2.642325e+02
## var          2.273244e+07 7.952997e+06
## std.dev      4.767854e+03 2.820106e+03
## coef.var     1.654647e+00 1.849407e+00
##  Channel Region      Fresh             Milk          Grocery     
##  1:298   1: 77   Min.   :     3   Min.   :   55   Min.   :    3  
##  2:142   2: 47   1st Qu.:  3128   1st Qu.: 1533   1st Qu.: 2153  
##          3:316   Median :  8504   Median : 3627   Median : 4756  
##                  Mean   : 12000   Mean   : 5796   Mean   : 7951  
##                  3rd Qu.: 16934   3rd Qu.: 7190   3rd Qu.:10656  
##                  Max.   :112151   Max.   :73498   Max.   :92780  
##      Frozen        Detergents_Paper    Delicassen     
##  Min.   :   25.0   Min.   :    3.0   Min.   :    3.0  
##  1st Qu.:  742.2   1st Qu.:  256.8   1st Qu.:  408.2  
##  Median : 1526.0   Median :  816.5   Median :  965.5  
##  Mean   : 3071.9   Mean   : 2881.5   Mean   : 1524.9  
##  3rd Qu.: 3554.2   3rd Qu.: 3922.0   3rd Qu.: 1820.2  
##  Max.   :60869.0   Max.   :40827.0   Max.   :47943.0

K-mean 는 이상치의 영향을 많이 받기 때문에, 이상치를 제거해주는 것이 좋다.

##   Channel Region Fresh  Milk Grocery Frozen Detergents_Paper Delicassen
## 1       2      3    85 20959   45828     36            24231       1423
## 2       2      3    85 20959   45828     36            24231       1423
## 3       2      2  8565  4980   67298    131            38102       1215
## 4       2      2  8565  4980   67298    131            38102       1215
## 5       1      3 11314  3090    2062  35009               71       2698
## 6       2      3 16117 46197   92780   1026            40827       2944

중복을 제거하기 distinct 함수

## null device 
##           1

1.K 군집 개수 설정 (Elbow Method)

WSS 의 최소 지점 : 5 개

2.K 군집 개수 설정 (Silloutte Method)

K 는 3개

구매 데이터의 고객 클러스터링이기 때문에 K 가 5개 인게 나을것 같다

3.K-Means Modelling

## K-means clustering with 5 clusters of sizes 179, 42, 72, 110, 18
## 
## Cluster means:
##       Fresh      Milk   Grocery   Frozen Detergents_Paper Delicassen
## 1  4267.933  3751.480  4672.950 2211.313        1550.4469   1036.006
## 2 25332.000  5603.548  7160.024 4144.667        1449.2381   2053.333
## 3  5152.250 12536.694 19616.472 1644.014        8794.1389   1696.653
## 4 14527.509  2606.064  3503.873 3202.073         804.8091   1037.882
## 5 40558.056  3113.444  3814.333 2974.833         684.2778   1271.333
## 
## Clustering vector:
##   [1] 4 1 1 4 2 1 4 1 1 3 1 4 2 2 2 4 1 1 2 1 4 1 2 2 4 4 4 3 5 2 1 4 2 1 1 2 3
##  [38] 3 2 4 3 3 1 3 3 4 3 1 1 5 3 2 1 3 3 4 1 1 1 3 1 1 2 1 1 4 1 2 1 4 1 3 4 1
##  [75] 1 3 1 4 4 1 2 4 4 3 3 1 1 1 1 4 3 3 1 4 4 1 3 1 3 4 3 4 4 4 4 4 1 4 1 4 1
## [112] 4 4 5 4 2 1 5 1 1 4 4 1 1 1 1 4 1 4 2 5 4 4 3 1 1 1 5 4 1 4 1 1 3 3 4 1 3
## [149] 1 4 4 3 1 3 1 1 1 1 3 3 1 3 1 1 5 4 4 1 4 1 1 1 1 1 3 3 4 4 1 3 1 4 1 4 4
## [186] 3 3 2 1 1 3 1 1 1 3 4 3 1 1 1 3 3 4 3 1 4 1 1 1 1 4 2 1 1 1 4 1 2 1 4 1 1
## [223] 4 1 5 2 2 4 4 1 3 1 4 4 1 1 3 1 2 1 5 4 1 5 1 1 2 1 3 3 3 4 3 4 1 1 1 5 1
## [260] 1 2 4 4 4 1 4 5 2 5 1 4 4 5 1 1 1 3 2 1 4 1 1 1 4 3 1 3 3 1 3 4 1 3 1 2 3
## [297] 4 4 3 1 1 4 3 1 1 4 4 2 1 1 4 1 4 3 2 4 2 4 4 1 1 1 1 1 3 1 1 3 2 1 3 1 3
## [334] 1 3 4 1 4 3 1 1 4 1 1 1 1 1 4 1 2 1 5 4 1 4 1 1 3 5 1 1 2 4 5 1 3 4 1 4 4
## [371] 4 1 1 1 2 4 4 1 4 4 4 1 2 2 2 4 1 2 3 1 1 1 1 1 1 1 1 3 1 3 1 3 4 2 4 4 4
## [408] 3 2 1 1 1 1 4 1 4 2 5 3 4 1
## 
## Within cluster sum of squares by cluster:
## [1] 7488224454 2823135964 9143410363 3900150510  861057236
##  (between_SS / total_SS =  70.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

4.시각화

##   Channel Region Fresh Milk Grocery Frozen Detergents_Paper Delicassen cluster
## 1       2      3 12669 9656    7561    214             2674       1338       4
## 2       2      3  7057 9810    9568   1762             3293       1776       1
## 3       2      3  6353 8808    7684   2405             3516       7844       1
## 4       1      3 13265 1196    4221   6404              507       1788       4
## 5       2      3 22615 5410    7198   3915             1777       5185       2
## 6       2      3  9413 8259    5126    666             1795       1451       1

Arbnb

## 'data.frame':    48895 obs. of  16 variables:
##  $ id                            : int  2539 2595 3647 3831 5022 5099 5121 5178 5203 5238 ...
##  $ name                          : chr  "Clean & quiet apt home by the park" "Skylit Midtown Castle" "THE VILLAGE OF HARLEM....NEW YORK !" "Cozy Entire Floor of Brownstone" ...
##  $ host_id                       : int  2787 2845 4632 4869 7192 7322 7356 8967 7490 7549 ...
##  $ host_name                     : chr  "John" "Jennifer" "Elisabeth" "LisaRoxanne" ...
##  $ neighbourhood_group           : chr  "Brooklyn" "Manhattan" "Manhattan" "Brooklyn" ...
##  $ neighbourhood                 : chr  "Kensington" "Midtown" "Harlem" "Clinton Hill" ...
##  $ latitude                      : num  40.6 40.8 40.8 40.7 40.8 ...
##  $ longitude                     : num  -74 -74 -73.9 -74 -73.9 ...
##  $ room_type                     : chr  "Private room" "Entire home/apt" "Private room" "Entire home/apt" ...
##  $ price                         : int  149 225 150 89 80 200 60 79 79 150 ...
##  $ minimum_nights                : int  1 1 3 1 10 3 45 2 2 1 ...
##  $ number_of_reviews             : int  9 45 0 270 9 74 49 430 118 160 ...
##  $ last_review                   : chr  "2018-10-19" "2019-05-21" "" "2019-07-05" ...
##  $ reviews_per_month             : num  0.21 0.38 NA 4.64 0.1 0.59 0.4 3.47 0.99 1.33 ...
##  $ calculated_host_listings_count: int  6 2 1 1 1 1 1 1 1 4 ...
##  $ availability_365              : int  365 355 365 194 0 129 0 220 0 188 ...

LS0tDQp0aXRsZTogIlVuc3VwZXJ2aXNlZCBNYWNoaW5lIExlYXJuaW5nIg0KYXV0aG9yOiAiRE9FVU4iDQpkYXRlOiAiMjMvMDIvMjAyMSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgICMgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgIyBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZmxhdGx5Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUpDQoNCiNpbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIsIGRlcGVuZGVuY2llcz1UUlVFKSANCiNpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpDQoNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KERUKQ0KbGlicmFyeShnZ2ZvcnRpZnkpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkocGFzdGVjcykNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkocHN5Y2gpDQpgYGANCg0KIyBQQ0EgLSBJcmlzIA0KDQpTcGVjaWVzIC0g67KU7KO8DQoNCuuCmOuouOyngCAtIOyXsOyGje2YlSANCmBgYHtyIGNhcnN9DQoNCmhlYWQoaXJpcykNCmBgYA0KDQoyLiDqsrDsuKHsuZgg7ZmV7J24IA0KDQpgYGB7ciBwcmVzc3VyZSwgZWNobz1GQUxTRX0NCg0KY29sU3Vtcyhpcy5uYShpcmlzKSkNCg0KYGBgDQoNCg0KMy4g67OA7IiY67OEIOq4sOyIoCDthrXqs4Qg67CPIOu2hO2PrCDtmZXsnbggDQoNCuykkeychOyImOyZgCDtj4nqt6DsnZgg7LCo7J206rCAIO2BrOuptCwg7J207IOB7LmY6rCAIOunjuuLpOuKlCDsnZjrr7jroZwg67O8IOyImCDsnojri6QuICjspJHsmpQpDQoNCmBgYHtyfQ0KDQpzdW1tYXJ5KGlyaXMpDQpgYGANCg0KDQpgYGB7cn0NCg0KYm94cGxvdChpcmlzWywxOjRdKQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KcHJjb21wKGlyaXNbLDE6NF0sIA0KICAgICAgIGNlbnRlciA9IFQsIA0KICAgICAgIHNjYWxlLiA9IFQpIC0+aXJpcy5wY2EgICNzY2FsZSDtj4nqt6AgMCwg67aE7IKwIDEg7J2865WMIOyymOumrO2VtOyjvOq4sCANCg0Kc3VtbWFyeShpcmlzLnBjYSkNCg0KYGBgDQoNCiAgICAgICBTdGFuZGFyZCBEZXZpYXRpb24gOiDsoJzqs7EgPSDrtoTsgrAgPSBlaWdlbnZhbHVlIA0KICAgICAgIFByb3BvcnRhaW9uIG9mIFZhcmlhbmNlIDog7KCE7LK0IOu2hOyCsOyXkOyEnCDssKjsp4DtlZjripQg67mE7JyoIA0KICAgICAgIEN1bWxhdGl2ZSBQcm9wb3J0aW9uIDog64iE7KCBIOu5hOycqCANCiAgICAgICANCiAgICAgICANCiAgICAgICBQQyAx7J2AIDcyLjklIOyghOyytCDrs4Drj5nrn4nsnYQg7ISk66qF7ZWc64ukIA0KICAgICAgIFBDIDEgKyBQQyAyIOuKlCA5NS44MSXrpbwg7ISk66qF7ZWc64ukLiANCg0KDQoqKipSb3RhdGlvbioqKg0KDQrqsIEg7KO87ISx67aE65Ok7J2YIGVpZ2VudmVjdG9yICg9IOqwgSDrs4DsiJjrk6TsnZgg6rCA7KSR7LmYKQ0KDQoNCmBgYHtyfQ0KDQppcmlzLnBjYSRyb3RhdGlvbg0KYGBgDQoNCioqKlgqKioNCg0KYGBge3J9DQoNCg0KaGVhZChpcmlzLnBjYSR4KQ0KYGBgDQoNCg0KKioqU2NyZWUgUGxvdCAqKioNCg0KDQpgYGB7cn0NCnBsb3QoaXJpcy5wY2EsIA0KICAgICB0eXBlPSdsJywgDQogICAgIG1haW4gPSAnc2NyZWUgcGxvdCcpDQpgYGANCg0KMS4g7Iuc6rCB7ZmUIOq4sOykgCAyIG9yIDMg6rCcIA0KMi4gRWlnZW52YWx1ZSA+IDEg6riw7KSA7Jy866GcIA0KMy4gU2NyZWUgcGxvdCDsl5DshJzsnZggZWxib3cgcG9pbnQg66W8IOyEpOygle2VnOuLpC4gDQoNCjMg67KI7KiwIOyjvOyEseu2hOq5jOyngCDshKDtg53tlZjrqbQg7JWI65CY64qUIOydtOycoCANCi0+IFZhcmlhbmNlIOuKlCAgZWlnZW52YWx1ZSDsnbjrjbAgMSDsnbTtlZgg7J6E7Jy866GcLCAy6rCc7J2YIOyjvOyEseu2hOydtCDsoIHri7ntlZjri6QuIA0KDQo0LiDssKjsm5Ag7LaV7IaMIA0KDQoyIOqwnOydmCDssKjsm5DsnLzroZwg7LaV7IaMIA0KDQpgYGB7cn0NCmhlYWQoaXJpcy5wY2EkeFssMToyXSwgMTApDQpgYGANCg0KNS4gMiDssKjsm5Ag7Iuc6rCB7ZmUIA0KDQpgYGB7cn0NCg0KYXV0b3Bsb3QoaXJpcy5wY2EsIA0KICAgICAgICAgZGF0YT1pcmlzLA0KICAgICAgICAgY29sb3VyPSAnU3BlY2llcycpDQpgYGANCg0KNi4g6rOg6riJIOyLnOqwge2ZlCAtMSANCg0KYGBge3J9DQoNCmZ2aXpfcGNhX2JpcGxvdChpcmlzLnBjYSwgDQogICAgICAgICAgICAgICAgIyBJbmRpdmlkdWFscw0KICAgICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwNCiAgICAgICAgICAgICAgICBmaWxsLmluZCA9IGlyaXMkU3BlY2llcywgY29sLmluZCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgcG9pbnRzaGFwZSA9IDIxLCBwb2ludHNpemUgPSAyLA0KICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwNCiAgICAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgIyBWYXJpYWJsZXMNCiAgICAgICAgICAgICAgICBhbHBoYS52YXIgPSJjb250cmliIiwgY29sLnZhciA9ICJjb250cmliIiwNCiAgICAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gIlJkWWxCdSIsDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gbGlzdChmaWxsID0gIlNwZWNpZXMiLCBjb2xvciA9ICJDb250cmliIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gIkNvbnRyaWIiKSkNCmBgYA0KDQrqs6DquIkg7Iuc6rCB7ZmULTIgDQoNCmBgYHtyfQ0KZnZpel9wY2FfYmlwbG90KGlyaXMucGNhLCANCiAgICAgICAgICAgICAgICAjIEZpbGwgaW5kaXZpZHVhbHMgYnkgZ3JvdXBzDQogICAgICAgICAgICAgICAgZ2VvbS5pbmQgPSAicG9pbnQiLA0KICAgICAgICAgICAgICAgIHBvaW50c2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICBwb2ludHNpemUgPSAyLjUsDQogICAgICAgICAgICAgICAgZmlsbC5pbmQgPSBpcmlzJFNwZWNpZXMsDQogICAgICAgICAgICAgICAgY29sLmluZCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgIyBDb2xvciB2YXJpYWJsZSBieSBncm91cHMNCiAgICAgICAgICAgICAgICBjb2wudmFyID0gZmFjdG9yKGMoInNlcGFsIiwgInNlcGFsIiwgInBldGFsIiwgInBldGFsIikpLA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGxpc3QoZmlsbCA9ICJTcGVjaWVzIiwgY29sb3IgPSAiQ2x1c3RlcnMiKSwNCiAgICAgICAgICAgICAgICByZXBlbCA9IFRSVUUpICsNCiAgZ2dwdWJyOjpmaWxsX3BhbGV0dGUoImpjbyIpDQpgYGANCg0KDQogViDqsIDquYzsmrQg6rGw66asL+uwqe2WpeyEsSA9IOyDgeq0gOyEsSDspp3qsIAgDQogUEMxIChESU0xKSDquLDspIAg7KKM7JqwIC8gUEMyKERJTTIpIOq4sOykgCDsg4HtlZggDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQojIFBDQSAtIEFpckJuQiANCg0KDQoyMDA464WEIOydtO2bhCwg6rKM7Iqk7Yq47JmAIO2YuOyKpO2KuOuKlCDsl6ztlonsnbTrgpgsIOyigCDrjZQg7IOJ64uk66W06rOgLCDqsJzrs4TsoIHsnbgg7Jes7ZaJIOqyve2XmOydhCDslrvqs6DsnpAg7JeQ7Ja067mE7JeU67mE66W8IOyCrOyaqe2VmOyYgOuLpC4gDQoNCg0KQ29sdW1uIEJvb2tzIA0KDQppZGxpc3Rpbmc6IElEDQpuYW1lOiBuYW1lIG9mIHRoZSBsaXN0aW5nDQpob3N0X2lkOiBob3N0IElEDQpob3N0X25hbWU6IG5hbWUgb2YgdGhlIGhvc3QNCm5laWdoYm91cmhvb2RfZ3JvdXBsb2NhdGlvbjogbmVpZ2hib3VyaG9vZGFyZWENCmxhdGl0dWRlOiBsYXRpdHVkZSBjb29yZGluYXRlcw0KbG9uZ2l0dWRlOiBsb25naXR1ZGUgY29vcmRpbmF0ZXMNCnJvb21fdHlwZWxpc3Rpbmc6IHNwYWNlIHR5cGUNCnByaWNlOiBwcmljZSBpbiBkb2xsYXJzDQptaW5pbXVtX25pZ2h0OiBzYW1vdW50IG9mIG5pZ2h0cyBtaW5pbXVtDQpudW1iZXJfb2ZfcmV2aWV3czogbnVtYmVyIG9mIHJldmlld3MNCmxhc3RfcmV2aWV3OiBsYXRlc3QgcmV2aWV3DQpyZXZpZXdzX3Blcl9tb250aDogbnVtYmVyIG9mIHJldmlld3MgcGVyIG1vbnRoDQpjYWxjdWxhdGVkX2hvc3RfbGlzdGluZ3NfY291bnQ6IGFtb3VudCBvZiBsaXN0aW5nIHBlciBob3N0DQphdmFpbGFiaWxpdHlfMzY1OiBudW1iZXIgb2YgZGF5cyB3aGVuIGxpc3RpbmcgaXMgYXZhaWxhYmxlIGZvciBib29raW5nDQoNCioqKkRhdGEgUHJlIFByb2Nlc3NpbmcqKioNCg0KYGBge3J9DQoNCnNldHdkKCJDOi9Vc2Vycy9BZG1pbmlzdHJhdG9yL0Rlc2t0b3AvUiBBbmFseXNpcy9CdXNpbmVzcyBSIEFhbmx5c2lzIHNvdXJjZSIpDQoNCnJlYWQuY3N2KCJBQl9OWUNfMjAxOS5jc3YiKSAtPiBkZg0KDQpzdHIoZGYpDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpkZiAlPiUgIA0KICBzZWxlY3QoLXJldmlld3NfcGVyX21vbnRoLCAtbGFzdF9yZXZpZXcsIC1sYXRpdHVkZSwgLWxvbmdpdHVkZSkgJT4lICANCiAgbXV0YXRlKG5hbWUgPSBhcy5jaGFyYWN0ZXIobmFtZSksIA0KICAgICAgICAgaWQgPSBhcy5jaGFyYWN0ZXIoaWQpLCANCiAgICAgICAgIGhvc3RfaWQ9IGFzLmNoYXJhY3Rlcihob3N0X2lkKSwgDQogICAgICAgICBob3RzX25hbWUgPSBhcy5jaGFyYWN0ZXIoaG9zdF9uYW1lKSwNCiAgICAgICAgIHByaWNlID0gYXMubnVtZXJpYyhwcmljZSkpIC0+IGRmXzINCmBgYA0KDQoNCioqKk51bWVyaWMg66eMIOy2lOy2nCoqKg0KDQogDQpgYGB7cn0NCg0KZGZfbnVtIDwtZGZfMiAlPiUgDQogIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KDQoNCg0KZGZfbm9uX251bWVyaWMgPC1kZl8yICU+JSANCiAgc2VsZWN0X2lmKE5lZ2F0ZShpcy5udW1lcmljKSkNCmBgYA0KDQoqKipEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzKioqDQoNCmBgYHtyfQ0KDQoNCnJvdW5kKHN0YXQuZGVzYyhkZl9udW0sIGJhc2ljPUYpLCBkaWdpdD0zKSAtPnN0YXRpc3RpY190YWJsZQ0KDQoNCmRhdGF0YWJsZShzdGF0aXN0aWNfdGFibGUpDQpgYGANCg0KDQpgYGB7cn0NCg0KYm94cGxvdChkZl9udW0pDQoNCmBgYA0KDQoqKipDb3JyZWxhdGlvbioqKg0KDQpgYGB7cn0NCg0KY29yKGRmX251bSwgbWV0aG9kPSJwZWFyc29uIikNCmBgYA0KDQoNCg0KKioqUENBIEFuYWx5c2lzKioqDQpgYGB7cn0NCg0KcHJjb21wKGRmX251bSwgDQogICAgICAgY2VudGVyPVQsDQogICAgICAgc2NhbGU9VCkgLT5wY2FfYmFiDQoNCg0Kc3VtbWFyeShwY2FfYmFiKQ0KDQpgYGANCg0KUEMgNOqwgCA4Ni44MyXsnZgg67OA64+Z66Wg7J2EIOyEpOuqhe2VmOuKlCDqsoPsnLzroZwgNOqwnOqwgCDsoIHri7ntlbTrs7Tsnbjri6QuIA0KDQoNCmBgYHtyfQ0KcGxvdChwY2FfYmFiLCANCiAgICAgdHlwZT0nbCcsIA0KICAgICBtYWluID0gJ3NjcmVlIHBsb3QnKQ0KYGBgDQoNClgNCg0KYGBge3J9DQoNCmhlYWQocGNhX2JhYiR4WywxOjVdLCA1KQ0KYGBgDQoNClJvdGF0aW9uIC0gZWlnZW52ZWN0b3JzIA0KDQpgYGB7cn0NCg0KcGNhX2JhYiRyb3RhdGlvbg0KYGBgDQoNCg0KICAgICAgICDtlbTshJ0pIFBDMSAzNjXsnbwg7KSRLCDqsIDsmqkg6rCA64qlIOuCoOynnOqwgCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiANCiAgICAgICAgICAgICAgUEMyIOumrOu3sOydmCDsiKvsnpDqsIAg6rCA7J6lIHBvc2l0dmUgY29ycmVsYXRpb24g7ZWY64ukLiANCiAgICAgICAgICAgICAgUEMzIOqwgOqyqQ0KICAgICAgICAgICAgICBQQzQg7LWc7IaMIOyImeuwleydvOydtCDrgq7slYTsp4DrqbQsIGxpc3RpbmdfY291bnQg7J2AIOymneqwgO2VnOuLpC4gDQoNCg0Kc2RldiANCg0KYGBge3J9DQoNCnBjYV9iYWIkc2Rldg0KYGBgDQoNCg0KYGBge3J9DQoNCnBsb3Qoc3VtbWFyeShwY2FfYmFiKSRpbXBvcnRhbmNlWzMsXSkNCmBgYA0KDQoNCmBgYHtyfQ0KDQpmdml6X2VpZyhwY2FfYmFiKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmZ2aXpfcGNhX3ZhcihwY2FfYmFiLCBjb2wudmFyID0gImJsYWNrIikNCmBgYA0KDQrsiKvsnpDtmJUg67OA7IiY66eMIOy2lOy2nO2VmOyXrCwgUENBIOu2hOyEnSDqsrDqs7wsIOyghOyytCDrs4Drj5kg7KSRIDUwJeydmCDrs4Drj5nsnYAgUEMxICgyNy4zNSUpIOyZgCBQQzIgKDIyLjY3JSnrpbwg7LCo7KeA7ZWY6rOgIOyeiOuLpC4NClBDMSDsl5DshJwgbGlzdGluZ19jb3VudCDsmYAgYXZhaWxhYmlsaXR5XzM2NeqwgCDqsIDsnqUg66eO7J2AIOuzgOuPmeufieydhCDshKTrqoXtlZjqs6Ag7J6I6rOgLCBQQzLsl5DshJzripQgcmV2aWV37J2YIOqwr+yImOydtOuLpC4g6re4IOyZuCDri6Trpbgg7Iir7J6Q7ZiVIOuzgOyImCDrk6TsnYAg7JW96rCE7J2YIA0K64uk7KSRIOqzteyEoOyEseydtCDshJzroZzqsIQg7J6I7Ja067O07J2464ukLiANCg0KYGBge3J9DQoNCmZ2aXpfcGNhX2luZChwY2FfYmFiLCBjb2wuaW5kPSJjb3MyIiwgZ2VvbSA9ICJwb2ludCIsIGdyYWRpZW50LmNvbHMgPSBjKCJ3aGl0ZSIsICIjMkU5RkRGIiwgIiNGQzRFMDciICkpDQpgYGANCg0KDQpgYGB7cn0NCnN1bW1hcnkocGNhX2JhYikNCmBgYA0KDQpgYGB7cn0NCmZ2aXpfZWlnKHBjYV9iYWIpDQpgYGANCg0KDQpgYGB7cn0NCmZ2aXpfcGNhX3ZhcihwY2FfYmFiKQ0KYGBgDQoNCiMjIygxKSDqsIEgUEPstpXsl5Ag6rCA6rmd6rKMIO2Pie2WieydhCDsnbTro6jripQg67OA7IiY6rCAIO2VtOuLuSBQQ+yXkCDsmIHtlqXsnYQg6rCA7J6lIOunjuydtCDso7zripQg67OA7IiYLg0KDQoNCiAgICA6IFBDIDHsl5Ag6rCA7J6lIOyYge2WpeydhCDrp47snbQg7KO864qUIOuzgOyImOuKlCBob3N0X2xpc3RpbmcgDQoNCiMjIygyKSDqsIEg67mo6rCE7ISg7J2YIOq4uOydtOuKlCDsm5Drs4DsiJjsnZgg67aE7IKw7J2EIO2RnO2YhCwg6ri47J206rCAIOq4uOyImOuhnSDrtoTsgrDsnbQg6ri464ukLg0KDQogICAgOiDqt7gg64uk7J2M7Jy866GcIFBDMSDsl5Ag7JiB7Zal7J2EIOyjvOuKlCDrs4DsiJjripQgbWltdW1fbmlnaHRzIOuhnCDrs7zsiJgg7J6I64ukLiANCiAgICANCiMjIygzKSDqsIEg67mo6rCE7ISg7J20IOqwgOq5jOyauOyImOuhnSDshJzroZwg7IOB6rSA6rSA6rOE6rCAIOyeiOuLpC4gKOuwmOuMgOuhnCDshJzroZwg6rGw66as6rCAIOupgOyImOuhnSDsg4HqtIDqtIDqs4TqsIAg7KCB64ukLikNCg0KICAgIDogbGlzdGluZ19jb3VudCwgcHJpY2UsIG1pbXVtX25pZ2h064qUIOyDgeq0gOq0gOqzhOqwgCDrhpLri6Tqs6Ag7YyQ64uo65CoIA0KICAgIA0KDQojIFBDQSAtIENyaW1lIA0KDQrrspTso4Tsl5Ag6rCA7J6lIOyXsOq0gOyEseydtCDsnojripQg67OA7IiY65Ok7J2EIO2MjOyVhe2VtOuztOq4sCANCg0KVVNBcnJlc3Qg642w7J207YSwIOyEuO2KuCDtmZzsmqkgDQoNCmBgYHtyfQ0KDQpkYXRhKCJVU0FycmVzdHMiKQ0KDQoNCg0Kcm91bmQoc3RhdC5kZXNjKFVTQXJyZXN0cyksIGRpZ2l0cyA9IDMpLT5kZg0KDQpEVDo6ZGF0YXRhYmxlKGRmKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmJveHBsb3QoVVNBcnJlc3RzKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoY29ycnBsb3QpDQpjb3IoVVNBcnJlc3RzLCBtZXRob2QgPSAicGVhcnNvbiIpIC0+IGNvcnINCg0KY29ycnBsb3QoY29yciwgbWV0aG9kID0gIm51bWJlciIpIC0+IGNvcnJfaW1hZ2UNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpwcmNvbXAoVVNBcnJlc3RzLCBzY2FsZSA9IFQpIC0+cGNhX2NyaW1lDQoNCnN1bW1hcnkocGNhX2NyaW1lKQ0KYGBgDQoNCg0KYGBge3J9DQoNCnNjcmVlcGxvdChwY2FfY3JpbWUsIHR5cGU9J2wnKQ0KDQpgYGANCg0KVmFyaWFuY2Ug6rCAIDEg7J207ZWY66GcIOuEmOyWtOqwgOyngCDslYrripTqsbgg7IOd6rCB7ZWY66m0IDLqsJzsnZgg7KO87ISx67aE7J20IOycoO2aqO2VqCANCg0KYGBge3J9DQoNCnBjYV9jcmltZSRzZGV2DQoNCmBgYA0KDQpgYGB7cn0NCnBjYV9jcmltZSRyb3RhdGlvbg0KYGBgDQoNCg0KYGBge3J9DQoNCmZ2aXpfZWlnKHBjYV9jcmltZSkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmZ2aXpfcGNhKHBjYV9jcmltZSwgDQogICAgICAgICBsYWJlbHNpemU9MykrdGhlbWVfYncoKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmZ2aXpfcGNhX3ZhcihwY2FfY3JpbWUpDQpgYGANCg0KDQpgYGB7cn0NCg0KZnZpel9jb250cmliKHBjYV9jcmltZSwgY2hvaWNlID0gInZhciIsIGF4ZXM9MSkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmZ2aXpfcGNhX3ZhcihwY2FfY3JpbWUsIGNvbC52YXIgPSAiY29udHJpYiIsDQogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikpDQpgYGANCg0KIyBLLU1lYW5zIHsudGFic2V0IH0NCg0KSy1tZWFuIOuRkOqwgOyngCDsmIjsoJwgDQoNCiMjIFdob2xlc2FsZSBjdXN0b21lcnMNCg0KDQpgYGB7cn0NCg0Kc2V0d2QoIkM6L1VzZXJzL0FkbWluaXN0cmF0b3IvRGVza3RvcC9SIEFuYWx5c2lzL0Zhc3QgQ2FtcHVzIikNCg0KcmVhZC5jc3YoIldob2xlc2FsZSBjdXN0b21lcnMgZGF0YS5jc3YiLCBoZWFkZXIgPSBULCANCiAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKSAtPiBkZg0KDQpgYGANCg0KDQpgYGB7cn0NCmhlYWQoZGYpDQoNCmBgYA0KDQpDaGFubmVsIOqzvCBSZWdpb24g67OA7IiY66W8IOuwlOq/lOyjvOq4sCANCg0KYGBge3J9DQoNCmRmJENoYW5uZWwgPC0gYXMuZmFjdG9yKGRmJENoYW5uZWwpDQpkZiRSZWdpb24gPC0gYXMuZmFjdG9yKGRmJFJlZ2lvbikNCg0KYGBgDQoNCuqysOy4oey5mCDtmZXsnbggDQoNCg0KYGBge3J9DQpjb2xTdW1zKGlzLm5hKGRmKSkNCg0KYGBgDQoNCuq4sOyIoO2GteqzhOyZgCDrtoTtj6wgDQoNCmBgYHtyfQ0KDQpzdGF0LmRlc2MoZGYsICBiYXNpYyA9IEYpDQpzdW1tYXJ5KGRmKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmJveHBsb3QoZGZbLDM6bmNvbChkZildKSAjbmNvbCA6IOyghOyytCDsl7TsnZgg642w7J207YSw66W8IOqwgOyguOyYpOq4sCANCmBgYA0KDQpLLW1lYW4g64qUIOydtOyDgey5mOydmCDsmIHtlqXsnYQg66eO7J20IOuwm+q4sCDrlYzrrLjsl5AsIOydtOyDgey5mOulvCDsoJzqsbDtlbTso7zripQg6rKD7J20IOyii+uLpC4gDQoNCmBgYHtyfQ0KDQp0ZW1wIDwtTlVMTCANCg0KDQpmb3IoaSBpbiAzOm5jb2woZGYpKSB7DQogICAgdGVtcCA8LXJiaW5kKHRlbXAsIGRmW29yZGVyKGRmWyxpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBUKSxdIA0KICAgICU+JSBzbGljZSgxOjUpKQ0KfQ0KDQoNCnRlbXAgJT4lIA0KICBhcnJhbmdlKEZyZXNoKSAlPiUgDQogIGhlYWQoKQ0KDQoj67O17JuQIOy2lOy2nCDrsKnsi53snLzroZwg7KSR67O17J20IOuwnOyDne2VnOuLpA0KDQpgYGANCg0K7KSR67O17J2EIOygnOqxsO2VmOq4sCBkaXN0aW5jdCDtlajsiJggDQoNCmBgYHtyfQ0KdGVtcCA8LWRpc3RpbmN0KHRlbXApDQoNCmFudGlfam9pbihkZiwgdGVtcCkgLT4gZGYucm0ub3V0bGllciANCg0KIyBkZuyXkOyEnCB0ZW1wIOuCtOyaqeydhCDsp4Dsm4zrnbwgDQpgYGANCg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93ID0gYygxLDIpKQ0KYm94cGxvdChkZlssMzpuY29sKGRmKV0pDQpib3hwbG90KGRmLnJtLm91dGxpZXJbLDM6bmNvbChkZildKQ0KDQpgYGANCg0KYGBge3J9DQpkZXYub2ZmKCkNCmBgYA0KDQoxLksg6rWw7KeRIOqwnOyImCDshKTsoJUgKEVsYm93IE1ldGhvZCkNCg0KV1NTIOydmCDstZzshowg7KeA7KCQIDogNSDqsJwgDQoNCmBgYHtyfQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0Kc2V0LnNlZWQoMTIzNCkNCg0KZnZpel9uYmNsdXN0KGRmLnJtLm91dGxpZXJbLCAzOm5jb2woZGYucm0ub3V0bGllcildLCANCiAgICAgICAgICAgICBrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiLCBrLm1heCA9IDE1KSsgDQogIHRoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KDQoyLksg6rWw7KeRIOqwnOyImCDshKTsoJUgKFNpbGxvdXR0ZSBNZXRob2QpDQoNCksg64qUIDPqsJwgDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzNCkNCg0KZnZpel9uYmNsdXN0KGRmLnJtLm91dGxpZXJbLCAzOm5jb2woZGYucm0ub3V0bGllcildLCANCiAgICAgICAgICAgICBrbWVhbnMsIG1ldGhvZCA9ICJzaWxob3VldHRlIiwgay5tYXggPSAxNSkrIA0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCg0K6rWs66ekIOuNsOydtO2EsOydmCDqs6DqsJ0g7YG065+s7Iqk7YSw66eB7J206riwIOuVjOusuOyXkCBLIOqwgCA16rCcIOyduOqyjCDrgpjsnYTqsoMg6rCZ64ukIA0KDQozLkstTWVhbnMgTW9kZWxsaW5nIA0KDQpgYGB7cn0NCg0Ka21lYW5zKGRmLnJtLm91dGxpZXJbLDM6bmNvbChkZi5ybS5vdXRsaWVyKV0sIA0KICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gNSwgDQogICAgICAgICAgICAgICAgICAgICBpdGVyLm1heD0gMTAwMCkgLT4gZGYua21lYW5zDQoNCiNpdGVyLm1heCA6IOq1sOynke2ZlCDtm4QsIOyerCDqtbDsp5HtmZQg6rO87KCV7JeQ7IScIOuqh+uyiCDrsJjrs7Ug7Iuc7YKsIOqyg+yduOqwgCANCg0KZGYua21lYW5zDQpgYGANCg0KNC7si5zqsIHtmZQgDQpgYGB7cn0NCmJhcnBsb3QodChkZi5rbWVhbnMkY2VudGVycyksIGJlc2lkZT1UUlVFLCBjb2wgPSAxOjYpDQpsZWdlbmQoInRvcGxlZnQiLCBjb2xuYW1lcyhkZlssMzo4XSksIGZpbGwgPSAxOjYsIGNleCA9IDAuNSkNCmBgYA0KDQpgYGB7cn0NCg0KZGYucm0ub3V0bGllciRjbHVzdGVyIDwtIGRmLmttZWFucyRjbHVzdGVyDQoNCmhlYWQoZGYucm0ub3V0bGllcikNCmBgYA0KDQojIyBBcmJuYiAgDQoNCmBgYHtyfQ0Kc2V0d2QoIkM6L1VzZXJzL0FkbWluaXN0cmF0b3IvRGVza3RvcC9SIEFuYWx5c2lzL0J1c2luZXNzIFIgQWFubHlzaXMgc291cmNlIikNCg0KcmVhZC5jc3YoIkFCX05ZQ18yMDE5LmNzdiIpIC0+IGRmDQoNCnN0cihkZikNCg0KZGYgJT4lICANCiAgc2VsZWN0KC1yZXZpZXdzX3Blcl9tb250aCwgLWxhc3RfcmV2aWV3LCAtbGF0aXR1ZGUsIC1sb25naXR1ZGUpICU+JSAgDQogIG11dGF0ZShuYW1lID0gYXMuY2hhcmFjdGVyKG5hbWUpLCANCiAgICAgICAgIGlkID0gYXMuY2hhcmFjdGVyKGlkKSwgDQogICAgICAgICBob3N0X2lkPSBhcy5jaGFyYWN0ZXIoaG9zdF9pZCksIA0KICAgICAgICAgaG90c19uYW1lID0gYXMuY2hhcmFjdGVyKGhvc3RfbmFtZSksDQogICAgICAgICBwcmljZSA9IGFzLm51bWVyaWMocHJpY2UpKSAtPiBkZl8yDQoNCg0KZGZfbnVtIDwtZGZfMiAlPiUgDQogIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmJveHBsb3QoZGZfbnVtKSAgICANCmBgYA0KDQoNCg0KYGBge3J9DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgcHJpY2Ug67aA67aE7J2YIG91dGxpZXIg7IKt7KCcIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCg0KZGZfbnVtICU+JSANCiAgZmlsdGVyKGF2YWlsYWJpbGl0eV8zNjUgPT0gMCkgLT4gdGVtcA0KDQphbnRpX2pvaW4oZGZfbnVtLCB0ZW1wKSAtPiBkZl9udW1fb3V0bGllcg0KDQpkZl9udW1fb3V0bGllciAlPiUgDQogIGZpbHRlcihwcmljZSA+PSA5MDAwICkgLT4gdGVtcF8yDQoNCg0KYW50aV9qb2luKGRmX251bV9vdXRsaWVyLCB0ZW1wXzIpIC0+IGRmXzINCg0KYm94cGxvdChkZl8yJHByaWNlKQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgU2NhbGluZyANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KDQpkZl9udW1fc2NhbGUgPC0gYXMuZGF0YS5mcmFtZShzY2FsZShkZl8yKSkNCg0Ka21lYW5zKGRmX251bV9zY2FsZSw3KSAtPiBkZl9rbQ0KDQpmdml6X2NsdXN0ZXIoZGZfa20sIA0KICAgICAgICAgICAgIGRhdGE9ZGZfbnVtX3NjYWxlKSsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBLIOywvuq4sCAtIG1hbnVhbCANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBEZXRlcm1pbmUgSw0Kd3NzIDwtIGZ1bmN0aW9uKGRhdGEsIG1heENsdXN0ZXIgPSAyMCkgew0KICAjIEluaXRpYWxpemUgd2l0aGluIHN1bSBvZiBzcXVhcmVzDQogIFNTdyA8LSAobnJvdyhkYXRhKSAtIDEpICogc3VtKGFwcGx5KGRhdGEsIDIsIHZhcikpDQogIFNTdyA8LSB2ZWN0b3IoKQ0KICBmb3IgKGkgaW4gMjptYXhDbHVzdGVyKSB7DQogICAgU1N3W2ldIDwtIHN1bShrbWVhbnMoZGF0YSwgY2VudGVycyA9IGkpJHdpdGhpbnNzKQ0KICB9DQogIHBsb3QoMTptYXhDbHVzdGVyLCBTU3csIHR5cGUgPSAibyIsIHhsYWIgPSAiTnVtYmVyIG9mIENsdXN0ZXJzIiwgeWxhYiA9ICJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIiwgcGNoPTE5KQ0KfQ0KDQp3c3MoZGZfbnVtX3NjYWxlKSAgIyM46rCcIA0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQprbWVhbnMoZGZfbnVtX3NjYWxlLCA4KSAtPiBkZl9rbTgNCg0KDQpmdml6X2NsdXN0ZXIoZGZfa204LCANCiAgICAgICAgICAgICBkYXRhPWRmX251bV9zY2FsZSkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmRmX2ttOCRjbHVzdGVyIC0+IGRmXzIkY2x1c3Rlcg0KDQoNCmJhcnBsb3QodChkZl9rbTgkY2VudGVycyksIGJlc2lkZT1UUlVFLCBjb2wgPSAxOjgpDQpsZWdlbmQoInRvcGxlZnQiLCBjb2xuYW1lcyhkZl8yWywxOjRdKSwgZmlsbD0xOjgsIGNleD0wLjUpDQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg==