library(tidyverse)
library(vegan)

Challenge from last week

Step 1

mydata <- read_csv("https://ndownloader.figshare.com/files/2292169")
glimpse(mydata)
Observations: 34,786
Variables: 13
$ record_id       <int> 1, 72, 224, 266, 349, 363, 435, 506, 588, 661, 748, 845, 990, 1164, 1261, 13...
$ month           <int> 7, 8, 9, 10, 11, 11, 12, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 4, 5, 7, 10, 11, 1,...
$ day             <int> 16, 19, 13, 16, 12, 12, 10, 8, 18, 11, 8, 6, 9, 5, 4, 8, 5, 29, 30, 4, 25, 1...
$ year            <int> 1977, 1977, 1977, 1977, 1977, 1977, 1977, 1978, 1978, 1978, 1978, 1978, 1978...
$ plot_id         <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2...
$ species_id      <chr> "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL", "NL"...
$ sex             <chr> "M", "M", NA, NA, NA, NA, NA, NA, "M", NA, NA, "M", "M", "M", "M", NA, "M", ...
$ hindfoot_length <int> 32, 31, NA, NA, NA, NA, NA, NA, NA, NA, NA, 32, NA, 34, 32, NA, NA, 33, 32, ...
$ weight          <int> NA, NA, NA, NA, NA, NA, NA, NA, 218, NA, NA, 204, 200, 199, 197, NA, 218, 16...
$ genus           <chr> "Neotoma", "Neotoma", "Neotoma", "Neotoma", "Neotoma", "Neotoma", "Neotoma",...
$ species         <chr> "albigula", "albigula", "albigula", "albigula", "albigula", "albigula", "alb...
$ taxa            <chr> "Rodent", "Rodent", "Rodent", "Rodent", "Rodent", "Rodent", "Rodent", "Roden...
$ plot_type       <chr> "Control", "Control", "Control", "Control", "Control", "Control", "Control",...
mydata %>% 
  filter(taxa == "Rodent") %>% 
  group_by(month, year, plot_id, species_id) %>% 
  summarise(N = n_distinct(record_id)) %>% 
  group_by(year, plot_id, species_id) %>% 
  summarise(MaxN = max(N)) %>% 
  group_by(plot_id, species_id) %>% 
  summarise(MaxN2 = max(MaxN)) %>% 
  spread(species_id, MaxN2, fill = 0) %>%
  ungroup()  ->  mydata_wide
mydata_wide
mydata_wide %>% 
  select(-plot_id) %>% 
  as.matrix() -> mydata_wide2
mydata_rel <- decostand(mydata_wide2, method = "total", MARGIN = 1)
head(mydata_rel) 
           AH         BA         DM         DO         DS         DX         NL         OL         OT
1 0.032258065 0.01075269 0.19354839 0.10752688 0.08602151 0.01075269 0.04301075 0.05376344 0.05376344
2 0.020000000 0.01000000 0.17000000 0.06000000 0.10000000 0.01000000 0.04000000 0.03000000 0.06000000
3 0.009433962 0.01886792 0.05660377 0.04716981 0.05660377 0.00000000 0.02830189 0.04716981 0.03773585
4 0.012345679 0.00000000 0.24691358 0.08641975 0.13580247 0.01234568 0.01234568 0.04938272 0.03703704
5 0.014492754 0.02898551 0.23188406 0.08695652 0.07246377 0.01449275 0.02898551 0.04347826 0.05797101
6 0.011494253 0.00000000 0.12643678 0.13793103 0.10344828 0.00000000 0.01149425 0.02298851 0.06896552
           OX         PB         PE         PF          PH          PI          PL         PM         PP
1 0.000000000 0.06451613 0.03225806 0.03225806 0.021505376 0.000000000 0.000000000 0.02150538 0.15053763
2 0.010000000 0.15000000 0.07000000 0.02000000 0.000000000 0.000000000 0.000000000 0.04000000 0.09000000
3 0.009433962 0.16981132 0.02830189 0.05660377 0.009433962 0.009433962 0.009433962 0.05660377 0.14150943
4 0.000000000 0.14814815 0.01234568 0.08641975 0.000000000 0.012345679 0.000000000 0.01234568 0.07407407
5 0.014492754 0.00000000 0.02898551 0.05797101 0.014492754 0.000000000 0.014492754 0.07246377 0.05797101
6 0.000000000 0.17241379 0.03448276 0.05747126 0.000000000 0.000000000 0.000000000 0.03448276 0.08045977
           PX          RF         RM         RO         RX          SF         SH         SO         SS
1 0.000000000 0.000000000 0.03225806 0.01075269 0.00000000 0.000000000 0.00000000 0.00000000 0.03225806
2 0.000000000 0.010000000 0.04000000 0.01000000 0.00000000 0.000000000 0.02000000 0.02000000 0.01000000
3 0.009433962 0.009433962 0.07547170 0.00000000 0.00000000 0.009433962 0.02830189 0.03773585 0.03773585
4 0.000000000 0.000000000 0.02469136 0.00000000 0.00000000 0.000000000 0.01234568 0.00000000 0.02469136
5 0.000000000 0.028985507 0.05797101 0.01449275 0.01449275 0.000000000 0.01449275 0.00000000 0.02898551
6 0.000000000 0.011494253 0.05747126 0.00000000 0.00000000 0.000000000 0.02298851 0.01149425 0.02298851
  ST         UR
1  0 0.01075269
2  0 0.01000000
3  0 0.00000000
4  0 0.00000000
5  0 0.00000000
6  0 0.01149425

Plot

mydata_wide %>% 
  gather(Species, MaxN, AH:UR) %>% 
  group_by(plot_id) %>% 
  mutate(Total = sum(MaxN)) %>% 
  arrange(plot_id, Species) %>% 
  mutate(Prop = MaxN / Total) -> mydata_prop
ggplot(data = mydata_prop) + 
  geom_bar(aes(x = plot_id, y = Prop, fill = Species), stat = "identity", position = "stack") + 
  theme_classic()

Data standardizations (continued from last week

Maximums

  • can be applied to any range of x
  • Outputs will range from 0 to 1, largest values will scale to 1
  • Converts vlaues to a relative value (equalized the peak abundance)
  • Useful when you have differences in total abundance

Rows

  • tells us the relative relationship within a site
  • Species with the greatest abundance will be 1
rawdata <- matrix(c(1,1,1,3,3,1,
                    2,2,4,6,6,0,
                    10,10,20,30,30,0,
                    3,3,2,1,1,0,
                    0,0,0,20,0,0), ncol = 6, byrow = TRUE)
colnames(rawdata) <- paste("species",toupper(letters[1:6]), sep = "_")
rawdata
     species_A species_B species_C species_D species_E species_F
[1,]         1         1         1         3         3         1
[2,]         2         2         4         6         6         0
[3,]        10        10        20        30        30         0
[4,]         3         3         2         1         1         0
[5,]         0         0         0        20         0         0
rowsum_data <- rawdata / apply(rawdata,1,sum)
rowmax_data <- rawdata / apply(rawdata,1,max)

Compare (visually) the sum and max standardizations for all species for sites 1, 3, and 5

rowsum.df <- as.data.frame(rowsum_data) # convert to data frame
rowsum.df$type <- "sum" # add a column of type
rowsum.df$site <- 1:nrow(rowsum.df) # add column for site
rowmax.df <- as.data.frame(rowmax_data) # convert to data frame
rowmax.df$type <- "max" # add a column of type
rowmax.df$site <- 1:nrow(rowmax.df) # add column for site
rowall.df <- rbind(rowsum.df,rowmax.df)
rowall.df %>% 
  gather(Species, Number, contains("species")) -> rowall.long
ggplot(data = rowall.long %>%  filter(site %in% c(1,3,5))) +
  geom_bar(aes(Species, y = Number, fill = type), stat = "identity", position = "dodge") + 
  facet_wrap(~site, ncol = 1, labeller = label_both) + 
  theme_classic()

Columns

decostand(rawdata, method = "max", MARGIN = 2)
     species_A species_B species_C  species_D  species_E species_F
[1,]       0.1       0.1      0.05 0.10000000 0.10000000         1
[2,]       0.2       0.2      0.20 0.20000000 0.20000000         0
[3,]       1.0       1.0      1.00 1.00000000 1.00000000         0
[4,]       0.3       0.3      0.10 0.03333333 0.03333333         0
[5,]       0.0       0.0      0.00 0.66666667 0.00000000         0
attr(,"decostand")
[1] "max"

Z-score standadization

  • Can be applied to any value of x
  • Output can be any value
  • Converts values to a z-score (mean = 0, variance = 1)
  • Commonly used to put variables on an equal scaling
  • Tend to use this across sites (i.e., by columns)

To do this transformation, we find the column mean and column standard deviation. Subtract mean from the cell value and divide by standard deviation

mvals <- apply(rawdata, 2, mean)
sdvals <- apply(rawdata, 2, sd)
centered <- sweep(rawdata, 2, colMeans(rawdata))
sweep(centered, 2, sdvals, '/')
       species_A   species_B  species_C  species_D  species_E  species_F
[1,] -0.55522991 -0.55522991 -0.5304671 -0.7194247 -0.3996804  1.7888544
[2,] -0.30285268 -0.30285268 -0.1687850 -0.4796165 -0.1598722 -0.4472136
[3,]  1.71616518  1.71616518  1.7601863  1.4388494  1.7585937 -0.4472136
[4,] -0.05047545 -0.05047545 -0.4099064 -0.8792968 -0.5595525 -0.4472136
[5,] -0.80760714 -0.80760714 -0.6510278  0.6394886 -0.6394886 -0.4472136
scale(rawdata, center = TRUE, scale = TRUE)
       species_A   species_B  species_C  species_D  species_E  species_F
[1,] -0.55522991 -0.55522991 -0.5304671 -0.7194247 -0.3996804  1.7888544
[2,] -0.30285268 -0.30285268 -0.1687850 -0.4796165 -0.1598722 -0.4472136
[3,]  1.71616518  1.71616518  1.7601863  1.4388494  1.7585937 -0.4472136
[4,] -0.05047545 -0.05047545 -0.4099064 -0.8792968 -0.5595525 -0.4472136
[5,] -0.80760714 -0.80760714 -0.6510278  0.6394886 -0.6394886 -0.4472136
attr(,"scaled:center")
species_A species_B species_C species_D species_E species_F 
      3.2       3.2       5.4      12.0       8.0       0.2 
attr(,"scaled:scale")
 species_A  species_B  species_C  species_D  species_E  species_F 
 3.9623226  3.9623226  8.2945765 12.5099960 12.5099960  0.4472136 
decostand(rawdata, method = "standardize", MARGIN = 2)
       species_A   species_B  species_C  species_D  species_E  species_F
[1,] -0.55522991 -0.55522991 -0.5304671 -0.7194247 -0.3996804  1.7888544
[2,] -0.30285268 -0.30285268 -0.1687850 -0.4796165 -0.1598722 -0.4472136
[3,]  1.71616518  1.71616518  1.7601863  1.4388494  1.7585937 -0.4472136
[4,] -0.05047545 -0.05047545 -0.4099064 -0.8792968 -0.5595525 -0.4472136
[5,] -0.80760714 -0.80760714 -0.6510278  0.6394886 -0.6394886 -0.4472136
attr(,"scaled:center")
species_A species_B species_C species_D species_E species_F 
      3.2       3.2       5.4      12.0       8.0       0.2 
attr(,"scaled:scale")
 species_A  species_B  species_C  species_D  species_E  species_F 
 3.9623226  3.9623226  8.2945765 12.5099960 12.5099960  0.4472136 
attr(,"decostand")
[1] "standardize"

Normalization

  • Can be applied to any value of x
  • Output will range between 0 and 1
  • Important to use when some rows have large variances and some with small variance
  • Common standardization in Principal Component Analysis (PCA)
decostand(rawdata, method = "normalize")
     species_A species_B species_C species_D species_E species_F
[1,] 0.2132007 0.2132007 0.2132007 0.6396021 0.6396021 0.2132007
[2,] 0.2041241 0.2041241 0.4082483 0.6123724 0.6123724 0.0000000
[3,] 0.2041241 0.2041241 0.4082483 0.6123724 0.6123724 0.0000000
[4,] 0.6123724 0.6123724 0.4082483 0.2041241 0.2041241 0.0000000
[5,] 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000
attr(,"decostand")
[1] "normalize"

Hellinger standardization

  • Can be applied to any value of x
  • Output can be any value but it tends to be below 1
  • Similar to relativization by site
  • Hellinger distance has good statistical properties with respect to R2 and monotonicity. Legendre and Gallagher (2001)

In this standardization, each element is divided by its row sum. After that, the square root of that relativized value is calculated

decostand(rawdata, method = "hellinger")
     species_A species_B species_C species_D species_E species_F
[1,] 0.3162278 0.3162278 0.3162278 0.5477226 0.5477226 0.3162278
[2,] 0.3162278 0.3162278 0.4472136 0.5477226 0.5477226 0.0000000
[3,] 0.3162278 0.3162278 0.4472136 0.5477226 0.5477226 0.0000000
[4,] 0.5477226 0.5477226 0.4472136 0.3162278 0.3162278 0.0000000
[5,] 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000
attr(,"decostand")
[1] "hellinger"

Wisconsin double standardization

  • Can be applied to any value of X > 0
  • Output will range between 0 and 1
  • Equalizes the emphasis among sample units and among species
  • Difficult to understand individual data after the standardization

To do this, each element is divided by its column max and then divided by the row total

col_max <- apply(rawdata, 2, max)
wtd_data.1 <- rawdata %*% diag(1/col_max)
row_ttl <- apply(wtd_data.1,1,sum)
wtd_data <- wtd_data.1/ row_ttl
wisconsin(rawdata)
      species_A  species_B  species_C  species_D  species_E species_F
[1,] 0.06896552 0.06896552 0.03448276 0.06896552 0.06896552 0.6896552
[2,] 0.20000000 0.20000000 0.20000000 0.20000000 0.20000000 0.0000000
[3,] 0.20000000 0.20000000 0.20000000 0.20000000 0.20000000 0.0000000
[4,] 0.39130435 0.39130435 0.13043478 0.04347826 0.04347826 0.0000000
[5,] 0.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
attr(,"decostand")
[1] "total"
LS0tCnRpdGxlOiAiQXBwbGllZCBNdWx0aXZhcmlhdGU6ICBEYXRhIHN0YW5kYXJkaXphdGlvbiAoY29udGludWVkKSIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpgYGB7ciBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHZlZ2FuKQpgYGAKCgoKIyMgQ2hhbGxlbmdlIGZyb20gbGFzdCB3ZWVrCgpTdGVwIDEKCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0KbXlkYXRhIDwtIHJlYWRfY3N2KCJodHRwczovL25kb3dubG9hZGVyLmZpZ3NoYXJlLmNvbS9maWxlcy8yMjkyMTY5IikKZ2xpbXBzZShteWRhdGEpCmBgYAoKCgpgYGB7cn0KbXlkYXRhICU+JSAKICBmaWx0ZXIodGF4YSA9PSAiUm9kZW50IikgJT4lIAogIGdyb3VwX2J5KG1vbnRoLCB5ZWFyLCBwbG90X2lkLCBzcGVjaWVzX2lkKSAlPiUgCiAgc3VtbWFyaXNlKE4gPSBuX2Rpc3RpbmN0KHJlY29yZF9pZCkpICU+JSAKICBncm91cF9ieSh5ZWFyLCBwbG90X2lkLCBzcGVjaWVzX2lkKSAlPiUgCiAgc3VtbWFyaXNlKE1heE4gPSBtYXgoTikpICU+JSAKICBncm91cF9ieShwbG90X2lkLCBzcGVjaWVzX2lkKSAlPiUgCiAgc3VtbWFyaXNlKE1heE4yID0gbWF4KE1heE4pKSAlPiUgCiAgc3ByZWFkKHNwZWNpZXNfaWQsIE1heE4yLCBmaWxsID0gMCkgJT4lCiAgdW5ncm91cCgpICAtPiAgbXlkYXRhX3dpZGUKCm15ZGF0YV93aWRlCmBgYAoKYGBge3J9Cm15ZGF0YV93aWRlICU+JSAKICBzZWxlY3QoLXBsb3RfaWQpICU+JSAKICBhcy5tYXRyaXgoKSAtPiBteWRhdGFfd2lkZTIKCm15ZGF0YV9yZWwgPC0gZGVjb3N0YW5kKG15ZGF0YV93aWRlMiwgbWV0aG9kID0gInRvdGFsIiwgTUFSR0lOID0gMSkKaGVhZChteWRhdGFfcmVsKSAKYGBgCgpQbG90CgpgYGB7cn0KbXlkYXRhX3dpZGUgJT4lIAogIGdhdGhlcihTcGVjaWVzLCBNYXhOLCBBSDpVUikgJT4lIAogIGdyb3VwX2J5KHBsb3RfaWQpICU+JSAKICBtdXRhdGUoVG90YWwgPSBzdW0oTWF4TikpICU+JSAKICBhcnJhbmdlKHBsb3RfaWQsIFNwZWNpZXMpICU+JSAKICBtdXRhdGUoUHJvcCA9IE1heE4gLyBUb3RhbCkgLT4gbXlkYXRhX3Byb3AKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBteWRhdGFfcHJvcCkgKyAKICBnZW9tX2JhcihhZXMoeCA9IHBsb3RfaWQsIHkgPSBQcm9wLCBmaWxsID0gU3BlY2llcyksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsgCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKIyMgRGF0YSBzdGFuZGFyZGl6YXRpb25zIChjb250aW51ZWQgZnJvbSBbbGFzdCB3ZWVrXShodHRwczovL2NocmlzY2hpemluc2tpLmdpdGh1Yi5pby9TTlJfUl9Hcm91cC8yMDE3LTA5LTE1LUludHJvdG9tdWx0aXZhcmlhdGUpCgojIyMgTWF4aW11bXMKCi0gY2FuIGJlIGFwcGxpZWQgdG8gYW55IHJhbmdlIG9mIHgKLSBPdXRwdXRzIHdpbGwgcmFuZ2UgZnJvbSAwIHRvIDEsIGxhcmdlc3QgdmFsdWVzIHdpbGwgc2NhbGUgdG8gMVwKLSBDb252ZXJ0cyB2bGF1ZXMgdG8gYSByZWxhdGl2ZSB2YWx1ZSAoZXF1YWxpemVkIHRoZSBwZWFrIGFidW5kYW5jZSkKLSBVc2VmdWwgd2hlbiB5b3UgaGF2ZSBkaWZmZXJlbmNlcyBpbiB0b3RhbCBhYnVuZGFuY2UgCgojIyMjIFJvd3MKCi0gdGVsbHMgdXMgdGhlIHJlbGF0aXZlIHJlbGF0aW9uc2hpcCB3aXRoaW4gYSBzaXRlCi0gU3BlY2llcyB3aXRoIHRoZSBncmVhdGVzdCBhYnVuZGFuY2Ugd2lsbCBiZSAxCgpgYGB7cn0KcmF3ZGF0YSA8LSBtYXRyaXgoYygxLDEsMSwzLDMsMSwKICAgICAgICAgICAgICAgICAgICAyLDIsNCw2LDYsMCwKICAgICAgICAgICAgICAgICAgICAxMCwxMCwyMCwzMCwzMCwwLAogICAgICAgICAgICAgICAgICAgIDMsMywyLDEsMSwwLAogICAgICAgICAgICAgICAgICAgIDAsMCwwLDIwLDAsMCksIG5jb2wgPSA2LCBieXJvdyA9IFRSVUUpCmNvbG5hbWVzKHJhd2RhdGEpIDwtIHBhc3RlKCJzcGVjaWVzIix0b3VwcGVyKGxldHRlcnNbMTo2XSksIHNlcCA9ICJfIikKCnJhd2RhdGEKCnJvd3N1bV9kYXRhIDwtIHJhd2RhdGEgLyBhcHBseShyYXdkYXRhLDEsc3VtKQpyb3dtYXhfZGF0YSA8LSByYXdkYXRhIC8gYXBwbHkocmF3ZGF0YSwxLG1heCkKYGBgCgpDb21wYXJlICh2aXN1YWxseSkgdGhlIHN1bSBhbmQgbWF4IHN0YW5kYXJkaXphdGlvbnMgZm9yIGFsbCBzcGVjaWVzIGZvciBzaXRlcyAxLCAzLCBhbmQgNQoKYGBge3J9CnJvd3N1bS5kZiA8LSBhcy5kYXRhLmZyYW1lKHJvd3N1bV9kYXRhKSAjIGNvbnZlcnQgdG8gZGF0YSBmcmFtZQpyb3dzdW0uZGYkdHlwZSA8LSAic3VtIiAjIGFkZCBhIGNvbHVtbiBvZiB0eXBlCnJvd3N1bS5kZiRzaXRlIDwtIDE6bnJvdyhyb3dzdW0uZGYpICMgYWRkIGNvbHVtbiBmb3Igc2l0ZQoKcm93bWF4LmRmIDwtIGFzLmRhdGEuZnJhbWUocm93bWF4X2RhdGEpICMgY29udmVydCB0byBkYXRhIGZyYW1lCnJvd21heC5kZiR0eXBlIDwtICJtYXgiICMgYWRkIGEgY29sdW1uIG9mIHR5cGUKcm93bWF4LmRmJHNpdGUgPC0gMTpucm93KHJvd21heC5kZikgIyBhZGQgY29sdW1uIGZvciBzaXRlCgpyb3dhbGwuZGYgPC0gcmJpbmQocm93c3VtLmRmLHJvd21heC5kZikKCnJvd2FsbC5kZiAlPiUgCiAgZ2F0aGVyKFNwZWNpZXMsIE51bWJlciwgY29udGFpbnMoInNwZWNpZXMiKSkgLT4gcm93YWxsLmxvbmcKCmdncGxvdChkYXRhID0gcm93YWxsLmxvbmcgJT4lICBmaWx0ZXIoc2l0ZSAlaW4lIGMoMSwzLDUpKSkgKwogIGdlb21fYmFyKGFlcyhTcGVjaWVzLCB5ID0gTnVtYmVyLCBmaWxsID0gdHlwZSksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgZmFjZXRfd3JhcCh+c2l0ZSwgbmNvbCA9IDEsIGxhYmVsbGVyID0gbGFiZWxfYm90aCkgKyAKICB0aGVtZV9jbGFzc2ljKCkKYGBgCgojIyMjIENvbHVtbnMKCmBgYHtyfQpkZWNvc3RhbmQocmF3ZGF0YSwgbWV0aG9kID0gIm1heCIsIE1BUkdJTiA9IDIpCmBgYAoKIyMjIFotc2NvcmUgc3RhbmRhZGl6YXRpb24KCi0gQ2FuIGJlIGFwcGxpZWQgdG8gYW55IHZhbHVlIG9mIHgKLSBPdXRwdXQgY2FuIGJlIGFueSB2YWx1ZQotIENvbnZlcnRzIHZhbHVlcyB0byBhIHotc2NvcmUgKG1lYW4gPSAwLCB2YXJpYW5jZSA9IDEpCi0gQ29tbW9ubHkgdXNlZCB0byBwdXQgdmFyaWFibGVzIG9uIGFuIGVxdWFsIHNjYWxpbmcgCi0gVGVuZCB0byB1c2UgdGhpcyBhY3Jvc3Mgc2l0ZXMgKGkuZS4sIGJ5IGNvbHVtbnMpCgpUbyBkbyB0aGlzIHRyYW5zZm9ybWF0aW9uLCB3ZSBmaW5kIHRoZSBjb2x1bW4gbWVhbiBhbmQgY29sdW1uIHN0YW5kYXJkIGRldmlhdGlvbi4gU3VidHJhY3QgbWVhbiBmcm9tIHRoZSBjZWxsIHZhbHVlIGFuZCBkaXZpZGUgYnkgc3RhbmRhcmQgZGV2aWF0aW9uCgpgYGB7cn0KbXZhbHMgPC0gYXBwbHkocmF3ZGF0YSwgMiwgbWVhbikKc2R2YWxzIDwtIGFwcGx5KHJhd2RhdGEsIDIsIHNkKQoKY2VudGVyZWQgPC0gc3dlZXAocmF3ZGF0YSwgMiwgY29sTWVhbnMocmF3ZGF0YSkpCnN3ZWVwKGNlbnRlcmVkLCAyLCBzZHZhbHMsICcvJykKCnNjYWxlKHJhd2RhdGEsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkKCmRlY29zdGFuZChyYXdkYXRhLCBtZXRob2QgPSAic3RhbmRhcmRpemUiLCBNQVJHSU4gPSAyKQpgYGAKCiMjIyBOb3JtYWxpemF0aW9uIAotIENhbiBiZSBhcHBsaWVkIHRvIGFueSB2YWx1ZSBvZiB4Ci0gT3V0cHV0IHdpbGwgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxCi0gSW1wb3J0YW50IHRvIHVzZSB3aGVuIHNvbWUgcm93cyBoYXZlIGxhcmdlIHZhcmlhbmNlcyBhbmQgc29tZSB3aXRoIHNtYWxsIHZhcmlhbmNlCi0gQ29tbW9uIHN0YW5kYXJkaXphdGlvbiBpbiBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpCgpgYGB7cn0KZGVjb3N0YW5kKHJhd2RhdGEsIG1ldGhvZCA9ICJub3JtYWxpemUiKQpgYGAKCiMjIyBIZWxsaW5nZXIgc3RhbmRhcmRpemF0aW9uIAotIENhbiBiZSBhcHBsaWVkIHRvIGFueSB2YWx1ZSBvZiB4Ci0gT3V0cHV0IGNhbiBiZSBhbnkgdmFsdWUgYnV0IGl0IHRlbmRzIHRvIGJlIGJlbG93IDEKLSBTaW1pbGFyIHRvIHJlbGF0aXZpemF0aW9uIGJ5IHNpdGUKLSBIZWxsaW5nZXIgZGlzdGFuY2UgaGFzIGdvb2Qgc3RhdGlzdGljYWwgcHJvcGVydGllcyB3aXRoIHJlc3BlY3QgdG8gUjxzdXA+Mjwvc3VwPiBhbmQgbW9ub3RvbmljaXR5LiAgW0xlZ2VuZHJlIGFuZCBHYWxsYWdoZXIgKDIwMDEpXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2FydGljbGUvMTAuMTAwNy9zMDA0NDIwMTAwNzE2KQoKSW4gdGhpcyBzdGFuZGFyZGl6YXRpb24sIGVhY2ggZWxlbWVudCBpcyBkaXZpZGVkIGJ5IGl0cyByb3cgc3VtLiBBZnRlciB0aGF0LCB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhhdCByZWxhdGl2aXplZCB2YWx1ZSBpcyBjYWxjdWxhdGVkIAoKYGBge3J9CmRlY29zdGFuZChyYXdkYXRhLCBtZXRob2QgPSAiaGVsbGluZ2VyIikKYGBgCgojIyMgV2lzY29uc2luIGRvdWJsZSBzdGFuZGFyZGl6YXRpb24KCi0gQ2FuIGJlIGFwcGxpZWQgdG8gYW55IHZhbHVlIG9mIFggPiAwCi0gT3V0cHV0IHdpbGwgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxCi0gRXF1YWxpemVzIHRoZSBlbXBoYXNpcyBhbW9uZyBzYW1wbGUgdW5pdHMgYW5kIGFtb25nIHNwZWNpZXMKLSBEaWZmaWN1bHQgdG8gdW5kZXJzdGFuZCBpbmRpdmlkdWFsIGRhdGEgYWZ0ZXIgdGhlIHN0YW5kYXJkaXphdGlvbiAKClRvIGRvIHRoaXMsIGVhY2ggZWxlbWVudCBpcyBkaXZpZGVkIGJ5IGl0cyBjb2x1bW4gbWF4IGFuZCB0aGVuIGRpdmlkZWQgYnkgdGhlIHJvdyB0b3RhbAoKYGBge3J9CmNvbF9tYXggPC0gYXBwbHkocmF3ZGF0YSwgMiwgbWF4KQoKd3RkX2RhdGEuMSA8LSByYXdkYXRhICUqJSBkaWFnKDEvY29sX21heCkKCnJvd190dGwgPC0gYXBwbHkod3RkX2RhdGEuMSwxLHN1bSkKCnd0ZF9kYXRhIDwtIHd0ZF9kYXRhLjEvIHJvd190dGwKCndpc2NvbnNpbihyYXdkYXRhKQpgYGAKCg==