I’m doing this analysis under the assumption that all three of the SL columns (SL_11212022, SL_12272022, and SL_mm) are measuring some consistent size/length value over three measurement dates. Similarly, I’m assuming the the columns WWT_11212022, WWT_12272022, and WholeBodyWW_g are measurements of body weight (maybe whole body wet weight?) on the same three measurement dates. I believe the first measurement date is from tagging (before acclimitization to lab conditions), the second is date of transfer to temperature treatment tanks, and the third is sampling post-treatment.

1 Data Munging

# read in the data
codTempData <- read.csv("../data/temp-experiment.csv")
head(codTempData)
##   Microchip.ID SL_11212022 WWT_11212022 Tank Temperature SL_12272022
## 1          620          93         8.53    1          16         101
## 2         1164          88         7.06    1          16          96
## 3         1476         102        10.70    1          16         108
## 4         9387          87         7.83    1          16          95
## 5         9407         100        11.51    1          16         117
## 6         9415          92         8.68    1          16         100
##   WWT_12272022 MortDate DissectionDate SL_mm WholeBodyWW_g TOTAL_Liver_WW_mg
## 1        11.12                  2/8/23   119         16.15            0.4945
## 2         8.64                  2/8/23   105         10.89            0.1997
## 3        12.25                  2/8/23   110         12.97            0.1715
## 4        10.16                  2/8/23   116         15.40            0.3625
## 5        14.98                  2/8/23   127         17.98            0.3482
## 6        10.96                  2/8/23   114         14.02            0.2343
##   LiverforLipids_WW_mg MuscleWWforLipids_mg GeneticSamplingCount
## 1               0.1546               0.3495                    8
## 2               0.1091               0.3328                    5
## 3               0.1107               0.3834                    4
## 4               0.1681               0.3262                    6
## 5               0.1210               0.3434                    2
## 6               0.1342               0.2776                    9
##   DissectionComments
## 1                   
## 2                   
## 3                   
## 4                   
## 5                   
## 6
# Create two new columns indicating change from Dec.2022 measurement to Feb.2022 measurement, for both size (mm) and weight (g). I'm excluding the Nov.2022 size/weight measurements, because Nov.2022-Dec.2022 was the acclimation period, not treatment. Also, modify the Temperature variable from a numeric to an ordered factor, since it's the treatment (will be necessary for ANOVA/TukeyHSD)
codTempData_plus <- transform(codTempData,
                              # create column for change in size
                              sizeChange_mm = SL_mm - SL_12272022,
                              # create column for change in weight
                              weightChange_g = WholeBodyWW_g - WWT_12272022) %>%
  # change type of Temperature variable to an ordered factor
  mutate(codTempData, Temperature = relevel(as.factor(Temperature), "0", "5", "9", "16"))
head(codTempData_plus)
##   Microchip.ID SL_11212022 WWT_11212022 Tank Temperature SL_12272022
## 1          620          93         8.53    1          16         101
## 2         1164          88         7.06    1          16          96
## 3         1476         102        10.70    1          16         108
## 4         9387          87         7.83    1          16          95
## 5         9407         100        11.51    1          16         117
## 6         9415          92         8.68    1          16         100
##   WWT_12272022 MortDate DissectionDate SL_mm WholeBodyWW_g TOTAL_Liver_WW_mg
## 1        11.12                  2/8/23   119         16.15            0.4945
## 2         8.64                  2/8/23   105         10.89            0.1997
## 3        12.25                  2/8/23   110         12.97            0.1715
## 4        10.16                  2/8/23   116         15.40            0.3625
## 5        14.98                  2/8/23   127         17.98            0.3482
## 6        10.96                  2/8/23   114         14.02            0.2343
##   LiverforLipids_WW_mg MuscleWWforLipids_mg GeneticSamplingCount
## 1               0.1546               0.3495                    8
## 2               0.1091               0.3328                    5
## 3               0.1107               0.3834                    4
## 4               0.1681               0.3262                    6
## 5               0.1210               0.3434                    2
## 6               0.1342               0.2776                    9
##   DissectionComments sizeChange_mm weightChange_g
## 1                               18           5.03
## 2                                9           2.25
## 3                                2           0.72
## 4                               21           5.24
## 5                               10           3.00
## 6                               14           3.06
# Reformatted data with single column for size values and single column for measurement values (and additional column indicating measurement date), enabling grouping by size/weight measurement date
#
# Sample of how data is being reformatted:
# Original data
# fishID | size_date1 | size_date2 | weight_date1 | weight_date2
#----------------------------------------------------------------
#  001   |     s11    |     s12    |      w11     |      w12
#  002   |     s21    |     s22    |      w21     |      w22
#
# Reformatted data
# fishID |  date  | size | weight
#---------------------------------
#  001   |  date1 |  s11 |  w11
#  001   |  date2 |  s12 |  w12
#  002   |  date1 |  s21 |  w21
#  002   |  date2 |  s22 |  w22
 
# Note I renamed the final size and weight measurements to include the date 02/08/2023 -- this is just so that the measurement date column can have a consistent option despite final measurements happening between the days of 02/08/2023 and 02/10/2023.

codTempData_reformat <- codTempData_plus %>%
  # Rename final size/weight variables to include date
  rename(WWT_02082023=WholeBodyWW_g) %>%
  rename(SL_02082023=SL_mm) %>%
  # Reformat data
  pivot_longer(
    cols = c("SL_11212022", "SL_12272022", "SL_02082023", "WWT_11212022", "WWT_12272022", "WWT_02082023"),
    names_to = "var",
    values_to = "value"
  ) %>%
  separate(var, into = c("var", "date"), sep = "_") %>%
  pivot_wider(
    names_from = "var",
    values_from = "value"
  )
# Set the date variable to have desired (chronological) order
codTempData_reformat$date <- factor(codTempData_reformat$date, levels = c("11212022", "12272022", "02082023"))

2 Plots

# Plot size measurements for all temperature treatments across the time of the study
codTempData_reformat %>%
  ggplot(aes(x=Temperature,
             y=SL,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.2,
              height = 0.2,
              size = 1.5) +
  xlab("Temperature Treatment (*C)") +
  ylab("Size (mm)") +
  facet_wrap(~date)

ggsave(
    "01_sizeVtreatment-all-dates.png",
    plot = last_plot(),
    path = "../output/01_temp-size-analysis"
  )

# Plot weight measurements for all temperature treatments across the time of the study
codTempData_reformat %>%
  ggplot(aes(x=Temperature,
             y=WWT,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.2,
              height = 0.2,
              size = 1.5) +
  xlab("Temperature Treatment (*C)") +
  ylab("Weight (g)") +
  facet_wrap(~date)

ggsave(
    "02_weightVtreatment-all-dates.png",
    plot = last_plot(),
    path = "../output/01_temp-size-analysis"
  )

3 Size/Weight Change

# Plot *change* in size from beginning to end of study for all temperature treatments
codTempData_plus %>%
  ggplot(aes(x=Temperature,
             y=sizeChange_mm,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.1,
              height = 0.2,
              size = 1.5) +
  xlab("Temperature Treatment (*C)") +
  ylab("Size Change (mm)")

# Plot *change* in weight from beginning to end of study for all temperature treatments
codTempData_plus %>%
  ggplot(aes(x=Temperature,
             y=weightChange_g,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.1,
              height = 0.2,
              size = 1.5) +
  xlab("Temperature Treatment (*C)") +
  ylab("Weight Change (g)")

Looking at these plots visually, there seems to be a difference in change in both size and weight over time among the treatment temperatures. Let’s test this statistically.

4 Check Assumptions

# Check conditions for ANOVA

# Normality
  # Not perfect, but normalish enough that I feel comfortable using ANOVA
codTempData_plus %>%
  ggplot(aes(sample = sizeChange_mm)) +
  stat_qq() +
  stat_qq_line() +
  facet_wrap(~Temperature)

codTempData_plus %>%
  ggplot(aes(sample = weightChange_g)) +
  stat_qq() +
  stat_qq_line() +
  facet_wrap(~Temperature)

# Variance
  # For both sizeChange and weightChange, the largest SD is, at most, ~2x the smallest SD. This is sufficiently similar to allow usage of ANOVA (which is fairly robust against heterogeneity of variance). May want to also test using randomization to be safe.
codTempData_plus %>%
  group_by(Temperature) %>%
  summarize(meanSizeChange = mean(sizeChange_mm),
            sdSizeChange = sd(sizeChange_mm),
            meanWeightChange = mean(weightChange_g),
            sdWeightChange = sd(weightChange_g))
## # A tibble: 4 × 5
##   Temperature meanSizeChange sdSizeChange meanWeightChange sdWeightChange
##   <fct>                <dbl>        <dbl>            <dbl>          <dbl>
## 1 0                     4.12         1.92           0.0518          0.526
## 2 5                     9            2.53           1.46            0.770
## 3 9                    14.4          3.51           3.44            1.25 
## 4 16                   11.6          5.01           2.64            1.72
# Assuming data are independent (part of experimental design)

5 ANOVA

5.1 Size Change

# ANOVA
sizeANOVA <- aov(sizeChange_mm~Temperature, data=codTempData_plus)

tidySizeANOVA <- tidy(sizeANOVA)
tidySizeANOVA
## # A tibble: 2 × 6
##   term           df sumsq meansq statistic   p.value
##   <chr>       <dbl> <dbl>  <dbl>     <dbl>     <dbl>
## 1 Temperature     3 2297.  766.       64.4  3.81e-27
## 2 Residuals     156 1855.   11.9      NA   NA
# Calculate R^2 (how much of the variation in the data is explained by the treatment)
r_squared <- tidySizeANOVA$sumsq[1]/(tidySizeANOVA$sumsq[1]+tidySizeANOVA$sumsq[2])
r_squared
## [1] 0.5532301

p = 1.79e-18 << 0.05, so there is a significant relationship between treatment (temperature) and size growth (change in size). R^2=0.422, indicating ~42% of variance in size change is explained by the temperature treatment.

# Tukey HSD
sizeTukeyHSD <- sizeANOVA %>%
  TukeyHSD() %>%
  tidy() %>% 
  select(contrast, estimate, adj.p.value) %>% 
  arrange(adj.p.value)

sizeTukeyHSD
## # A tibble: 6 × 3
##   contrast estimate adj.p.value
##   <chr>       <dbl>       <dbl>
## 1 9-0         10.3     1.44e-15
## 2 16-0         7.52    3.99e-14
## 3 9-5          5.4     4.21e-10
## 4 5-0          4.87    1.55e- 8
## 5 16-9        -2.75    2.68e- 3
## 6 16-5         2.65    4.16e- 3
kable(sizeTukeyHSD,
      caption = "Tukey HSD for change in size across treatments")
Table 5.1: Tukey HSD for change in size across treatments
contrast estimate adj.p.value
9-0 10.275 0.0000000
16-0 7.525 0.0000000
9-5 5.400 0.0000000
5-0 4.875 0.0000000
16-9 -2.750 0.0026842
16-5 2.650 0.0041642
codTempData_plus %>%
  ggplot(aes(x=Temperature,
             y=sizeChange_mm,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.1, 
              height = 0.2, 
              size = 1.5) +
  annotate(geom = "text", x = 1:4, y = 25, label = c("A","B","C","D")) +
  xlab("Temperature Treatment (*C)") +
  ylab("Size Change (mm), 12/27/2022 to 02/08/23")

  ggsave(
    "03_size-change-TukeyHSD-plot.png",
    plot = last_plot(),
    path = "../output/01_temp-size-analysis"
  )

5.2 Weight Change

# ANOVA
weightANOVA <- aov(weightChange_g~Temperature, data=codTempData_plus)

tidyWeightANOVA <- tidy(weightANOVA)
tidyWeightANOVA
## # A tibble: 2 × 6
##   term           df sumsq meansq statistic   p.value
##   <chr>       <dbl> <dbl>  <dbl>     <dbl>     <dbl>
## 1 Temperature     3  261.  86.9       64.5  3.65e-27
## 2 Residuals     156  210.   1.35      NA   NA
# Calculate R^2 (how much of the variation in the data is explained by the treatment)
r_squared <- tidyWeightANOVA$sumsq[1]/(tidyWeightANOVA$sumsq[1]+tidyWeightANOVA$sumsq[2])
r_squared
## [1] 0.5534805

p = 3.73e-15 << 0.05, so there is a significant relationship between treatment (temperature) and weight change. R^2=0.362, indicating ~36% of variance in weight change is explained by the temperature treatment.

# Tukey HSD
weightTukeyHSD <- weightANOVA %>%
  TukeyHSD() %>%
  tidy() %>% 
  select(contrast, estimate, adj.p.value) %>% 
  arrange(adj.p.value)

weightTukeyHSD
## # A tibble: 6 × 3
##   contrast estimate adj.p.value
##   <chr>       <dbl>       <dbl>
## 1 9-0         3.38     1.55e-15
## 2 16-0        2.59     3.77e-14
## 3 9-5         1.97     1.57e-11
## 4 5-0         1.41     1.23e- 6
## 5 16-5        1.18     6.43e- 5
## 6 16-9       -0.793    1.40e- 2
kable(weightTukeyHSD,
      caption = "Tukey HSD for change in weight across treatments")
Table 5.2: Tukey HSD for change in weight across treatments
contrast estimate adj.p.value
9-0 3.38325 0.0000000
16-0 2.59075 0.0000000
9-5 1.97225 0.0000000
5-0 1.41100 0.0000012
16-5 1.17975 0.0000643
16-9 -0.79250 0.0140387
codTempData_plus %>%
  ggplot(aes(x=Temperature,
             y=weightChange_g,
             group=Temperature)) +
  geom_boxplot() +
  geom_jitter(width = 0.1, 
              height = 0.2, 
              size = 1.5) +
  annotate(geom = "text", x = 1:4, y = 8, label = c("A","B","C","D")) +
  xlab("Temperature Treatment (*C)") +
  ylab("Weight Change (g), 12/27/2022 to 02/08/23")

ggsave(
    "04_weight-change-TukeyHSD-plot.png",
    plot = last_plot(),
    path = "../output/01_temp-size-analysis"
  )

For both size and weight, growth from 12/27/2022 to 02/08/23 significantly differed among all temperature treatments, with the exception of the 9 degree and 16 degree treatments. For the 9 and 16 degree treatments, changes in size and weight were statistically similar. In other words, growth increased with the treatment temperature until the 16 degree treatment, for which growth was not significantly different from the 9 degree treatment in either size or weight.

LS0tCnRpdGxlOiAnVGVtcC9TaXplIEFuYWx5c2lzJwphdXRob3I6ICJLYXRobGVlbiBEdXJraW4iCmRhdGU6ICIyMDIzLTEwLTEyIgphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgaHRtbF9wcmV2aWV3OiB0cnVlIAotLS0KYGBge3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTgsZmlnLmFsaWduID0gImNlbnRlciIpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShpbmZlcikKbGlicmFyeShicm9vbSkKbGlicmFyeShrbml0cikKYGBgCgpJJ20gZG9pbmcgdGhpcyBhbmFseXNpcyB1bmRlciB0aGUgYXNzdW1wdGlvbiB0aGF0IGFsbCB0aHJlZSBvZiB0aGUgU0wgY29sdW1ucyAoU0xfMTEyMTIwMjIsIFNMXzEyMjcyMDIyLCBhbmQgU0xfbW0pIGFyZSBtZWFzdXJpbmcgc29tZSBjb25zaXN0ZW50IHNpemUvbGVuZ3RoIHZhbHVlIG92ZXIgdGhyZWUgbWVhc3VyZW1lbnQgZGF0ZXMuIFNpbWlsYXJseSwgSSdtIGFzc3VtaW5nIHRoZSB0aGUgY29sdW1ucyBXV1RfMTEyMTIwMjIsIFdXVF8xMjI3MjAyMiwgYW5kIFdob2xlQm9keVdXX2cgYXJlIG1lYXN1cmVtZW50cyBvZiBib2R5IHdlaWdodCAobWF5YmUgd2hvbGUgYm9keSB3ZXQgd2VpZ2h0Pykgb24gdGhlIHNhbWUgdGhyZWUgbWVhc3VyZW1lbnQgZGF0ZXMuIEkgYmVsaWV2ZSB0aGUgZmlyc3QgbWVhc3VyZW1lbnQgZGF0ZSBpcyBmcm9tIHRhZ2dpbmcgKGJlZm9yZSBhY2NsaW1pdGl6YXRpb24gdG8gbGFiIGNvbmRpdGlvbnMpLCB0aGUgc2Vjb25kIGlzIGRhdGUgb2YgdHJhbnNmZXIgdG8gdGVtcGVyYXR1cmUgdHJlYXRtZW50IHRhbmtzLCBhbmQgdGhlIHRoaXJkIGlzIHNhbXBsaW5nIHBvc3QtdHJlYXRtZW50LgoKIyBEYXRhIE11bmdpbmcKYGBge3J9CiMgcmVhZCBpbiB0aGUgZGF0YQpjb2RUZW1wRGF0YSA8LSByZWFkLmNzdigiLi4vZGF0YS90ZW1wLWV4cGVyaW1lbnQuY3N2IikKaGVhZChjb2RUZW1wRGF0YSkKCiMgQ3JlYXRlIHR3byBuZXcgY29sdW1ucyBpbmRpY2F0aW5nIGNoYW5nZSBmcm9tIERlYy4yMDIyIG1lYXN1cmVtZW50IHRvIEZlYi4yMDIyIG1lYXN1cmVtZW50LCBmb3IgYm90aCBzaXplIChtbSkgYW5kIHdlaWdodCAoZykuIEknbSBleGNsdWRpbmcgdGhlIE5vdi4yMDIyIHNpemUvd2VpZ2h0IG1lYXN1cmVtZW50cywgYmVjYXVzZSBOb3YuMjAyMi1EZWMuMjAyMiB3YXMgdGhlIGFjY2xpbWF0aW9uIHBlcmlvZCwgbm90IHRyZWF0bWVudC4gQWxzbywgbW9kaWZ5IHRoZSBUZW1wZXJhdHVyZSB2YXJpYWJsZSBmcm9tIGEgbnVtZXJpYyB0byBhbiBvcmRlcmVkIGZhY3Rvciwgc2luY2UgaXQncyB0aGUgdHJlYXRtZW50ICh3aWxsIGJlIG5lY2Vzc2FyeSBmb3IgQU5PVkEvVHVrZXlIU0QpCmNvZFRlbXBEYXRhX3BsdXMgPC0gdHJhbnNmb3JtKGNvZFRlbXBEYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNyZWF0ZSBjb2x1bW4gZm9yIGNoYW5nZSBpbiBzaXplCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVDaGFuZ2VfbW0gPSBTTF9tbSAtIFNMXzEyMjcyMDIyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNyZWF0ZSBjb2x1bW4gZm9yIGNoYW5nZSBpbiB3ZWlnaHQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0Q2hhbmdlX2cgPSBXaG9sZUJvZHlXV19nIC0gV1dUXzEyMjcyMDIyKSAlPiUKICAjIGNoYW5nZSB0eXBlIG9mIFRlbXBlcmF0dXJlIHZhcmlhYmxlIHRvIGFuIG9yZGVyZWQgZmFjdG9yCiAgbXV0YXRlKGNvZFRlbXBEYXRhLCBUZW1wZXJhdHVyZSA9IHJlbGV2ZWwoYXMuZmFjdG9yKFRlbXBlcmF0dXJlKSwgIjAiLCAiNSIsICI5IiwgIjE2IikpCmhlYWQoY29kVGVtcERhdGFfcGx1cykKCgojIFJlZm9ybWF0dGVkIGRhdGEgd2l0aCBzaW5nbGUgY29sdW1uIGZvciBzaXplIHZhbHVlcyBhbmQgc2luZ2xlIGNvbHVtbiBmb3IgbWVhc3VyZW1lbnQgdmFsdWVzIChhbmQgYWRkaXRpb25hbCBjb2x1bW4gaW5kaWNhdGluZyBtZWFzdXJlbWVudCBkYXRlKSwgZW5hYmxpbmcgZ3JvdXBpbmcgYnkgc2l6ZS93ZWlnaHQgbWVhc3VyZW1lbnQgZGF0ZQojCiMgU2FtcGxlIG9mIGhvdyBkYXRhIGlzIGJlaW5nIHJlZm9ybWF0dGVkOgojIE9yaWdpbmFsIGRhdGEKIyBmaXNoSUQgfCBzaXplX2RhdGUxIHwgc2l6ZV9kYXRlMiB8IHdlaWdodF9kYXRlMSB8IHdlaWdodF9kYXRlMgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojICAwMDEgICB8ICAgICBzMTEgICAgfCAgICAgczEyICAgIHwgICAgICB3MTEgICAgIHwgICAgICB3MTIKIyAgMDAyICAgfCAgICAgczIxICAgIHwgICAgIHMyMiAgICB8ICAgICAgdzIxICAgICB8ICAgICAgdzIyCiMKIyBSZWZvcm1hdHRlZCBkYXRhCiMgZmlzaElEIHwgIGRhdGUgIHwgc2l6ZSB8IHdlaWdodAojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgIDAwMSAgIHwgIGRhdGUxIHwgIHMxMSB8ICB3MTEKIyAgMDAxICAgfCAgZGF0ZTIgfCAgczEyIHwgIHcxMgojICAwMDIgICB8ICBkYXRlMSB8ICBzMjEgfCAgdzIxCiMgIDAwMiAgIHwgIGRhdGUyIHwgIHMyMiB8ICB3MjIKIAojIE5vdGUgSSByZW5hbWVkIHRoZSBmaW5hbCBzaXplIGFuZCB3ZWlnaHQgbWVhc3VyZW1lbnRzIHRvIGluY2x1ZGUgdGhlIGRhdGUgMDIvMDgvMjAyMyAtLSB0aGlzIGlzIGp1c3Qgc28gdGhhdCB0aGUgbWVhc3VyZW1lbnQgZGF0ZSBjb2x1bW4gY2FuIGhhdmUgYSBjb25zaXN0ZW50IG9wdGlvbiBkZXNwaXRlIGZpbmFsIG1lYXN1cmVtZW50cyBoYXBwZW5pbmcgYmV0d2VlbiB0aGUgZGF5cyBvZiAwMi8wOC8yMDIzIGFuZCAwMi8xMC8yMDIzLgoKY29kVGVtcERhdGFfcmVmb3JtYXQgPC0gY29kVGVtcERhdGFfcGx1cyAlPiUKICAjIFJlbmFtZSBmaW5hbCBzaXplL3dlaWdodCB2YXJpYWJsZXMgdG8gaW5jbHVkZSBkYXRlCiAgcmVuYW1lKFdXVF8wMjA4MjAyMz1XaG9sZUJvZHlXV19nKSAlPiUKICByZW5hbWUoU0xfMDIwODIwMjM9U0xfbW0pICU+JQogICMgUmVmb3JtYXQgZGF0YQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBjKCJTTF8xMTIxMjAyMiIsICJTTF8xMjI3MjAyMiIsICJTTF8wMjA4MjAyMyIsICJXV1RfMTEyMTIwMjIiLCAiV1dUXzEyMjcyMDIyIiwgIldXVF8wMjA4MjAyMyIpLAogICAgbmFtZXNfdG8gPSAidmFyIiwKICAgIHZhbHVlc190byA9ICJ2YWx1ZSIKICApICU+JQogIHNlcGFyYXRlKHZhciwgaW50byA9IGMoInZhciIsICJkYXRlIiksIHNlcCA9ICJfIikgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gInZhciIsCiAgICB2YWx1ZXNfZnJvbSA9ICJ2YWx1ZSIKICApCiMgU2V0IHRoZSBkYXRlIHZhcmlhYmxlIHRvIGhhdmUgZGVzaXJlZCAoY2hyb25vbG9naWNhbCkgb3JkZXIKY29kVGVtcERhdGFfcmVmb3JtYXQkZGF0ZSA8LSBmYWN0b3IoY29kVGVtcERhdGFfcmVmb3JtYXQkZGF0ZSwgbGV2ZWxzID0gYygiMTEyMTIwMjIiLCAiMTIyNzIwMjIiLCAiMDIwODIwMjMiKSkKICAKYGBgCgojIFBsb3RzCmBgYHtyfQojIFBsb3Qgc2l6ZSBtZWFzdXJlbWVudHMgZm9yIGFsbCB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzIGFjcm9zcyB0aGUgdGltZSBvZiB0aGUgc3R1ZHkKY29kVGVtcERhdGFfcmVmb3JtYXQgJT4lCiAgZ2dwbG90KGFlcyh4PVRlbXBlcmF0dXJlLAogICAgICAgICAgICAgeT1TTCwKICAgICAgICAgICAgIGdyb3VwPVRlbXBlcmF0dXJlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwKICAgICAgICAgICAgICBoZWlnaHQgPSAwLjIsCiAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogIHhsYWIoIlRlbXBlcmF0dXJlIFRyZWF0bWVudCAoKkMpIikgKwogIHlsYWIoIlNpemUgKG1tKSIpICsKICBmYWNldF93cmFwKH5kYXRlKQoKZ2dzYXZlKAogICAgIjAxX3NpemVWdHJlYXRtZW50LWFsbC1kYXRlcy5wbmciLAogICAgcGxvdCA9IGxhc3RfcGxvdCgpLAogICAgcGF0aCA9ICIuLi9vdXRwdXQvMDFfdGVtcC1zaXplLWFuYWx5c2lzIgogICkKCiMgUGxvdCB3ZWlnaHQgbWVhc3VyZW1lbnRzIGZvciBhbGwgdGVtcGVyYXR1cmUgdHJlYXRtZW50cyBhY3Jvc3MgdGhlIHRpbWUgb2YgdGhlIHN0dWR5CmNvZFRlbXBEYXRhX3JlZm9ybWF0ICU+JQogIGdncGxvdChhZXMoeD1UZW1wZXJhdHVyZSwKICAgICAgICAgICAgIHk9V1dULAogICAgICAgICAgICAgZ3JvdXA9VGVtcGVyYXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yLAogICAgICAgICAgICAgIGhlaWdodCA9IDAuMiwKICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgeGxhYigiVGVtcGVyYXR1cmUgVHJlYXRtZW50ICgqQykiKSArCiAgeWxhYigiV2VpZ2h0IChnKSIpICsKICBmYWNldF93cmFwKH5kYXRlKQoKZ2dzYXZlKAogICAgIjAyX3dlaWdodFZ0cmVhdG1lbnQtYWxsLWRhdGVzLnBuZyIsCiAgICBwbG90ID0gbGFzdF9wbG90KCksCiAgICBwYXRoID0gIi4uL291dHB1dC8wMV90ZW1wLXNpemUtYW5hbHlzaXMiCiAgKQpgYGAKCiMgU2l6ZS9XZWlnaHQgQ2hhbmdlCmBgYHtyfQojIFBsb3QgKmNoYW5nZSogaW4gc2l6ZSBmcm9tIGJlZ2lubmluZyB0byBlbmQgb2Ygc3R1ZHkgZm9yIGFsbCB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzCmNvZFRlbXBEYXRhX3BsdXMgJT4lCiAgZ2dwbG90KGFlcyh4PVRlbXBlcmF0dXJlLAogICAgICAgICAgICAgeT1zaXplQ2hhbmdlX21tLAogICAgICAgICAgICAgZ3JvdXA9VGVtcGVyYXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xLAogICAgICAgICAgICAgIGhlaWdodCA9IDAuMiwKICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgeGxhYigiVGVtcGVyYXR1cmUgVHJlYXRtZW50ICgqQykiKSArCiAgeWxhYigiU2l6ZSBDaGFuZ2UgKG1tKSIpCgojIFBsb3QgKmNoYW5nZSogaW4gd2VpZ2h0IGZyb20gYmVnaW5uaW5nIHRvIGVuZCBvZiBzdHVkeSBmb3IgYWxsIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMKY29kVGVtcERhdGFfcGx1cyAlPiUKICBnZ3Bsb3QoYWVzKHg9VGVtcGVyYXR1cmUsCiAgICAgICAgICAgICB5PXdlaWdodENoYW5nZV9nLAogICAgICAgICAgICAgZ3JvdXA9VGVtcGVyYXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xLAogICAgICAgICAgICAgIGhlaWdodCA9IDAuMiwKICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgeGxhYigiVGVtcGVyYXR1cmUgVHJlYXRtZW50ICgqQykiKSArCiAgeWxhYigiV2VpZ2h0IENoYW5nZSAoZykiKQpgYGAKTG9va2luZyBhdCB0aGVzZSBwbG90cyB2aXN1YWxseSwgdGhlcmUgc2VlbXMgdG8gYmUgYSBkaWZmZXJlbmNlIGluIGNoYW5nZSBpbiBib3RoIHNpemUgYW5kIHdlaWdodCBvdmVyIHRpbWUgYW1vbmcgdGhlIHRyZWF0bWVudCB0ZW1wZXJhdHVyZXMuIExldCdzIHRlc3QgdGhpcyBzdGF0aXN0aWNhbGx5LgoKIyBDaGVjayBBc3N1bXB0aW9ucwpgYGB7cn0KIyBDaGVjayBjb25kaXRpb25zIGZvciBBTk9WQQoKIyBOb3JtYWxpdHkKICAjIE5vdCBwZXJmZWN0LCBidXQgbm9ybWFsaXNoIGVub3VnaCB0aGF0IEkgZmVlbCBjb21mb3J0YWJsZSB1c2luZyBBTk9WQQpjb2RUZW1wRGF0YV9wbHVzICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gc2l6ZUNoYW5nZV9tbSkpICsKICBzdGF0X3FxKCkgKwogIHN0YXRfcXFfbGluZSgpICsKICBmYWNldF93cmFwKH5UZW1wZXJhdHVyZSkKCmNvZFRlbXBEYXRhX3BsdXMgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSB3ZWlnaHRDaGFuZ2VfZykpICsKICBzdGF0X3FxKCkgKwogIHN0YXRfcXFfbGluZSgpICsKICBmYWNldF93cmFwKH5UZW1wZXJhdHVyZSkKCiMgVmFyaWFuY2UKICAjIEZvciBib3RoIHNpemVDaGFuZ2UgYW5kIHdlaWdodENoYW5nZSwgdGhlIGxhcmdlc3QgU0QgaXMsIGF0IG1vc3QsIH4yeCB0aGUgc21hbGxlc3QgU0QuIFRoaXMgaXMgc3VmZmljaWVudGx5IHNpbWlsYXIgdG8gYWxsb3cgdXNhZ2Ugb2YgQU5PVkEgKHdoaWNoIGlzIGZhaXJseSByb2J1c3QgYWdhaW5zdCBoZXRlcm9nZW5laXR5IG9mIHZhcmlhbmNlKS4gTWF5IHdhbnQgdG8gYWxzbyB0ZXN0IHVzaW5nIHJhbmRvbWl6YXRpb24gdG8gYmUgc2FmZS4KY29kVGVtcERhdGFfcGx1cyAlPiUKICBncm91cF9ieShUZW1wZXJhdHVyZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5TaXplQ2hhbmdlID0gbWVhbihzaXplQ2hhbmdlX21tKSwKICAgICAgICAgICAgc2RTaXplQ2hhbmdlID0gc2Qoc2l6ZUNoYW5nZV9tbSksCiAgICAgICAgICAgIG1lYW5XZWlnaHRDaGFuZ2UgPSBtZWFuKHdlaWdodENoYW5nZV9nKSwKICAgICAgICAgICAgc2RXZWlnaHRDaGFuZ2UgPSBzZCh3ZWlnaHRDaGFuZ2VfZykpCgojIEFzc3VtaW5nIGRhdGEgYXJlIGluZGVwZW5kZW50IChwYXJ0IG9mIGV4cGVyaW1lbnRhbCBkZXNpZ24pCgpgYGAKCiMgQU5PVkEKCiMjIFNpemUgQ2hhbmdlCmBgYHtyfQojIEFOT1ZBCnNpemVBTk9WQSA8LSBhb3Yoc2l6ZUNoYW5nZV9tbX5UZW1wZXJhdHVyZSwgZGF0YT1jb2RUZW1wRGF0YV9wbHVzKQoKdGlkeVNpemVBTk9WQSA8LSB0aWR5KHNpemVBTk9WQSkKdGlkeVNpemVBTk9WQQoKIyBDYWxjdWxhdGUgUl4yIChob3cgbXVjaCBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBkYXRhIGlzIGV4cGxhaW5lZCBieSB0aGUgdHJlYXRtZW50KQpyX3NxdWFyZWQgPC0gdGlkeVNpemVBTk9WQSRzdW1zcVsxXS8odGlkeVNpemVBTk9WQSRzdW1zcVsxXSt0aWR5U2l6ZUFOT1ZBJHN1bXNxWzJdKQpyX3NxdWFyZWQKYGBgCnAgPSAxLjc5ZS0xOCA8PCAwLjA1LCBzbyB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRyZWF0bWVudCAodGVtcGVyYXR1cmUpIGFuZCBzaXplIGdyb3d0aCAoY2hhbmdlIGluIHNpemUpLiBSXjI9MC40MjIsIGluZGljYXRpbmcgfjQyJSBvZiB2YXJpYW5jZSBpbiBzaXplIGNoYW5nZSBpcyBleHBsYWluZWQgYnkgdGhlIHRlbXBlcmF0dXJlIHRyZWF0bWVudC4KCmBgYHtyfQojIFR1a2V5IEhTRApzaXplVHVrZXlIU0QgPC0gc2l6ZUFOT1ZBICU+JQogIFR1a2V5SFNEKCkgJT4lCiAgdGlkeSgpICU+JSAKICBzZWxlY3QoY29udHJhc3QsIGVzdGltYXRlLCBhZGoucC52YWx1ZSkgJT4lIAogIGFycmFuZ2UoYWRqLnAudmFsdWUpCgpzaXplVHVrZXlIU0QKCmthYmxlKHNpemVUdWtleUhTRCwKICAgICAgY2FwdGlvbiA9ICJUdWtleSBIU0QgZm9yIGNoYW5nZSBpbiBzaXplIGFjcm9zcyB0cmVhdG1lbnRzIikKCmNvZFRlbXBEYXRhX3BsdXMgJT4lCiAgZ2dwbG90KGFlcyh4PVRlbXBlcmF0dXJlLAogICAgICAgICAgICAgeT1zaXplQ2hhbmdlX21tLAogICAgICAgICAgICAgZ3JvdXA9VGVtcGVyYXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xLCAKICAgICAgICAgICAgICBoZWlnaHQgPSAwLjIsIAogICAgICAgICAgICAgIHNpemUgPSAxLjUpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCB4ID0gMTo0LCB5ID0gMjUsIGxhYmVsID0gYygiQSIsIkIiLCJDIiwiRCIpKSArCiAgeGxhYigiVGVtcGVyYXR1cmUgVHJlYXRtZW50ICgqQykiKSArCiAgeWxhYigiU2l6ZSBDaGFuZ2UgKG1tKSwgMTIvMjcvMjAyMiB0byAwMi8wOC8yMyIpCgogIGdnc2F2ZSgKICAgICIwM19zaXplLWNoYW5nZS1UdWtleUhTRC1wbG90LnBuZyIsCiAgICBwbG90ID0gbGFzdF9wbG90KCksCiAgICBwYXRoID0gIi4uL291dHB1dC8wMV90ZW1wLXNpemUtYW5hbHlzaXMiCiAgKQpgYGAKCgojIyBXZWlnaHQgQ2hhbmdlCmBgYHtyfQojIEFOT1ZBCndlaWdodEFOT1ZBIDwtIGFvdih3ZWlnaHRDaGFuZ2VfZ35UZW1wZXJhdHVyZSwgZGF0YT1jb2RUZW1wRGF0YV9wbHVzKQoKdGlkeVdlaWdodEFOT1ZBIDwtIHRpZHkod2VpZ2h0QU5PVkEpCnRpZHlXZWlnaHRBTk9WQQoKIyBDYWxjdWxhdGUgUl4yIChob3cgbXVjaCBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBkYXRhIGlzIGV4cGxhaW5lZCBieSB0aGUgdHJlYXRtZW50KQpyX3NxdWFyZWQgPC0gdGlkeVdlaWdodEFOT1ZBJHN1bXNxWzFdLyh0aWR5V2VpZ2h0QU5PVkEkc3Vtc3FbMV0rdGlkeVdlaWdodEFOT1ZBJHN1bXNxWzJdKQpyX3NxdWFyZWQKYGBgCnAgPSAzLjczZS0xNSA8PCAwLjA1LCBzbyB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRyZWF0bWVudCAodGVtcGVyYXR1cmUpIGFuZCB3ZWlnaHQgY2hhbmdlLiBSXjI9MC4zNjIsIGluZGljYXRpbmcgfjM2JSBvZiB2YXJpYW5jZSBpbiB3ZWlnaHQgY2hhbmdlIGlzIGV4cGxhaW5lZCBieSB0aGUgdGVtcGVyYXR1cmUgdHJlYXRtZW50LgoKYGBge3J9CiMgVHVrZXkgSFNECndlaWdodFR1a2V5SFNEIDwtIHdlaWdodEFOT1ZBICU+JQogIFR1a2V5SFNEKCkgJT4lCiAgdGlkeSgpICU+JSAKICBzZWxlY3QoY29udHJhc3QsIGVzdGltYXRlLCBhZGoucC52YWx1ZSkgJT4lIAogIGFycmFuZ2UoYWRqLnAudmFsdWUpCgp3ZWlnaHRUdWtleUhTRAoKa2FibGUod2VpZ2h0VHVrZXlIU0QsCiAgICAgIGNhcHRpb24gPSAiVHVrZXkgSFNEIGZvciBjaGFuZ2UgaW4gd2VpZ2h0IGFjcm9zcyB0cmVhdG1lbnRzIikKCmNvZFRlbXBEYXRhX3BsdXMgJT4lCiAgZ2dwbG90KGFlcyh4PVRlbXBlcmF0dXJlLAogICAgICAgICAgICAgeT13ZWlnaHRDaGFuZ2VfZywKICAgICAgICAgICAgIGdyb3VwPVRlbXBlcmF0dXJlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMSwgCiAgICAgICAgICAgICAgaGVpZ2h0ID0gMC4yLCAKICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IDE6NCwgeSA9IDgsIGxhYmVsID0gYygiQSIsIkIiLCJDIiwiRCIpKSArCiAgeGxhYigiVGVtcGVyYXR1cmUgVHJlYXRtZW50ICgqQykiKSArCiAgeWxhYigiV2VpZ2h0IENoYW5nZSAoZyksIDEyLzI3LzIwMjIgdG8gMDIvMDgvMjMiKQoKZ2dzYXZlKAogICAgIjA0X3dlaWdodC1jaGFuZ2UtVHVrZXlIU0QtcGxvdC5wbmciLAogICAgcGxvdCA9IGxhc3RfcGxvdCgpLAogICAgcGF0aCA9ICIuLi9vdXRwdXQvMDFfdGVtcC1zaXplLWFuYWx5c2lzIgogICkKCmBgYAoKRm9yIGJvdGggc2l6ZSBhbmQgd2VpZ2h0LCBncm93dGggZnJvbSAxMi8yNy8yMDIyIHRvIDAyLzA4LzIzIHNpZ25pZmljYW50bHkgZGlmZmVyZWQgYW1vbmcgYWxsIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMsIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiB0aGUgOSBkZWdyZWUgYW5kIDE2IGRlZ3JlZSB0cmVhdG1lbnRzLiBGb3IgdGhlIDkgYW5kIDE2IGRlZ3JlZSB0cmVhdG1lbnRzLCBjaGFuZ2VzIGluIHNpemUgYW5kIHdlaWdodCB3ZXJlIHN0YXRpc3RpY2FsbHkgc2ltaWxhci4KSW4gb3RoZXIgd29yZHMsIGdyb3d0aCBpbmNyZWFzZWQgd2l0aCB0aGUgdHJlYXRtZW50IHRlbXBlcmF0dXJlIHVudGlsIHRoZSAxNiBkZWdyZWUgdHJlYXRtZW50LCBmb3Igd2hpY2ggZ3Jvd3RoIHdhcyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB0aGUgOSBkZWdyZWUgdHJlYXRtZW50IGluIGVpdGhlciBzaXplIG9yIHdlaWdodC4KCgo=