Dowmload libraries

library(survival)
library(survminer)
library(rms)
library(shiny)
library(readxl)
library(DynNom)
# You need to create an account in Shinyapps- they host DynNom apps. https://www.shinyapps.io/admin/#/login?redirect=%2Fdashboard
# DynNom documentation https://cran.r-project.org/web/packages/DynNom/DynNom.pdf

Nomogram


data <- read.csv("user/documents/data.csv")

ddist <- datadist(data)
options(datadist = 'ddist')

model <-
  cph(
    Surv(time = time, event = event) ~ 
      x1 + 
      x2 + 
      x3,
    data = data,
    x = TRUE,
    y = TRUE,
    surv = TRUE,
    time.inc = 5 ## time frame to evaluate 
)

model$Design$label <-
  c(
    "Variable 1",
    "Variable 2",
    "Variable 3",
  )

surv.model <- Survival(model)

nomogram <-
  nomogram(
    model,
    fun = list(function(x)
      surv.model(2, x), #add as many time frames as needed
      funlabel = c(
      "2-year risk"),
      lp = F,
      fun.at = c(0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2)
      )
    
# to export as pdf 

pdf(
  "nomogram.pdf",
  width = cm(17),
  height = cm(10)
)

plot(
  nomogram,
  cex.axis = 4 ,
  cex.var = 4.5 ,
  col.grid = gray(c(0.8, 0.95)),
  theme(text = element_text(
    family = "Times New Roman",
    face = "bold",
    size = 20)
    )
  )

dev.off

Dynamic Nomogram


data <- read.csv("user/documents/data.csv")
ddist <- datadist(data)
options(datadist = 'ddist')

tool <- cph(
  Surv(time = time, event = event) ~ 
      x1 + 
      x2 + 
      x3,
  data = data
  )

DNbuilder( #this uses DynNom and will create 3 new files: ui.R, server.R, global.R. These will be the scripts needed to run the app. 
  tool, 
  data = data, 
  clevel = 0.95, 
  covariate = c("numeric"),
  ptype = c("1-st") # or st
  )

Example of DynNom scripts




GLOBAL.R

library(ggplot2)
library(shiny)
library(shinythemes)
library(plotly)
library(stargazer)
library(compare)
library(prediction)
library(rms)
library(shinythemes)

#######################################################
#### Before publishing your dynamic nomogram:
####
#### - You may need to edit the following lines if
#### data or model objects are not defined correctly
#### - You could modify ui.R or server.R for
#### making any required changes to your app
#######################################################

load('data.RData')  
source('functions.R') 
data=data
t.dist <- datadist(data)
options(datadist = 't.dist')
model <- coxph(Surv(Time, event) ~ x1 +x2 +x3 , data = data)

modellabels <- c("variable 1", "variable 2", "variable 3")
m.summary <- 'raw'
covariate <- 'numeric'
clevel <- 0.95


UI.R 


ui = bootstrapPage(fluidPage(
  theme=shinytheme("cyborg"),
  titlePanel(
    'gf'
  ),
  p("This is an example.", style=" padding:10px; color: lightgrey; height: 60px",
  br(),
  br(),
  "This is an example how to use it :", style="padding:20px; " ),
  actionButton('showEligibility', 'Eligibility', style="color: black; background-color: lightblue; border-color: white"),
  actionButton('showLimitations', 'Limitations', style="color: black; background-color: lightblue; border-color: white"),
  actionButton('showPerformance', 'Performance', style="color: black; background-color: lightblue; border-color: white"),
  actionButton('readArticle', 'Reference Manuscript', style="color: black; background-color: lightblue; border-color: white", onclick="window.open('https://drive.google.com/file/dk6UQT/view?usp=sharing', '_blank')"),
  p("Instructions on how to use this tool can be found here:", style=" padding:20px; color: lightgrey;"),
  actionButton('showHowtouse', "How to use",style="color: white; background-color:green; border-color: white"),
  br(),
  br(), 
  sidebarLayout(
    sidebarPanel( 
      uiOutput('manySliders.f'),
      uiOutput('manySliders.n'),
      checkboxInput('trans', 'Ready!', value = FALSE),
      actionButton('add', 'Predict', style="color: white; background-color: green;,  border-color: white"),
      style="color: black; background-color:    #298AAE ; border-color: black"),
    mainPanel(
      tabsetPanel(
        id = 'tabs',
        tabPanel('Predicted Survival', plotOutput('plot')),
        tabPanel('95% Confidence Interval', plotlyOutput('plot2')),
        tabPanel('Numerical Summary', verbatimTextOutput('data.pred')),
    sidebarPanel( 
      p("How to interpret the results?", style="color: lightgrey;"),
      actionButton('showInterpret', "Interpret",style="color: white; background-color:green; border-color: white")

      )
    )
  )
)))



Server.R

server = function(input, output) {
  observeEvent(input$showPerformance, {
    showModal(modalDialog(
      title = "Performance",
      p(
        "This is an example."
      ),
      easyClose = TRUE
    ))
  })
  
  observeEvent(input$showHowtouse, {
    showModal( 
      modalDialog( 
        title = "How to use", style="color: white; background-color: black; border-color: black",
        p(
          "This is a step-by-step guide on how to use this interactive clinical tool.",
          tags$br(),
          tags$br(),
          "Once",tags$strong("all"), "the boxes are filled-in, check the", tags$strong("'Ready!'"), "box and click",
          tags$strong("'Predict.'")),
    easyClose = TRUE
    ))
    
  })
  

  

  
  neededVar <- n.mterms[-1]
  if (length(mtermslab) == 1) {
    input.data <<- data.frame(data[1, neededVar])
    names(input.data)[1] <<- n.mterms[-1]
  } else {
    input.data <<- data[1, neededVar]
  }
  
  input.data[1, ] <<- NA
  b <- 1
  i.factor <- NULL
  i.numeric <- NULL
  for (j in 2:length(mterms)) {
    for (i in 1:length(data)) {
      if (n.mterms[j] == names(data)[i]) {
        if (mterms[[j]] == 'factor' |
            mterms[[j]] == 'ordered' |
            mterms[[j]] == 'logical') {
          i.factor <- rbind(i.factor, c(n.mterms[j], j, i, b))
          (break)()
        }
        if (mterms[[j]] == 'numeric') {
          i.numeric <- rbind(i.numeric, c(n.mterms[j], j, i))
          b <- b 
          (break)()
        }

#etc etc
LS0tCnRpdGxlOiAiTm9tb2dyYW0gYW5kIG9ubGluZSB0b29sIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgoKIyMjRG93bWxvYWQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShzdXJ2aXZhbCkKbGlicmFyeShzdXJ2bWluZXIpCmxpYnJhcnkocm1zKQpsaWJyYXJ5KHNoaW55KQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShEeW5Ob20pCiMgWW91IG5lZWQgdG8gY3JlYXRlIGFuIGFjY291bnQgaW4gU2hpbnlhcHBzLSB0aGV5IGhvc3QgRHluTm9tIGFwcHMuIGh0dHBzOi8vd3d3LnNoaW55YXBwcy5pby9hZG1pbi8jL2xvZ2luP3JlZGlyZWN0PSUyRmRhc2hib2FyZAojIER5bk5vbSBkb2N1bWVudGF0aW9uIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9EeW5Ob20vRHluTm9tLnBkZgpgYGAKCiMjTm9tb2dyYW0KYGBge3IsIHdhcm5pbmc9IEZBTFNFfSAKCmRhdGEgPC0gcmVhZC5jc3YoInVzZXIvZG9jdW1lbnRzL2RhdGEuY3N2IikKCmRkaXN0IDwtIGRhdGFkaXN0KGRhdGEpCm9wdGlvbnMoZGF0YWRpc3QgPSAnZGRpc3QnKQoKbW9kZWwgPC0KICBjcGgoCiAgICBTdXJ2KHRpbWUgPSB0aW1lLCBldmVudCA9IGV2ZW50KSB+IAogICAgICB4MSArIAogICAgICB4MiArIAogICAgICB4MywKICAgIGRhdGEgPSBkYXRhLAogICAgeCA9IFRSVUUsCiAgICB5ID0gVFJVRSwKICAgIHN1cnYgPSBUUlVFLAogICAgdGltZS5pbmMgPSA1ICMjIHRpbWUgZnJhbWUgdG8gZXZhbHVhdGUgCikKCm1vZGVsJERlc2lnbiRsYWJlbCA8LQogIGMoCiAgICAiVmFyaWFibGUgMSIsCiAgICAiVmFyaWFibGUgMiIsCiAgICAiVmFyaWFibGUgMyIsCiAgKQoKc3Vydi5tb2RlbCA8LSBTdXJ2aXZhbChtb2RlbCkKCm5vbW9ncmFtIDwtCiAgbm9tb2dyYW0oCiAgICBtb2RlbCwKICAgIGZ1biA9IGxpc3QoZnVuY3Rpb24oeCkKICAgICAgc3Vydi5tb2RlbCgyLCB4KSwgI2FkZCBhcyBtYW55IHRpbWUgZnJhbWVzIGFzIG5lZWRlZAogICAgICBmdW5sYWJlbCA9IGMoCiAgICAgICIyLXllYXIgcmlzayIpLAogICAgICBscCA9IEYsCiAgICAgIGZ1bi5hdCA9IGMoMC45LCAwLjgsIDAuNywgMC42LCAwLjUsIDAuNCwgMC4zLCAwLjIpCiAgICAgICkKICAgIAojIHRvIGV4cG9ydCBhcyBwZGYgCgpwZGYoCiAgIm5vbW9ncmFtLnBkZiIsCiAgd2lkdGggPSBjbSgxNyksCiAgaGVpZ2h0ID0gY20oMTApCikKCnBsb3QoCiAgbm9tb2dyYW0sCiAgY2V4LmF4aXMgPSA0ICwKICBjZXgudmFyID0gNC41ICwKICBjb2wuZ3JpZCA9IGdyYXkoYygwLjgsIDAuOTUpKSwKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KAogICAgZmFtaWx5ID0gIlRpbWVzIE5ldyBSb21hbiIsCiAgICBmYWNlID0gImJvbGQiLAogICAgc2l6ZSA9IDIwKQogICAgKQogICkKCmRldi5vZmYKCgpgYGAKIyMgRHluYW1pYyBOb21vZ3JhbSAKCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CgpkYXRhIDwtIHJlYWQuY3N2KCJ1c2VyL2RvY3VtZW50cy9kYXRhLmNzdiIpCmRkaXN0IDwtIGRhdGFkaXN0KGRhdGEpCm9wdGlvbnMoZGF0YWRpc3QgPSAnZGRpc3QnKQoKdG9vbCA8LSBjcGgoCiAgU3Vydih0aW1lID0gdGltZSwgZXZlbnQgPSBldmVudCkgfiAKICAgICAgeDEgKyAKICAgICAgeDIgKyAKICAgICAgeDMsCiAgZGF0YSA9IGRhdGEKICApCgpETmJ1aWxkZXIoICN0aGlzIHVzZXMgRHluTm9tIGFuZCB3aWxsIGNyZWF0ZSAzIG5ldyBmaWxlczogdWkuUiwgc2VydmVyLlIsIGdsb2JhbC5SLiBUaGVzZSB3aWxsIGJlIHRoZSBzY3JpcHRzIG5lZWRlZCB0byBydW4gdGhlIGFwcC4gCiAgdG9vbCwgCiAgZGF0YSA9IGRhdGEsIAogIGNsZXZlbCA9IDAuOTUsIAogIGNvdmFyaWF0ZSA9IGMoIm51bWVyaWMiKSwKICBwdHlwZSA9IGMoIjEtc3QiKSAjIG9yIHN0CiAgKQpgYGAKIyNFeGFtcGxlIG9mIER5bk5vbSBzY3JpcHRzCmBgYHtyfQoKCgpHTE9CQUwuUgoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNoaW55KQpsaWJyYXJ5KHNoaW55dGhlbWVzKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShzdGFyZ2F6ZXIpCmxpYnJhcnkoY29tcGFyZSkKbGlicmFyeShwcmVkaWN0aW9uKQpsaWJyYXJ5KHJtcykKbGlicmFyeShzaGlueXRoZW1lcykKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyBCZWZvcmUgcHVibGlzaGluZyB5b3VyIGR5bmFtaWMgbm9tb2dyYW06CiMjIyMKIyMjIyAtIFlvdSBtYXkgbmVlZCB0byBlZGl0IHRoZSBmb2xsb3dpbmcgbGluZXMgaWYKIyMjIyBkYXRhIG9yIG1vZGVsIG9iamVjdHMgYXJlIG5vdCBkZWZpbmVkIGNvcnJlY3RseQojIyMjIC0gWW91IGNvdWxkIG1vZGlmeSB1aS5SIG9yIHNlcnZlci5SIGZvcgojIyMjIG1ha2luZyBhbnkgcmVxdWlyZWQgY2hhbmdlcyB0byB5b3VyIGFwcAojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpsb2FkKCdkYXRhLlJEYXRhJykgIApzb3VyY2UoJ2Z1bmN0aW9ucy5SJykgCmRhdGE9ZGF0YQp0LmRpc3QgPC0gZGF0YWRpc3QoZGF0YSkKb3B0aW9ucyhkYXRhZGlzdCA9ICd0LmRpc3QnKQptb2RlbCA8LSBjb3hwaChTdXJ2KFRpbWUsIGV2ZW50KSB+IHgxICt4MiAreDMgLCBkYXRhID0gZGF0YSkKCm1vZGVsbGFiZWxzIDwtIGMoInZhcmlhYmxlIDEiLCAidmFyaWFibGUgMiIsICJ2YXJpYWJsZSAzIikKbS5zdW1tYXJ5IDwtICdyYXcnCmNvdmFyaWF0ZSA8LSAnbnVtZXJpYycKY2xldmVsIDwtIDAuOTUKCgpVSS5SIAoKCnVpID0gYm9vdHN0cmFwUGFnZShmbHVpZFBhZ2UoCiAgdGhlbWU9c2hpbnl0aGVtZSgiY3lib3JnIiksCiAgdGl0bGVQYW5lbCgKICAgICdnZicKICApLAogIHAoIlRoaXMgaXMgYW4gZXhhbXBsZS4iLCBzdHlsZT0iIHBhZGRpbmc6MTBweDsgY29sb3I6IGxpZ2h0Z3JleTsgaGVpZ2h0OiA2MHB4IiwKICBicigpLAogIGJyKCksCiAgIlRoaXMgaXMgYW4gZXhhbXBsZSBob3cgdG8gdXNlIGl0IDoiLCBzdHlsZT0icGFkZGluZzoyMHB4OyAiICksCiAgYWN0aW9uQnV0dG9uKCdzaG93RWxpZ2liaWxpdHknLCAnRWxpZ2liaWxpdHknLCBzdHlsZT0iY29sb3I6IGJsYWNrOyBiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGJsdWU7IGJvcmRlci1jb2xvcjogd2hpdGUiKSwKICBhY3Rpb25CdXR0b24oJ3Nob3dMaW1pdGF0aW9ucycsICdMaW1pdGF0aW9ucycsIHN0eWxlPSJjb2xvcjogYmxhY2s7IGJhY2tncm91bmQtY29sb3I6IGxpZ2h0Ymx1ZTsgYm9yZGVyLWNvbG9yOiB3aGl0ZSIpLAogIGFjdGlvbkJ1dHRvbignc2hvd1BlcmZvcm1hbmNlJywgJ1BlcmZvcm1hbmNlJywgc3R5bGU9ImNvbG9yOiBibGFjazsgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRibHVlOyBib3JkZXItY29sb3I6IHdoaXRlIiksCiAgYWN0aW9uQnV0dG9uKCdyZWFkQXJ0aWNsZScsICdSZWZlcmVuY2UgTWFudXNjcmlwdCcsIHN0eWxlPSJjb2xvcjogYmxhY2s7IGJhY2tncm91bmQtY29sb3I6IGxpZ2h0Ymx1ZTsgYm9yZGVyLWNvbG9yOiB3aGl0ZSIsIG9uY2xpY2s9IndpbmRvdy5vcGVuKCdodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZmlsZS9kazZVUVQvdmlldz91c3A9c2hhcmluZycsICdfYmxhbmsnKSIpLAogIHAoIkluc3RydWN0aW9ucyBvbiBob3cgdG8gdXNlIHRoaXMgdG9vbCBjYW4gYmUgZm91bmQgaGVyZToiLCBzdHlsZT0iIHBhZGRpbmc6MjBweDsgY29sb3I6IGxpZ2h0Z3JleTsiKSwKICBhY3Rpb25CdXR0b24oJ3Nob3dIb3d0b3VzZScsICJIb3cgdG8gdXNlIixzdHlsZT0iY29sb3I6IHdoaXRlOyBiYWNrZ3JvdW5kLWNvbG9yOmdyZWVuOyBib3JkZXItY29sb3I6IHdoaXRlIiksCiAgYnIoKSwKICBicigpLCAKICBzaWRlYmFyTGF5b3V0KAogICAgc2lkZWJhclBhbmVsKCAKICAgICAgdWlPdXRwdXQoJ21hbnlTbGlkZXJzLmYnKSwKICAgICAgdWlPdXRwdXQoJ21hbnlTbGlkZXJzLm4nKSwKICAgICAgY2hlY2tib3hJbnB1dCgndHJhbnMnLCAnUmVhZHkhJywgdmFsdWUgPSBGQUxTRSksCiAgICAgIGFjdGlvbkJ1dHRvbignYWRkJywgJ1ByZWRpY3QnLCBzdHlsZT0iY29sb3I6IHdoaXRlOyBiYWNrZ3JvdW5kLWNvbG9yOiBncmVlbjssICBib3JkZXItY29sb3I6IHdoaXRlIiksCiAgICAgIHN0eWxlPSJjb2xvcjogYmxhY2s7IGJhY2tncm91bmQtY29sb3I6IAkjMjk4QUFFIDsgYm9yZGVyLWNvbG9yOiBibGFjayIpLAogICAgbWFpblBhbmVsKAogICAgICB0YWJzZXRQYW5lbCgKICAgICAgICBpZCA9ICd0YWJzJywKICAgICAgICB0YWJQYW5lbCgnUHJlZGljdGVkIFN1cnZpdmFsJywgcGxvdE91dHB1dCgncGxvdCcpKSwKICAgICAgICB0YWJQYW5lbCgnOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwnLCBwbG90bHlPdXRwdXQoJ3Bsb3QyJykpLAogICAgICAgIHRhYlBhbmVsKCdOdW1lcmljYWwgU3VtbWFyeScsIHZlcmJhdGltVGV4dE91dHB1dCgnZGF0YS5wcmVkJykpLAogICAgc2lkZWJhclBhbmVsKCAKICAgICAgcCgiSG93IHRvIGludGVycHJldCB0aGUgcmVzdWx0cz8iLCBzdHlsZT0iY29sb3I6IGxpZ2h0Z3JleTsiKSwKICAgICAgYWN0aW9uQnV0dG9uKCdzaG93SW50ZXJwcmV0JywgIkludGVycHJldCIsc3R5bGU9ImNvbG9yOiB3aGl0ZTsgYmFja2dyb3VuZC1jb2xvcjpncmVlbjsgYm9yZGVyLWNvbG9yOiB3aGl0ZSIpCgogICAgICApCiAgICApCiAgKQopKSkKCgoKU2VydmVyLlIKCnNlcnZlciA9IGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQpIHsKICBvYnNlcnZlRXZlbnQoaW5wdXQkc2hvd1BlcmZvcm1hbmNlLCB7CiAgICBzaG93TW9kYWwobW9kYWxEaWFsb2coCiAgICAgIHRpdGxlID0gIlBlcmZvcm1hbmNlIiwKICAgICAgcCgKICAgICAgICAiVGhpcyBpcyBhbiBleGFtcGxlLiIKICAgICAgKSwKICAgICAgZWFzeUNsb3NlID0gVFJVRQogICAgKSkKICB9KQogIAogIG9ic2VydmVFdmVudChpbnB1dCRzaG93SG93dG91c2UsIHsKICAgIHNob3dNb2RhbCggCiAgICAgIG1vZGFsRGlhbG9nKCAKICAgICAgICB0aXRsZSA9ICJIb3cgdG8gdXNlIiwgc3R5bGU9ImNvbG9yOiB3aGl0ZTsgYmFja2dyb3VuZC1jb2xvcjogYmxhY2s7IGJvcmRlci1jb2xvcjogYmxhY2siLAogICAgICAgIHAoCiAgICAgICAgICAiVGhpcyBpcyBhIHN0ZXAtYnktc3RlcCBndWlkZSBvbiBob3cgdG8gdXNlIHRoaXMgaW50ZXJhY3RpdmUgY2xpbmljYWwgdG9vbC4iLAogICAgICAgICAgdGFncyRicigpLAogICAgICAgICAgdGFncyRicigpLAogICAgICAgICAgIk9uY2UiLHRhZ3Mkc3Ryb25nKCJhbGwiKSwgInRoZSBib3hlcyBhcmUgZmlsbGVkLWluLCBjaGVjayB0aGUiLCB0YWdzJHN0cm9uZygiJ1JlYWR5ISciKSwgImJveCBhbmQgY2xpY2siLAogICAgICAgICAgdGFncyRzdHJvbmcoIidQcmVkaWN0LiciKSksCiAgICBlYXN5Q2xvc2UgPSBUUlVFCiAgICApKQogICAgCiAgfSkKICAKCiAgCgogIAogIG5lZWRlZFZhciA8LSBuLm10ZXJtc1stMV0KICBpZiAobGVuZ3RoKG10ZXJtc2xhYikgPT0gMSkgewogICAgaW5wdXQuZGF0YSA8PC0gZGF0YS5mcmFtZShkYXRhWzEsIG5lZWRlZFZhcl0pCiAgICBuYW1lcyhpbnB1dC5kYXRhKVsxXSA8PC0gbi5tdGVybXNbLTFdCiAgfSBlbHNlIHsKICAgIGlucHV0LmRhdGEgPDwtIGRhdGFbMSwgbmVlZGVkVmFyXQogIH0KICAKICBpbnB1dC5kYXRhWzEsIF0gPDwtIE5BCiAgYiA8LSAxCiAgaS5mYWN0b3IgPC0gTlVMTAogIGkubnVtZXJpYyA8LSBOVUxMCiAgZm9yIChqIGluIDI6bGVuZ3RoKG10ZXJtcykpIHsKICAgIGZvciAoaSBpbiAxOmxlbmd0aChkYXRhKSkgewogICAgICBpZiAobi5tdGVybXNbal0gPT0gbmFtZXMoZGF0YSlbaV0pIHsKICAgICAgICBpZiAobXRlcm1zW1tqXV0gPT0gJ2ZhY3RvcicgfAogICAgICAgICAgICBtdGVybXNbW2pdXSA9PSAnb3JkZXJlZCcgfAogICAgICAgICAgICBtdGVybXNbW2pdXSA9PSAnbG9naWNhbCcpIHsKICAgICAgICAgIGkuZmFjdG9yIDwtIHJiaW5kKGkuZmFjdG9yLCBjKG4ubXRlcm1zW2pdLCBqLCBpLCBiKSkKICAgICAgICAgIChicmVhaykoKQogICAgICAgIH0KICAgICAgICBpZiAobXRlcm1zW1tqXV0gPT0gJ251bWVyaWMnKSB7CiAgICAgICAgICBpLm51bWVyaWMgPC0gcmJpbmQoaS5udW1lcmljLCBjKG4ubXRlcm1zW2pdLCBqLCBpKSkKICAgICAgICAgIGIgPC0gYiAKICAgICAgICAgIChicmVhaykoKQogICAgICAgIH0KCiNldGMgZXRjCmBgYAo=