1 Zakład Bioinformatyki, Instytut Informatyki, Uniwersytet w Białymstoku

1 Podczytanie danych z wykorzystaniem pakietu readr

Inspiracją do napisania tego notebooka jest rodział 6.1 książki Jareda P. Landera “R dla każdego. Zaawansowane analizy i grafika statystyczna”.1 Dane wykorzystane pochodzą również ze strony Jareda P. Landera.2

Korzystamy z

  1. R,3
  2. bibliotek R,4–6
  3. piszemy używając języka znaczników i biblioteki rmarkdown7,8 w RStudio z wykorzystaniem R Notebook.

Uwaga:

1.1 Czyścimy środowisko

rm(list = ls())

1.2 Podczytujemy dane

acsNew <- read_csv("http://www.jaredlander.com/data/acsNew.csv", 
                   col_types = 
                   cols(FamilyType = col_factor(levels = c("Married","Female Head", "Male Head")), 
                        Income = col_factor(levels = c("Below", "Above"))
                        )
                   )

Wczytujemy bibliotekę dplyr

1.3 Trochę podsumowania, co jest w danych

Zobaczmy, co ukrywa się pod danymi (wykorzystujemy funkcję summary).

acsNew %>% summary
    Acres            FamilyIncome           FamilyType    NumBedrooms   
 Length:2273        Min.   :   1125   Married    :1831   Min.   :0.000  
 Class :character   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000  
 Mode  :character   Median :  89200   Male Head  : 115   Median :3.000  
                    Mean   : 110982                      Mean   :3.404  
                    3rd Qu.: 136630                      3rd Qu.:4.000  
                    Max.   :1014000                      Max.   :8.000  
  NumChildren       NumPeople         NumRooms        NumUnits        
 Min.   :0.0000   Min.   : 2.000   Min.   : 1.000   Length:2273       
 1st Qu.:0.0000   1st Qu.: 2.000   1st Qu.: 6.000   Class :character  
 Median :0.0000   Median : 3.000   Median : 7.000   Mode  :character  
 Mean   :0.8847   Mean   : 3.401   Mean   : 7.241                     
 3rd Qu.:2.0000   3rd Qu.: 4.000   3rd Qu.: 8.000                     
 Max.   :8.0000   Max.   :12.000   Max.   :21.000                     
  NumVehicles      NumWorkers      OwnRent           YearBuilt           HouseCosts  
 Min.   :0.000   Min.   :0.000   Length:2273        Length:2273        Min.   :   4  
 1st Qu.:2.000   1st Qu.:1.000   Class :character   Class :character   1st Qu.: 670  
 Median :2.000   Median :2.000   Mode  :character   Mode  :character   Median :1200  
 Mean   :2.118   Mean   :1.778                                         Mean   :1488  
 3rd Qu.:3.000   3rd Qu.:2.000                                         3rd Qu.:2000  
 Max.   :6.000   Max.   :3.000                                         Max.   :6500  
  ElectricBill    FoodStamp         HeatingFuel          Insurance     
 Min.   :  1.0   Length:2273        Length:2273        Min.   :   0.0  
 1st Qu.:100.0   Class :character   Class :character   1st Qu.: 400.0  
 Median :150.0   Mode  :character   Mode  :character   Median : 720.0  
 Mean   :176.6                                         Mean   : 968.1  
 3rd Qu.:220.0                                         3rd Qu.:1200.0  
 Max.   :580.0                                         Max.   :6600.0  
   Language           Income    
 Length:2273        Below:1817  
 Class :character   Above: 456  
 Mode  :character               
                                
                                
                                

Sprawdźmy tym danych (funkcja class)

acsNew %>% class
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 

1.4 Zmianna na typ czynikowy niektórych zmiennych

Zmienna Language wygaje się, że powinna być zmienna czynnikową. Wyciągnimy kolumnę Language polecenim select.

acsNew.lang <- acsNew %>%
  select(Language)

Zobaczmy pierwsze 6 wierszy tej kolumny

acsNew.lang %>% head

oraz zobaczmy jakiej klasy jest ten obiekt.

acsNew.lang %>% class 
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 

To spóbujemy z niej taka zrobić.

1.5 Jak nie powinno się tego robić

1.5.1 Sposób pierwszy

Ponieważ funkcja select nie działał poprawnie wykorzystamy funkcję **pull* tworząc obiekt acsNew.lang.pull i sprawdzimy typ obiektu oraz obejrzymy 6 pierwszych elementów.

acsNew.lang.pull <- acsNew %>%
  pull(Language)
acsNew.lang.pull %>% class 
[1] "character"
acsNew.lang %>% head

Tworzymy nowy obiekt acsNew.lang.pull.fac z wektora danych acsNew.lang.pull, oglądamy go i nadpisujemy kolumnę Language w danych acsNew tym obiektem wykorzystując funkcję $.

acsNew.lang.pull.fac <- acsNew.lang.pull %>% 
  as.factor
acsNew.lang.pull.fac %>% head
[1] English       Spanish       Spanish       English       Asian Pacific
[6] English      
Levels: Asian Pacific English Other Other European Spanish
acsNew$Language <- acsNew.lang.pull.fac

1.5.1.1 Zapiszemy tylko dane na później

Zapisujemy otrzymane dane (obiekt acsNew).

save(acsNew, file = "acsNew.RData")

1.5.2 Sposób drugi dla zmiennej *NumUnits i pozostałych

Ponieważ oszczędzamy pamięć opisane poprzednio operacje można zapisać jako jeden ciąg poleceń wykorzystując przetwarzanie potokowe. Zobaczmy też podsumowanie.

acsNew$NumUnits <- acsNew %>%
  pull(NumUnits) %>%
  as.factor
acsNew %>% summary
    Acres            FamilyIncome           FamilyType    NumBedrooms   
 Length:2273        Min.   :   1125   Married    :1831   Min.   :0.000  
 Class :character   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000  
 Mode  :character   Median :  89200   Male Head  : 115   Median :3.000  
                    Mean   : 110982                      Mean   :3.404  
                    3rd Qu.: 136630                      3rd Qu.:4.000  
                    Max.   :1014000                      Max.   :8.000  
  NumChildren       NumPeople         NumRooms                 NumUnits   
 Min.   :0.0000   Min.   : 2.000   Min.   : 1.000   Mobile home    :  67  
 1st Qu.:0.0000   1st Qu.: 2.000   1st Qu.: 6.000   Single attached: 235  
 Median :0.0000   Median : 3.000   Median : 7.000   Single detached:1971  
 Mean   :0.8847   Mean   : 3.401   Mean   : 7.241                         
 3rd Qu.:2.0000   3rd Qu.: 4.000   3rd Qu.: 8.000                         
 Max.   :8.0000   Max.   :12.000   Max.   :21.000                         
  NumVehicles      NumWorkers      OwnRent           YearBuilt           HouseCosts  
 Min.   :0.000   Min.   :0.000   Length:2273        Length:2273        Min.   :   4  
 1st Qu.:2.000   1st Qu.:1.000   Class :character   Class :character   1st Qu.: 670  
 Median :2.000   Median :2.000   Mode  :character   Mode  :character   Median :1200  
 Mean   :2.118   Mean   :1.778                                         Mean   :1488  
 3rd Qu.:3.000   3rd Qu.:2.000                                         3rd Qu.:2000  
 Max.   :6.000   Max.   :3.000                                         Max.   :6500  
  ElectricBill    FoodStamp         HeatingFuel          Insurance     
 Min.   :  1.0   Length:2273        Length:2273        Min.   :   0.0  
 1st Qu.:100.0   Class :character   Class :character   1st Qu.: 400.0  
 Median :150.0   Mode  :character   Mode  :character   Median : 720.0  
 Mean   :176.6                                         Mean   : 968.1  
 3rd Qu.:220.0                                         3rd Qu.:1200.0  
 Max.   :580.0                                         Max.   :6600.0  
           Language      Income    
 Asian Pacific :  62   Below:1817  
 English       :1786   Above: 456  
 Other         :  39               
 Other European: 219               
 Spanish       : 167               
                                   

Powtórzmy czynność dla pozostałych zmiennych typu character.

acsNew$Acres <- acsNew %>%
  pull(Acres) %>%
  as.factor
acsNew$OwnRent <- acsNew %>%
  pull(OwnRent) %>%
  as.factor
acsNew$FoodStamp <- acsNew %>%
  pull(FoodStamp) %>%
  as.factor
acsNew$HeatingFuel <- acsNew %>%
  pull(HeatingFuel) %>%
  as.factor
acsNew %>% summary
   Acres       FamilyIncome           FamilyType    NumBedrooms     NumChildren    
 1-10 : 452   Min.   :   1125   Married    :1831   Min.   :0.000   Min.   :0.0000  
 10+  :  90   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000   1st Qu.:0.0000  
 Sub 1:1731   Median :  89200   Male Head  : 115   Median :3.000   Median :0.0000  
              Mean   : 110982                      Mean   :3.404   Mean   :0.8847  
              3rd Qu.: 136630                      3rd Qu.:4.000   3rd Qu.:2.0000  
              Max.   :1014000                      Max.   :8.000   Max.   :8.0000  
                                                                                   
   NumPeople         NumRooms                 NumUnits     NumVehicles   
 Min.   : 2.000   Min.   : 1.000   Mobile home    :  67   Min.   :0.000  
 1st Qu.: 2.000   1st Qu.: 6.000   Single attached: 235   1st Qu.:2.000  
 Median : 3.000   Median : 7.000   Single detached:1971   Median :2.000  
 Mean   : 3.401   Mean   : 7.241                          Mean   :2.118  
 3rd Qu.: 4.000   3rd Qu.: 8.000                          3rd Qu.:3.000  
 Max.   :12.000   Max.   :21.000                          Max.   :6.000  
                                                                         
   NumWorkers        OwnRent      YearBuilt           HouseCosts    ElectricBill  
 Min.   :0.000   Mortgage:2008   Length:2273        Min.   :   4   Min.   :  1.0  
 1st Qu.:1.000   Outright:  15   Class :character   1st Qu.: 670   1st Qu.:100.0  
 Median :2.000   Rented  : 250   Mode  :character   Median :1200   Median :150.0  
 Mean   :1.778                                      Mean   :1488   Mean   :176.6  
 3rd Qu.:2.000                                      3rd Qu.:2000   3rd Qu.:220.0  
 Max.   :3.000                                      Max.   :6500   Max.   :580.0  
                                                                                  
 FoodStamp       HeatingFuel     Insurance                Language      Income    
 No :2106   Coal       :  16   Min.   :   0.0   Asian Pacific :  62   Below:1817  
 Yes: 167   Electricity: 109   1st Qu.: 400.0   English       :1786   Above: 456  
            Gas        :1387   Median : 720.0   Other         :  39               
            None       :   4   Mean   : 968.1   Other European: 219               
            Oil        : 622   3rd Qu.:1200.0   Spanish       : 167               
            Other      :  18   Max.   :6600.0                                     
            Wood       : 117                                                      

1.5.2.1 Zmienna YearBuilt

Coś nie tak z jedną daną ze zmiennej YearBuilt

Podczytujemy bibliotekę DT.

Filtrujemy dane (funkcja filter) i oglądamy.

acsNew %>%
  filter(YearBuilt == 15) %>%
  datatable

Filtrujemy dane dla zmiennej NumUnits. Ponieważ nazwa zawiera spację używamy apostrofów (‘Mobile home’) i oglądamy.

acsNew %>%
  filter(NumUnits == 'Mobile home') %>%
  datatable

Jest błąd, ale go zignorujemy. Wyświetlamy podsumowanie i wprowadzamy nowy obiekt acsNew.ver.StepByStep, w którym przechowywać będziemy wynik naszych operacji.

acsNew$YearBuilt <- acsNew %>%
  pull(YearBuilt) %>%
  as.factor
acsNew %>% summary
   Acres       FamilyIncome           FamilyType    NumBedrooms     NumChildren    
 1-10 : 452   Min.   :   1125   Married    :1831   Min.   :0.000   Min.   :0.0000  
 10+  :  90   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000   1st Qu.:0.0000  
 Sub 1:1731   Median :  89200   Male Head  : 115   Median :3.000   Median :0.0000  
              Mean   : 110982                      Mean   :3.404   Mean   :0.8847  
              3rd Qu.: 136630                      3rd Qu.:4.000   3rd Qu.:2.0000  
              Max.   :1014000                      Max.   :8.000   Max.   :8.0000  
                                                                                   
   NumPeople         NumRooms                 NumUnits     NumVehicles   
 Min.   : 2.000   Min.   : 1.000   Mobile home    :  67   Min.   :0.000  
 1st Qu.: 2.000   1st Qu.: 6.000   Single attached: 235   1st Qu.:2.000  
 Median : 3.000   Median : 7.000   Single detached:1971   Median :2.000  
 Mean   : 3.401   Mean   : 7.241                          Mean   :2.118  
 3rd Qu.: 4.000   3rd Qu.: 8.000                          3rd Qu.:3.000  
 Max.   :12.000   Max.   :21.000                          Max.   :6.000  
                                                                         
   NumWorkers        OwnRent           YearBuilt     HouseCosts    ElectricBill  
 Min.   :0.000   Mortgage:2008   Before 1939:588   Min.   :   4   Min.   :  1.0  
 1st Qu.:1.000   Outright:  15   1950-1959  :423   1st Qu.: 670   1st Qu.:100.0  
 Median :2.000   Rented  : 250   1960-1969  :269   Median :1200   Median :150.0  
 Mean   :1.778                   1970-1979  :229   Mean   :1488   Mean   :176.6  
 3rd Qu.:2.000                   1990-1999  :198   3rd Qu.:2000   3rd Qu.:220.0  
 Max.   :3.000                   1980-1989  :195   Max.   :6500   Max.   :580.0  
                                 (Other)    :371                                 
 FoodStamp       HeatingFuel     Insurance                Language      Income    
 No :2106   Coal       :  16   Min.   :   0.0   Asian Pacific :  62   Below:1817  
 Yes: 167   Electricity: 109   1st Qu.: 400.0   English       :1786   Above: 456  
            Gas        :1387   Median : 720.0   Other         :  39               
            None       :   4   Mean   : 968.1   Other European: 219               
            Oil        : 622   3rd Qu.:1200.0   Spanish       : 167               
            Other      :  18   Max.   :6600.0                                     
            Wood       : 117                                                      
acsNew -> acsNew.ver.StepByStep

1.6 Jak należy to zrobić

Można to zrobić jednym ciągiem poleceń. Wykorzystujemy w tym celu funkcję mutate_if, gdzie przekształcamy tylko te zmienne, które są typu charakter (argument is.charakter), na zmienne czyniikowe (argument list(~as.factor(.))). Kropka w ostatnim argumencie oznacza zmienną, do której ma być stosowana funkcja as.factor.

load("acsNew.RData")
acsNew %>%  summary
    Acres            FamilyIncome           FamilyType    NumBedrooms   
 Length:2273        Min.   :   1125   Married    :1831   Min.   :0.000  
 Class :character   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000  
 Mode  :character   Median :  89200   Male Head  : 115   Median :3.000  
                    Mean   : 110982                      Mean   :3.404  
                    3rd Qu.: 136630                      3rd Qu.:4.000  
                    Max.   :1014000                      Max.   :8.000  
  NumChildren       NumPeople         NumRooms        NumUnits        
 Min.   :0.0000   Min.   : 2.000   Min.   : 1.000   Length:2273       
 1st Qu.:0.0000   1st Qu.: 2.000   1st Qu.: 6.000   Class :character  
 Median :0.0000   Median : 3.000   Median : 7.000   Mode  :character  
 Mean   :0.8847   Mean   : 3.401   Mean   : 7.241                     
 3rd Qu.:2.0000   3rd Qu.: 4.000   3rd Qu.: 8.000                     
 Max.   :8.0000   Max.   :12.000   Max.   :21.000                     
  NumVehicles      NumWorkers      OwnRent           YearBuilt           HouseCosts  
 Min.   :0.000   Min.   :0.000   Length:2273        Length:2273        Min.   :   4  
 1st Qu.:2.000   1st Qu.:1.000   Class :character   Class :character   1st Qu.: 670  
 Median :2.000   Median :2.000   Mode  :character   Mode  :character   Median :1200  
 Mean   :2.118   Mean   :1.778                                         Mean   :1488  
 3rd Qu.:3.000   3rd Qu.:2.000                                         3rd Qu.:2000  
 Max.   :6.000   Max.   :3.000                                         Max.   :6500  
  ElectricBill    FoodStamp         HeatingFuel          Insurance     
 Min.   :  1.0   Length:2273        Length:2273        Min.   :   0.0  
 1st Qu.:100.0   Class :character   Class :character   1st Qu.: 400.0  
 Median :150.0   Mode  :character   Mode  :character   Median : 720.0  
 Mean   :176.6                                         Mean   : 968.1  
 3rd Qu.:220.0                                         3rd Qu.:1200.0  
 Max.   :580.0                                         Max.   :6600.0  
           Language      Income    
 Asian Pacific :  62   Below:1817  
 English       :1786   Above: 456  
 Other         :  39               
 Other European: 219               
 Spanish       : 167               
                                   
acsNew <- acsNew %>% 
  mutate_if(is.character, list(~as.factor(.)))

Oglądamy wynik podsumowania.

acsNew %>%  summary
   Acres       FamilyIncome           FamilyType    NumBedrooms     NumChildren    
 1-10 : 452   Min.   :   1125   Married    :1831   Min.   :0.000   Min.   :0.0000  
 10+  :  90   1st Qu.:  53700   Female Head: 327   1st Qu.:3.000   1st Qu.:0.0000  
 Sub 1:1731   Median :  89200   Male Head  : 115   Median :3.000   Median :0.0000  
              Mean   : 110982                      Mean   :3.404   Mean   :0.8847  
              3rd Qu.: 136630                      3rd Qu.:4.000   3rd Qu.:2.0000  
              Max.   :1014000                      Max.   :8.000   Max.   :8.0000  
                                                                                   
   NumPeople         NumRooms                 NumUnits     NumVehicles   
 Min.   : 2.000   Min.   : 1.000   Mobile home    :  67   Min.   :0.000  
 1st Qu.: 2.000   1st Qu.: 6.000   Single attached: 235   1st Qu.:2.000  
 Median : 3.000   Median : 7.000   Single detached:1971   Median :2.000  
 Mean   : 3.401   Mean   : 7.241                          Mean   :2.118  
 3rd Qu.: 4.000   3rd Qu.: 8.000                          3rd Qu.:3.000  
 Max.   :12.000   Max.   :21.000                          Max.   :6.000  
                                                                         
   NumWorkers        OwnRent           YearBuilt     HouseCosts    ElectricBill  
 Min.   :0.000   Mortgage:2008   Before 1939:588   Min.   :   4   Min.   :  1.0  
 1st Qu.:1.000   Outright:  15   1950-1959  :423   1st Qu.: 670   1st Qu.:100.0  
 Median :2.000   Rented  : 250   1960-1969  :269   Median :1200   Median :150.0  
 Mean   :1.778                   1970-1979  :229   Mean   :1488   Mean   :176.6  
 3rd Qu.:2.000                   1990-1999  :198   3rd Qu.:2000   3rd Qu.:220.0  
 Max.   :3.000                   1980-1989  :195   Max.   :6500   Max.   :580.0  
                                 (Other)    :371                                 
 FoodStamp       HeatingFuel     Insurance                Language      Income    
 No :2106   Coal       :  16   Min.   :   0.0   Asian Pacific :  62   Below:1817  
 Yes: 167   Electricity: 109   1st Qu.: 400.0   English       :1786   Above: 456  
            Gas        :1387   Median : 720.0   Other         :  39               
            None       :   4   Mean   : 968.1   Other European: 219               
            Oil        : 622   3rd Qu.:1200.0   Spanish       : 167               
            Other      :  18   Max.   :6600.0                                     
            Wood       : 117                                                      

Zapisujemy otrzymany wynik, zmieniając nazwę obiektu na acsNew.ver.OneStep, do pliku acsNewVerOneStep.RData.

Na koniec usuwamy ze środowiska bibliotek

2 Bibliografia

1 J.P. Lander, R dla każdego. Zaawansowane analizy i grafika statystyczna (APN Promise, Warszawa, 2018).

2 J.P. Lander, (2020).

3 R Core Team, R: A Language and Environment for Statistical Computing (R Foundation for Statistical Computing, Vienna, Austria, 2019).

4 H. Wickham, J. Hester, and R. Francois, readr: Read Rectangular Text Data (2018).

5 H. Wickham, R. François, L. Henry, and K. Müller, dplyr: A Grammar of Data Manipulation (2020).

6 Y. Xie, J. Cheng, and X. Tan, DT: A Wrapper of the JavaScript Library ’DataTables’ (2020).

7 Y. Xie, J.J. Allaire, and G. Grolemund, R Markdown: The Definitive Guide (Chapman; Hall/CRC, Boca Raton, Florida, 2018).

8 J. Allaire, Y. Xie, J. McPherson, J. Luraschi, K. Ushey, A. Atkins, H. Wickham, J. Cheng, W. Chang, and R. Iannone, rmarkdown: Dynamic Documents for R (2020).

LS0tDQp0aXRsZTogIlByYWNhIHogZGFueW1pIC0gY3rEmcWbxIcgdHJ6ZWNpYSINCmF1dGhvcjogDQogIC0gSmFyb3PFgmF3IEtvdG93aWN6Og0KICAgICAgaW5zdGl0dXRlOiANCiAgICAgICAgLSBJSVV3Qg0KICAgICAgY29ycmVzcG9uZGVuY2U6IGZhbHNlDQogICAgICBlbWFpbDogai5rb3Rvd2ljekB1d2IuZWR1LnBsDQpkYXRlOiAiNCBtYXJjYSAyMDIwIg0KYWx3YXlzX2FsbG93X2h0bWw6IHRydWUNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgcGFuZG9jX2FyZ3M6DQogICAgICAtIC0tbHVhLWZpbHRlcj1zY2hvbGFybHktbWV0YWRhdGEubHVhDQogICAgICAtIC0tbHVhLWZpbHRlcj1hdXRob3ItaW5mby1ibG9ja3MubHVhDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQppbnN0aXR1dGU6IA0KICAtIElJVXdCOiBaYWvFgmFkIEJpb2luZm9ybWF0eWtpLCBJbnN0eXR1dCBJbmZvcm1hdHlraSwgVW5pd2Vyc3l0ZXQgdyBCaWHFgnltc3Rva3UNCmNzbDogam91cm5hbC1vZi1tYXRoZW1hdGljYWwtcGh5c2ljcy5jc2wNCmJpYmxpb2dyYXBoeTogSW5mRWtvLmJpYg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgUG9kY3p5dGFuaWUgZGFueWNoIHogd3lrb3J6eXN0YW5pZW0gcGFraWV0dSAqKnJlYWRyKioNCg0KSW5zcGlyYWNqxIUgZG8gbmFwaXNhbmlhIHRlZ28gKm5vdGVib29rYSogamVzdCByb2R6aWHFgiA2LjEga3NpxIXFvGtpIEphcmVkYSBQLiBMYW5kZXJhICoiUiBkbGEga2HFvGRlZ28uIFphYXdhbnNvd2FuZSBhbmFsaXp5IGkgZ3JhZmlrYSBzdGF0eXN0eWN6bmEiKiBbQGxhbmRlcl9SZEtdLiBEYW5lIHd5a29yenlzdGFuZSBwb2Nob2R6xIUgcsOzd25pZcW8IHplIHN0cm9ueSBKYXJlZGEgUC4gTGFuZGVyYSBbQHdlYnNpdGVfbGFuZGVyX1JkS10uDQoNCktvcnp5c3RhbXkgeiANCg0KMS4gUiBbQGxhbmd1YWdlX1JdLA0KMi4gYmlibGlvdGVrIFIgW0BwYWNrYWdlX3JlYWRyOyBAcGFja2FnZV9kcGx5cjsgQHBhY2thZ2VfRFRdLA0KMy4gcGlzemVteSB1xbx5d2FqxIVjIGrEmXp5a2Egem5hY3puaWvDs3cgaSBiaWJsaW90ZWtpICoqcm1hcmtkb3duKiogW0Bib29rX3JtYXJrZG93bjsgQHBhY2thZ2Vfcm1hcmtkb3duXSB3ICoqUlN0dWRpbyoqIHogd3lrb3J6eXN0YW5pZW0gKipSIE5vdGVib29rKiouDQoNClV3YWdhOg0KDQoqIEtvZCBwb2Rjenl0YW5pYSBiaWJsaW90ZWsgamVzdCB1a3J5dHkuDQoNCiMjIEN6ecWbY2lteSDFm3JvZG93aXNrbw0KDQpgYGB7ciBjenlzemN6ZW5pZV9kYW55Y2gsIGVjaG89VFJVRX0NCnJtKGxpc3QgPSBscygpKQ0KYGBgDQoNCiMjIFBvZGN6eXR1amVteSBkYW5lDQoNCmBgYHtyIHBha2lldF9yZWFkciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkocmVhZHIpDQpgYGANCg0KYGBge3IgcG9kY3p5dGFuaWVfYWNzTmV3fQ0KYWNzTmV3IDwtIHJlYWRfY3N2KCJodHRwOi8vd3d3LmphcmVkbGFuZGVyLmNvbS9kYXRhL2Fjc05ldy5jc3YiLCANCiAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSANCiAgICAgICAgICAgICAgICAgICBjb2xzKEZhbWlseVR5cGUgPSBjb2xfZmFjdG9yKGxldmVscyA9IGMoIk1hcnJpZWQiLCJGZW1hbGUgSGVhZCIsICJNYWxlIEhlYWQiKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgSW5jb21lID0gY29sX2ZhY3RvcihsZXZlbHMgPSBjKCJCZWxvdyIsICJBYm92ZSIpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQpXY3p5dHVqZW15IGJpYmxpb3Rla8SZICoqZHBseXIqKg0KDQpgYGB7ciBwYWtpZXRfZHBseXIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiMjIFRyb2NoxJkgcG9kc3Vtb3dhbmlhLCBjbyBqZXN0IHcgZGFueWNoDQoNClpvYmFjem15LCBjbyB1a3J5d2Egc2nEmSBwb2QgZGFueW1pICh3eWtvcnp5c3R1amVteSBmdW5rY2rEmSAqKnN1bW1hcnkqKikuDQoNCmBgYHtyIGZ1bmtjamFfc3VtbWFyeX0NCmFjc05ldyAlPiUgc3VtbWFyeQ0KYGBgDQpTcHJhd2TFum15IHR5bSBkYW55Y2ggKGZ1bmtjamEgKipjbGFzcyoqKQ0KYGBge3IgZnVua2NqYV9jbGFzc30NCmFjc05ldyAlPiUgY2xhc3MNCmBgYA0KDQojIyBabWlhbm5hIG5hIHR5cCBjenluaWtvd3kgbmlla3TDs3J5Y2ggem1pZW5ueWNoDQoNClptaWVubmEgKipMYW5ndWFnZSoqIHd5Z2FqZSBzacSZLCDFvGUgcG93aW5uYSBiecSHIHptaWVubmEgY3p5bm5pa293xIUuDQpXeWNpxIVnbmlteSBrb2x1bW7EmSAqKkxhbmd1YWdlKiogcG9sZWNlbmltICoqc2VsZWN0KiouDQoNCmBgYHtyIGFjc05ld19MYW5ndWFnZX0NCmFjc05ldy5sYW5nIDwtIGFjc05ldyAlPiUNCiAgc2VsZWN0KExhbmd1YWdlKQ0KYGBgDQoNClpvYmFjem15IHBpZXJ3c3plIDYgd2llcnN6eSB0ZWoga29sdW1ueQ0KYGBge3IgYWNzTmV3X0xhbmd1YWdlXzAyfQ0KYWNzTmV3LmxhbmcgJT4lIGhlYWQNCmBgYA0KDQpvcmF6IHpvYmFjem15IGpha2llaiBrbGFzeSBqZXN0IHRlbiBvYmlla3QuDQpgYGB7ciBhY3NOZXdfTGFuZ3VhZ2VfMDN9DQphY3NOZXcubGFuZyAlPiUgY2xhc3MgDQpgYGANCg0KKlRvIHNww7NidWplbXkgeiBuaWVqIHRha2EgenJvYmnEhy4qDQoNCiMjIEphayBuaWUgcG93aW5ubyBzacSZIHRlZ28gcm9iacSHDQoNCiMjIyBTcG9zw7NiIHBpZXJ3c3p5DQoNClBvbmlld2HFvCBmdW5rY2phICoqc2VsZWN0KiogbmllIGR6aWHFgmHFgiBwb3ByYXduaWUgd3lrb3J6eXN0YW15IGZ1bmtjasSZICoqcHVsbCogIHR3b3J6xIVjIA0Kb2JpZWt0ICphY3NOZXcubGFuZy5wdWxsKiBpIHNwcmF3ZHppbXkgdHlwIG9iaWVrdHUgb3JheiBvYmVqcnp5bXkgNiBwaWVyd3N6eWNoIGVsZW1lbnTDs3cuDQpgYGB7ciBzdGVwX2J5X3N0ZXBfMDF9DQphY3NOZXcubGFuZy5wdWxsIDwtIGFjc05ldyAlPiUNCiAgcHVsbChMYW5ndWFnZSkNCg0KYWNzTmV3LmxhbmcucHVsbCAlPiUgY2xhc3MgDQoNCmFjc05ldy5sYW5nICU+JSBoZWFkDQpgYGANCg0KVHdvcnp5bXkgbm93eSBvYmlla3QgKmFjc05ldy5sYW5nLnB1bGwuZmFjKiB6IHdla3RvcmEgZGFueWNoICphY3NOZXcubGFuZy5wdWxsKiwgb2dsxIVkYW15IGdvIGkgbmFkcGlzdWplbXkga29sdW1uxJkgKipMYW5ndWFnZSoqIHcgZGFueWNoICoqYWNzTmV3KiogdHltIG9iaWVrdGVtIHd5a29yenlzdHVqxIVjIGZ1bmtjasSZICoqJCoqLg0KYGBge3Igc3RlcF9ieV9zdGVwXzEwfQ0KYWNzTmV3LmxhbmcucHVsbC5mYWMgPC0gYWNzTmV3LmxhbmcucHVsbCAlPiUgDQogIGFzLmZhY3Rvcg0KDQphY3NOZXcubGFuZy5wdWxsLmZhYyAlPiUgaGVhZA0KDQphY3NOZXckTGFuZ3VhZ2UgPC0gYWNzTmV3LmxhbmcucHVsbC5mYWMNCmBgYA0KDQojIyMjIFphcGlzemVteSB0eWxrbyBkYW5lIG5hIHDDs8W6bmllag0KDQpaYXBpc3VqZW15IG90cnp5bWFuZSBkYW5lIChvYmlla3QgKmFjc05ldyopLg0KYGBge3Igc2F2ZV9hY3NOZXcsIGVjaG89VFJVRX0NCnNhdmUoYWNzTmV3LCBmaWxlID0gImFjc05ldy5SRGF0YSIpDQpgYGANCg0KIyMjIFNwb3PDs2IgZHJ1Z2kgZGxhIHptaWVubmVqICoqKk51bVVuaXRzKiogaSBwb3pvc3RhxYJ5Y2gNCg0KUG9uaWV3YcW8IG9zemN6xJlkemFteSBwYW1pxJnEhyBvcGlzYW5lIHBvcHJ6ZWRuaW8gb3BlcmFjamUgbW/FvG5hIHphcGlzYcSHIGpha28gamVkZW4gY2nEhWcgcG9sZWNlxYQgd3lrb3J6eXN0dWrEhWMgcHJ6ZXR3YXJ6YW5pZSBwb3Rva293ZS4gWm9iYWN6bXkgdGXFvCBwb2RzdW1vd2FuaWUuDQpgYGB7ciBhY3NOZXdfTnVtVW5pdHN9DQphY3NOZXckTnVtVW5pdHMgPC0gYWNzTmV3ICU+JQ0KICBwdWxsKE51bVVuaXRzKSAlPiUNCiAgYXMuZmFjdG9yDQphY3NOZXcgJT4lIHN1bW1hcnkNCmBgYA0KDQpQb3d0w7Nyem15IGN6eW5ub8WbxIcgZGxhIHBvem9zdGHFgnljaCB6bWllbm55Y2ggdHlwdSAqKmNoYXJhY3RlcioqLg0KYGBge3IgYWNzTmV3X290aGVyc30NCmFjc05ldyRBY3JlcyA8LSBhY3NOZXcgJT4lDQogIHB1bGwoQWNyZXMpICU+JQ0KICBhcy5mYWN0b3INCg0KYWNzTmV3JE93blJlbnQgPC0gYWNzTmV3ICU+JQ0KICBwdWxsKE93blJlbnQpICU+JQ0KICBhcy5mYWN0b3INCg0KYWNzTmV3JEZvb2RTdGFtcCA8LSBhY3NOZXcgJT4lDQogIHB1bGwoRm9vZFN0YW1wKSAlPiUNCiAgYXMuZmFjdG9yDQoNCmFjc05ldyRIZWF0aW5nRnVlbCA8LSBhY3NOZXcgJT4lDQogIHB1bGwoSGVhdGluZ0Z1ZWwpICU+JQ0KICBhcy5mYWN0b3INCg0KYWNzTmV3ICU+JSBzdW1tYXJ5DQpgYGANCg0KIyMjIyBabWllbm5hICoqWWVhckJ1aWx0KioNCg0KQ2/FmyBuaWUgdGFrIHogamVkbsSFIGRhbsSFIHplIHptaWVubmVqICoqWWVhckJ1aWx0KioNCg0KUG9kY3p5dHVqZW15IGJpYmxpb3Rla8SZICoqRFQqKi4NCmBgYHtyIHBha2lldF9EVCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoRFQpDQpgYGANCg0KRmlsdHJ1amVteSBkYW5lIChmdW5rY2phICoqZmlsdGVyKiopIGkgb2dsxIVkYW15LiANCmBgYHtyIGFjc05ld19ZZWFyQnVpbHRfMDF9DQphY3NOZXcgJT4lDQogIGZpbHRlcihZZWFyQnVpbHQgPT0gMTUpICU+JQ0KICBkYXRhdGFibGUNCmBgYA0KDQpGaWx0cnVqZW15IGRhbmUgZGxhIHptaWVubmVqICoqTnVtVW5pdHMqKi4gUG9uaWV3YcW8IG5hendhIHphd2llcmEgc3BhY2rEmSB1xbx5d2FteSBhcG9zdHJvZsOzdw0KKCoqJ01vYmlsZSBob21lJyoqKSBpIG9nbMSFZGFteS4NCmBgYHtyIGFjc05ld19ZZWFyQnVpbHRfMDJ9DQphY3NOZXcgJT4lDQogIGZpbHRlcihOdW1Vbml0cyA9PSAnTW9iaWxlIGhvbWUnKSAlPiUNCiAgZGF0YXRhYmxlDQpgYGANCg0KSmVzdCBixYLEhWQsIGFsZSBnbyB6aWdub3J1amVteS4gV3nFm3dpZXRsYW15IHBvZHN1bW93YW5pZSBpIHdwcm93YWR6YW15IG5vd3kgb2JpZWt0DQoqKmFjc05ldy52ZXIuU3RlcEJ5U3RlcCoqLCB3IGt0w7NyeW0gcHJ6ZWNob3d5d2HEhyBixJlkemllbXkgd3luaWsgbmFzenljaCBvcGVyYWNqaS4NCmBgYHtyIGFjc05ld19ZZWFyQnVpbHRfMDN9DQphY3NOZXckWWVhckJ1aWx0IDwtIGFjc05ldyAlPiUNCiAgcHVsbChZZWFyQnVpbHQpICU+JQ0KICBhcy5mYWN0b3INCg0KYWNzTmV3ICU+JSBzdW1tYXJ5DQphY3NOZXcgLT4gYWNzTmV3LnZlci5TdGVwQnlTdGVwDQpgYGANCg0KIyMgSmFrIG5hbGXFvHkgdG8genJvYmnEhw0KDQpNb8W8bmEgdG8genJvYmnEhyBqZWRueW0gY2nEhWdpZW0gcG9sZWNlxYQuIFd5a29yenlzdHVqZW15IHcgdHltIGNlbHUgZnVua2NqxJkgKiptdXRhdGVfaWYqKiwNCmdkemllIHByemVrc3p0YcWCY2FteSB0eWxrbyB0ZSB6bWllbm5lLCBrdMOzcmUgc8SFIHR5cHUgKmNoYXJha3RlciogKGFyZ3VtZW50ICoqaXMuY2hhcmFrdGVyKiopLCBuYSB6bWllbm5lIGN6eW5paWtvd2UgKGFyZ3VtZW50ICoqbGlzdCh+YXMuZmFjdG9yKC4pKSoqKS4NCktyb3BrYSB3IG9zdGF0bmltIGFyZ3VtZW5jaWUgb3puYWN6YSB6bWllbm7EhSwgZG8ga3TDs3JlaiBtYSBiecSHIHN0b3Nvd2FuYSBmdW5rY2phDQoqKmFzLmZhY3RvcioqLg0KDQpgYGB7ciBvbmVfc3RlcH0NCmxvYWQoImFjc05ldy5SRGF0YSIpDQphY3NOZXcgJT4lICBzdW1tYXJ5DQphY3NOZXcgPC0gYWNzTmV3ICU+JSANCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgbGlzdCh+YXMuZmFjdG9yKC4pKSkNCmBgYA0KDQpPZ2zEhWRhbXkgd3luaWsgcG9kc3Vtb3dhbmlhLg0KYGBge3Igb25lX3N0ZXBfMDF9DQphY3NOZXcgJT4lICBzdW1tYXJ5DQpgYGANCg0KWmFwaXN1amVteSBvdHJ6eW1hbnkgd3luaWssIHptaWVuaWFqxIVjIG5henfEmSBvYmlla3R1IG5hICoqYWNzTmV3LnZlci5PbmVTdGVwKiosIGRvIHBsaWt1ICoqYWNzTmV3VmVyT25lU3RlcC5SRGF0YSoqLg0KYGBge3Igc2F2ZV9hY3NOZXcudmVyLk9uZVN0ZXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQphY3NOZXcgLT4gYWNzTmV3LnZlci5PbmVTdGVwDQpzYXZlKGFjc05ldy52ZXIuT25lU3RlcCwgZmlsZSA9ICJhY3NOZXdWZXJPbmVTdGVwLlJEYXRhIikNCg0KYGBgDQoNCk5hIGtvbmllYyB1c3V3YW15IHplIMWbcm9kb3dpc2thIGJpYmxpb3Rlaw0KYGBge3IgcGFraWV0eV96YW15a2FuaWUsIGluY2x1ZGU9RkFMU0V9DQpkZXRhY2gocGFja2FnZTpyZWFkcikNCmRldGFjaChwYWNrYWdlOmRwbHlyKQ0KZGV0YWNoKHBhY2thZ2U6RFQpDQpgYGANCiMgQmlibGlvZ3JhZmlhDQoNCjxkaXYgaWQ9InJlZnMiPjwvZGl2Pg0K