1. Sankey diagram: 入院方式 → 急救責任分級 → 轉診型態
### 使用資料: EMOC_v7.csv
df = read.csv('EMOC_v7.csv', na = c('', 'NA'), stringsAsFactors = FALSE) # 21781 examples
### Columns to use
left_col = '入院方式'
cen_col = 'EMOC_轉出醫院急救責任醫院等級'
right_col = '轉診型態'
### Set the labels
unique_labs = do.call('c', sapply(c(left_col, cen_col, right_col), function(x) unique(df[, x])))
unique_labs_ref = seq(1:length(unique_labs)) - 1
names(unique_labs_ref) = unique_labs
### Set the names of the starting point,the ending point and the values of links
starts = c()
ends = c()
links = c()
## The left part
df_left = aggregate(as.formula(paste(right_col, '~', paste(left_col, cen_col, sep = '+'))), df, function(x) length(x))
starts = c(starts, as.vector(sapply(as.vector(df_left[, 1]), function(x) unique_labs_ref[x])))
ends = c(ends, as.vector(sapply(as.vector(df_left[, 2]), function(x) unique_labs_ref[x])))
links = c(links, df_left[, 3])
## The righgt part
df_right = aggregate(as.formula(paste(left_col, '~', paste(cen_col, right_col, sep = '+'))), df, function(x) length(x))
starts = c(starts, as.vector(sapply(as.vector(df_right[, 1]), function(x) unique_labs_ref[x])))
ends = c(ends, as.vector(sapply(as.vector(df_right[, 2]), function(x) unique_labs_ref[x])))
links = c(links, df_right[, 3])
### Set the colors
color_left_ref = c('rgba(213, 185, 0, 1)', 'rgba(135, 0, 0, 1)', 'rgba(0, 0, 0, 1)', 'rgba(17, 0, 140, 1)', 'rgba(0, 88, 191, 1)')
names(color_left_ref) = unique(df[, left_col])
color_cen_ref = c('rgba(53, 68, 73, 1)', 'rgba(235, 189, 135, 1)', 'rgba(57, 49, 47, 1)')
names(color_cen_ref) = unique(df[, cen_col])
color_right_ref = c('rgba(220, 20, 60, 1)', 'rgba(34, 139, 34, 1)', 'rgba(65, 105, 225, 1)')
names(color_right_ref) = unique(df[, right_col])
color_left = as.vector(color_left_ref[df_left[, 1]])
color_right = as.vector(color_cen_ref[df_right[, 1]])
color_node = as.vector(c(color_left_ref, color_cen_ref, color_right_ref)[unique_labs])
alpha_set = 0.3
### Plotting
library(plotly)
p <- plot_ly(
type = "sankey",
domain = c(
x = c(0,1),
y = c(0,1)
),
orientation = "h",
valueformat = ".0f",
valuesuffix = " 位",
node = list(
label = unique_labs,
color = color_node,
pad = 15,
thickness = 15,
line = list(
color = color_node,
width = 0.1
)
),
link = list(
source = starts,
target = ends,
value = links,
color = c( gsub('1)', paste(alpha_set, ')', sep = ''), color_left), gsub('1)', paste(alpha_set, ')', sep = ''), color_right))
)
) %>%
layout(
title = "入院方式 → 急救責任分級 → 轉診型態",
autosize = F, width = 1200, height = 600,
font = list(
size = 12
),
xaxis = list(showgrid = F, zeroline = F, showticklabels = FALSE),
yaxis = list(showgrid = F, zeroline = F, showticklabels = FALSE)
)
### Output
htmlwidgets::saveWidget(as_widget(p), "Sankey_v1.html")
p
2. Sankey diagram: 入院方式 → 急救責任分級 → 轉院原因 → 轉診型態
### Use the same data as the previous plot
### Columns to use
left_col = '入院方式'
cen_col = 'EMOC_轉出醫院急救責任醫院等級'
cen_2_col = 'EMOC轉院原因大類別'
right_col = '轉診型態'
### Set the labels
unique_labs = do.call('c', sapply(c(left_col, cen_col, cen_2_col, right_col), function(x) unique(df[, x])))
unique_labs_ref = seq(1:length(unique_labs)) - 1
names(unique_labs_ref) = unique_labs
### Set the names of the starting point, ending point and the values of links
starts = c()
ends = c()
links = c()
### The left part
df_left = aggregate(as.formula(paste(right_col, '~', paste(left_col, cen_col, sep = '+'))), df, function(x) length(x))
starts = c(starts, as.vector(sapply(as.vector(df_left[, 1]), function(x) unique_labs_ref[x])))
ends = c(ends, as.vector(sapply(as.vector(df_left[, 2]), function(x) unique_labs_ref[x])))
links = c(links, df_left[, 3])
### The niddle part
df_cen = aggregate(as.formula(paste(left_col, '~', paste(cen_col, cen_2_col, sep = '+'))), df, function(x) length(x))
starts = c(starts, as.vector(sapply(as.vector(df_cen[, 1]), function(x) unique_labs_ref[x])))
ends = c(ends, as.vector(sapply(as.vector(df_cen[, 2]), function(x) unique_labs_ref[x])))
links = c(links, df_cen[, 3])
### The righgt part
df_right = aggregate(as.formula(paste(left_col, '~', paste(cen_2_col, right_col, sep = '+'))), df, function(x) length(x))
starts = c(starts, as.vector(sapply(as.vector(df_right[, 1]), function(x) unique_labs_ref[x])))
ends = c(ends, as.vector(sapply(as.vector(df_right[, 2]), function(x) unique_labs_ref[x])))
links = c(links, df_right[, 3])
### Set the colors
color_left_ref = c('rgba(213, 185, 0, 1)', 'rgba(135, 0, 0, 1)', 'rgba(0, 0, 0, 1)', 'rgba(17, 0, 140, 1)', 'rgba(0, 88, 191, 1)')
names(color_left_ref) = unique(df[, left_col])
color_cen_ref = c('rgba(53, 68, 73, 1)', 'rgba(235, 189, 135, 1)', 'rgba(57, 49, 47, 1)')
names(color_cen_ref) = unique(df[, cen_col])
color_cen_2_ref = c('rgba(35, 49, 73, 1)', 'rgba(78, 114, 39, 1)', 'rgba(57, 55, 51, 1)')
names(color_cen_2_ref) = unique(df[, cen_2_col])
color_right_ref = c('rgba(220, 20, 60, 1)', 'rgba(34, 139, 34, 1)', 'rgba(65, 105, 225, 1)')
names(color_right_ref) = unique(df[, right_col])
color_left = as.vector(color_left_ref[df_left[, 1]])
color_cen = as.vector(color_cen_ref[df_cen[, 1]])
color_right = as.vector(color_cen_2_ref[df_right[, 1]])
color_node = as.vector(c(color_left_ref, color_cen_ref, color_cen_2_ref, color_right_ref)[unique_labs])
alpha_set = 0.3
### Plotting
library(plotly)
p <- plot_ly(
type = "sankey",
domain = c(
x = c(0,1),
y = c(0,1)
),
orientation = "h",
valueformat = ".0f",
valuesuffix = " 人",
node = list(
label = unique_labs,
color = color_node,
pad = 15,
thickness = 15,
line = list(
color = color_node,
width = 0.1
)
),
link = list(
source = starts,
target = ends,
value = links,
color = c( gsub('1)', paste(alpha_set, ')', sep = ''), color_left),
gsub('1)', paste(alpha_set, ')', sep = ''), color_cen),
gsub('1)', paste(alpha_set, ')', sep = ''), color_right))
)
) %>%
layout(
title = "入院方式 → 急救責任分級 → 轉院原因 → 轉診型態",
autosize = F, width = 1200, height = 600,
font = list(
size = 12
),
xaxis = list(showgrid = F, zeroline = F, showticklabels = FALSE),
yaxis = list(showgrid = F, zeroline = F, showticklabels = FALSE)
)
### Output
htmlwidgets::saveWidget(as_widget(p), "Sankey_v2.html")
p
LS0tCnRpdGxlOiAi5oCl6Ki66L2J6Ki65rWB5YuV5YiG5p6QIFNhbmtleSBEaWFncmFtIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgo8YnI+Cjxicj4KCiMjIzEuIFNhbmtleSBkaWFncmFtOiDlhaXpmaLmlrnlvI8g4oaSIOaApeaVkeiyrOS7u+WIhue0miDihpIg6L2J6Ki65Z6L5oWLCgpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0V9CgojIyMg5L2/55So6LOH5paZOiBFTU9DX3Y3LmNzdgpkZiA9IHJlYWQuY3N2KCdFTU9DX3Y3LmNzdicsIG5hID0gYygnJywgJ05BJyksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgIyAyMTc4MSBleGFtcGxlcwoKIyMjIENvbHVtbnMgdG8gdXNlCmxlZnRfY29sID0gJ+WFpemZouaWueW8jycKY2VuX2NvbCA9ICdFTU9DX+i9ieWHuumGq+mZouaApeaVkeiyrOS7u+mGq+mZouetiee0micKcmlnaHRfY29sID0gJ+i9ieiouuWei+aFiycKCiMjIyBTZXQgdGhlIGxhYmVscwp1bmlxdWVfbGFicyA9IGRvLmNhbGwoJ2MnLCBzYXBwbHkoYyhsZWZ0X2NvbCwgY2VuX2NvbCwgcmlnaHRfY29sKSwgZnVuY3Rpb24oeCkgdW5pcXVlKGRmWywgeF0pKSkKdW5pcXVlX2xhYnNfcmVmID0gc2VxKDE6bGVuZ3RoKHVuaXF1ZV9sYWJzKSkgLSAxCm5hbWVzKHVuaXF1ZV9sYWJzX3JlZikgPSB1bmlxdWVfbGFicwoKIyMjIFNldCB0aGUgbmFtZXMgb2YgdGhlIHN0YXJ0aW5nIHBvaW50LHRoZSBlbmRpbmcgcG9pbnQgYW5kIHRoZSB2YWx1ZXMgb2YgbGlua3MKc3RhcnRzID0gYygpCmVuZHMgPSBjKCkKbGlua3MgPSBjKCkKCiMjIFRoZSBsZWZ0IHBhcnQKZGZfbGVmdCA9IGFnZ3JlZ2F0ZShhcy5mb3JtdWxhKHBhc3RlKHJpZ2h0X2NvbCwgJ34nLCBwYXN0ZShsZWZ0X2NvbCwgY2VuX2NvbCwgc2VwID0gJysnKSkpLCBkZiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHgpKQpzdGFydHMgPSBjKHN0YXJ0cywgYXMudmVjdG9yKHNhcHBseShhcy52ZWN0b3IoZGZfbGVmdFssIDFdKSwgZnVuY3Rpb24oeCkgdW5pcXVlX2xhYnNfcmVmW3hdKSkpCmVuZHMgPSBjKGVuZHMsIGFzLnZlY3RvcihzYXBwbHkoYXMudmVjdG9yKGRmX2xlZnRbLCAyXSksIGZ1bmN0aW9uKHgpIHVuaXF1ZV9sYWJzX3JlZlt4XSkpKQpsaW5rcyA9IGMobGlua3MsIGRmX2xlZnRbLCAzXSkKCiMjIFRoZSByaWdoZ3QgcGFydApkZl9yaWdodCA9IGFnZ3JlZ2F0ZShhcy5mb3JtdWxhKHBhc3RlKGxlZnRfY29sLCAnficsIHBhc3RlKGNlbl9jb2wsIHJpZ2h0X2NvbCwgc2VwID0gJysnKSkpLCBkZiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHgpKQpzdGFydHMgPSBjKHN0YXJ0cywgYXMudmVjdG9yKHNhcHBseShhcy52ZWN0b3IoZGZfcmlnaHRbLCAxXSksIGZ1bmN0aW9uKHgpIHVuaXF1ZV9sYWJzX3JlZlt4XSkpKQplbmRzID0gYyhlbmRzLCBhcy52ZWN0b3Ioc2FwcGx5KGFzLnZlY3RvcihkZl9yaWdodFssIDJdKSwgZnVuY3Rpb24oeCkgdW5pcXVlX2xhYnNfcmVmW3hdKSkpCmxpbmtzID0gYyhsaW5rcywgZGZfcmlnaHRbLCAzXSkKCiMjIyBTZXQgdGhlIGNvbG9ycwpjb2xvcl9sZWZ0X3JlZiA9IGMoJ3JnYmEoMjEzLCAxODUsIDAsIDEpJywgJ3JnYmEoMTM1LCAwLCAwLCAxKScsICdyZ2JhKDAsIDAsIDAsIDEpJywgJ3JnYmEoMTcsIDAsIDE0MCwgMSknLCAncmdiYSgwLCA4OCwgMTkxLCAxKScpCm5hbWVzKGNvbG9yX2xlZnRfcmVmKSA9IHVuaXF1ZShkZlssIGxlZnRfY29sXSkKY29sb3JfY2VuX3JlZiA9IGMoJ3JnYmEoNTMsIDY4LCA3MywgMSknLCAncmdiYSgyMzUsIDE4OSwgMTM1LCAxKScsICdyZ2JhKDU3LCA0OSwgNDcsIDEpJykKbmFtZXMoY29sb3JfY2VuX3JlZikgPSB1bmlxdWUoZGZbLCBjZW5fY29sXSkKY29sb3JfcmlnaHRfcmVmID0gYygncmdiYSgyMjAsIDIwLCA2MCwgMSknLCAncmdiYSgzNCwgMTM5LCAzNCwgMSknLCAncmdiYSg2NSwgMTA1LCAyMjUsIDEpJykKbmFtZXMoY29sb3JfcmlnaHRfcmVmKSA9IHVuaXF1ZShkZlssIHJpZ2h0X2NvbF0pCgpjb2xvcl9sZWZ0ID0gYXMudmVjdG9yKGNvbG9yX2xlZnRfcmVmW2RmX2xlZnRbLCAxXV0pCmNvbG9yX3JpZ2h0ID0gYXMudmVjdG9yKGNvbG9yX2Nlbl9yZWZbZGZfcmlnaHRbLCAxXV0pCmNvbG9yX25vZGUgPSBhcy52ZWN0b3IoYyhjb2xvcl9sZWZ0X3JlZiwgY29sb3JfY2VuX3JlZiwgY29sb3JfcmlnaHRfcmVmKVt1bmlxdWVfbGFic10pCgphbHBoYV9zZXQgPSAwLjMKCiMjIyBQbG90dGluZwpsaWJyYXJ5KHBsb3RseSkKCnAgPC0gcGxvdF9seSgKICB0eXBlID0gInNhbmtleSIsCiAgZG9tYWluID0gYygKICAgIHggPSAgYygwLDEpLAogICAgeSA9ICBjKDAsMSkKICApLAogIG9yaWVudGF0aW9uID0gImgiLAogIHZhbHVlZm9ybWF0ID0gIi4wZiIsCiAgdmFsdWVzdWZmaXggPSAiIOS6uiIsCiAgCiAgbm9kZSA9IGxpc3QoCiAgICBsYWJlbCA9IHVuaXF1ZV9sYWJzLAogICAgY29sb3IgPSBjb2xvcl9ub2RlLAogICAgcGFkID0gMTUsCiAgICB0aGlja25lc3MgPSAxNSwKICAgIGxpbmUgPSBsaXN0KAogICAgICBjb2xvciA9IGNvbG9yX25vZGUsCiAgICAgIHdpZHRoID0gMC4xCiAgICApCiAgKSwKICAKICBsaW5rID0gbGlzdCgKICAgIHNvdXJjZSA9IHN0YXJ0cywKICAgIHRhcmdldCA9IGVuZHMsCiAgICB2YWx1ZSA9ICBsaW5rcywKICAgIGNvbG9yID0gYyggZ3N1YignMSknLCBwYXN0ZShhbHBoYV9zZXQsICcpJywgc2VwID0gJycpLCBjb2xvcl9sZWZ0KSwgIGdzdWIoJzEpJywgcGFzdGUoYWxwaGFfc2V0LCAnKScsIHNlcCA9ICcnKSwgY29sb3JfcmlnaHQpKQogICkKKSAlPiUgCiAgbGF5b3V0KAogICAgdGl0bGUgPSAi5YWl6Zmi5pa55byPIOKGkiDmgKXmlZHosqzku7vliIbntJog4oaSIOi9ieiouuWei+aFiyIsCiAgICBhdXRvc2l6ZSA9IEYsIHdpZHRoID0gMTIwMCwgaGVpZ2h0ID0gNjAwLAogICAgZm9udCA9IGxpc3QoCiAgICAgIHNpemUgPSAxMgogICAgKSwKICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEYsIHplcm9saW5lID0gRiwgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSksCiAgICB5YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpCiAgKQoKIyMjIE91dHB1dApodG1sd2lkZ2V0czo6c2F2ZVdpZGdldChhc193aWRnZXQocCksICJTYW5rZXlfdjEuaHRtbCIpCnAKYGBgCjxicj4KPGJyPgo8YnI+Cjxicj4KPGJyPgo8YnI+Cjxicj4KCiMjIzIuIFNhbmtleSBkaWFncmFtOiDlhaXpmaLmlrnlvI8g4oaSIOaApeaVkeiyrOS7u+WIhue0miDihpIg6L2J6Zmi5Y6f5ZugIOKGkiDovYnoqLrlnovmhYsKCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1GQUxTRX0KCiMjIyBVc2UgdGhlIHNhbWUgZGF0YSBhcyB0aGUgcHJldmlvdXMgcGxvdAoKIyMjIENvbHVtbnMgdG8gdXNlCmxlZnRfY29sID0gJ+WFpemZouaWueW8jycKY2VuX2NvbCA9ICdFTU9DX+i9ieWHuumGq+mZouaApeaVkeiyrOS7u+mGq+mZouetiee0micKY2VuXzJfY29sID0gJ0VNT0PovYnpmaLljp/lm6DlpKfpoZ7liKUnCnJpZ2h0X2NvbCA9ICfovYnoqLrlnovmhYsnCgojIyMgU2V0IHRoZSBsYWJlbHMKdW5pcXVlX2xhYnMgPSBkby5jYWxsKCdjJywgc2FwcGx5KGMobGVmdF9jb2wsIGNlbl9jb2wsIGNlbl8yX2NvbCwgcmlnaHRfY29sKSwgZnVuY3Rpb24oeCkgdW5pcXVlKGRmWywgeF0pKSkKdW5pcXVlX2xhYnNfcmVmID0gc2VxKDE6bGVuZ3RoKHVuaXF1ZV9sYWJzKSkgLSAxCm5hbWVzKHVuaXF1ZV9sYWJzX3JlZikgPSB1bmlxdWVfbGFicwoKIyMjIFNldCB0aGUgbmFtZXMgb2YgdGhlIHN0YXJ0aW5nIHBvaW50LCBlbmRpbmcgcG9pbnQgYW5kIHRoZSB2YWx1ZXMgb2YgbGlua3MKc3RhcnRzID0gYygpCmVuZHMgPSBjKCkKbGlua3MgPSBjKCkKCiMjIyBUaGUgbGVmdCBwYXJ0CmRmX2xlZnQgPSBhZ2dyZWdhdGUoYXMuZm9ybXVsYShwYXN0ZShyaWdodF9jb2wsICd+JywgcGFzdGUobGVmdF9jb2wsIGNlbl9jb2wsIHNlcCA9ICcrJykpKSwgZGYsIGZ1bmN0aW9uKHgpIGxlbmd0aCh4KSkKc3RhcnRzID0gYyhzdGFydHMsIGFzLnZlY3RvcihzYXBwbHkoYXMudmVjdG9yKGRmX2xlZnRbLCAxXSksIGZ1bmN0aW9uKHgpIHVuaXF1ZV9sYWJzX3JlZlt4XSkpKQplbmRzID0gYyhlbmRzLCBhcy52ZWN0b3Ioc2FwcGx5KGFzLnZlY3RvcihkZl9sZWZ0WywgMl0pLCBmdW5jdGlvbih4KSB1bmlxdWVfbGFic19yZWZbeF0pKSkKbGlua3MgPSBjKGxpbmtzLCBkZl9sZWZ0WywgM10pCgojIyMgVGhlIG5pZGRsZSBwYXJ0CmRmX2NlbiA9IGFnZ3JlZ2F0ZShhcy5mb3JtdWxhKHBhc3RlKGxlZnRfY29sLCAnficsIHBhc3RlKGNlbl9jb2wsIGNlbl8yX2NvbCwgc2VwID0gJysnKSkpLCBkZiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHgpKQpzdGFydHMgPSBjKHN0YXJ0cywgYXMudmVjdG9yKHNhcHBseShhcy52ZWN0b3IoZGZfY2VuWywgMV0pLCBmdW5jdGlvbih4KSB1bmlxdWVfbGFic19yZWZbeF0pKSkKZW5kcyA9IGMoZW5kcywgYXMudmVjdG9yKHNhcHBseShhcy52ZWN0b3IoZGZfY2VuWywgMl0pLCBmdW5jdGlvbih4KSB1bmlxdWVfbGFic19yZWZbeF0pKSkKbGlua3MgPSBjKGxpbmtzLCBkZl9jZW5bLCAzXSkKCiMjIyBUaGUgcmlnaGd0IHBhcnQKZGZfcmlnaHQgPSBhZ2dyZWdhdGUoYXMuZm9ybXVsYShwYXN0ZShsZWZ0X2NvbCwgJ34nLCBwYXN0ZShjZW5fMl9jb2wsIHJpZ2h0X2NvbCwgc2VwID0gJysnKSkpLCBkZiwgZnVuY3Rpb24oeCkgbGVuZ3RoKHgpKQpzdGFydHMgPSBjKHN0YXJ0cywgYXMudmVjdG9yKHNhcHBseShhcy52ZWN0b3IoZGZfcmlnaHRbLCAxXSksIGZ1bmN0aW9uKHgpIHVuaXF1ZV9sYWJzX3JlZlt4XSkpKQplbmRzID0gYyhlbmRzLCBhcy52ZWN0b3Ioc2FwcGx5KGFzLnZlY3RvcihkZl9yaWdodFssIDJdKSwgZnVuY3Rpb24oeCkgdW5pcXVlX2xhYnNfcmVmW3hdKSkpCmxpbmtzID0gYyhsaW5rcywgZGZfcmlnaHRbLCAzXSkKCiMjIyBTZXQgdGhlIGNvbG9ycwpjb2xvcl9sZWZ0X3JlZiA9IGMoJ3JnYmEoMjEzLCAxODUsIDAsIDEpJywgJ3JnYmEoMTM1LCAwLCAwLCAxKScsICdyZ2JhKDAsIDAsIDAsIDEpJywgJ3JnYmEoMTcsIDAsIDE0MCwgMSknLCAncmdiYSgwLCA4OCwgMTkxLCAxKScpCm5hbWVzKGNvbG9yX2xlZnRfcmVmKSA9IHVuaXF1ZShkZlssIGxlZnRfY29sXSkKY29sb3JfY2VuX3JlZiA9IGMoJ3JnYmEoNTMsIDY4LCA3MywgMSknLCAncmdiYSgyMzUsIDE4OSwgMTM1LCAxKScsICdyZ2JhKDU3LCA0OSwgNDcsIDEpJykKbmFtZXMoY29sb3JfY2VuX3JlZikgPSB1bmlxdWUoZGZbLCBjZW5fY29sXSkKY29sb3JfY2VuXzJfcmVmID0gYygncmdiYSgzNSwgNDksIDczLCAxKScsICdyZ2JhKDc4LCAxMTQsIDM5LCAxKScsICdyZ2JhKDU3LCA1NSwgNTEsIDEpJykKbmFtZXMoY29sb3JfY2VuXzJfcmVmKSA9IHVuaXF1ZShkZlssIGNlbl8yX2NvbF0pCmNvbG9yX3JpZ2h0X3JlZiA9IGMoJ3JnYmEoMjIwLCAyMCwgNjAsIDEpJywgJ3JnYmEoMzQsIDEzOSwgMzQsIDEpJywgJ3JnYmEoNjUsIDEwNSwgMjI1LCAxKScpCm5hbWVzKGNvbG9yX3JpZ2h0X3JlZikgPSB1bmlxdWUoZGZbLCByaWdodF9jb2xdKQoKY29sb3JfbGVmdCA9IGFzLnZlY3Rvcihjb2xvcl9sZWZ0X3JlZltkZl9sZWZ0WywgMV1dKQpjb2xvcl9jZW4gPSBhcy52ZWN0b3IoY29sb3JfY2VuX3JlZltkZl9jZW5bLCAxXV0pCmNvbG9yX3JpZ2h0ID0gYXMudmVjdG9yKGNvbG9yX2Nlbl8yX3JlZltkZl9yaWdodFssIDFdXSkKY29sb3Jfbm9kZSA9IGFzLnZlY3RvcihjKGNvbG9yX2xlZnRfcmVmLCBjb2xvcl9jZW5fcmVmLCBjb2xvcl9jZW5fMl9yZWYsIGNvbG9yX3JpZ2h0X3JlZilbdW5pcXVlX2xhYnNdKQoKYWxwaGFfc2V0ID0gMC4zCgojIyMgUGxvdHRpbmcKbGlicmFyeShwbG90bHkpCgpwIDwtIHBsb3RfbHkoCiAgdHlwZSA9ICJzYW5rZXkiLAogIGRvbWFpbiA9IGMoCiAgICB4ID0gIGMoMCwxKSwKICAgIHkgPSAgYygwLDEpCiAgKSwKICBvcmllbnRhdGlvbiA9ICJoIiwKICB2YWx1ZWZvcm1hdCA9ICIuMGYiLAogIHZhbHVlc3VmZml4ID0gIiDkuroiLAogIAogIG5vZGUgPSBsaXN0KAogICAgbGFiZWwgPSB1bmlxdWVfbGFicywKICAgIGNvbG9yID0gY29sb3Jfbm9kZSwKICAgIHBhZCA9IDE1LAogICAgdGhpY2tuZXNzID0gMTUsCiAgICBsaW5lID0gbGlzdCgKICAgICAgY29sb3IgPSBjb2xvcl9ub2RlLAogICAgICB3aWR0aCA9IDAuMQogICAgKQogICksCiAgCiAgbGluayA9IGxpc3QoCiAgICBzb3VyY2UgPSBzdGFydHMsCiAgICB0YXJnZXQgPSBlbmRzLAogICAgdmFsdWUgPSAgbGlua3MsCiAgICBjb2xvciA9IGMoIGdzdWIoJzEpJywgcGFzdGUoYWxwaGFfc2V0LCAnKScsIHNlcCA9ICcnKSwgY29sb3JfbGVmdCksCiAgICAgICAgICAgICAgIGdzdWIoJzEpJywgcGFzdGUoYWxwaGFfc2V0LCAnKScsIHNlcCA9ICcnKSwgY29sb3JfY2VuKSwKICAgICAgICAgICAgICAgZ3N1YignMSknLCBwYXN0ZShhbHBoYV9zZXQsICcpJywgc2VwID0gJycpLCBjb2xvcl9yaWdodCkpCiAgKQopICU+JSAKICBsYXlvdXQoCiAgICB0aXRsZSA9ICLlhaXpmaLmlrnlvI8g4oaSIOaApeaVkeiyrOS7u+WIhue0miDihpIg6L2J6Zmi5Y6f5ZugIOKGkiDovYnoqLrlnovmhYsiLAogICAgYXV0b3NpemUgPSBGLCB3aWR0aCA9IDEyMDAsIGhlaWdodCA9IDYwMCwKICAgIGZvbnQgPSBsaXN0KAogICAgICBzaXplID0gMTIKICAgICksCiAgICB4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpLAogICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRiwgemVyb2xpbmUgPSBGLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKQogICkKCiMjIyBPdXRwdXQKaHRtbHdpZGdldHM6OnNhdmVXaWRnZXQoYXNfd2lkZ2V0KHApLCAiU2Fua2V5X3YyLmh0bWwiKQpwCmBgYAo8YnI+Cjxicj4K