Flight Analysis

Flight Statistics

Data normalized across several flight logs, spanning from NS45 to NS80, excepting NS54, NS55, and NS68 (NS54 is reserved for a flight still in development, and both NS55 and NS68 failed to record location data).

Due to a settings issue, before NS59, the cell tracker hardware stopped recording above 12.1 km (except for NS53). This limit is shown as a grey horizontal line in the figures depicting altitude.

require(ggplot2)
require(ggmap)
require(directlabels)
require(scales)
source("setup.R")
flight_times <- read_flight_times("flight_times.txt")
flight_data <- read_flight_data("flight_data/", calculate_difftime = TRUE)

1 Summary

1.1 Flight Times

This table shows launch time, burst time, burst altitude, landing time, and masses of each flight.

rmarkdown::paged_table(read.csv("flight_times.txt"))

1.2 Map

Usually, the program launches balloons from the parking lot of Clear Spring Elementary School in Clear Spring, MD. However, flight predictions sometimes force launches from further west to avoid landing in either Baltimore or the Chesapeake Bay.

# get data excluding NS69 (eclipse launch in South Carolina)
maryland_flights <- flight_data[flight_data$Flight != "NS69",]
# get map tile
if (!exists("map"))
{
    map <-
        get_map(location = c(
            min(maryland_flights$Longitude),
            min(maryland_flights$Latitude),
            max(maryland_flights$Longitude),
            max(maryland_flights$Latitude)
        ),
        maptype = "roadmap")
}
# plot base layer to map tile
ggmap(map,
      base_layer = ggplot(maryland_flights,
                          aes(
                              x = Longitude, y = Latitude, colour = Flight
                          )),
      extent = "normal") +
    geom_point() + geom_path() +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list("far.from.others.borders", "small.box.labels")) + guides(colour = FALSE) +
    labs(title = "Maryland Flights", x = "Longitude", y = "Latitude")

D. Kahle and H. Wickham. ggmap: Spatial Visualization with ggplot2. The R Journal, 5(1), 144-161.

1.3 Altitude vs Downrange Distance

ggplot(flight_data,
       aes(
           x = Downrange_Distance_m / 1000,
           y = Altitude_m / 1000,
           colour = Flight
       )) +
    geom_point(size = 0.75) + geom_path(alpha = 0.3) +
    coord_fixed(ratio = 3) +
    scale_x_continuous(breaks = seq(
        from = 0,
        to = max(flight_data$Downrange_Distance_m),
        by = 30
    )) +
    scale_y_continuous(breaks = seq(
        from = 0,
        to = max(flight_data$Altitude_m),
        by = 10
    )) +
    geom_hline(yintercept = 12.1, alpha = 0.2) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list("far.from.others.borders", "small.box.labels")) + guides(colour = FALSE) +
    labs(title = "Altitude vs Downrange Distance", x = "Downrange Distance (km)", y = "Altitude (km)")

axes to 1:3 scale

2 Altitude

2.1 Altitude vs Date

ggplot(flight_data,
       aes(x = DateTime,
           y = Altitude_m / 1000,
           colour = Flight)) +
    geom_point() + geom_path() +
    geom_hline(yintercept = 12.1, alpha = 0.2) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, dl.trans(y = y + 0.2), "top.bumpup")) + guides(colour = FALSE) +
    labs(title = "Altitude vs Date", x = "Date", y = "Altitude (km)")

2.2 Altitude vs Time of Year

ggplot(flight_data,
       aes(
           x = as.Date(format(DateTime, format = "%m-%d"), format = "%m-%d"),
           y = Altitude_m / 1000,
           colour = Flight
       )) +
    geom_point() + geom_path() +
    geom_hline(yintercept = 12.100, alpha = 0.2) +
    scale_x_date(
        date_breaks = "1 month",
        labels = date_format("%b"),
        limits = as.Date(c("01-01", "12-31"), format = "%m-%d"),
        expand = c(0, 0)
    ) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, dl.trans(y = y + 0.2), "top.bumpup")) + guides(colour = FALSE) +
    labs(title = "Altitude vs Time of Year", x = "Time of Year", y = "Altitude (km)")

2.3 Altitude vs Time After Launch

ggplot(flight_data,
       aes(
           x = launch_difftime / 60,
           y = Altitude_m / 1000,
           colour = Flight
       )) +
    geom_point(size = 0.75) + geom_path() +
    geom_hline(yintercept = 12.100, alpha = 0.2) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list("far.from.others.borders", "small.box.labels")) + guides(colour = FALSE) +
    labs(title = "Altitude vs Time After Launch", x = "Time After Launch (minutes)", y = "Altitude (km)")

3 Downrange Distance

Using a geodesic, we can calculate distance between coordinate points to get downrange distance. Downrange distance represents the distance from the coordinates of the launch site to the coordinates of the data point.

3.1 Downrange Distance vs Time of Year

ggplot(flight_data,
       aes(
           x = as.Date(format(DateTime, format = "%m-%d"), format = "%m-%d"),
           y = Downrange_Distance_m / 1000,
           colour = Flight
       )) +
    geom_point() + geom_path() +
    scale_x_date(
        date_breaks = "1 month",
        labels = date_format("%b"),
        limits = as.Date(c("01-01", "12-31"), format = "%m-%d"),
        expand = c(0, 0)
    ) +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list(cex = 0.8, dl.trans(y = y + 0.2), "top.bumpup")) + guides(colour = FALSE) +
    labs(title = "Downrange Distance vs Time of Year", x = "Time of Year", y = "Downrange Distance (km)")

3.2 Downrange Distance vs Time After Launch

ggplot(
    flight_data,
    aes(
        x = launch_difftime / 60,
        y = Downrange_Distance_m / 1000,
        colour = Flight
    )
) +
    geom_point(size = 0.75) + geom_path() +
    geom_dl(aes(label = gsub("NS", "", Flight)),
            method = list("far.from.others.borders", "small.box.labels")) + guides(colour = FALSE) +
    labs(title = "Downrange Distance vs Time After Launch", x = "Time After Launch (minutes)", y = "Downrange Distance (km)")

LS0tCnRpdGxlOiAiRmxpZ2h0IFN1bW1hcnkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICAgIGNvbGxhcHNlZDogZmFsc2UKLS0tCgpbRmxpZ2h0IEFuYWx5c2lzXShmbGlnaHRfYW5hbHlzaXMubmIuaHRtbCkKCltGbGlnaHQgU3RhdGlzdGljc10oZmxpZ2h0X3N0YXRpc3RpY3MubmIuaHRtbCkKCkRhdGEgbm9ybWFsaXplZCBhY3Jvc3Mgc2V2ZXJhbCBmbGlnaHQgbG9ncywgc3Bhbm5pbmcgZnJvbSBgciBtaW4obGV2ZWxzKGZsaWdodF9kYXRhJEZsaWdodCkpYCB0byBgciBtYXgobGV2ZWxzKGZsaWdodF9kYXRhJEZsaWdodCkpYCwgZXhjZXB0aW5nIE5TNTQsIE5TNTUsIGFuZCBOUzY4IChOUzU0IGlzIHJlc2VydmVkIGZvciBhIGZsaWdodCBzdGlsbCBpbiBkZXZlbG9wbWVudCwgYW5kIGJvdGggTlM1NSBhbmQgTlM2OCBmYWlsZWQgdG8gcmVjb3JkIGxvY2F0aW9uIGRhdGEpLgoKRHVlIHRvIGEgc2V0dGluZ3MgaXNzdWUsIGJlZm9yZSBOUzU5LCB0aGUgY2VsbCB0cmFja2VyIGhhcmR3YXJlIHN0b3BwZWQgcmVjb3JkaW5nIGFib3ZlIDEyLjEga20gKGV4Y2VwdCBmb3IgTlM1MykuIFRoaXMgbGltaXQgaXMgc2hvd24gYXMgYSBncmV5IGhvcml6b250YWwgbGluZSBpbiB0aGUgZmlndXJlcyBkZXBpY3RpbmcgYWx0aXR1ZGUuCgpgYGB7ciBzZXR1cH0KcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKGdnbWFwKQpyZXF1aXJlKGRpcmVjdGxhYmVscykKcmVxdWlyZShzY2FsZXMpCgpzb3VyY2UoInNldHVwLlIiKQoKZmxpZ2h0X3RpbWVzIDwtIHJlYWRfZmxpZ2h0X3RpbWVzKCJmbGlnaHRfdGltZXMudHh0IikKZmxpZ2h0X2RhdGEgPC0gcmVhZF9mbGlnaHRfZGF0YSgiZmxpZ2h0X2RhdGEvIiwgY2FsY3VsYXRlX2RpZmZ0aW1lID0gVFJVRSkKYGBgCgojIFN1bW1hcnkKCiMjIEZsaWdodCBUaW1lcwoKVGhpcyB0YWJsZSBzaG93cyBsYXVuY2ggdGltZSwgYnVyc3QgdGltZSwgYnVyc3QgYWx0aXR1ZGUsIGxhbmRpbmcgdGltZSwgYW5kIG1hc3NlcyBvZiBlYWNoIGZsaWdodC4KCmBgYHtyIGZsaWdodF90aW1lcywgZmlnLmhlaWdodD03LjQxNjQwNzksIGZpZy53aWR0aD0xMn0Kcm1hcmtkb3duOjpwYWdlZF90YWJsZShyZWFkLmNzdigiZmxpZ2h0X3RpbWVzLnR4dCIpKQpgYGAKCiMjIE1hcAoKVXN1YWxseSwgdGhlIHByb2dyYW0gbGF1bmNoZXMgYmFsbG9vbnMgZnJvbSB0aGUgcGFya2luZyBsb3Qgb2YgW0NsZWFyIFNwcmluZyBFbGVtZW50YXJ5IFNjaG9vbCBpbiBDbGVhciBTcHJpbmcsIE1EXShodHRwczovL3d3dy5nb29nbGUuY29tL21hcHMvcGxhY2UvQ2xlYXIrU3ByaW5nK0VsZW1lbnRhcnkrU2Nob29sL0AzOS42NTY3Mzk5LC03Ny45MzU1NjE2LDE3ei9kYXRhPSE0bTUhM200ITFzMHg4OWNhMWZkZGRlYjM1M2Q5OjB4NzFjYjFiMjJiMzAyYzk4ZCE4bTIhM2QzOS42NTY3MDghNGQtNzcuOTM0MTc2NikuIEhvd2V2ZXIsIGZsaWdodCBwcmVkaWN0aW9ucyBzb21ldGltZXMgZm9yY2UgbGF1bmNoZXMgZnJvbSBmdXJ0aGVyIHdlc3QgdG8gYXZvaWQgbGFuZGluZyBpbiBlaXRoZXIgQmFsdGltb3JlIG9yIHRoZSBDaGVzYXBlYWtlIEJheS4KCmBgYHtyIGNvb3JkaW5hdGVzX21hcCwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQojIGdldCBkYXRhIGV4Y2x1ZGluZyBOUzY5IChlY2xpcHNlIGxhdW5jaCBpbiBTb3V0aCBDYXJvbGluYSkKbWFyeWxhbmRfZmxpZ2h0cyA8LSBmbGlnaHRfZGF0YVtmbGlnaHRfZGF0YSRGbGlnaHQgIT0gIk5TNjkiLF0KCiMgZ2V0IG1hcCB0aWxlCmlmICghZXhpc3RzKCJtYXAiKSkKewogICAgbWFwIDwtCiAgICAgICAgZ2V0X21hcChsb2NhdGlvbiA9IGMoCiAgICAgICAgICAgIG1pbihtYXJ5bGFuZF9mbGlnaHRzJExvbmdpdHVkZSksCiAgICAgICAgICAgIG1pbihtYXJ5bGFuZF9mbGlnaHRzJExhdGl0dWRlKSwKICAgICAgICAgICAgbWF4KG1hcnlsYW5kX2ZsaWdodHMkTG9uZ2l0dWRlKSwKICAgICAgICAgICAgbWF4KG1hcnlsYW5kX2ZsaWdodHMkTGF0aXR1ZGUpCiAgICAgICAgKSwKICAgICAgICBtYXB0eXBlID0gInJvYWRtYXAiKQp9CgojIHBsb3QgYmFzZSBsYXllciB0byBtYXAgdGlsZQpnZ21hcChtYXAsCiAgICAgIGJhc2VfbGF5ZXIgPSBnZ3Bsb3QobWFyeWxhbmRfZmxpZ2h0cywKICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSwgY29sb3VyID0gRmxpZ2h0CiAgICAgICAgICAgICAgICAgICAgICAgICAgKSksCiAgICAgIGV4dGVudCA9ICJub3JtYWwiKSArCiAgICBnZW9tX3BvaW50KCkgKyBnZW9tX3BhdGgoKSArCiAgICBnZW9tX2RsKGFlcyhsYWJlbCA9IGdzdWIoIk5TIiwgIiIsIEZsaWdodCkpLAogICAgICAgICAgICBtZXRob2QgPSBsaXN0KCJmYXIuZnJvbS5vdGhlcnMuYm9yZGVycyIsICJzbWFsbC5ib3gubGFiZWxzIikpICsgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgICBsYWJzKHRpdGxlID0gIk1hcnlsYW5kIEZsaWdodHMiLCB4ID0gIkxvbmdpdHVkZSIsIHkgPSAiTGF0aXR1ZGUiKQpgYGAKCltELiBLYWhsZSBhbmQgSC4gV2lja2hhbS4gZ2dtYXA6IFNwYXRpYWwgVmlzdWFsaXphdGlvbiB3aXRoIGdncGxvdDIuIFRoZSBSIEpvdXJuYWwsIDUoMSksIDE0NC0xNjEuXShodHRwOi8vam91cm5hbC5yLXByb2plY3Qub3JnL2FyY2hpdmUvMjAxMy0xL2thaGxlLXdpY2toYW0ucGRmKQoKIyMgQWx0aXR1ZGUgdnMgRG93bnJhbmdlIERpc3RhbmNlCgpgYGB7ciBhbHRpdHVkZV92c19kb3ducmFuZ2VfZGlzdGFuY2UsIGZpZy5oZWlnaHQ9Ny40MTY0MDc5LCBmaWcud2lkdGg9MTJ9CmdncGxvdChmbGlnaHRfZGF0YSwKICAgICAgIGFlcygKICAgICAgICAgICB4ID0gRG93bnJhbmdlX0Rpc3RhbmNlX20gLyAxMDAwLAogICAgICAgICAgIHkgPSBBbHRpdHVkZV9tIC8gMTAwMCwKICAgICAgICAgICBjb2xvdXIgPSBGbGlnaHQKICAgICAgICkpICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNzUpICsgZ2VvbV9wYXRoKGFscGhhID0gMC4zKSArCiAgICBjb29yZF9maXhlZChyYXRpbyA9IDMpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoCiAgICAgICAgZnJvbSA9IDAsCiAgICAgICAgdG8gPSBtYXgoZmxpZ2h0X2RhdGEkRG93bnJhbmdlX0Rpc3RhbmNlX20pLAogICAgICAgIGJ5ID0gMzAKICAgICkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoCiAgICAgICAgZnJvbSA9IDAsCiAgICAgICAgdG8gPSBtYXgoZmxpZ2h0X2RhdGEkQWx0aXR1ZGVfbSksCiAgICAgICAgYnkgPSAxMAogICAgKSkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTIuMSwgYWxwaGEgPSAwLjIpICsKICAgIGdlb21fZGwoYWVzKGxhYmVsID0gZ3N1YigiTlMiLCAiIiwgRmxpZ2h0KSksCiAgICAgICAgICAgIG1ldGhvZCA9IGxpc3QoImZhci5mcm9tLm90aGVycy5ib3JkZXJzIiwgInNtYWxsLmJveC5sYWJlbHMiKSkgKyBndWlkZXMoY29sb3VyID0gRkFMU0UpICsKICAgIGxhYnModGl0bGUgPSAiQWx0aXR1ZGUgdnMgRG93bnJhbmdlIERpc3RhbmNlIiwgeCA9ICJEb3ducmFuZ2UgRGlzdGFuY2UgKGttKSIsIHkgPSAiQWx0aXR1ZGUgKGttKSIpCmBgYApheGVzIHRvIDE6MyBzY2FsZQoKIyBBbHRpdHVkZQoKIyMgQWx0aXR1ZGUgdnMgRGF0ZQoKYGBge3IgYWx0aXR1ZGVfdnNfZGF0ZSwgZmlnLmhlaWdodD03LjQxNjQwNzksIGZpZy53aWR0aD0xMn0KZ2dwbG90KGZsaWdodF9kYXRhLAogICAgICAgYWVzKHggPSBEYXRlVGltZSwKICAgICAgICAgICB5ID0gQWx0aXR1ZGVfbSAvIDEwMDAsCiAgICAgICAgICAgY29sb3VyID0gRmxpZ2h0KSkgKwogICAgZ2VvbV9wb2ludCgpICsgZ2VvbV9wYXRoKCkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTIuMSwgYWxwaGEgPSAwLjIpICsKICAgIGdlb21fZGwoYWVzKGxhYmVsID0gZ3N1YigiTlMiLCAiIiwgRmxpZ2h0KSksCiAgICAgICAgICAgIG1ldGhvZCA9IGxpc3QoY2V4ID0gMC44LCBkbC50cmFucyh5ID0geSArIDAuMiksICJ0b3AuYnVtcHVwIikpICsgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgICBsYWJzKHRpdGxlID0gIkFsdGl0dWRlIHZzIERhdGUiLCB4ID0gIkRhdGUiLCB5ID0gIkFsdGl0dWRlIChrbSkiKQpgYGAKCiMjIEFsdGl0dWRlIHZzIFRpbWUgb2YgWWVhcgoKYGBge3IgYWx0aXR1ZGVfdnNfdGltZV9vZl95ZWFyLCBmaWcuaGVpZ2h0PTcuNDE2NDA3OSwgZmlnLndpZHRoPTEyfQpnZ3Bsb3QoZmxpZ2h0X2RhdGEsCiAgICAgICBhZXMoCiAgICAgICAgICAgeCA9IGFzLkRhdGUoZm9ybWF0KERhdGVUaW1lLCBmb3JtYXQgPSAiJW0tJWQiKSwgZm9ybWF0ID0gIiVtLSVkIiksCiAgICAgICAgICAgeSA9IEFsdGl0dWRlX20gLyAxMDAwLAogICAgICAgICAgIGNvbG91ciA9IEZsaWdodAogICAgICAgKSkgKwogICAgZ2VvbV9wb2ludCgpICsgZ2VvbV9wYXRoKCkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTIuMTAwLCBhbHBoYSA9IDAuMikgKwogICAgc2NhbGVfeF9kYXRlKAogICAgICAgIGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLAogICAgICAgIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlYiIpLAogICAgICAgIGxpbWl0cyA9IGFzLkRhdGUoYygiMDEtMDEiLCAiMTItMzEiKSwgZm9ybWF0ID0gIiVtLSVkIiksCiAgICAgICAgZXhwYW5kID0gYygwLCAwKQogICAgKSArCiAgICBnZW9tX2RsKGFlcyhsYWJlbCA9IGdzdWIoIk5TIiwgIiIsIEZsaWdodCkpLAogICAgICAgICAgICBtZXRob2QgPSBsaXN0KGNleCA9IDAuOCwgZGwudHJhbnMoeSA9IHkgKyAwLjIpLCAidG9wLmJ1bXB1cCIpKSArIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICJBbHRpdHVkZSB2cyBUaW1lIG9mIFllYXIiLCB4ID0gIlRpbWUgb2YgWWVhciIsIHkgPSAiQWx0aXR1ZGUgKGttKSIpCmBgYAoKIyMgQWx0aXR1ZGUgdnMgVGltZSBBZnRlciBMYXVuY2gKCmBgYHtyIGFsdGl0dWRlX3ZzX3RpbWVfYWZ0ZXJfbGF1bmNoLCBmaWcuaGVpZ2h0PTcuNDE2NDA3OSwgZmlnLndpZHRoPTEyfQpnZ3Bsb3QoZmxpZ2h0X2RhdGEsCiAgICAgICBhZXMoCiAgICAgICAgICAgeCA9IGxhdW5jaF9kaWZmdGltZSAvIDYwLAogICAgICAgICAgIHkgPSBBbHRpdHVkZV9tIC8gMTAwMCwKICAgICAgICAgICBjb2xvdXIgPSBGbGlnaHQKICAgICAgICkpICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDAuNzUpICsgZ2VvbV9wYXRoKCkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTIuMTAwLCBhbHBoYSA9IDAuMikgKwogICAgZ2VvbV9kbChhZXMobGFiZWwgPSBnc3ViKCJOUyIsICIiLCBGbGlnaHQpKSwKICAgICAgICAgICAgbWV0aG9kID0gbGlzdCgiZmFyLmZyb20ub3RoZXJzLmJvcmRlcnMiLCAic21hbGwuYm94LmxhYmVscyIpKSArIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICJBbHRpdHVkZSB2cyBUaW1lIEFmdGVyIExhdW5jaCIsIHggPSAiVGltZSBBZnRlciBMYXVuY2ggKG1pbnV0ZXMpIiwgeSA9ICJBbHRpdHVkZSAoa20pIikKYGBgCgojIERvd25yYW5nZSBEaXN0YW5jZQoKVXNpbmcgYSBnZW9kZXNpYywgd2UgY2FuIGNhbGN1bGF0ZSBkaXN0YW5jZSBiZXR3ZWVuIGNvb3JkaW5hdGUgcG9pbnRzIHRvIGdldCBkb3ducmFuZ2UgZGlzdGFuY2UuIERvd25yYW5nZSBkaXN0YW5jZSByZXByZXNlbnRzIHRoZSBkaXN0YW5jZSBmcm9tIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgbGF1bmNoIHNpdGUgdG8gdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBkYXRhIHBvaW50LiAKCiMjIERvd25yYW5nZSBEaXN0YW5jZSB2cyBUaW1lIG9mIFllYXIKCmBgYHtyIGRvd25yYW5nZV9kaXN0YW5jZV92c190aW1lX29mX3llYXIsIGZpZy5oZWlnaHQ9Ny40MTY0MDc5LCBmaWcud2lkdGg9MTJ9CmdncGxvdChmbGlnaHRfZGF0YSwKICAgICAgIGFlcygKICAgICAgICAgICB4ID0gYXMuRGF0ZShmb3JtYXQoRGF0ZVRpbWUsIGZvcm1hdCA9ICIlbS0lZCIpLCBmb3JtYXQgPSAiJW0tJWQiKSwKICAgICAgICAgICB5ID0gRG93bnJhbmdlX0Rpc3RhbmNlX20gLyAxMDAwLAogICAgICAgICAgIGNvbG91ciA9IEZsaWdodAogICAgICAgKSkgKwogICAgZ2VvbV9wb2ludCgpICsgZ2VvbV9wYXRoKCkgKwogICAgc2NhbGVfeF9kYXRlKAogICAgICAgIGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLAogICAgICAgIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlYiIpLAogICAgICAgIGxpbWl0cyA9IGFzLkRhdGUoYygiMDEtMDEiLCAiMTItMzEiKSwgZm9ybWF0ID0gIiVtLSVkIiksCiAgICAgICAgZXhwYW5kID0gYygwLCAwKQogICAgKSArCiAgICBnZW9tX2RsKGFlcyhsYWJlbCA9IGdzdWIoIk5TIiwgIiIsIEZsaWdodCkpLAogICAgICAgICAgICBtZXRob2QgPSBsaXN0KGNleCA9IDAuOCwgZGwudHJhbnMoeSA9IHkgKyAwLjIpLCAidG9wLmJ1bXB1cCIpKSArIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogICAgbGFicyh0aXRsZSA9ICJEb3ducmFuZ2UgRGlzdGFuY2UgdnMgVGltZSBvZiBZZWFyIiwgeCA9ICJUaW1lIG9mIFllYXIiLCB5ID0gIkRvd25yYW5nZSBEaXN0YW5jZSAoa20pIikKYGBgCgojIyBEb3ducmFuZ2UgRGlzdGFuY2UgdnMgVGltZSBBZnRlciBMYXVuY2gKCmBgYHtyIGRvd25yYW5nZV9kaXN0YW5jZV92c190aW1lX2FmdGVyX2xhdW5jaCwgZmlnLmhlaWdodD03LjQxNjQwNzksIGZpZy53aWR0aD0xMn0KZ2dwbG90KAogICAgZmxpZ2h0X2RhdGEsCiAgICBhZXMoCiAgICAgICAgeCA9IGxhdW5jaF9kaWZmdGltZSAvIDYwLAogICAgICAgIHkgPSBEb3ducmFuZ2VfRGlzdGFuY2VfbSAvIDEwMDAsCiAgICAgICAgY29sb3VyID0gRmxpZ2h0CiAgICApCikgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC43NSkgKyBnZW9tX3BhdGgoKSArCiAgICBnZW9tX2RsKGFlcyhsYWJlbCA9IGdzdWIoIk5TIiwgIiIsIEZsaWdodCkpLAogICAgICAgICAgICBtZXRob2QgPSBsaXN0KCJmYXIuZnJvbS5vdGhlcnMuYm9yZGVycyIsICJzbWFsbC5ib3gubGFiZWxzIikpICsgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgICBsYWJzKHRpdGxlID0gIkRvd25yYW5nZSBEaXN0YW5jZSB2cyBUaW1lIEFmdGVyIExhdW5jaCIsIHggPSAiVGltZSBBZnRlciBMYXVuY2ggKG1pbnV0ZXMpIiwgeSA9ICJEb3ducmFuZ2UgRGlzdGFuY2UgKGttKSIpCmBgYAoKYGBge3IgdGVhcmRvd24sIGluY2x1ZGU9RkFMU0V9CnJtKHJlYWRfZmxpZ2h0X3RpbWVzLCByZWFkX2ZsaWdodF9kYXRhKQoKcm0oc21hbGwuYm94LmxhYmVscykKI3JtKGZsaWdodF9kYXRhKQoKcm0obWFyeWxhbmRfZmxpZ2h0cykKI3JtKG1hcCkKYGBg