Bootstrap w estymacji punktowej i przedziałowej na przykładzie badania średniej.

  1. Zapoznaj się ze składnią i działaniem następujących funkcji w pakiecie R: sample(), rnorm(), replicate(), boot (pakiet boot), boot.ci (pakiet boot).

  2. Wygeneruj ciąg losowo wybranych liczb z zakresu od 1 do 10. Zastosuj losowanie ze zwracaniem i bez zwracania.

Zadania

Zadanie 1. Estymacja błędu standardowego średniej próbkowej metodą bootstrap.

library(haven)
dane <- dataset <- read_sav('dane.sav')
Dochod_na_osobe<-dane$Dochod_na_osobe

#punktowo klasycznie
mean(Dochod_na_osobe)
## [1] 808.5322
sd(Dochod_na_osobe)
## [1] 1064.67
se<-sd(Dochod_na_osobe)/sqrt(length(Dochod_na_osobe))
se
## [1] 6.146569
sep<-se/mean(Dochod_na_osobe)
sep
## [1] 0.007602133

#przedziałowo klasycznie
cat(paste('Przedziały ufności w danych surowych: \n'))
## Przedziały ufności w danych surowych:
mean(Dochod_na_osobe)-1.96*se   #dolna krawędź
## [1] 796.4849
mean(Dochod_na_osobe)+1.96*se   #górna krawędź
## [1] 820.5794
B=1e3
mean.Dochod_na_osobe=rep(0,B)
nobs=length(Dochod_na_osobe) 
#liczba obserwacji - ma być: 50, 250, 500, 1000, 10000

cat(paste('Przyjęto wielkość obserwacji z bootstrapa:', B))
## Przyjęto wielkość obserwacji z bootstrapa: 1000
 for (i in 1:B) 
{
 boot.data=sample(Dochod_na_osobe,nobs,replace=TRUE)
 mean.Dochod_na_osobe[i]=mean(boot.data)
 }

cat(paste('\nStatystyki opisowe bootstrap: \n'))
## 
## Statystyki opisowe bootstrap:
mean(boot.data)
## [1] 804.2442
sd(boot.data)
## [1] 1058.132
se2<-sd(boot.data)/sqrt(length(boot.data))
se2
## [1] 6.108825
sep2<-se/mean(boot.data)
sep2
## [1] 0.007642665
hist(boot.data)

plot(density(boot.data))

cat(paste('Przedziały ufności w danych surowych: \n'))
## Przedziały ufności w danych surowych:
#quantile(boot.data,0.975)
#quantile(boot.data,0.025)

dolny<-mean(boot.data)-1.96*se2
gorny<-mean(boot.data)+1.96*se2
cbind(dolny,gorny)
##         dolny    gorny
## [1,] 792.2709 816.2175
cat(paste('Przedziałowy Efron: \n'))
## Przedziałowy Efron:
gorny<-quantile(boot.data,0.975)
dolny<-quantile(boot.data,0.025)
cbind(dolny,gorny)
##      dolny    gorny
## 2.5%     0 3047.567
cat(paste('Przedziałowy Hall: \n'))
## Przedziałowy Hall:
dolny<-2*mean(boot.data)-quantile(boot.data,0.025)
gorny<-2*mean(boot.data)-quantile(boot.data,0.975)
cbind(dolny,gorny)
##         dolny     gorny
## 2.5% 1608.488 -1439.079

A teraz z bootstrapem:

#install.packages('boot')
library(boot)

mean.boot=function(Dochod_na_osobe,idx) {
ans=mean(Dochod_na_osobe[idx])
ans
}

DOCHOD.mean.boot = boot(Dochod_na_osobe,statistic=mean.boot, R=999)
class(DOCHOD.mean.boot)
## [1] "boot"
names(DOCHOD.mean.boot)
##  [1] "t0"        "t"         "R"         "data"      "seed"      "statistic"
##  [7] "sim"       "call"      "stype"     "strata"    "weights"
DOCHOD.mean.boot
## 
## ORDINARY NONPARAMETRIC BOOTSTRAP
## 
## 
## Call:
## boot(data = Dochod_na_osobe, statistic = mean.boot, R = 999)
## 
## 
## Bootstrap Statistics :
##     original    bias    std. error
## t1* 808.5322 0.5337111     5.97603
plot(DOCHOD.mean.boot)

boot.ci(DOCHOD.mean.boot,conf=0.95,type=c("norm","perc"))
## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
## Based on 999 bootstrap replicates
## 
## CALL : 
## boot.ci(boot.out = DOCHOD.mean.boot, conf = 0.95, type = c("norm", 
##     "perc"))
## 
## Intervals : 
## Level      Normal             Percentile     
## 95%   (796.3, 819.7 )   (797.4, 820.6 )  
## Calculations and Intervals on Original Scale

Testy t studenta

Czy dochody na osobę różnią się istotnie w woj. pomorskim i podkarpackim?

#install.packages('MKinfer')
library(MKinfer) 
## Warning: pakiet 'MKinfer' został zbudowany w wersji R 4.3.3
library(tidyverse)
## Warning: pakiet 'tidyverse' został zbudowany w wersji R 4.3.3
## Warning: pakiet 'ggplot2' został zbudowany w wersji R 4.3.3
## Warning: pakiet 'dplyr' został zbudowany w wersji R 4.3.3
## Warning: pakiet 'lubridate' został zbudowany w wersji R 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
?boot.t.test
## uruchamianie serwera httpd dla pomocy ... wykonano
dane2<- dane %>%
  filter(Wojewodztwo %in% c(16,22)) 

  boot.t.test(Dochod_na_osobe~Wojewodztwo, R=999, dane2)
## 
##  Bootstrap Welch Two Sample t-test
## 
## data:  Dochod_na_osobe by Wojewodztwo
## number of bootstrap samples:  999
## bootstrap p-value = 0.6326 
## bootstrap difference of means (SE) = 18.81337 (53.75527) 
## 95 percent bootstrap percentile confidence interval:
##  -82.78772 127.37836
## 
## Results without bootstrap:
## t = 0.39855, df = 1363.8, p-value = 0.6903
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -84.90621 128.20264
## sample estimates:
## mean in group 16 mean in group 22 
##         865.8145         844.1663
  t.test(Dochod_na_osobe~Wojewodztwo, dane2)
## 
##  Welch Two Sample t-test
## 
## data:  Dochod_na_osobe by Wojewodztwo
## t = 0.39855, df = 1363.8, p-value = 0.6903
## alternative hypothesis: true difference in means between group 16 and group 22 is not equal to 0
## 95 percent confidence interval:
##  -84.90621 128.20264
## sample estimates:
## mean in group 16 mean in group 22 
##         865.8145         844.1663
wyniki<-boot.t.test(Dochod_na_osobe[as.numeric(dane$Wojewodztwo)==22],
               Dochod_na_osobe[as.numeric(dane$Wojewodztwo)==16],R=999,data=dane2)
wyniki
## 
##  Bootstrap Welch Two Sample t-test
## 
## data:  Dochod_na_osobe[as.numeric(dane$Wojewodztwo) == 22] and Dochod_na_osobe[as.numeric(dane$Wojewodztwo) == 16]
## number of bootstrap samples:  999
## bootstrap p-value = 0.6987 
## bootstrap difference of means (SE) = -21.26549 (53.55983) 
## 95 percent bootstrap percentile confidence interval:
##  -119.55926   76.39046
## 
## Results without bootstrap:
## t = -0.39855, df = 1363.8, p-value = 0.6903
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -128.20264   84.90621
## sample estimates:
## mean of x mean of y 
##  844.1663  865.8145

Test proporcji

#install.packages('ISLR')
library(ISLR)
data("Credit")
attach(Credit)

cat(paste('Test niezależności grup \n'))
## Test niezależności grup
tabelka<-table(Student,Gender)

#chisq.test(tabelka,simulate.p.value = TRUE, B = 2000)
chisq.test(tabelka,simulate.p.value = TRUE, B = 2000)
## 
##  Pearson's Chi-squared test with simulated p-value (based on 2000
##  replicates)
## 
## data:  tabelka
## X-squared = 1.2115, df = NA, p-value = 0.3123
chisq.test(tabelka) # różnice???
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tabelka
## X-squared = 0.87218, df = 1, p-value = 0.3504

Testy ANOVA

Wykonaj i zwizualizuj test ANOVA dla danych “Credit” (z pakietu ISLR) test Anova: czy średni bilans na karcie kredytowej różni się istotnie w zależności od pochodzenia, stanu cywilnego, statusu studenta i płci?

## Analysis of Variance Table
## 
## Response: Balance
##            Df   Sum Sq Mean Sq F value    Pr(>F)    
## Ethnicity   2    18454    9227  0.0463    0.9548    
## Married     1     1332    1332  0.0067    0.9349    
## Student     1  5713181 5713181 28.6378 1.484e-07 ***
## Gender      1     4828    4828  0.0242    0.8765    
## Residuals 394 78602117  199498                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

A teraz z włączonym bootstrapem:

library(lmboot)
## Warning: pakiet 'lmboot' został zbudowany w wersji R 4.3.3
anova_boot<-ANOVA.boot(Balance ~ Ethnicity + Married + Student + Gender,data=Credit,B=999)
## Warning in ANOVA.boot(Balance ~ Ethnicity + Married + Student + Gender, : This function has only been fully tested for one-way and two-way ANOVA.
anova_boot$`p-values`
## [1] 0.9469469 0.9459459 0.0000000 0.8778779

W przypadku Anovy 1-czynnikowej, możemy wykorzystać pakiet wizualizująco - obliczeniowy “ggstatsplot”. Pakiet ten ma w sobie opcję bootstrappingu, która pozwala na obliczenie wartości p-wartości dla testu ANOVA.

library(ggstatsplot)
## You can cite this package as:
##      Patil, I. (2021). Visualizations with statistical details: The 'ggstatsplot' approach.
##      Journal of Open Source Software, 6(61), 3167, doi:10.21105/joss.03167
ggbetweenstats(data=Credit,
  y=Balance,
  x=Ethnicity,
  nboot=999  #liczba prób bootstrapowych
)

Różnice nie wyszły istotne. Zależność między resamplingiem a wynikami polega na tym, że im wyższa ilość resamplingu tym wynik zbliżony do tego bez bootstrapa. Test ANOVA względem testu ANOVA z bootstrapem nie różni się znacząco. Wyniki i istotności zmiennych są na podobnych poziomach.

LS0tDQp0aXRsZTogIk5pZWtsYXN5Y3puZSBtZXRvZHkgc3RhdHlzdHlraSINCnN1YnRpdGxlOiAiQm9vdHN0cmFwIHcgZXN0eW1hY2ppIGkgdGVzdG93YW5pdSINCmF1dGhvcjogIlBpb3RyIFN6eXB1bGnFhHNraSINCmRhdGU6ICIyMDI0LTAxLTA3Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBmb250c2l6ZTogOHB0DQogICAgdG9jOiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyMgQm9vdHN0cmFwIHcgZXN0eW1hY2ppIHB1bmt0b3dlaiBpIHByemVkemlhxYJvd2VqIG5hIHByenlrxYJhZHppZSBiYWRhbmlhIMWbcmVkbmllai4NCg0KKDEpDQpaYXBvem5haiBzacSZIHplIHNrxYJhZG5pxIUgaSBkemlhxYJhbmllbSBuYXN0xJlwdWrEhWN5Y2ggZnVua2NqaSB3IHBha2llY2llIFI6IHNhbXBsZSgpLCBybm9ybSgpLCByZXBsaWNhdGUoKSwgYm9vdCAocGFraWV0IGJvb3QpLCBib290LmNpIChwYWtpZXQgYm9vdCkuDQoNCigyKQ0KV3lnZW5lcnVqIGNpxIVnIGxvc293byB3eWJyYW55Y2ggbGljemIgeiB6YWtyZXN1IG9kIDEgZG8gMTAuIFphc3Rvc3VqIGxvc293YW5pZSB6ZSB6d3JhY2FuaWVtIGkgYmV6IHp3cmFjYW5pYS4NCg0KIyMjIFphZGFuaWENCg0KIyMjIyBaYWRhbmllIDEuIEVzdHltYWNqYSBixYLEmWR1IHN0YW5kYXJkb3dlZ28gxZtyZWRuaWVqIHByw7Nia293ZWogbWV0b2TEhSBib290c3RyYXAuDQoNCmBgYHtyfQ0KbGlicmFyeShoYXZlbikNCmRhbmUgPC0gZGF0YXNldCA8LSByZWFkX3NhdignZGFuZS5zYXYnKQ0KRG9jaG9kX25hX29zb2JlPC1kYW5lJERvY2hvZF9uYV9vc29iZQ0KDQojcHVua3Rvd28ga2xhc3ljem5pZQ0KbWVhbihEb2Nob2RfbmFfb3NvYmUpDQpzZChEb2Nob2RfbmFfb3NvYmUpDQpzZTwtc2QoRG9jaG9kX25hX29zb2JlKS9zcXJ0KGxlbmd0aChEb2Nob2RfbmFfb3NvYmUpKQ0Kc2UNCnNlcDwtc2UvbWVhbihEb2Nob2RfbmFfb3NvYmUpDQpzZXANCmBgYA0KDQpgYGB7ciBwcmVzc3VyZSwgZWNobz1GQUxTRX0NCnBsb3QocHJlc3N1cmUpDQpgYGANCg0KYGBge3J9DQojcHJ6ZWR6aWHFgm93byBrbGFzeWN6bmllDQpjYXQocGFzdGUoJ1ByemVkemlhxYJ5IHVmbm/Fm2NpIHcgZGFueWNoIHN1cm93eWNoOiBcbicpKQ0KDQptZWFuKERvY2hvZF9uYV9vc29iZSktMS45NipzZSAgICNkb2xuYSBrcmF3xJlkxboNCm1lYW4oRG9jaG9kX25hX29zb2JlKSsxLjk2KnNlICAgI2fDs3JuYSBrcmF3xJlkxboNCmBgYA0KDQpgYGB7cn0NCkI9MWUzDQptZWFuLkRvY2hvZF9uYV9vc29iZT1yZXAoMCxCKQ0Kbm9icz1sZW5ndGgoRG9jaG9kX25hX29zb2JlKSANCiNsaWN6YmEgb2JzZXJ3YWNqaSAtIG1hIGJ5xIc6IDUwLCAyNTAsIDUwMCwgMTAwMCwgMTAwMDANCg0KY2F0KHBhc3RlKCdQcnp5asSZdG8gd2llbGtvxZvEhyBvYnNlcndhY2ppIHogYm9vdHN0cmFwYTonLCBCKSkNCg0KIGZvciAoaSBpbiAxOkIpIA0Kew0KIGJvb3QuZGF0YT1zYW1wbGUoRG9jaG9kX25hX29zb2JlLG5vYnMscmVwbGFjZT1UUlVFKQ0KIG1lYW4uRG9jaG9kX25hX29zb2JlW2ldPW1lYW4oYm9vdC5kYXRhKQ0KIH0NCg0KY2F0KHBhc3RlKCdcblN0YXR5c3R5a2kgb3Bpc293ZSBib290c3RyYXA6IFxuJykpDQoNCm1lYW4oYm9vdC5kYXRhKQ0Kc2QoYm9vdC5kYXRhKQ0Kc2UyPC1zZChib290LmRhdGEpL3NxcnQobGVuZ3RoKGJvb3QuZGF0YSkpDQpzZTINCnNlcDI8LXNlL21lYW4oYm9vdC5kYXRhKQ0Kc2VwMg0KDQpoaXN0KGJvb3QuZGF0YSkNCnBsb3QoZGVuc2l0eShib290LmRhdGEpKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KHBhc3RlKCdQcnplZHppYcWCeSB1Zm5vxZtjaSB3IGRhbnljaCBzdXJvd3ljaDogXG4nKSkNCiNxdWFudGlsZShib290LmRhdGEsMC45NzUpDQojcXVhbnRpbGUoYm9vdC5kYXRhLDAuMDI1KQ0KDQpkb2xueTwtbWVhbihib290LmRhdGEpLTEuOTYqc2UyDQpnb3JueTwtbWVhbihib290LmRhdGEpKzEuOTYqc2UyDQpjYmluZChkb2xueSxnb3JueSkNCmBgYA0KDQpgYGB7cn0NCmNhdChwYXN0ZSgnUHJ6ZWR6aWHFgm93eSBFZnJvbjogXG4nKSkNCg0KZ29ybnk8LXF1YW50aWxlKGJvb3QuZGF0YSwwLjk3NSkNCmRvbG55PC1xdWFudGlsZShib290LmRhdGEsMC4wMjUpDQpjYmluZChkb2xueSxnb3JueSkNCg0KY2F0KHBhc3RlKCdQcnplZHppYcWCb3d5IEhhbGw6IFxuJykpDQoNCmRvbG55PC0yKm1lYW4oYm9vdC5kYXRhKS1xdWFudGlsZShib290LmRhdGEsMC4wMjUpDQpnb3JueTwtMiptZWFuKGJvb3QuZGF0YSktcXVhbnRpbGUoYm9vdC5kYXRhLDAuOTc1KQ0KY2JpbmQoZG9sbnksZ29ybnkpDQpgYGANCg0KQSB0ZXJheiB6IGJvb3RzdHJhcGVtOg0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCdib290JykNCmxpYnJhcnkoYm9vdCkNCg0KbWVhbi5ib290PWZ1bmN0aW9uKERvY2hvZF9uYV9vc29iZSxpZHgpIHsNCmFucz1tZWFuKERvY2hvZF9uYV9vc29iZVtpZHhdKQ0KYW5zDQp9DQoNCkRPQ0hPRC5tZWFuLmJvb3QgPSBib290KERvY2hvZF9uYV9vc29iZSxzdGF0aXN0aWM9bWVhbi5ib290LCBSPTk5OSkNCmNsYXNzKERPQ0hPRC5tZWFuLmJvb3QpDQpuYW1lcyhET0NIT0QubWVhbi5ib290KQ0KDQpET0NIT0QubWVhbi5ib290DQoNCnBsb3QoRE9DSE9ELm1lYW4uYm9vdCkNCmJvb3QuY2koRE9DSE9ELm1lYW4uYm9vdCxjb25mPTAuOTUsdHlwZT1jKCJub3JtIiwicGVyYyIpKQ0KYGBgDQoNCiMjIFRlc3R5IHQgc3R1ZGVudGENCg0KQ3p5IGRvY2hvZHkgbmEgb3NvYsSZIHLDs8W8bmnEhSBzacSZIGlzdG90bmllIHcgd29qLiBwb21vcnNraW0gaSBwb2RrYXJwYWNraW0/DQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoJ01LaW5mZXInKQ0KbGlicmFyeShNS2luZmVyKSANCmxpYnJhcnkodGlkeXZlcnNlKQ0KP2Jvb3QudC50ZXN0DQoNCmRhbmUyPC0gZGFuZSAlPiUNCiAgZmlsdGVyKFdvamV3b2R6dHdvICVpbiUgYygxNiwyMikpIA0KDQogIGJvb3QudC50ZXN0KERvY2hvZF9uYV9vc29iZX5Xb2pld29kenR3bywgUj05OTksIGRhbmUyKQ0KICB0LnRlc3QoRG9jaG9kX25hX29zb2JlfldvamV3b2R6dHdvLCBkYW5lMikNCiAgDQoNCnd5bmlraTwtYm9vdC50LnRlc3QoRG9jaG9kX25hX29zb2JlW2FzLm51bWVyaWMoZGFuZSRXb2pld29kenR3byk9PTIyXSwNCiAgICAgICAgICAgICAgIERvY2hvZF9uYV9vc29iZVthcy5udW1lcmljKGRhbmUkV29qZXdvZHp0d28pPT0xNl0sUj05OTksZGF0YT1kYW5lMikNCnd5bmlraQ0KYGBgDQoNCiMjIFRlc3QgcHJvcG9yY2ppDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoJ0lTTFInKQ0KbGlicmFyeShJU0xSKQ0KZGF0YSgiQ3JlZGl0IikNCmF0dGFjaChDcmVkaXQpDQoNCmNhdChwYXN0ZSgnVGVzdCBuaWV6YWxlxbxub8WbY2kgZ3J1cCBcbicpKQ0KDQp0YWJlbGthPC10YWJsZShTdHVkZW50LEdlbmRlcikNCg0KI2NoaXNxLnRlc3QodGFiZWxrYSxzaW11bGF0ZS5wLnZhbHVlID0gVFJVRSwgQiA9IDIwMDApDQpjaGlzcS50ZXN0KHRhYmVsa2Esc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAyMDAwKQ0KY2hpc3EudGVzdCh0YWJlbGthKSAjIHLDs8W8bmljZT8/Pw0KYGBgDQoNCiMjIFRlc3R5IEFOT1ZBDQoNCld5a29uYWogaSB6d2l6dWFsaXp1aiB0ZXN0IEFOT1ZBIGRsYSBkYW55Y2ggIkNyZWRpdCIgKHogcGFraWV0dSBJU0xSKSB0ZXN0IEFub3ZhOiBjenkgxZtyZWRuaSBiaWxhbnMgbmEga2FyY2llIGtyZWR5dG93ZWogcsOzxbxuaSBzacSZIGlzdG90bmllIHcgemFsZcW8bm/Fm2NpIG9kIHBvY2hvZHplbmlhLCBzdGFudSBjeXdpbG5lZ28sIHN0YXR1c3Ugc3R1ZGVudGEgaSBwxYJjaT8NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmF0dGFjaChDcmVkaXQpDQptb2RlbDEgPC0gbG0oQmFsYW5jZSB+IEV0aG5pY2l0eSArIE1hcnJpZWQgKyBTdHVkZW50ICsgR2VuZGVyLCBkYXRhPUNyZWRpdCkNCmFub3ZhKG1vZGVsMSkNCmBgYA0KDQoNCkEgdGVyYXogeiB3xYLEhWN6b255bSBib290c3RyYXBlbToNCg0KYGBge3J9DQpsaWJyYXJ5KGxtYm9vdCkNCmFub3ZhX2Jvb3Q8LUFOT1ZBLmJvb3QoQmFsYW5jZSB+IEV0aG5pY2l0eSArIE1hcnJpZWQgKyBTdHVkZW50ICsgR2VuZGVyLGRhdGE9Q3JlZGl0LEI9OTk5KQ0KYW5vdmFfYm9vdCRgcC12YWx1ZXNgDQpgYGANCg0KVyBwcnp5cGFka3UgQW5vdnkgMS1jenlubmlrb3dlaiwgbW/FvGVteSB3eWtvcnp5c3RhxIcgcGFraWV0IHdpenVhbGl6dWrEhWNvIC0gb2JsaWN6ZW5pb3d5ICJnZ3N0YXRzcGxvdCIuIFBha2lldCB0ZW4gbWEgdyBzb2JpZSBvcGNqxJkgYm9vdHN0cmFwcGluZ3UsIGt0w7NyYSBwb3p3YWxhIG5hIG9ibGljemVuaWUgd2FydG/Fm2NpIHAtd2FydG/Fm2NpIGRsYSB0ZXN0dSBBTk9WQS4gDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3N0YXRzcGxvdCkNCmdnYmV0d2VlbnN0YXRzKGRhdGE9Q3JlZGl0LA0KICB5PUJhbGFuY2UsDQogIHg9RXRobmljaXR5LA0KICBuYm9vdD05OTkgICNsaWN6YmEgcHLDs2IgYm9vdHN0cmFwb3d5Y2gNCikNCmBgYA0KDQpSw7PFvG5pY2UgbmllIHd5c3rFgnkgaXN0b3RuZS4gWmFsZcW8bm/Fm8SHIG1pxJlkenkgcmVzYW1wbGluZ2llbSBhIHd5bmlrYW1pIHBvbGVnYSBuYSB0eW0sIMW8ZSBpbSB3ecW8c3phIGlsb8WbxIcgcmVzYW1wbGluZ3UgdHltIHd5bmlrIHpibGnFvG9ueSBkbyB0ZWdvIGJleiBib290c3RyYXBhLiBUZXN0IEFOT1ZBIHd6Z2zEmWRlbSB0ZXN0dSBBTk9WQSB6IGJvb3RzdHJhcGVtIG5pZSByw7PFvG5pIHNpxJkgem5hY3rEhWNvLiBXeW5pa2kgaSBpc3RvdG5vxZtjaSB6bWllbm55Y2ggc8SFIG5hIHBvZG9ibnljaCBwb3ppb21hY2guDQoNCg==