Datasets
The following data sets are included in this notebook. Datasets were sub-sampled to a max 200,000 K cells per dataset.
| Individual Single-Cell RNA-seq PBMC Data from Arunachalam et al. |
49,139 |
Aronow |
Link |
| Individual Single-Cell RNA-seq PBMC Data from Schulte-Schrepping et al. |
90,957 |
Aronow |
Link |
| Individual Single-Cell RNA-seq PBMC Data from Lee et al. |
43,512 |
Aronow |
Link |
| Individual Single-Cell RNA-seq PBMC Data from Wilk et al. |
41,305 |
Aronow |
Link |
| Individual Single-Cell RNA-seq PBMC Data from Guo et al. |
14,783 |
Aronow |
Link |
| Azimuth meta-analysis from Adams et al. |
312,928 |
Satija |
Link |
| Azimuth meta-analysis from Delorey et al. |
106,043 |
Satija |
Link |
| Azimuth meta-analysis from Habermann et al. |
114,396 |
Satija |
Link |
| Large-scale single-cell analysis reveals critical immune characteristics of COVID-19 patients |
1,462,702 |
Zemin Zenhg |
Link |
Read data
This will load all data from the datasets above. Only run this once per session
all_data <- readRDS("all_data.rds")
Parameters
Input the genes and cell types of interest/
Gene set 1 - minimal
#genes <- c("MALAT1", "CD68", "CD79A")
#cell_types <- c("B cell", "T cell", "neutrophil")
Gene set 2 - marker genes
genes <- c("MALAT1", "CD68", "CD79A", "CD8A", "FOXJ1", "GNLY", "CD4", "GNLY", "CD79A", "JCHAIN", "MNDA", "MUC5B", "KTR18")
cell_types <- c("B cell", "T cell", "neutrophil", "natural killer cell", "plasma cell", "macrophage", "ciliated cell")
Gene set 3 - constitutive genes
#genes <- c("LDHA", "PGK1", "ENO1", "SKP1", "TGFB1", "CDKN1C", "PKM", "CCND3", "SKP1", "ZBTB17", "MALAT1", "GAPDH", "ACTB", "RP9", "MT3", "MTR")
#cell_types <- c("B cell", "T cell", "neutrophil", "natural killer cell", "plasma cell", "macrophage", "ciliated cell", "epithelial cell")
Visual prototypes
Any time genes and/or cell types are updated this code has to be run again.
# Summarizing into median, mean, and percent cells
current_data <- get_expression(all_data, genes, cell_types)
Processing dataset 1 / 10
Processing dataset 2 / 10
Processing dataset 3 / 10
Processing dataset 4 / 10
Processing dataset 5 / 10
Processing dataset 6 / 10
Processing dataset 7 / 10
Processing dataset 8 / 10
Processing dataset 9 / 10
Processing dataset 10 / 10
dot_data <- current_data %>%
group_by (Gene, cell_type) %>%
summarise(mean = mean(Expression[Expression!=0]), median = median(Expression[Expression!=0]), percent_cells = sum(Expression != 0) / n()) %>%
ungroup()
# Appending summary to all data
current_data <- current_data %>%
dplyr::filter(Expression != 0)
ids <- str_c(current_data$Gene, current_data$cell_type)
mapping <- setNames(dot_data$median, str_c(dot_data$Gene, dot_data$cell_type))
current_data$median <- mapping[ids]
Dot plot: 2-color gradient
Dot plot: 3-color gradient
Dot plot: cellxgene colors
Density plot: 2-color gradient
Density plot: 3-color gradient
LS0tCnRpdGxlOiAiV2hlcmUncyBteSBnZW5lIHByb3RvdHlwZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGRwaT0xNTApCmxpYnJhcnkoIk1hdHJpeCIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgidGlkeXIiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeSgia2FibGVFeHRyYSIpCmxpYnJhcnkoInNjYWxlcyIpCmxpYnJhcnkoInN0cmluZ3IiKQpsaWJyYXJ5KCJ2aXJpZGlzIikKc291cmNlKCIuL2Z1bmN0aW9ucy5SIikKCmhpZ2hfcmVkIDwtICIjYTgyYzJjIgptaWRfcmVkIDwtICIjZDRiYWJhIgpsb3cgPC0gImdyZXk4NSIKCmNlbGx4Z2VuZV9jb2xvcnMgPC0gcmV2KGMoIiM2NjQyYTciLCAiIzU1NjBjZiIsICIjNDc4ZGRkIiwgIiM1NWMyYzQiLCAiIzYyZGFhOCIsICIjODFmNDc0IiwgIiNiYmVmNjkiKSkKYGBgCgojIyBEYXRhc2V0cwoKVGhlIGZvbGxvd2luZyBkYXRhIHNldHMgYXJlIGluY2x1ZGVkIGluIHRoaXMgbm90ZWJvb2suIERhdGFzZXRzIHdlcmUgc3ViLXNhbXBsZWQgdG8gYSBtYXggMjAwLDAwMCBLIGNlbGxzIHBlciBkYXRhc2V0LiAKCnxEYXRhc2V0fENlbGxzfENvbGxlY3Rpb258Y2VsbHhnZW5lfAp8IC0tLS0tLS0tLS0tLS0tLS0tIHwgLS06IHwgLS0tLS06IHwgOi0tLS06IHwKfEluZGl2aWR1YWwgU2luZ2xlLUNlbGwgUk5BLXNlcSBQQk1DIERhdGEgZnJvbSBBcnVuYWNoYWxhbSBldCBhbC58NDksMTM5fEFyb25vd3xbTGlua10oaHR0cHM6Ly9jZWxseGdlbmUuY3ppc2NpZW5jZS5jb20vY29sbGVjdGlvbnMvYjlmYzNkNzAtNWE3Mi00NDc5LWEwNDYtYzJjYzFhYjE5ZWZjKXwKfEluZGl2aWR1YWwgU2luZ2xlLUNlbGwgUk5BLXNlcSBQQk1DIERhdGEgZnJvbSBTY2h1bHRlLVNjaHJlcHBpbmcgZXQgYWwufDkwLDk1N3xBcm9ub3d8W0xpbmtdKGh0dHBzOi8vY2VsbHhnZW5lLmN6aXNjaWVuY2UuY29tL2NvbGxlY3Rpb25zL2I5ZmMzZDcwLTVhNzItNDQ3OS1hMDQ2LWMyY2MxYWIxOWVmYyl8CnxJbmRpdmlkdWFsIFNpbmdsZS1DZWxsIFJOQS1zZXEgUEJNQyBEYXRhIGZyb20gTGVlIGV0IGFsLnw0Myw1MTJ8QXJvbm93fFtMaW5rXShodHRwczovL2NlbGx4Z2VuZS5jemlzY2llbmNlLmNvbS9jb2xsZWN0aW9ucy9iOWZjM2Q3MC01YTcyLTQ0NzktYTA0Ni1jMmNjMWFiMTllZmMpfAp8SW5kaXZpZHVhbCBTaW5nbGUtQ2VsbCBSTkEtc2VxIFBCTUMgRGF0YSBmcm9tIFdpbGsgZXQgYWwufDQxLDMwNXxBcm9ub3d8W0xpbmtdKGh0dHBzOi8vY2VsbHhnZW5lLmN6aXNjaWVuY2UuY29tL2NvbGxlY3Rpb25zL2I5ZmMzZDcwLTVhNzItNDQ3OS1hMDQ2LWMyY2MxYWIxOWVmYyl8CnxJbmRpdmlkdWFsIFNpbmdsZS1DZWxsIFJOQS1zZXEgUEJNQyBEYXRhIGZyb20gR3VvIGV0IGFsLnwxNCw3ODN8QXJvbm93fFtMaW5rXShodHRwczovL2NlbGx4Z2VuZS5jemlzY2llbmNlLmNvbS9jb2xsZWN0aW9ucy9iOWZjM2Q3MC01YTcyLTQ0NzktYTA0Ni1jMmNjMWFiMTllZmMpfAp8QXppbXV0aCBtZXRhLWFuYWx5c2lzIGZyb20gQWRhbXMgZXQgYWwufDMxMiw5Mjh8U2F0aWphfFtMaW5rXShodHRwczovL2NlbGx4Z2VuZS5jemlzY2llbmNlLmNvbS9jb2xsZWN0aW9ucy8yZjc1ZDI0OS0xYmVjLTQ1OWItYmYyYi1iODYyMjEwOTdjZWQpfAp8QXppbXV0aCBtZXRhLWFuYWx5c2lzIGZyb20gRGVsb3JleSBldCBhbC58MTA2LDA0M3xTYXRpamF8W0xpbmtdKGh0dHBzOi8vY2VsbHhnZW5lLmN6aXNjaWVuY2UuY29tL2NvbGxlY3Rpb25zLzJmNzVkMjQ5LTFiZWMtNDU5Yi1iZjJiLWI4NjIyMTA5N2NlZCl8CnxBemltdXRoIG1ldGEtYW5hbHlzaXMgZnJvbSBIYWJlcm1hbm4gZXQgYWwufDExNCwzOTZ8U2F0aWphfFtMaW5rXShodHRwczovL2NlbGx4Z2VuZS5jemlzY2llbmNlLmNvbS9jb2xsZWN0aW9ucy8yZjc1ZDI0OS0xYmVjLTQ1OWItYmYyYi1iODYyMjEwOTdjZWQpfAp8TGFyZ2Utc2NhbGUgc2luZ2xlLWNlbGwgYW5hbHlzaXMgcmV2ZWFscyBjcml0aWNhbCBpbW11bmUgY2hhcmFjdGVyaXN0aWNzIG9mIENPVklELTE5IHBhdGllbnRzfDEsNDYyLDcwMnxaZW1pbiBaZW5oZ3xbTGlua10oaHR0cHM6Ly9jZWxseGdlbmUuY3ppc2NpZW5jZS5jb20vY29sbGVjdGlvbnMvMmY3NWQyNDktMWJlYy00NTliLWJmMmItYjg2MjIxMDk3Y2VkKXwKCiMjIFJlYWQgZGF0YQoKVGhpcyB3aWxsIGxvYWQgYWxsIGRhdGEgZnJvbSB0aGUgZGF0YXNldHMgYWJvdmUuICoqT25seSBydW4gdGhpcyBvbmNlIHBlciBzZXNzaW9uKioKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KYWxsX2RhdGEgPC0gcmVhZFJEUygiYWxsX2RhdGEucmRzIikKYGBgCgojIyBQYXJhbWV0ZXJzCgpJbnB1dCB0aGUgZ2VuZXMgYW5kIGNlbGwgdHlwZXMgb2YgaW50ZXJlc3QvCgoqKkdlbmUgc2V0IDEgLSBtaW5pbWFsKioKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KI2dlbmVzIDwtIGMoIk1BTEFUMSIsICJDRDY4IiwgIkNENzlBIikKI2NlbGxfdHlwZXMgPC0gYygiQiBjZWxsIiwgIlQgY2VsbCIsICJuZXV0cm9waGlsIikKYGBgCgoqKkdlbmUgc2V0IDIgLSBtYXJrZXIgZ2VuZXMqKgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KZ2VuZXMgPC0gYygiTUFMQVQxIiwgIkNENjgiLCAiQ0Q3OUEiLCAiQ0Q4QSIsICJGT1hKMSIsICJHTkxZIiwgIkNENCIsICJHTkxZIiwgIkNENzlBIiwgIkpDSEFJTiIsICJNTkRBIiwgIk1VQzVCIiwgIktUUjE4IikKY2VsbF90eXBlcyA8LSBjKCJCIGNlbGwiLCAiVCBjZWxsIiwgIm5ldXRyb3BoaWwiLCAibmF0dXJhbCBraWxsZXIgY2VsbCIsICJwbGFzbWEgY2VsbCIsICJtYWNyb3BoYWdlIiwgImNpbGlhdGVkIGNlbGwiKQpgYGAKCioqR2VuZSBzZXQgMyAtIGNvbnN0aXR1dGl2ZSBnZW5lcyoqCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFfQojZ2VuZXMgPC0gYygiTERIQSIsICJQR0sxIiwgIkVOTzEiLCAiU0tQMSIsICJUR0ZCMSIsICJDREtOMUMiLCAiUEtNIiwgIkNDTkQzIiwgIlNLUDEiLCAiWkJUQjE3IiwgIk1BTEFUMSIsICJHQVBESCIsICJBQ1RCIiwgIlJQOSIsICJNVDMiLCAiTVRSIikKI2NlbGxfdHlwZXMgPC0gYygiQiBjZWxsIiwgIlQgY2VsbCIsICJuZXV0cm9waGlsIiwgIm5hdHVyYWwga2lsbGVyIGNlbGwiLCAicGxhc21hIGNlbGwiLCAibWFjcm9waGFnZSIsICJjaWxpYXRlZCBjZWxsIiwgImVwaXRoZWxpYWwgY2VsbCIpCmBgYAoKCiMjIFZpc3VhbCBwcm90b3R5cGVzCgpBbnkgdGltZSBnZW5lcyBhbmQvb3IgY2VsbCB0eXBlcyBhcmUgdXBkYXRlZCB0aGlzIGNvZGUgaGFzIHRvIGJlIHJ1biBhZ2Fpbi4KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0KIyBTdW1tYXJpemluZyBpbnRvIG1lZGlhbiwgbWVhbiwgYW5kIHBlcmNlbnQgY2VsbHMKY3VycmVudF9kYXRhIDwtIGdldF9leHByZXNzaW9uKGFsbF9kYXRhLCBnZW5lcywgY2VsbF90eXBlcykKZG90X2RhdGEgPC0gY3VycmVudF9kYXRhICU+JQogIGdyb3VwX2J5IChHZW5lLCBjZWxsX3R5cGUpICU+JQogIHN1bW1hcmlzZShtZWFuID0gbWVhbihFeHByZXNzaW9uW0V4cHJlc3Npb24hPTBdKSwgbWVkaWFuID0gbWVkaWFuKEV4cHJlc3Npb25bRXhwcmVzc2lvbiE9MF0pLCBwZXJjZW50X2NlbGxzID0gc3VtKEV4cHJlc3Npb24gIT0gMCkgLyBuKCkpICU+JQogIHVuZ3JvdXAoKQoKIyBBcHBlbmRpbmcgc3VtbWFyeSB0byBhbGwgZGF0YQpjdXJyZW50X2RhdGEgPC0gY3VycmVudF9kYXRhICU+JQogIGRwbHlyOjpmaWx0ZXIoRXhwcmVzc2lvbiAhPSAwKQoKaWRzIDwtIHN0cl9jKGN1cnJlbnRfZGF0YSRHZW5lLCBjdXJyZW50X2RhdGEkY2VsbF90eXBlKQptYXBwaW5nIDwtIHNldE5hbWVzKGRvdF9kYXRhJG1lZGlhbiwgc3RyX2MoZG90X2RhdGEkR2VuZSwgZG90X2RhdGEkY2VsbF90eXBlKSkKY3VycmVudF9kYXRhJG1lZGlhbiA8LSBtYXBwaW5nW2lkc10KYGBgCgojIyMgRG90IHBsb3Q6IDItY29sb3IgZ3JhZGllbnQKYGBge3IsIHJlc3VsdHM9J2FzaXMnLCBlY2hvPUZBTFNFfQpuX2dlbmVzIDwtIGxlbmd0aCh1bmlxdWUoY3VycmVudF9kYXRhJEdlbmUpKQpuX2NlbGxzIDwtIGxlbmd0aCh1bmlxdWUoY3VycmVudF9kYXRhJGNlbGxfdHlwZSkpCgojQ3JlYXRlIHBsb3QKZG90X3Bsb3QgPC0gZnVuY3Rpb24oeCkgewogIGdncGxvdCh4LCBhZXMoeD1HZW5lLCB5PWNlbGxfdHlwZSkpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG91cj1tZWRpYW4sIHNpemU9cGVyY2VudF9jZWxscykpKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnM9Yyhsb3csIG1pZF9yZWQsIGhpZ2hfcmVkKSwgbGltaXRzPWMoLTUuMiw1LjIpKSArCiAgICB4bGFiKCIiKSArIHlsYWIoIiIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZSAoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9MzAsIGhqdXN0PTEpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTguNSkpCn0KCnN1YmNodW5raWZ5KGRvdF9wbG90KGRvdF9kYXRhKSwgZmlnX2hlaWdodCA9IDEuNSArIChuX2NlbGxzKjAuMyksIGZpZ193aWR0aCA9IDMgKyAobl9nZW5lcyAqIDAuMykpCmBgYAoKIyMjIERvdCBwbG90OiAzLWNvbG9yIGdyYWRpZW50CmBgYHtyLCByZXN1bHRzPSdhc2lzJywgZWNobz1GQUxTRX0Kbl9nZW5lcyA8LSBsZW5ndGgodW5pcXVlKGN1cnJlbnRfZGF0YSRHZW5lKSkKbl9jZWxscyA8LSBsZW5ndGgodW5pcXVlKGN1cnJlbnRfZGF0YSRjZWxsX3R5cGUpKQoKI0NyZWF0ZSBwbG90CmRvdF9wbG90IDwtIGZ1bmN0aW9uKHgpIHsKICBnZ3Bsb3QoeCwgYWVzKHg9R2VuZSwgeT1jZWxsX3R5cGUpKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9bWVkaWFuLCBzaXplPXBlcmNlbnRfY2VsbHMpKSsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudDIobG93PW11dGVkKCJibHVlIiksIGhpZ2ggPSBtdXRlZCgicmVkIiksIGxpbWl0cz1jKC01LjIsNS4yKSkgKwogICAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUgKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTMwLCBoanVzdD0xKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT04LjUpKQp9CgpzdWJjaHVua2lmeShkb3RfcGxvdChkb3RfZGF0YSksIGZpZ19oZWlnaHQgPSAxLjUgKyAobl9jZWxscyowLjMpLCBmaWdfd2lkdGggPSAzICsgKG5fZ2VuZXMgKiAwLjMpKQpgYGAKIyMjIERvdCBwbG90OiBjZWxseGdlbmUgY29sb3JzCmBgYHtyLCByZXN1bHRzPSdhc2lzJywgZWNobz1GQUxTRX0Kbl9nZW5lcyA8LSBsZW5ndGgodW5pcXVlKGN1cnJlbnRfZGF0YSRHZW5lKSkKbl9jZWxscyA8LSBsZW5ndGgodW5pcXVlKGN1cnJlbnRfZGF0YSRjZWxsX3R5cGUpKQoKI0NyZWF0ZSBwbG90CmRvdF9wbG90IDwtIGZ1bmN0aW9uKHgpIHsKICBnZ3Bsb3QoeCwgYWVzKHg9R2VuZSwgeT1jZWxsX3R5cGUpKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9bWVkaWFuLCBzaXplPXBlcmNlbnRfY2VsbHMpKSsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3JzPWNlbGx4Z2VuZV9jb2xvcnMsIGxpbWl0cz1jKC01LjIsNS4yKSkgKwogICAgeGxhYigiIikgKyB5bGFiKCIiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUgKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTMwLCBoanVzdD0xKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT04LjUpKQp9CgpzdWJjaHVua2lmeShkb3RfcGxvdChkb3RfZGF0YSksIGZpZ19oZWlnaHQgPSAxLjUgKyAobl9jZWxscyowLjMpLCBmaWdfd2lkdGggPSAzICsgKG5fZ2VuZXMgKiAwLjMpKQpgYGAKCgojIyMgRGVuc2l0eSBwbG90OiAyLWNvbG9yIGdyYWRpZW50CgpgYGB7ciwgcmVzdWx0cz0nYXNpcycsIGVjaG89RkFMU0V9CnZpb2xpbl9wbG90IDwtIGZ1bmN0aW9uKHgpIHsKICBnZ3Bsb3QoeCwgYWVzKHk9RXhwcmVzc2lvbiwgeCA9IGNlbGxfdHlwZSkpICsKICAgIGdlb21fZmxhdF92aW9saW4oYWVzKGZpbGw9bWVkaWFuLCBjb2xvdXI9bWVkaWFuKSkgKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnM9Yyhsb3csIG1pZF9yZWQsIGhpZ2hfcmVkKSwgbGltaXRzPWMoLTUuMiw1LjIpKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yyhsb3csIG1pZF9yZWQsIGhpZ2hfcmVkKSwgbGltaXRzPWMoLTUuMiw1LjIpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZmFjZXRfZ3JpZCgufkdlbmUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgCn0KCnN1YmNodW5raWZ5KHZpb2xpbl9wbG90KGN1cnJlbnRfZGF0YSksIGZpZ19oZWlnaHQgPSAxLjUgKyAobl9jZWxscyowLjgpLCBmaWdfd2lkdGggPSAzICsgKG5fZ2VuZXMgKiAxKSkKCgpgYGAKCgoKIyMjIERlbnNpdHkgcGxvdDogMy1jb2xvciBncmFkaWVudAoKYGBge3IsIHJlc3VsdHM9J2FzaXMnLCBlY2hvPUZBTFNFfQp2aW9saW5fcGxvdCA8LSBmdW5jdGlvbih4KSB7CiAgZ2dwbG90KHgsIGFlcyh5PUV4cHJlc3Npb24sIHggPSBjZWxsX3R5cGUpKSArCiAgICBnZW9tX2ZsYXRfdmlvbGluKGFlcyhmaWxsPW1lZGlhbiwgY29sb3VyPW1lZGlhbikpICsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudDIobG93PW11dGVkKCJibHVlIiksIGhpZ2ggPSBtdXRlZCgicmVkIiksIGxpbWl0cz1jKC01LjIsNS4yKSkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93PW11dGVkKCJibHVlIiksIGhpZ2ggPSBtdXRlZCgicmVkIiksIGxpbWl0cz1jKC01LjIsNS4yKSkgKwogICAgY29vcmRfZmxpcCgpICsKICAgIGZhY2V0X2dyaWQoLn5HZW5lLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgdGhlbWVfY2xhc3NpYygpIAp9CgpzdWJjaHVua2lmeSh2aW9saW5fcGxvdChjdXJyZW50X2RhdGEpLCBmaWdfaGVpZ2h0ID0gMS41ICsgKG5fY2VsbHMqMC44KSwgZmlnX3dpZHRoID0gMyArIChuX2dlbmVzICogMSkpCgoKYGBgCgojIyMgRGVuc2l0eSBwbG90OiB2aXJpZGlzCgpgYGB7ciwgcmVzdWx0cz0nYXNpcycsIGVjaG89RkFMU0V9CnZpb2xpbl9wbG90IDwtIGZ1bmN0aW9uKHgpIHsKICBnZ3Bsb3QoeCwgYWVzKHk9RXhwcmVzc2lvbiwgeCA9IGNlbGxfdHlwZSkpICsKICAgIGdlb21fZmxhdF92aW9saW4oYWVzKGZpbGw9bWVkaWFuLCBjb2xvdXI9bWVkaWFuKSkgKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnM9Y2VsbHhnZW5lX2NvbG9ycywgbGltaXRzPWMoLTUuMiw1LjIpKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Y2VsbHhnZW5lX2NvbG9ycywgbGltaXRzPWMoLTUuMiw1LjIpKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgZmFjZXRfZ3JpZCgufkdlbmUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgCn0KCnN1YmNodW5raWZ5KHZpb2xpbl9wbG90KGN1cnJlbnRfZGF0YSksIGZpZ19oZWlnaHQgPSAxLjUgKyAobl9jZWxscyowLjgpLCBmaWdfd2lkdGggPSAzICsgKG5fZ2VuZXMgKiAxKSkKCmBgYAo=