rm(list=ls(all=T))
options(digits=4, scipen=12)
library(dplyr); library(ggplot2)

Introduction

議題:使用歌曲的屬性,預測它會不會進入流行歌曲排行榜的前10名

學習重點:



1 基本的資料處理 Understanding the Data

1.1】How many observations (songs) are from the year 2010?

songs=read.csv('./data/songs.csv')
nrow(songs)
[1] 7574

1.2】How many songs does the dataset include for which the artist name is “Michael Jackson”?

library(dplyr)
(songs$artistname=='Michael Jackson') %>% sum
[1] 18

1.3】Which of these songs by Michael Jackson made it to the Top 10? Select all that apply.

c('Beat It','You Rock My World','Billie Jean','You Are Not Alone') %>% 
  sapply(.,function(v){
    cx=which(songs$songtitle==v)
    songs$Top10[cx]
  })
          Beat It You Rock My World       Billie Jean 
                0                 1                 0 
You Are Not Alone 
                1 

1.4】(a) What are the values of timesignature that occur in our dataset? (b) Which timesignature value is the most frequent among songs in our dataset?

songs$timesignature  %>% factor %>% head
[1] 3 4 4 4 4 4
Levels: 0 1 3 4 5 7
songs$timesignature  %>% table
.
   0    1    3    4    5    7 
  10  143  503 6787  112   19 

1.5】 Which of the following songs has the highest tempo?

c('Until The Day I Die',"Wanna Be Startin' Somethin'",'My Happy Ending','You Make Me Wanna...') %>%
  sapply(.,function(v){
    cx=(songs$songtitle==v) %>% which
    songs$tempo[cx]
  })
$`Until The Day I Die`
numeric(0)

$`Wanna Be Startin' Somethin'`
[1] 244.3

$`My Happy Ending`
[1] 169

$`You Make Me Wanna...`
[1] 164.2



2 建立模型 Creating Our Prediction Model

2.1 依時間分割資料】How many observations (songs) are in the training set?

SongsTrain=subset(songs,year<=2009)
SongsTest=subset(songs,year>2009)
nrow(SongsTrain)
[1] 7201

2.2 建立模型、模型摘要】What is the value of the Akaike Information Criterion (AIC)?

nonvars = c("year", "songtitle", "artistname", "songID", "artistID")
SongsTrain = SongsTrain[ , !(names(SongsTrain) %in% nonvars) ]
SongsTest = SongsTest[ , !(names(SongsTest) %in% nonvars) ]
SongsLog1 = glm(Top10 ~ ., data=SongsTrain, family=binomial)
summary(SongsLog1)

Call:
glm(formula = Top10 ~ ., family = binomial, data = SongsTrain)

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-1.922  -0.540  -0.346  -0.184   3.077  

Coefficients:
                            Estimate  Std. Error
(Intercept)               14.6999882   1.8063875
timesignature              0.1263948   0.0867357
timesignature_confidence   0.7449923   0.1953053
loudness                   0.2998794   0.0291654
tempo                      0.0003634   0.0016915
tempo_confidence           0.4732270   0.1421740
key                        0.0158820   0.0103895
key_confidence             0.3086751   0.1411562
energy                    -1.5021445   0.3099240
pitch                    -44.9077399   6.8348831
timbre_0_min               0.0231589   0.0042562
timbre_0_max              -0.3309820   0.0256926
timbre_1_min               0.0058810   0.0007798
timbre_1_max              -0.0002449   0.0007152
timbre_2_min              -0.0021274   0.0011260
timbre_2_max               0.0006586   0.0009066
timbre_3_min               0.0006920   0.0005985
timbre_3_max              -0.0029673   0.0005815
timbre_4_min               0.0103956   0.0019850
timbre_4_max               0.0061105   0.0015503
timbre_5_min              -0.0055980   0.0012767
timbre_5_max               0.0000774   0.0007935
timbre_6_min              -0.0168562   0.0022640
timbre_6_max               0.0036681   0.0021895
timbre_7_min              -0.0045492   0.0017815
timbre_7_max              -0.0037737   0.0018320
timbre_8_min               0.0039110   0.0028510
timbre_8_max               0.0040113   0.0030030
timbre_9_min               0.0013673   0.0029981
timbre_9_max               0.0016027   0.0024336
timbre_10_min              0.0041263   0.0018391
timbre_10_max              0.0058250   0.0017694
timbre_11_min             -0.0262523   0.0036933
timbre_11_max              0.0196734   0.0033855
                         z value           Pr(>|z|)    
(Intercept)                 8.14 0.0000000000000004 ***
timesignature               1.46            0.14505    
timesignature_confidence    3.81            0.00014 ***
loudness                   10.28            < 2e-16 ***
tempo                       0.21            0.82989    
tempo_confidence            3.33            0.00087 ***
key                         1.53            0.12635    
key_confidence              2.19            0.02876 *  
energy                     -4.85 0.0000012545913310 ***
pitch                      -6.57 0.0000000000501890 ***
timbre_0_min                5.44 0.0000000529331342 ***
timbre_0_max              -12.88            < 2e-16 ***
timbre_1_min                7.54 0.0000000000000464 ***
timbre_1_max               -0.34            0.73209    
timbre_2_min               -1.89            0.05884 .  
timbre_2_max                0.73            0.46757    
timbre_3_min                1.16            0.24758    
timbre_3_max               -5.10 0.0000003344570390 ***
timbre_4_min                5.24 0.0000001632385067 ***
timbre_4_max                3.94 0.0000809670432888 ***
timbre_5_min               -4.38 0.0000116146773897 ***
timbre_5_max                0.10            0.92234    
timbre_6_min               -7.45 0.0000000000000966 ***
timbre_6_max                1.68            0.09388 .  
timbre_7_min               -2.55            0.01066 *  
timbre_7_max               -2.06            0.03941 *  
timbre_8_min                1.37            0.17012    
timbre_8_max                1.34            0.18162    
timbre_9_min                0.46            0.64836    
timbre_9_max                0.66            0.51019    
timbre_10_min               2.24            0.02485 *  
timbre_10_max               3.29            0.00099 ***
timbre_11_min              -7.11 0.0000000000011760 ***
timbre_11_max               5.81 0.0000000062068661 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 6017.5  on 7200  degrees of freedom
Residual deviance: 4759.2  on 7167  degrees of freedom
AIC: 4827

Number of Fisher Scoring iterations: 6
#AIC: 4827.2

2.3 模型係數判讀】The LOWER or HIGHER our confidence about time signature, key and tempo, the more likely the song is to be in the Top 10

#The higher our confidence about time signature, key and tempo, the more likely the song is to be in the Top 10

2.4 進行推論】What does Model 1 suggest in terms of complexity?

#Mainstream listeners tend to prefer less complex songs

2.5 檢查異常係數】 (a) By inspecting the coefficient of the variable “loudness”, what does Model 1 suggest? (b) By inspecting the coefficient of the variable “energy”, do we draw the same conclusions as above?

#(a)Mainstream listeners prefer songs with heavy instrumentation
#(b)No



3 處理共線性 Beware of Multicollinearity Issues!

3.1 檢查相關係數】What is the correlation between loudness and energy in the training set?

cor(SongsTrain$loudness, SongsTrain$energy)
[1] 0.7399

3.2 重新建立模型、檢查係數】Look at the summary of SongsLog2, and inspect the coefficient of the variable “energy”. What do you observe?

SongsLog2 = glm(Top10 ~ . - loudness, data=SongsTrain, family=binomial)
summary(SongsLog2)

Call:
glm(formula = Top10 ~ . - loudness, family = binomial, data = SongsTrain)

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-2.098  -0.561  -0.360  -0.190   3.311  

Coefficients:
                           Estimate Std. Error z value
(Intercept)               -2.240612   0.746484   -3.00
timesignature              0.162461   0.087341    1.86
timesignature_confidence   0.688471   0.192419    3.58
tempo                      0.000552   0.001665    0.33
tempo_confidence           0.549657   0.140736    3.91
key                        0.017403   0.010256    1.70
key_confidence             0.295367   0.139446    2.12
energy                     0.181260   0.260768    0.70
pitch                    -51.498579   6.856544   -7.51
timbre_0_min               0.024789   0.004240    5.85
timbre_0_max              -0.100697   0.011776   -8.55
timbre_1_min               0.007143   0.000771    9.27
timbre_1_max              -0.000783   0.000706   -1.11
timbre_2_min              -0.001579   0.001109   -1.42
timbre_2_max               0.000389   0.000896    0.43
timbre_3_min               0.000650   0.000595    1.09
timbre_3_max              -0.002462   0.000567   -4.34
timbre_4_min               0.009115   0.001952    4.67
timbre_4_max               0.006306   0.001532    4.12
timbre_5_min              -0.005641   0.001255   -4.50
timbre_5_max               0.000694   0.000781    0.89
timbre_6_min              -0.016122   0.002235   -7.21
timbre_6_max               0.003814   0.002157    1.77
timbre_7_min              -0.005102   0.001755   -2.91
timbre_7_max              -0.003158   0.001811   -1.74
timbre_8_min               0.004488   0.002810    1.60
timbre_8_max               0.006422   0.002950    2.18
timbre_9_min              -0.000428   0.002955   -0.14
timbre_9_max               0.003525   0.002377    1.48
timbre_10_min              0.002993   0.001804    1.66
timbre_10_max              0.007367   0.001731    4.25
timbre_11_min             -0.028370   0.003630   -7.82
timbre_11_max              0.018294   0.003341    5.48
                                   Pr(>|z|)    
(Intercept)                         0.00269 ** 
timesignature                       0.06287 .  
timesignature_confidence            0.00035 ***
tempo                               0.74023    
tempo_confidence         0.0000940005473689 ***
key                                 0.08974 .  
key_confidence                      0.03416 *  
energy                              0.48699    
pitch                    0.0000000000000587 ***
timbre_0_min             0.0000000050055433 ***
timbre_0_max                        < 2e-16 ***
timbre_1_min                        < 2e-16 ***
timbre_1_max                        0.26765    
timbre_2_min                        0.15453    
timbre_2_max                        0.66443    
timbre_3_min                        0.27452    
timbre_3_max             0.0000143015554481 ***
timbre_4_min             0.0000030176578261 ***
timbre_4_max             0.0000387139806484 ***
timbre_5_min             0.0000069522013076 ***
timbre_5_max                        0.37426    
timbre_6_min             0.0000000000005452 ***
timbre_6_max                        0.07698 .  
timbre_7_min                        0.00364 ** 
timbre_7_max                        0.08109 .  
timbre_8_min                        0.11025    
timbre_8_max                        0.02950 *  
timbre_9_min                        0.88479    
timbre_9_max                        0.13802    
timbre_10_min                       0.09700 .  
timbre_10_max            0.0000209292079939 ***
timbre_11_min            0.0000000000000055 ***
timbre_11_max            0.0000000434235974 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 6017.5  on 7200  degrees of freedom
Residual deviance: 4871.8  on 7168  degrees of freedom
AIC: 4938

Number of Fisher Scoring iterations: 6
#Model 2 suggests that songs with high energy levels tend to be more popular. This contradicts our observation in Model 1. 

3.3 選擇模型】 do we make the same observation about the popularity of heavy instrumentation as we did with Model 2?

#model , without energy 
SongsLog3 = glm(Top10 ~ . - energy, data=SongsTrain, family=binomial)
summary(SongsLog3)

Call:
glm(formula = Top10 ~ . - energy, family = binomial, data = SongsTrain)

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-1.918  -0.542  -0.348  -0.187   3.417  

Coefficients:
                            Estimate  Std. Error
(Intercept)               11.9605621   1.7141947
timesignature              0.1150942   0.0872615
timesignature_confidence   0.7142698   0.1946175
loudness                   0.2305565   0.0252798
tempo                     -0.0006460   0.0016655
tempo_confidence           0.3840930   0.1398350
key                        0.0164946   0.0103514
key_confidence             0.3394064   0.1408744
pitch                    -53.2840575   6.7328544
timbre_0_min               0.0220452   0.0042394
timbre_0_max              -0.3104800   0.0253654
timbre_1_min               0.0054160   0.0007643
timbre_1_max              -0.0005115   0.0007110
timbre_2_min              -0.0022544   0.0011203
timbre_2_max               0.0004119   0.0009020
timbre_3_min               0.0003179   0.0005869
timbre_3_max              -0.0029637   0.0005758
timbre_4_min               0.0110465   0.0019779
timbre_4_max               0.0064668   0.0015413
timbre_5_min              -0.0051345   0.0012690
timbre_5_max               0.0002979   0.0007856
timbre_6_min              -0.0178447   0.0022460
timbre_6_max               0.0034469   0.0021821
timbre_7_min              -0.0051284   0.0017685
timbre_7_max              -0.0033935   0.0018198
timbre_8_min               0.0036861   0.0028331
timbre_8_max               0.0046578   0.0029879
timbre_9_min              -0.0000932   0.0029569
timbre_9_max               0.0013417   0.0024239
timbre_10_min              0.0040500   0.0018270
timbre_10_max              0.0057925   0.0017586
timbre_11_min             -0.0263767   0.0036829
timbre_11_max              0.0198361   0.0033646
                         z value           Pr(>|z|)    
(Intercept)                 6.98 0.0000000000030077 ***
timesignature               1.32            0.18718    
timesignature_confidence    3.67            0.00024 ***
loudness                    9.12            < 2e-16 ***
tempo                      -0.39            0.69811    
tempo_confidence            2.75            0.00602 ** 
key                         1.59            0.11106    
key_confidence              2.41            0.01598 *  
pitch                      -7.91 0.0000000000000025 ***
timbre_0_min                5.20 0.0000001992236315 ***
timbre_0_max              -12.24            < 2e-16 ***
timbre_1_min                7.09 0.0000000000013757 ***
timbre_1_max               -0.72            0.47193    
timbre_2_min               -2.01            0.04419 *  
timbre_2_max                0.46            0.64791    
timbre_3_min                0.54            0.58808    
timbre_3_max               -5.15 0.0000002640646649 ***
timbre_4_min                5.58 0.0000000233875661 ***
timbre_4_max                4.20 0.0000272139788370 ***
timbre_5_min               -4.05 0.0000520513667576 ***
timbre_5_max                0.38            0.70453    
timbre_6_min               -7.94 0.0000000000000019 ***
timbre_6_max                1.58            0.11420    
timbre_7_min               -2.90            0.00373 ** 
timbre_7_max               -1.86            0.06221 .  
timbre_8_min                1.30            0.19323    
timbre_8_max                1.56            0.11902    
timbre_9_min               -0.03            0.97486    
timbre_9_max                0.55            0.57990    
timbre_10_min               2.22            0.02664 *  
timbre_10_max               3.29            0.00099 ***
timbre_11_min              -7.16 0.0000000000007958 ***
timbre_11_max               5.90 0.0000000037350899 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 6017.5  on 7200  degrees of freedom
Residual deviance: 4782.7  on 7168  degrees of freedom
AIC: 4849

Number of Fisher Scoring iterations: 6
#YES



4 驗證模型 Validating Our Model

4.1 正確性】What is the accuracy of Model 3 on the test set, using a threshold of 0.45?

testPredict = predict(SongsLog3, newdata=SongsTest, type="response")
table(Actual=SongsTest$Top10,Predict=ifelse(testPredict >= 0.45,1,0))
      Predict
Actual   0   1
     0 309   5
     1  40  19
(309+19)/(309+5+40+19) 
[1] 0.8794

4.2 底線正確率】What would the accuracy of the baseline model be on the test set? ?

table(SongsTest$Top10)

  0   1 
314  59 
314/(314+59)
[1] 0.8418

4.3 正確性 vs. 辨識率】How many songs does Model 3 correctly predict as Top 10 hits in 2010? How many non-hit songs does Model 3 predict will be Top 10 hits?

table(Actual=SongsTest$Top10,Predict=ifelse(testPredict >= 0.45,1,0))
      Predict
Actual   0   1
     0 309   5
     1  40  19
19
[1] 19
5
[1] 5

Q】不能大幅度增加正確性的模型也會有用嗎?為甚麼? 如果辨識率很高,這樣就可以區分Top10,雖然模型不能增加正確性,但是能區分類別。我們可以用預測出來的模型想出一個商業上的情境,做出報酬矩陣,來衡量我們做的決策有多少期望值

4.4 敏感性 & 明確性】What is the sensitivity and specificity of Model 3 on the test set, using a threshold of 0.45?

table(Actual=SongsTest$Top10,Predict=ifelse(testPredict >= 0.45,1,0))
      Predict
Actual   0   1
     0 309   5
     1  40  19
19/(40+19)
[1] 0.322
309/(309+5)
[1] 0.9841
#sensitivity=0.3220339
#specificity=0.9840764

4.5 結論】What conclusions can you make about our model?

#Model 3 favors specificity over sensitivity.
#Model 3 provides conservative predictions, and predicts that a song will make it to the Top 10 very rarely. So while it detects less than half of the Top 10 songs, we can be very confident in the songs that it does predict to be Top 10 hits.


Q】從這個結論我們學到什麼? 我們將threshold設定0.45,可以看到Sensitivity很低(0.32), Specificity很高(0.9841) 所以model3在Sensitivity & Specificity中對Sensitivity比較保守估計。 所以當預測結果為TP(Top10)時,我們有很高的信心猜對





LS0tDQp0aXRsZTogIkFTMy0xIFBvcHVsYXJpdHkgb2YgbXVzaWMgcmVjb3JkcyINCmdyb3VwOiAi56ysMee1hCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIGVjaG89VCwgbWVzc2FnZT1GLCBjYWNoZT1GLCB3YXJuaW5nPUZ9DQpybShsaXN0PWxzKGFsbD1UKSkNCm9wdGlvbnMoZGlnaXRzPTQsIHNjaXBlbj0xMikNCmxpYnJhcnkoZHBseXIpOyBsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KLSAtIC0NCg0KIyMjIEludHJvZHVjdGlvbg0KDQrorbDpoYzvvJrkvb/nlKjmrYzmm7LnmoTlsazmgKfvvIzpoJDmuKzlroPmnIPkuI3mnIPpgLLlhaXmtYHooYzmrYzmm7LmjpLooYzmppznmoTliY0xMOWQjQ0KDQrlrbjnv5Lph43pu57vvJoNCg0KKyDkvp3mmYLplpPliIblibLos4fmlpkNCisgbW9kZWwgZm9ybXVsYSDnmoTlr6vms5UNCisg6auY55u46ZecKOWFsee3muaApynoh6rorormlbjkuYvplpPnmoTpgbjmk4cNCisgYWNjdXJhY3ksIHNlbnNpdGl2aXR5LCBzcGVjaWZpY2l0eeeahOWvpumam+aEj+e+qSANCisg5aaC5L2V6Kq/5pW06Ieo55WM5qmf546H5L6G5qyK6KGh77yaVEZSL3NlbnNpdGl2aXR5IHZzLiBGUFIvc3BlY2lmaWNpdHkgDQoNCjxicj4NCg0KLSAtIC0NCg0KIyMjIDEg5Z+65pys55qE6LOH5paZ6JmV55CGIFVuZGVyc3RhbmRpbmcgdGhlIERhdGENCg0K44CQKioxLjEqKuOAkUhvdyBtYW55IG9ic2VydmF0aW9ucyAoc29uZ3MpIGFyZSBmcm9tIHRoZSB5ZWFyIDIwMTA/DQpgYGB7cn0NCnNvbmdzPXJlYWQuY3N2KCcuL2RhdGEvc29uZ3MuY3N2JykNCm5yb3coc29uZ3MpDQpgYGANCg0K44CQKioxLjIqKuOAkUhvdyBtYW55IHNvbmdzIGRvZXMgdGhlIGRhdGFzZXQgaW5jbHVkZSBmb3Igd2hpY2ggdGhlIGFydGlzdCBuYW1lIGlzICJNaWNoYWVsIEphY2tzb24iPw0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KKHNvbmdzJGFydGlzdG5hbWU9PSdNaWNoYWVsIEphY2tzb24nKSAlPiUgc3VtDQpgYGANCg0K44CQKioxLjMqKuOAkVdoaWNoIG9mIHRoZXNlIHNvbmdzIGJ5IE1pY2hhZWwgSmFja3NvbiBtYWRlIGl0IHRvIHRoZSBUb3AgMTA/IFNlbGVjdCBhbGwgdGhhdCBhcHBseS4NCmBgYHtyfQ0KYygnQmVhdCBJdCcsJ1lvdSBSb2NrIE15IFdvcmxkJywnQmlsbGllIEplYW4nLCdZb3UgQXJlIE5vdCBBbG9uZScpICU+JSANCiAgc2FwcGx5KC4sZnVuY3Rpb24odil7DQogICAgY3g9d2hpY2goc29uZ3Mkc29uZ3RpdGxlPT12KQ0KICAgIHNvbmdzJFRvcDEwW2N4XQ0KICB9KQ0KDQpgYGANCg0K44CQKioxLjQqKuOAkShhKSBXaGF0IGFyZSB0aGUgdmFsdWVzIG9mIGB0aW1lc2lnbmF0dXJlYCB0aGF0IG9jY3VyIGluIG91ciBkYXRhc2V0PyAoYikgV2hpY2ggdGltZXNpZ25hdHVyZSB2YWx1ZSBpcyB0aGUgbW9zdCBmcmVxdWVudCBhbW9uZyBzb25ncyBpbiBvdXIgZGF0YXNldD8gDQpgYGB7cn0NCnNvbmdzJHRpbWVzaWduYXR1cmUgICU+JSBmYWN0b3IgJT4lIGhlYWQNCnNvbmdzJHRpbWVzaWduYXR1cmUgICU+JSB0YWJsZQ0KYGBgDQoNCuOAkCoqMS41KirjgJEgV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBzb25ncyBoYXMgdGhlIGhpZ2hlc3QgdGVtcG8/DQpgYGB7cn0NCg0KYygnVW50aWwgVGhlIERheSBJIERpZScsIldhbm5hIEJlIFN0YXJ0aW4nIFNvbWV0aGluJyIsJ015IEhhcHB5IEVuZGluZycsJ1lvdSBNYWtlIE1lIFdhbm5hLi4uJykgJT4lDQogIHNhcHBseSguLGZ1bmN0aW9uKHYpew0KICAgIGN4PShzb25ncyRzb25ndGl0bGU9PXYpICU+JSB3aGljaA0KICAgIHNvbmdzJHRlbXBvW2N4XQ0KICB9KQ0KDQoNCmBgYA0KPGJyPg0KDQotIC0gLQ0KDQojIyMgMiDlu7rnq4vmqKHlnosgQ3JlYXRpbmcgT3VyIFByZWRpY3Rpb24gTW9kZWwNCg0K44CQKioyLjEg5L6d5pmC6ZaT5YiG5Ymy6LOH5paZKirjgJFIb3cgbWFueSBvYnNlcnZhdGlvbnMgKHNvbmdzKSBhcmUgaW4gdGhlIHRyYWluaW5nIHNldD8NCmBgYHtyfQ0KU29uZ3NUcmFpbj1zdWJzZXQoc29uZ3MseWVhcjw9MjAwOSkNClNvbmdzVGVzdD1zdWJzZXQoc29uZ3MseWVhcj4yMDA5KQ0KbnJvdyhTb25nc1RyYWluKQ0KDQpgYGANCg0K44CQKioyLjIg5bu656uL5qih5Z6L44CB5qih5Z6L5pGY6KaBKirjgJFXaGF0IGlzIHRoZSB2YWx1ZSBvZiB0aGUgQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQUlDKT8NCmBgYHtyfQ0Kbm9udmFycyA9IGMoInllYXIiLCAic29uZ3RpdGxlIiwgImFydGlzdG5hbWUiLCAic29uZ0lEIiwgImFydGlzdElEIikNClNvbmdzVHJhaW4gPSBTb25nc1RyYWluWyAsICEobmFtZXMoU29uZ3NUcmFpbikgJWluJSBub252YXJzKSBdDQpTb25nc1Rlc3QgPSBTb25nc1Rlc3RbICwgIShuYW1lcyhTb25nc1Rlc3QpICVpbiUgbm9udmFycykgXQ0KU29uZ3NMb2cxID0gZ2xtKFRvcDEwIH4gLiwgZGF0YT1Tb25nc1RyYWluLCBmYW1pbHk9Ymlub21pYWwpDQpzdW1tYXJ5KFNvbmdzTG9nMSkNCiNBSUM6IDQ4MjcuMg0KYGBgDQoNCuOAkCoqMi4zIOaooeWei+S/guaVuOWIpOiugCoq44CRVGhlIGBMT1dFUmAgb3IgYEhJR0hFUmAgb3VyIGNvbmZpZGVuY2UgYWJvdXQgdGltZSBzaWduYXR1cmUsIGtleSBhbmQgdGVtcG8sIHRoZSBtb3JlIGxpa2VseSB0aGUgc29uZyBpcyB0byBiZSBpbiB0aGUgVG9wIDEwDQpgYGB7cn0NCiNUaGUgaGlnaGVyIG91ciBjb25maWRlbmNlIGFib3V0IHRpbWUgc2lnbmF0dXJlLCBrZXkgYW5kIHRlbXBvLCB0aGUgbW9yZSBsaWtlbHkgdGhlIHNvbmcgaXMgdG8gYmUgaW4gdGhlIFRvcCAxMA0KYGBgDQoNCuOAkCoqMi40IOmAsuihjOaOqOirlioq44CRV2hhdCBkb2VzIE1vZGVsIDEgc3VnZ2VzdCBpbiB0ZXJtcyBvZiBjb21wbGV4aXR5Pw0KYGBge3J9DQojTWFpbnN0cmVhbSBsaXN0ZW5lcnMgdGVuZCB0byBwcmVmZXIgbGVzcyBjb21wbGV4IHNvbmdzDQpgYGANCg0K44CQKioyLjUg5qqi5p+l55Ww5bi45L+C5pW4KirjgJEgKGEpIEJ5IGluc3BlY3RpbmcgdGhlIGNvZWZmaWNpZW50IG9mIHRoZSB2YXJpYWJsZSAibG91ZG5lc3MiLCB3aGF0IGRvZXMgTW9kZWwgMSBzdWdnZXN0PyAoYikgQnkgaW5zcGVjdGluZyB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHZhcmlhYmxlICJlbmVyZ3kiLCBkbyB3ZSBkcmF3IHRoZSBzYW1lIGNvbmNsdXNpb25zIGFzIGFib3ZlPw0KYGBge3J9DQojKGEpTWFpbnN0cmVhbSBsaXN0ZW5lcnMgcHJlZmVyIHNvbmdzIHdpdGggaGVhdnkgaW5zdHJ1bWVudGF0aW9uDQojKGIpTm8NCmBgYA0KPGJyPg0KDQotIC0gLQ0KDQojIyMgMyDomZXnkIblhbHnt5rmgKcgQmV3YXJlIG9mIE11bHRpY29sbGluZWFyaXR5IElzc3VlcyENCg0K44CQKiozLjEg5qqi5p+l55u46Zec5L+C5pW4KirjgJFXaGF0IGlzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGBsb3VkbmVzc2AgYW5kIGBlbmVyZ3lgIGluIHRoZSB0cmFpbmluZyBzZXQ/DQpgYGB7cn0NCmNvcihTb25nc1RyYWluJGxvdWRuZXNzLCBTb25nc1RyYWluJGVuZXJneSkNCmBgYA0KDQrjgJAqKjMuMiDph43mlrDlu7rnq4vmqKHlnovjgIHmqqLmn6Xkv4LmlbgqKuOAkUxvb2sgYXQgdGhlIHN1bW1hcnkgb2YgU29uZ3NMb2cyLCBhbmQgaW5zcGVjdCB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHZhcmlhYmxlICJlbmVyZ3kiLiBXaGF0IGRvIHlvdSBvYnNlcnZlPw0KYGBge3J9DQpTb25nc0xvZzIgPSBnbG0oVG9wMTAgfiAuIC0gbG91ZG5lc3MsIGRhdGE9U29uZ3NUcmFpbiwgZmFtaWx5PWJpbm9taWFsKQ0Kc3VtbWFyeShTb25nc0xvZzIpDQojTW9kZWwgMiBzdWdnZXN0cyB0aGF0IHNvbmdzIHdpdGggaGlnaCBlbmVyZ3kgbGV2ZWxzIHRlbmQgdG8gYmUgbW9yZSBwb3B1bGFyLiBUaGlzIGNvbnRyYWRpY3RzIG91ciBvYnNlcnZhdGlvbiBpbiBNb2RlbCAxLiANCmBgYA0KDQrjgJAqKjMuMyDpgbjmk4fmqKHlnosqKuOAkSBkbyB3ZSBtYWtlIHRoZSBzYW1lIG9ic2VydmF0aW9uIGFib3V0IHRoZSBwb3B1bGFyaXR5IG9mIGhlYXZ5IGluc3RydW1lbnRhdGlvbiBhcyB3ZSBkaWQgd2l0aCBNb2RlbCAyPw0KYGBge3J9DQojbW9kZWwgLCB3aXRob3V0IGVuZXJneSANClNvbmdzTG9nMyA9IGdsbShUb3AxMCB+IC4gLSBlbmVyZ3ksIGRhdGE9U29uZ3NUcmFpbiwgZmFtaWx5PWJpbm9taWFsKQ0Kc3VtbWFyeShTb25nc0xvZzMpDQojWUVTDQpgYGANCjxicj4NCg0KLSAtIC0NCg0KIyMjIDQg6amX6K2J5qih5Z6LIFZhbGlkYXRpbmcgT3VyIE1vZGVsDQoNCuOAkCoqNC4xIOato+eiuuaApyoq44CRV2hhdCBpcyB0aGUgYWNjdXJhY3kgb2YgTW9kZWwgMyBvbiB0aGUgdGVzdCBzZXQsIHVzaW5nIGEgdGhyZXNob2xkIG9mIDAuNDU/IA0KYGBge3J9DQp0ZXN0UHJlZGljdCA9IHByZWRpY3QoU29uZ3NMb2czLCBuZXdkYXRhPVNvbmdzVGVzdCwgdHlwZT0icmVzcG9uc2UiKQ0KdGFibGUoQWN0dWFsPVNvbmdzVGVzdCRUb3AxMCxQcmVkaWN0PWlmZWxzZSh0ZXN0UHJlZGljdCA+PSAwLjQ1LDEsMCkpDQooMzA5KzE5KS8oMzA5KzUrNDArMTkpIA0KYGBgDQoNCuOAkCoqNC4yIOW6lee3muato+eiuueOhyoq44CRV2hhdCB3b3VsZCB0aGUgYWNjdXJhY3kgb2YgdGhlIGJhc2VsaW5lIG1vZGVsIGJlIG9uIHRoZSB0ZXN0IHNldD8gPyANCmBgYHtyfQ0KdGFibGUoU29uZ3NUZXN0JFRvcDEwKQ0KMzE0LygzMTQrNTkpDQpgYGANCg0K44CQKio0LjMg5q2j56K65oCnIHZzLiDovqjorZjnjocqKuOAkUhvdyBtYW55IHNvbmdzIGRvZXMgTW9kZWwgMyBjb3JyZWN0bHkgcHJlZGljdCBhcyBUb3AgMTAgaGl0cyBpbiAyMDEwPyAgSG93IG1hbnkgbm9uLWhpdCBzb25ncyBkb2VzIE1vZGVsIDMgcHJlZGljdCB3aWxsIGJlIFRvcCAxMCBoaXRzPw0KYGBge3J9DQp0YWJsZShBY3R1YWw9U29uZ3NUZXN0JFRvcDEwLFByZWRpY3Q9aWZlbHNlKHRlc3RQcmVkaWN0ID49IDAuNDUsMSwwKSkNCjE5DQo1DQpgYGANCg0K44CQKipRKirjgJHkuI3og73lpKfluYXluqblop7liqDmraPnorrmgKfnmoTmqKHlnovkuZ/mnIPmnInnlKjll47vvJ/ngrrnlJrpurzvvJ8NCuWmguaenOi+qOitmOeOh+W+iOmrmO+8jOmAmeaoo+WwseWPr+S7peWNgOWIhlRvcDEw77yM6ZuW54S25qih5Z6L5LiN6IO95aKe5Yqg5q2j56K65oCn77yM5L2G5piv6IO95Y2A5YiG6aGe5Yil44CC5oiR5YCR5Y+v5Lul55So6aCQ5ris5Ye65L6G55qE5qih5Z6L5oOz5Ye65LiA5YCL5ZWG5qWt5LiK55qE5oOF5aKD77yM5YGa5Ye65aCx6YWs55+p6Zmj77yM5L6G6KGh6YeP5oiR5YCR5YGa55qE5rG6562W5pyJ5aSa5bCR5pyf5pyb5YC8DQoNCuOAkCoqNC40IOaVj+aEn+aApyAmIOaYjueiuuaApyoq44CRV2hhdCBpcyB0aGUgYHNlbnNpdGl2aXR5YCBhbmQgYHNwZWNpZmljaXR5YCBvZiBNb2RlbCAzIG9uIHRoZSB0ZXN0IHNldCwgdXNpbmcgYSB0aHJlc2hvbGQgb2YgMC40NT8NCmBgYHtyfQ0KdGFibGUoQWN0dWFsPVNvbmdzVGVzdCRUb3AxMCxQcmVkaWN0PWlmZWxzZSh0ZXN0UHJlZGljdCA+PSAwLjQ1LDEsMCkpDQoxOS8oNDArMTkpDQozMDkvKDMwOSs1KQ0KI3NlbnNpdGl2aXR5PTAuMzIyMDMzOQ0KI3NwZWNpZmljaXR5PTAuOTg0MDc2NA0KYGBgDQoNCuOAkCoqNC41IOe1kOirlioq44CRV2hhdCBjb25jbHVzaW9ucyBjYW4geW91IG1ha2UgYWJvdXQgb3VyIG1vZGVsPw0KYGBge3J9DQojTW9kZWwgMyBmYXZvcnMgc3BlY2lmaWNpdHkgb3ZlciBzZW5zaXRpdml0eS4NCiNNb2RlbCAzIHByb3ZpZGVzIGNvbnNlcnZhdGl2ZSBwcmVkaWN0aW9ucywgYW5kIHByZWRpY3RzIHRoYXQgYSBzb25nIHdpbGwgbWFrZSBpdCB0byB0aGUgVG9wIDEwIHZlcnkgcmFyZWx5LiBTbyB3aGlsZSBpdCBkZXRlY3RzIGxlc3MgdGhhbiBoYWxmIG9mIHRoZSBUb3AgMTAgc29uZ3MsIHdlIGNhbiBiZSB2ZXJ5IGNvbmZpZGVudCBpbiB0aGUgc29uZ3MgdGhhdCBpdCBkb2VzIHByZWRpY3QgdG8gYmUgVG9wIDEwIGhpdHMuDQpgYGANCg0KPGJyPg0KDQrjgJAqKlEqKuOAkeW+numAmeWAi+e1kOirluaIkeWAkeWtuOWIsOS7gOm6vO+8nw0K5oiR5YCR5bCHdGhyZXNob2xk6Kit5a6aMC40Ne+8jOWPr+S7peeci+WIsFNlbnNpdGl2aXR55b6I5L2OKDAuMzIpLA0KU3BlY2lmaWNpdHnlvojpq5goMC45ODQxKQ0K5omA5LulbW9kZWwz5ZyoU2Vuc2l0aXZpdHkgJiBTcGVjaWZpY2l0eeS4reWwjVNlbnNpdGl2aXR55q+U6LyD5L+d5a6I5Lyw6KiI44CCDQrmiYDku6XnlbbpoJDmuKzntZDmnpzngrpUUChUb3AxMCnmmYLvvIzmiJHlgJHmnInlvojpq5jnmoTkv6Hlv4PnjJzlsI0NCg0KDQotIC0gLQ0KDQo8YnI+PGJyPjxicj4NCg==