diff --git a/docker/environment.yml b/docker/environment.yml index 92f6303..0e8b702 100755 --- a/docker/environment.yml +++ b/docker/environment.yml @@ -80,6 +80,7 @@ dependencies: - pytz==2023.3 - requests==2.31.0 - requests-oauthlib==1.3.1 + - rectanglepy==1.0.0 - rich==13.3.5 - rsa==4.9 - git+https://github.com/omnideconv/scaden.git diff --git a/docker_rectangle/Dockerfile b/docker_rectangle/Dockerfile new file mode 100755 index 0000000..7e33643 --- /dev/null +++ b/docker_rectangle/Dockerfile @@ -0,0 +1,84 @@ +FROM eddelbuettel/r2u:20.04 + +LABEL description="Image for Omnideconv benchmarking pipeline" +LABEL maintainer="Alexander Dietrich" + +# needed so that R r-base installation does not get stuck +ENV DEBIAN_FRONTEND noninteractive + +# install system dependencies +RUN apt-get update -y && apt-get --no-install-recommends --fix-broken install -y git \ + wget \ + vim \ + software-properties-common \ + dirmngr \ + gdebi \ + curl + +# install miniconda into /root/miniconda3 +RUN wget \ + https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && bash Miniconda3-latest-Linux-x86_64.sh -b -p /root/.local/share/r-miniconda \ + && rm Miniconda3-latest-Linux-x86_64.sh + +ENV PATH="/root/.local/share/r-miniconda/bin:${PATH}" +ARG PATH="/root/.local/share/r-miniconda/bin:${PATH}" + +RUN conda --version + +RUN conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main +RUN conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r + +# create r-omnideconv environment based on yml file +COPY environment.yml . +RUN conda env create -f environment.yml +RUN echo "source activate r-omnideconv" > ~/.bashrc + + +ENV PATH="/root/.local/share/r-miniconda/envs/omnideconv/bin:${PATH}" +ARG PATH="/root/.local/share/r-miniconda/envs/omnideconv/bin:${PATH}" + +# install omnideconv with all dependencies +RUN apt-get --no-install-recommends --fix-broken install -y libcurl4-openssl-dev \ + libxml2-dev \ + libfontconfig1-dev \ + libssl-dev \ + libharfbuzz-dev \ + libfribidi-dev \ + libfreetype6-dev \ + libpng-dev \ + libtiff5-dev \ + libjpeg-dev \ + libgdal-dev \ + cmake + + +RUN R -e "install.packages(c('pak','pkgdepends','devtools','remotes','harmony','terra','igraph', 'RSQLite'), repos='https://cloud.r-project.org')" +# Note: Set GITHUB_PAT as a build argument if needed: docker build --build-arg GITHUB_PAT=your_token +RUN R -e "remotes::install_github('omnideconv/omnideconv@benchmark', dependencies = TRUE)" +#RUN R -e "pak::pkg_install('omnideconv/SCDC')" +#RUN R -e "pak::pkg_install('omnideconv/SCDC')" +#RUN R -e "remotes::install_version('NMF', '0.27', repos='https://cloud.r-project.org')" + + +# set systems variable RETICULATE_PYTHON to new conda env, so that omnideconv will use it +RUN echo "RETICULATE_PYTHON = '/root/.local/share/r-miniconda/envs/r-omnideconv/bin/python'" > /root/.Rprofile +RUN R -e "reticulate::use_miniconda(condaenv = 'r-omnideconv', required = TRUE)" + +# install benchmarking related dependencies +RUN R -e "install.packages(c('conflicted','docopt','readxl','tidyverse','profvis'), repos='https://cloud.r-project.org')" +RUN R -e "BiocManager::install('SimBu')" + +# install Docker, so that CibersortX can run +RUN mkdir -p /etc/apt/keyrings +RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg +RUN echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null +RUN apt-get update -y +RUN apt-get install -y --no-install-recommends \ + docker-ce \ + docker-ce-cli \ + containerd.io + + diff --git a/docker_rectangle/environment.yml b/docker_rectangle/environment.yml new file mode 100644 index 0000000..1b2af6e --- /dev/null +++ b/docker_rectangle/environment.yml @@ -0,0 +1,6 @@ +name: r-omnideconv +dependencies: + - python=3.11 + - pip + - pip: + - rectanglepy==1.0.0 diff --git a/pipeline/bin/computeSignaturesNF.R b/pipeline/bin/computeSignaturesNF.R index f1fc0b2..68861fc 100755 --- a/pipeline/bin/computeSignaturesNF.R +++ b/pipeline/bin/computeSignaturesNF.R @@ -76,7 +76,6 @@ bulk_matrix <- as.matrix(bulk_matrix) - #################################### #### Perform signature building #### #################################### diff --git a/pipeline/bin/runDeconvolutionNF.R b/pipeline/bin/runDeconvolutionNF.R index 6ff22c7..bd95cb6 100755 --- a/pipeline/bin/runDeconvolutionNF.R +++ b/pipeline/bin/runDeconvolutionNF.R @@ -106,6 +106,17 @@ if(method=='cibersortx'){ #### Perform devonvolution #### ############################### +if(method == 'rectangle'){ + # do not incluce anndata creation in runtime measurement + AnnData <- reticulate::import("anndata") + counts <- as.data.frame(t(sc_matrix)) + + ad <- AnnData$AnnData(X = counts, + obs = data.frame('cell_type' = sc_celltype_annotations, row.names = colnames(sc_matrix)), + var = data.frame('genes' = rownames(sc_matrix), row.names = rownames(sc_matrix))) + sc_matrix <- ad +} + runtime <- system.time({ deconvolution <- deconvolution_workflow_general( diff --git a/pipeline/bin/utils.R b/pipeline/bin/utils.R index c7daac9..9611a20 100755 --- a/pipeline/bin/utils.R +++ b/pipeline/bin/utils.R @@ -215,6 +215,7 @@ signature_workflow_general <- function(sc_matrix, annotations, annotation_catego # path to temporary directory that is inside results directory of one unique result tmp_dir_path <- paste0(res_path, '/tmp/') + ncores <- as.numeric(ncores) # Signature building part # Dependent on which method we have @@ -282,8 +283,7 @@ signature_workflow_general <- function(sc_matrix, annotations, annotation_catego model_path = paste0(res_path, '/model'), verbose = TRUE ) - - }else if (method %in% c('autogenes', 'bayesprism', 'bisque', 'music')){ + } else if (method %in% c('autogenes', 'bayesprism', 'bisque', 'music', 'rectangle')){ signature <- NULL } else { @@ -312,6 +312,7 @@ deconvolution_workflow_general <- function(sc_matrix, annotations, annotation_ca # path to temporary directory that is inside results directory of one unique result tmp_dir_path <- paste0(res_path, '/tmp/') + ncores <- as.numeric(ncores) if(method=="autogenes"){ @@ -463,6 +464,16 @@ deconvolution_workflow_general <- function(sc_matrix, annotations, annotation_ca ) #unlink(tmp_dir_path, recursive=TRUE) + } else if (method == "rectangle") { + + rp <- reticulate::import("rectanglepy") + + #ad <- anndata::AnnData(X = t(sc_matrix), + # obs = data.frame('cell_type' = annotations, row.names = colnames(sc_matrix)), + # var = data.frame('genes' = rownames(sc_matrix), row.names = rownames(sc_matrix))) + + deconvolution <- rp$rectangle(sc_matrix, bulks = as.data.frame(t(bulk_matrix)), n_cpus=ncores)[[1]] + } else { message('Selected method is not supported in the benchmark. Please check again.') stop() diff --git a/pipeline/cibersortx_credentials.csv b/pipeline/cibersortx_credentials.csv index 2f64c43..6bce71a 100755 --- a/pipeline/cibersortx_credentials.csv +++ b/pipeline/cibersortx_credentials.csv @@ -1,2 +1,2 @@ email, token -alex.dietrich@tum.de, e1750b96fcfef36421bf9927a9f0fc49 +alex.dietrich@tum.de, 8ad207154371cd524393fd78e1bb16f0 diff --git a/pipeline/main.nf b/pipeline/main.nf index 136946f..e23ce9d 100755 --- a/pipeline/main.nf +++ b/pipeline/main.nf @@ -118,6 +118,8 @@ process ANALYSIS_SPILLOVER { } process SIMULATE_BULK_UNKNOWN_CELL_TYPE { + + label 'process_default' publishDir "${params.preProcess_dir}/pseudo_bulk_unknown_content", mode: 'copy' @@ -145,6 +147,8 @@ process SIMULATE_BULK_UNKNOWN_CELL_TYPE { process ANALYSIS_BULK_UNKNOWN_CELL_TYPE { + label 'process_default' + input: tuple val(sc_dataset), val(sim_bulk_name), diff --git a/pipeline/nextflow_alex.config b/pipeline/nextflow_alex.config deleted file mode 100755 index 25d43ff..0000000 --- a/pipeline/nextflow_alex.config +++ /dev/null @@ -1,116 +0,0 @@ -params { - - /*** input directories ***/ - - data_dir_bulk = "/vol/omnideconv_input/omnideconv_data/PBMC" // absolute path to directory that contains RNA-seq datasets - data_dir_sc = "/vol/omnideconv_input/omnideconv_data/singleCell" // absolute path to directory that contains scRNA-seq datasets - - - /*** output directories ***/ - results_dir_general = "/vol/omnideconv_results/results_tmp" // absolute path to directory in which final results of the main and subsampling workflow are stored - preProcess_dir = "/vol/omnideconv_input/preprocess" // absolute path to directory in which temporary files are stored - - - /*** Benchmarking Parameters [general] ***/ - single_cell_list = ["hao-sampled-3"] // list of scRNA-seq dataset names that will be used for deconvolution. - bulk_list = ["hoek-simulation-nobias"] // list of RNA-seq dataset names that will be used for deconvolution. - method_list = ["scaden"] // list of method names that are used for deconvolution. Possible values are: ["autogenes","bayesprism","bisque","cibersortx" ,"dwls","music","scaden","scdc"] - - - /*** general parameters ***/ - ncores = '4' // Number of cores that are available for methods - species_sc = 'hs' // Type of species in scRNA-seq dataset (mm or hs). Currently only supported by BayesPrism. - - - /****** Workflow-specific parameters ******/ - - - /*** subsampling ***/ - - ct_fractions = [5, 50] // cell-type fractions for subsampling - replicates = 5 // number of replicates for subsampling - - - /*** simulation_impact_technology ***/ - results_dir_impact_technology = "/path/to/impact_technology/results/" // results directory for this workflow - replicates_simulation = [5] // number of simulation replicates for this workflow - datasets_impact_technology = ["lambrechts", "maynard"] // names of sc datasets that are used for this workflow - - - /*** simulation_spillover ***/ - results_dir_spillover = "/path/to/simulation_spillover/results/" // results directory for this workflow - spillover_samples_per_cell = 10 // number of simulation replicates for this workflow - spillover_celltypes = ["B cells,Monocytes,NK cells,T cells CD8,T cells CD4 conv"] // names of cell types for which spillover analysis will be done; have to be present in single-cell dataset - - - /*** simulation_unkown_content ***/ - results_dir_unkown_content = "/path/to/simulation_unkown_content/results/" // results directory for this workflow - known_cell_types = ["B cells,Stromal cells,T cells CD4 conv,Macrophages"] // subset of cell types that we will use to build the signature matrix - unkown_cell_types = ["Tumor cells"] // unknown cell type to use - fractions_unkown_cells = [0, 0.2, 0.3, 0.9] // How large the fraction of the unkown cell type is - replicates_unknown_content = [5] // number of technical replicates for pseudo-bulk simulation - - - /*** simulation_resolution_analysis ***/ - results_dir_resolution = "/path/to/simulation_resolution_analysis/results/" // results directory for this workflow - cell_types_finer_res = ["Endothelial ACKR1,Endothelial RGS5,Endothelial CXCL12, ..."] //which cell types will we inspect at various resolutions? // number of simulation replicates for this workflow - - - /*** impact_missing_cell_types ***/ - results_dir_missing_cell_types = "/path/to/impact_missing_cell_types/results/" // results directory for this workflow - cell_types_to_exclude = ["B cells","mDC","Monocytes","NK cells","T cells CD4 conv"] // each of the cell types that will be excluded from the single cell dataset before deconvoltion // in the spillover analysis samples contain only one cell types. How many samples we should generate this way - - -} - - -profiles { - standard { - process.executor = 'local' - process.cpus = 4 - process.memory = '50 GB' - docker.enabled = false - } - docker { - process.executor = 'local' - process.cpus = 4 - process.memory = '10 GB' - docker.enabled = true - process.container = 'alexd13/omnideconv_benchmark:latest' - docker.temp = "auto" - } - apptainer { - process.executor = 'local' - process.cpus = 4 - process.memory = '10 GB' - apptainer.enabled = true - process.container = '/nfs/proj/omnideconv_benchmarking/deconvBench/omnideconv_benchmark.sif' - } - slurm_no_docker { - process.executor = 'slurm' - process.cpus = 4 - process.memory = '50 GB' - docker.enabled = false - } - slurm_docker { - process.executor = 'slurm' - process.cpus = 4 - process.memory = '200 GB' - docker.enabled = true - process.container = 'alexd13/omnideconv_benchmark:1.2' - docker.temp = "auto" - } -} - -// this is necessary to run CIBERSORTx with a docker in docker environment. The local docker socket has to be mapped as a volume into the omnideconv_benchmark container, so that the CIBERSORTx container can be started inside -docker { - runOptions = '-v /var/run/docker.sock:/var/run/docker.sock -v /vol/omnideconv_results/:/vol/omnideconv_results/' - -} - -// use the `-with-trace` command to get tracing information on each job. Useful for the subsampling workflow, to see how resources scale with size of single-cell dataset -trace { - fields = 'task_id,process,name,status,module,container,cpus,time,disk,memory,realtime,%cpu,%mem,rss,vmem,peak_rss,peak_vmem,script' - sep = ',' - overwrite = true -} diff --git a/pipeline/run_cibersortx.sh b/pipeline/run_cibersortx.sh index 3d8d92e..c7a8f8b 100755 --- a/pipeline/run_cibersortx.sh +++ b/pipeline/run_cibersortx.sh @@ -1,3 +1,5 @@ #!/bin/bash -nextflow -C /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/nextflow_norm.config run /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/main.nf -profile cibersortx -work-dir /localscratch/omnideconv_work "$@" \ No newline at end of file +nextflow -C /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/nextflow_norm.config run /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/main.nf \ + -profile cibersortx \ + -work-dir /localscratch/omnideconv_work "$@" \ No newline at end of file diff --git a/pipeline/run_default.sh b/pipeline/run_default.sh index c982487..17ca48b 100755 --- a/pipeline/run_default.sh +++ b/pipeline/run_default.sh @@ -1,3 +1,6 @@ #!/bin/bash -nextflow -C /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/nextflow_norm.config run /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/main.nf -profile apptainer -work-dir /nfs/scratch/nf-core_work/omnideconv.benchmark -with-trace "$@" \ No newline at end of file +nextflow -C /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/nextflow_norm.config run /nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/pipeline/main.nf \ + -profile apptainer \ + -work-dir /nfs/scratch/nf-core_work/omnideconv.benchmark \ + -with-trace "$@" \ No newline at end of file diff --git a/visualisation/fig2/fig2.nb.html b/visualisation/fig2/fig2.nb.html index 8ab963a..beec0ce 100755 --- a/visualisation/fig2/fig2.nb.html +++ b/visualisation/fig2/fig2.nb.html @@ -1754,27 +1754,13 @@

R Notebook

- -
source("../helper_functions.R")
-source('ggradar_custom.R')
+
+
source("../../visualisation/helper_functions.R")
+source('../../revision/ggradar_custom.R')
 library(tidyverse)
 library(data.table)
-library(cowplot)
- - -

-Attaching package: ‘cowplot’
-
-The following object is masked from ‘package:patchwork’:
-
-    align_plots
-
-The following object is masked from ‘package:lubridate’:
-
-    stamp
- - -
library(patchwork)
+library(cowplot)
+library(patchwork)
 
 color_palette <- c('B cells'='#999933',
                    'Macrophages'='#CC6677',
@@ -1830,25 +1816,8 @@ 

R Notebook

df.cor <- data_summary(performance_df, 'cor', c('cell_type','method','bulk_ds','org'))
- -
Loading required package: plyr
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-You have loaded plyr after dplyr - this is likely to cause problems.
-If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
-library(plyr); library(dplyr)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-Attaching package: ‘plyr’
-
-The following objects are masked from ‘package:dplyr’:
-
-    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize
-
-The following object is masked from ‘package:purrr’:
-
-    compact
-
-using median as new default.
+ +
using median as new default.
df.rmse <- data_summary(performance_df, 'RMSE', c('cell_type','method','bulk_ds','org'))
@@ -1951,38 +1920,24 @@

Fig2a

-

+

- -
```r
-ggsave('../../revision/visualization/fig2/fig_2a.pdf', plot=fig_2a, width = 18, height = 9)
-

-<!-- rnb-source-end -->
-
-<!-- rnb-chunk-end -->
-
-
-<!-- rnb-text-begin -->
-
-
-
-# Fig2b
-
-
-<!-- rnb-text-end -->
-
-
-<!-- rnb-chunk-begin -->
-
-
-<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxucHJlcGFyZV9tZXRyaWNfZGYgPC0gZnVuY3Rpb24oZGYsIGRzLCBtZXRyaWMsIHRyYW5zZm9ybV9mbiA9IGlkZW50aXR5KSB7XG4gIGRmIHw+XG4gICAgZmlsdGVyKGJ1bGtfZHMgPT0gZHMsIGNlbGxfdHlwZSAhPSBcImFsbFwiKSB8PlxuICAgIHNlbGVjdChtZXRob2QsIGNlbGxfdHlwZSwgYnVsa19kcywgdmFsdWUgPSBhbGxfb2YobWV0cmljKSkgfD5cbiAgICBtdXRhdGUodmFsdWUgPSB0cmFuc2Zvcm1fZm4odmFsdWUpKSB8PlxuICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjZWxsX3R5cGUsIHZhbHVlc19mcm9tID0gdmFsdWUpIHw+XG4gICAgc2VsZWN0KC1idWxrX2RzKSB8PlxuICAgIHJlcGxhY2UoaXMubmEoLiksIDApIHw+IFxuICAgIGFzX3RpYmJsZSgpXG59XG5cbnByZXBhcmVfbWV0cmljX2RmX3Blcl9jZWxsdHlwZSA8LSBmdW5jdGlvbihkZiwgZHMsIG1ldHJpYywgdHJhbnNmb3JtX2ZuID0gaWRlbnRpdHkpIHtcbiAgZGYgfD5cbiAgICBmaWx0ZXIoYnVsa19kcyA9PSBkcywgY2VsbF90eXBlICE9IFwiYWxsXCIpIHw+XG4gICAgc2VsZWN0KG1ldGhvZCwgY2VsbF90eXBlLCBidWxrX2RzLCB2YWx1ZSA9IGFsbF9vZihtZXRyaWMpKSB8PlxuICAgIG11dGF0ZSh2YWx1ZSA9IHRyYW5zZm9ybV9mbih2YWx1ZSkpIHw+XG4gICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG1ldGhvZCwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgfD5cbiAgICBzZWxlY3QoLWJ1bGtfZHMpIHw+XG4gICAgcmVwbGFjZShpcy5uYSguKSwgMCkgfD4gXG4gICAgYXNfdGliYmxlKClcbn1cblxuY29tcHV0ZV9leHRyZW1lIDwtIGZ1bmN0aW9uKGRmLCBmdW4sIGFkanVzdCA9IDApIHtcbiAgcm91bmQoZnVuKGFwcGx5KGRmWywtMV0sIDIsIGZ1biksIG5hLnJtID0gVFJVRSksIDEpICsgYWRqdXN0XG59XG5cbiMgSGVscGVyIGZ1bmN0aW9uIHRvIGNyZWF0ZSByYWRhciBwbG90XG5wbG90X3JhZGFyIDwtIGZ1bmN0aW9uKGRmLCB0aXRsZSwgZ3JpZC5taW4sIGdyaWQubWlkLCBncmlkLm1heCwgdmFsdWVzLnJhZGFyLCBsZWdlbmQucG9zaXRpb249J25vbmUnLCBwYWxldHRlKSB7XG4gIGdncmFkYXIoZGYsXG4gICAgICAgICAgZ3JvdXAuY29sb3VycyA9IHBhbGV0dGUsXG4gICAgICAgICAgZ3JvdXAucG9pbnQuc2l6ZSA9IDIsXG4gICAgICAgICAgZ3JvdXAubGluZS53aWR0aCA9IC44LFxuICAgICAgICAgIGdyaWQubWluID0gZ3JpZC5taW4sXG4gICAgICAgICAgZ3JpZC5taWQgPSBncmlkLm1pZCxcbiAgICAgICAgICBncmlkLm1heCA9IGdyaWQubWF4LFxuICAgICAgICAgIHZhbHVlcy5yYWRhciA9IHZhbHVlcy5yYWRhcixcbiAgICAgICAgICBmb250LnJhZGFyID0gXCJzYW5zXCIsXG4gICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEwLFxuICAgICAgICAgIGF4aXMubGFiZWwuc2l6ZSA9IDMuNSxcbiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBsZWdlbmQucG9zaXRpb24sXG4gICAgICAgICAgcGxvdC50aXRsZSA9IHRpdGxlKVxufVxuXG5wbG90X3JhZGFyX2N1c3RvbSA8LSBmdW5jdGlvbihkZiwgdGl0bGUsIGdyaWQubWluLCBncmlkLm1pZCwgZ3JpZC5hZGQsIGdyaWQubWF4LCB2YWx1ZXMucmFkYXIsIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScsIGdyaWRsaW5lLm1pZC5jb2xvdXI9J2dyZXknLCBwYWxldHRlKSB7XG4gIGdncmFkYXJfY3VzdG9tKGRmLFxuICAgICAgICAgIGdyb3VwLmNvbG91cnMgPSBwYWxldHRlLFxuICAgICAgICAgIGdyb3VwLnBvaW50LnNpemUgPSAyLFxuICAgICAgICAgIGdyb3VwLmxpbmUud2lkdGggPSAuNSxcbiAgICAgICAgICBncmlkLm1pbiA9IGdyaWQubWluLFxuICAgICAgICAgIGdyaWQubWlkID0gZ3JpZC5taWQsXG4gICAgICAgICAgZ3JpZC5hZGQgPSBncmlkLmFkZCxcbiAgICAgICAgICBncmlkLm1heCA9IGdyaWQubWF4LFxuICAgICAgICAgIHZhbHVlcy5yYWRhciA9IHZhbHVlcy5yYWRhciwgXG4gICAgICAgICAgZ3JpZGxpbmUuYWRkLmNvbG91ciA9ICdncmV5JyxcbiAgICAgICAgICBncmlkbGluZS5taWQuY29sb3VyID0gZ3JpZGxpbmUubWlkLmNvbG91cixcbiAgICAgICAgICBmb250LnJhZGFyID0gXCJzYW5zXCIsXG4gICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEwLFxuICAgICAgICAgIGF4aXMubGFiZWwuc2l6ZSA9IDMuNSxcbiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBsZWdlbmQucG9zaXRpb24sXG4gICAgICAgICAgcGxvdC50aXRsZSA9IHRpdGxlKVxufVxuXG5gYGAifQ== -->
-
-```r
-prepare_metric_df <- function(df, ds, metric, transform_fn = identity) {
+
+
ggsave('../../revision2/visualization/fig2/fig_2a.pdf', plot=fig_2a, width = 18, height = 9)
+ + + + +
+

Fig2b

+ + + +
prepare_metric_df <- function(df, ds, metric, transform_fn = identity) {
   df |>
     filter(bulk_ds == ds, cell_type != "all") |>
     select(method, cell_type, bulk_ds, value = all_of(metric)) |>
@@ -2109,36 +2064,20 @@ 

Fig2a

- -
```r
-fig_2b <- (rmse_plots$p_rmse_morandini + rmse_plots$p_rmse_finotello + rmse_plots$p_rmse_hoek) / (cor_plots$p_cor_morandini + cor_plots$p_cor_finotello + cor_plots$p_cor_hoek)
-
-ggsave('/nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/revision/visualization/fig2/fig_2b.pdf', plot = fig_2b, width = 20, height = 10)
-

-<!-- rnb-source-end -->
-
-<!-- rnb-chunk-end -->
-
-
-<!-- rnb-text-begin -->
-
-
-
-
-# Fig S2
+
+
fig_2b <- (rmse_plots$p_rmse_morandini + rmse_plots$p_rmse_finotello + rmse_plots$p_rmse_hoek) / (cor_plots$p_cor_morandini + cor_plots$p_cor_finotello + cor_plots$p_cor_hoek)
 
-
-<!-- rnb-text-end -->
-
-
-<!-- rnb-chunk-begin -->
-
-
-<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZmlnX3MyYSA8LSBmcmFjdGlvbnNfZGYgJT4lIHN1YnNldChidWxrX2RzICVpbiUgYygnQ2hlbicsJ1BldGl0cHJleicsJ0FsdG1hbicpKSAlPiVcbiAgZ2dwbG90KC4sIGFlcyh4PWZyYWN0aW9uLnRydWUsIHk9ZnJhY3Rpb24uZXN0aW1hdGUpKStcbiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpK1xuICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxKStcbiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Y2VsbHR5cGUpLCBzaXplPTIsIGFscGhhPS43KStcbiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKStcbiAgeGxhYignR3JvdW5kIHRydXRoIGNlbGwtdHlwZSBmcmFjdGlvbicpK1xuICB5bGFiKCdFc3RpbWF0ZWQgY2VsbC10eXBlIGZyYWN0aW9uJykrXG4gIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKStcbiAgdGhlbWVfYncoKStcbiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSxcbiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsXG4gICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScpKStcbiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3BhbGV0dGUsIGRyb3AgPSBUKStcbiAgZ2VvbV90ZXh0KGRhdGE9ZGYuYm90aCAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdDaGVuJywnUGV0aXRwcmV6JywnQWx0bWFuJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCBcbiAgICAgICAgICAgIGFlcyhsYWJlbD1wYXN0ZTAoJ1I6ICcscm91bmQoY29yLCAzKSwnXFxuUk1TRTogJywgcm91bmQoUk1TRSwgMykpKSwgeD0uMDMsIHk9MS4xMywgc2l6ZT0zLCBoanVzdD0wKStcbiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKVxuXG5cbmZpZ19zMmIgPC0gZnJhY3Rpb25zX2RmICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykpICU+JVxuICBnZ3Bsb3QoLiwgYWVzKHg9ZnJhY3Rpb24udHJ1ZSwgeT1mcmFjdGlvbi5lc3RpbWF0ZSkpK1xuICBnZW9tX2FibGluZShsaW5ldHlwZT0nZGFzaGVkJykrXG4gIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpK1xuICBnZW9tX3BvaW50KGFlcyhjb2xvcj1jZWxsdHlwZSksIHNpemU9MiwgYWxwaGE9LjIpK1xuICBmYWNldF9ncmlkKGJ1bGtfZHMgfiBtZXRob2QpK1xuICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrXG4gIHlsYWIoJ0VzdGltYXRlZCBjZWxsLXR5cGUgZnJhY3Rpb24nKStcbiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMS4yKSwgYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yNSkpK1xuICB0aGVtZV9idygpK1xuICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLFxuICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJyxcbiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpK1xuICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT01LCBhbHBoYT0xKSkpK1xuICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfcGFsZXR0ZSwgZHJvcCA9IFQpK1xuICBnZW9tX3RleHQoZGF0YT1kZi5ib3RoICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCBcbiAgICAgICAgICAgIGFlcyhsYWJlbD1wYXN0ZTAoJ1I6ICcscm91bmQoY29yLCAzKSwnXFxuUk1TRTogJywgcm91bmQoUk1TRSwgMykpKSwgeD0uMDMsIHk9MS4xMywgc2l6ZT0zLCBoanVzdD0wKStcbiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKVxuXG5maWdfczIgPC0gcGxvdF9ncmlkKFxuICBmaWdfczJhICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPVxcbm9uZVxcKSxcbiAgZmlnX3MyYixcbiAgYWxpZ24gPSAnaCcsXG4gIGxhYmVscyA9IGMoXFxBXFwsIFxcQlxcKSwgXG4gIGxhYmVsX3NpemUgPSAxNSwgXG4gIGhqdXN0ID0gLTEsXG4gIG5yb3cgPSAyLCBuY29sID0gMSxcbiAgcmVsX2hlaWdodHMgPSBjKC40NSwgLjc1KVxuKVxuYGBgXG5gYGAifQ== -->
-
-```r
-```r
-fig_s2a <- fractions_df %>% subset(bulk_ds %in% c('Chen','Petitprez','Altman')) %>%
+ggsave('/nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/revision2/visualization/fig2/fig_2b.pdf', plot = fig_2b, width = 20, height = 10)
+ + + +
+
+

Fig S2

+ + + +
fig_s2a <- fractions_df %>% subset(bulk_ds %in% c('Chen','Petitprez','Altman')) %>%
   ggplot(., aes(x=fraction.true, y=fraction.estimate))+
   geom_abline(linetype='dashed')+
   geom_hline(yintercept = 1)+
@@ -2177,57 +2116,31 @@ 

Fig2a

labs(color='Celltype') fig_s2 <- plot_grid( - fig_s2a + theme(legend.position=\none\), + fig_s2a + theme(legend.position="none"), fig_s2b, align = 'h', - labels = c(\A\, \B\), + labels = c("A", "B"), label_size = 15, hjust = -1, nrow = 2, ncol = 1, rel_heights = c(.45, .75) )
-

-<!-- rnb-source-end -->
-
-<!-- rnb-output-begin eyJkYXRhIjoiV2FybmluZzogUmVtb3ZlZCAxMTYgcm93cyBjb250YWluaW5nIG1pc3NpbmcgdmFsdWVzIG9yIHZhbHVlcyBvdXRzaWRlIHRoZSBzY2FsZSByYW5nZSAoYGdlb21fcG9pbnQoKWApLldhcm5pbmc6IFJlbW92ZWQgMTggcm93cyBjb250YWluaW5nIG1pc3NpbmcgdmFsdWVzIG9yIHZhbHVlcyBvdXRzaWRlIHRoZSBzY2FsZSByYW5nZSAoYGdlb21fcG9pbnQoKWApLldhcm5pbmc6IEdyYXBocyBjYW5ub3QgYmUgaG9yaXpvbnRhbGx5IGFsaWduZWQgdW5sZXNzIHRoZSBheGlzIHBhcmFtZXRlciBpcyBzZXQuIFBsYWNpbmcgZ3JhcGhzIHVuYWxpZ25lZC5cbiJ9 -->
-
-

Warning: Removed 116 rows containing missing values or values outside -the scale range (geom_point()).Warning: Removed 18 rows -containing missing values or values outside the scale range -(geom_point()).Warning: Graphs cannot be horizontally -aligned unless the axis parameter is set. Placing graphs unaligned.

-

-
-
-<!-- rnb-output-end -->
-
-<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZ2dzYXZlKHBsb3QgPSBmaWdfczIsIGZpbGVuYW1lID0gJy9uZnMvcHJvai9vbW5pZGVjb252X2JlbmNobWFya2luZy9vbW5pZGVjb252L2JlbmNobWFyay9yZXZpc2lvbi92aXN1YWxpemF0aW9uL2ZpZzIvZmlnX3MyLnBkZicsIHdpZHRoID0gMTIsIGhlaWdodCA9IDE3KVxuYGBgXG5gYGAifQ== -->
-
-```r
-```r
-ggsave(plot = fig_s2, filename = '/nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/revision/visualization/fig2/fig_s2.pdf', width = 12, height = 17)
-

-<!-- rnb-source-end -->
-
-<!-- rnb-chunk-end -->
-
-
-<!-- rnb-text-begin -->
-
-
-# Fig S3
-
-
-<!-- rnb-text-end -->
-
-
-<!-- rnb-chunk-begin -->
-
-
-<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuZGF0YXNldHMgPC0gYyhcIk1vcmFuZGluaVwiLCBcIkZpbm90ZWxsb1wiLCBcIkhvZWtcIiwgXCJBbHRtYW5cIiwnQ2hlbicsJ1BldGl0cHJleicsJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJylcblxuZGYuaGVhdG1hcCA8LSBkZi5ib3RoIHw+IHN1YnNldChidWxrX2RzICVpbiUgZGF0YXNldHMgJiBjZWxsX3R5cGUgIT0gJ2FsbCcpIHw+IHNlbGVjdChjZWxsX3R5cGUsIG1ldGhvZCwgYnVsa19kcywgY29yLCBSTVNFKVxuXG5kZl9sb25nIDwtIGRmLmhlYXRtYXAgJT4lXG4gIHBpdm90X2xvbmdlcihjb2xzID0gYyhjb3IsIFJNU0UpLCBuYW1lc190byA9IFwibWV0cmljXCIsIHZhbHVlc190byA9IFwidmFsdWVcIilcbnhfbGV2ZWxzIDwtIHVuaXF1ZShkZi5oZWF0bWFwJGNlbGxfdHlwZSlcbnlfbGV2ZWxzIDwtIHVuaXF1ZShkZi5oZWF0bWFwJG1ldGhvZClcbmRmX2xvbmcgPC0gZGZfbG9uZyAlPiVcbiAgbXV0YXRlKFxuICAgIHhfbnVtID0gYXMubnVtZXJpYyhmYWN0b3IoY2VsbF90eXBlLCBsZXZlbHMgPSB4X2xldmVscykpLFxuICAgIHlfbnVtID0gYXMubnVtZXJpYyhmYWN0b3IobWV0aG9kLCBsZXZlbHMgPSByZXYoeV9sZXZlbHMpKSkgICMgUmV2ZXJzZSBmb3IgaGVhdG1hcCBsYXlvdXRcbiAgKVxuXG5nZXRfdHJpX2Nvb3JkcyA8LSBmdW5jdGlvbih4LCB5LCBtZXRyaWMpIHtcbiAgaWYgKG1ldHJpYyA9PSBcImNvclwiKSB7XG4gICAgdGliYmxlKFxuICAgICAgeF9jb29yZCA9IGMoeCAtIDAuNSwgeCArIDAuNSwgeCAtIDAuNSksXG4gICAgICB5X2Nvb3JkID0gYyh5ICsgMC41LCB5ICsgMC41LCB5IC0gMC41KVxuICAgIClcbiAgfSBlbHNlIHtcbiAgICB0aWJibGUoXG4gICAgICB4X2Nvb3JkID0gYyh4ICsgMC41LCB4ICsgMC41LCB4IC0gMC41KSxcbiAgICAgIHlfY29vcmQgPSBjKHkgKyAwLjUsIHkgLSAwLjUsIHkgLSAwLjUpXG4gICAgKVxuICB9XG59XG5cbmRmX3BvbHkgPC0gZGZfbG9uZyAlPiVcbiAgZHBseXI6Om11dGF0ZShjb29yZHMgPSBwbWFwKGxpc3QoeF9udW0sIHlfbnVtLCBtZXRyaWMpLCBnZXRfdHJpX2Nvb3JkcykpICU+JVxuICB1bm5lc3QoY29vcmRzKSAlPiVcbiAgZ3JvdXBfYnkoY2VsbF90eXBlLCBtZXRob2QsIGJ1bGtfZHMsIG1ldHJpYykgJT4lXG4gIGRwbHlyOjptdXRhdGUodGlsZV9pZCA9IGN1cl9ncm91cF9pZCgpKSAlPiVcbiAgdW5ncm91cCgpXG5cbmRmX2xhYmVscyA8LSBkZl9sb25nICU+JVxuICBtdXRhdGUoXG4gICAgbGFiZWwgPSBpZmVsc2UobWV0cmljID09IFwiY29yXCIsXG4gICAgICAgICAgICAgICAgICAgc3ByaW50ZihcIiUuMmZcIiwgdmFsdWUpLFxuICAgICAgICAgICAgICAgICAgIHNwcmludGYoXCIlLjJmXCIsIHZhbHVlKSksXG4gICAgeF9sYWJlbCA9IHhfbnVtICsgaWZlbHNlKG1ldHJpYyA9PSBcImNvclwiLCAtMC4yLCAwLjIpLFxuICAgIHlfbGFiZWwgPSB5X251bSArIGlmZWxzZShtZXRyaWMgPT0gXCJjb3JcIiwgMC4yLCAtMC4yKVxuICApXG5cbmRmX3IgPC0gZGZfcG9seSAlPiUgZmlsdGVyKG1ldHJpYyA9PSBcImNvclwiKVxuZGZfcm1zZSA8LSBkZl9wb2x5ICU+JSBmaWx0ZXIobWV0cmljID09IFwiUk1TRVwiKVxuXG50cmlhbmdsZV9oZWF0bWFwIDwtIGdncGxvdCgpICtcbiAgIyBSIHRyaWFuZ2xlc1xuICBnZW9tX3BvbHlnb24oZGF0YSA9IGRmX3IsIGFlcyh4ID0geF9jb29yZCwgeSA9IHlfY29vcmQsIGdyb3VwID0gdGlsZV9pZCwgZmlsbCA9IHZhbHVlKSwgY29sb3IgPSBcImJsYWNrXCIpICtcbiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobWlkID0gJ2RhcmtyZWQnLCBsb3cgPSBcImJsYWNrXCIsIGhpZ2ggPSBcInN0ZWVsYmx1ZVwiLCBuYW1lID0gXCJSXCIpICtcbiAgbmV3X3NjYWxlX2ZpbGwoKSArXG4gICMgUk1TRSB0cmlhbmdsZXNcbiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBkZl9ybXNlLCBhZXMoeCA9IHhfY29vcmQsIHkgPSB5X2Nvb3JkLCBncm91cCA9IHRpbGVfaWQsIGZpbGwgPSB2YWx1ZSksIGNvbG9yID0gXCJibGFja1wiKSArXG4gIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gXCJzdGVlbGJsdWVcIiwgaGlnaCA9IFwiZGFya3JlZFwiLCBuYW1lID0gXCJSTVNFXCIpICtcbiAgZ2VvbV90ZXh0KGRhdGEgPSBkZl9sYWJlbHMsIGFlcyh4ID0geF9sYWJlbCwgeSA9IHlfbGFiZWwsIGxhYmVsID0gbGFiZWwsIGdyb3VwID0gbWV0cmljKSwgc2l6ZSA9IDIsIGNvbG9yPSd3aGl0ZScpICtcbiAgZmFjZXRfd3JhcCh+YnVsa19kcywgc2NhbGVzID0gJ2ZyZWUnLCBuY29sID0gMykgK1xuICB0aGVtZV9idygpICtcbiAgdGhlbWUoXG4gICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSxcbiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpXG4gICkgK1xuICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IHhfbGV2ZWxzKSArXG4gIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KHlfbGV2ZWxzKSkgK1xuICBsYWJzKHggPSBcIlwiLCB5ID0gXCJcIilcblxuYGBgIn0= -->
-
-```r
-datasets <- c("Morandini", "Finotello", "Hoek", "Altman",'Chen','Petitprez','ChenSim','PetitprezSim','FinotelloSim','HoekSim','MorandiniSim','AltmanSim')
+
+
+
Warning: Removed 116 rows containing missing values or values outside the scale range (`geom_point()`).Warning: Removed 18 rows containing missing values or values outside the scale range (`geom_point()`).Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
+ + +
ggsave(plot = fig_s2, filename = '/nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/revision2/visualization/fig2/fig_s2_v2.pdf', width = 12, height = 17)
+ + + +
+
+

Fig S3

+ + + +
datasets <- c("Morandini", "Finotello", "Hoek", "Altman",'Chen','Petitprez','ChenSim','PetitprezSim','FinotelloSim','HoekSim','MorandiniSim','AltmanSim')
 
 df.heatmap <- df.both |> subset(bulk_ds %in% datasets & cell_type != 'all') |> select(cell_type, method, bulk_ds, cor, RMSE)
 
@@ -2292,17 +2205,15 @@ 

Fig2a

scale_x_discrete(limits = x_levels) + scale_y_discrete(limits = rev(y_levels)) + labs(x = "", y = "") -
+ +ggsave('/nfs/proj/omnideconv_benchmarking/omnideconv/benchmark/revision2/visualization/fig2/fig_s3_v3.pdf', plot = triangle_heatmap, width = 14, height = 16)
- -
Error in new_scale_fill() : could not find function "new_scale_fill"
- -
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgiLi4vaGVscGVyX2Z1bmN0aW9ucy5SIikKc291cmNlKCdnZ3JhZGFyX2N1c3RvbS5SJykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ25ld3NjYWxlKQoKY29sb3JfcGFsZXR0ZSA8LSBjKCdCIGNlbGxzJz0nIzk5OTkzMycsCiAgICAgICAgICAgICAgICAgICAnTWFjcm9waGFnZXMnPScjQ0M2Njc3JywKICAgICAgICAgICAgICAgICAgICdtREMnPScjODgyMjU1JywKICAgICAgICAgICAgICAgICAgICdNb25vY3l0ZXMnPScjQUE0NDk5JywKICAgICAgICAgICAgICAgICAgICdOSyBjZWxscyc9JyNERENDNzcnLAogICAgICAgICAgICAgICAgICAgJ1QgY2VsbCc9JyMzMzIyODgnLAogICAgICAgICAgICAgICAgICAgJ0NENCBUIGNlbGxzJz0nIzExNzczMycsCiAgICAgICAgICAgICAgICAgICAnQ0Q4IFQgY2VsbHMnPScjNDRBQTk5JywKICAgICAgICAgICAgICAgICAgICdUcmVncyc9JyM4OENDRUUnLAogICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMnPScjMzMyMjg4JywKICAgICAgICAgICAgICAgICAgICdMeW1waG9jeXRlcycgPSAnIzY2MDBDQycpCgptZXRob2RfcGFsZXR0ZSA8LSBwYWxldHRlLmNvbG9ycyhwYWxldHRlID0gIk9rYWJlLUl0byIpWzE6OF0KbmFtZXMobWV0aG9kX3BhbGV0dGUpIDwtIGMoJ0F1dG9HZW5lUycsJ0JheWVzUHJpc20nLCdCaXNxdWUnLCdDSUJFUlNPUlR4JywnRFdMUycsJ011U2lDJywnU2NhZGVuJywnU0NEQycpCmBgYAoKYGBge3J9Cm1ldGhvZHMgPC0gYygnYXV0b2dlbmVzJywnYmF5ZXNwcmlzbScsJ2Jpc3F1ZScsJ2NpYmVyc29ydHgnLCdkd2xzJywnbXVzaWMnLCdzY2FkZW4nLCdzY2RjJykKc2Nfbm9ybSA8LSBjKCdjcG0nLCByZXAoJ2NvdW50cycsIDIpLCdjcG0nLHJlcCgnY291bnRzJyw0KSkKYnVsa19ub3JtIDwtIGMoJ3RwbScsIHJlcCgnY291bnRzJywgMiksIHJlcCgndHBtJyw1KSkKbWV0aG9kX3BhcmFtZXRlcl9kZiA8LSBkYXRhLmZyYW1lKG1ldGhvZD1tZXRob2RzLCBzY19ub3JtPXNjX25vcm0sIGJ1bGtfbm9ybT1idWxrX25vcm0pCm1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kX25vcm1fY29tYmkgPC0gcGFzdGUwKG1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kLCBtZXRob2RfcGFyYW1ldGVyX2RmJHNjX25vcm0sIG1ldGhvZF9wYXJhbWV0ZXJfZGYkYnVsa19ub3JtKQoKZnJhY3Rpb25zX2RmX21vdXNlIDwtIGdldF9mcmFjdGlvbnMoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21vdXNlLycsICcwJywgJ3RhYnVsYS1tdXJpcycsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCmZyYWN0aW9uc19kZl9tb3VzZSRvcmcgPC0gJ21tJwpmcmFjdGlvbnNfZGZfaGFvIDwtIGdldF9hbGxfZnJhY3Rpb25zKCcvbmZzL2RhdGEvb21uaWRlY29udl9iZW5jaG1hcmtpbmdfY2xlYW4vYmVuY2htYXJrX3Jlc3VsdHMvcmVzdWx0c19tYWluMy8nLCAnMCcsICdIYW9DbGVhbmVkLXNhbXBsZWQnLCBtZXRob2RfcGFyYW1ldGVyX2RmKQpmcmFjdGlvbnNfZGZfaGFvJG9yZyA8LSAnaHMnCmZyYWN0aW9uc19kZiA8LSByYmluZChmcmFjdGlvbnNfZGZfaGFvLCBmcmFjdGlvbnNfZGZfbW91c2UpCmZyYWN0aW9uc19kZiA8LSBzdWJzZXQoZnJhY3Rpb25zX2RmLCBtZXRob2Rfbm9ybV9jb21iaSAlaW4lIG1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kX25vcm1fY29tYmkpCgpmcmFjdGlvbnNfZGYkY2VsbHR5cGUgPC0gcmVjb2RlKGZyYWN0aW9uc19kZiRjZWxsdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVCBjZWxsJyA9ICdUIGNlbGxzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVCBjZWxscyBDRDQgY29udicgPSAnQ0Q0IFQgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENENCcgPSAnQ0Q0IFQgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENEOCcgPSAnQ0Q4IFQgY2VsbHMnKQoKcGVyZm9ybWFuY2VfZGZfbW91c2UgPC0gZ2V0X3BlcmZvcm1hbmNlX21ldHJpY3MoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21vdXNlLycsICcwJywgJ3RhYnVsYS1tdXJpcycsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCnBlcmZvcm1hbmNlX2RmX21vdXNlJG9yZyA8LSAnbW0nCnBlcmZvcm1hbmNlX2RmX2hhbyA8LSBnZXRfYWxsX3BlcmZvcm1hbmNlX21ldHJpY3MoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21haW4zLycsICcwJywgJ0hhb0NsZWFuZWQtc2FtcGxlZCcsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCnBlcmZvcm1hbmNlX2RmX2hhbyRvcmcgPC0gJ2hzJwpwZXJmb3JtYW5jZV9kZiA8LSByYmluZChwZXJmb3JtYW5jZV9kZl9oYW8sIHBlcmZvcm1hbmNlX2RmX21vdXNlKQpwZXJmb3JtYW5jZV9kZiA8LSBzdWJzZXQocGVyZm9ybWFuY2VfZGYsIG1ldGhvZF9ub3JtX2NvbWJpICVpbiUgbWV0aG9kX3BhcmFtZXRlcl9kZiRtZXRob2Rfbm9ybV9jb21iaSkKCnBlcmZvcm1hbmNlX2RmJGNlbGxfdHlwZSA8LSByZWNvZGUocGVyZm9ybWFuY2VfZGYkY2VsbF90eXBlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGwnID0gJ1QgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENENCBjb252JyA9ICdDRDQgVCBjZWxscycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMgQ0Q0JyA9ICdDRDQgVCBjZWxscycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMgQ0Q4JyA9ICdDRDggVCBjZWxscycpCgpkZi5jb3IgPC0gZGF0YV9zdW1tYXJ5KHBlcmZvcm1hbmNlX2RmLCAnY29yJywgYygnY2VsbF90eXBlJywnbWV0aG9kJywnYnVsa19kcycsJ29yZycpKQpkZi5ybXNlIDwtIGRhdGFfc3VtbWFyeShwZXJmb3JtYW5jZV9kZiwgJ1JNU0UnLCBjKCdjZWxsX3R5cGUnLCdtZXRob2QnLCdidWxrX2RzJywnb3JnJykpCmRmLmJvdGggPC0gZGF0YS50YWJsZShtZXJnZShkZi5jb3IsIGRmLnJtc2UsIGJ5ID0gYygnY2VsbF90eXBlJywnbWV0aG9kJywnYnVsa19kcycsJ29yZycpLCBzdWZmaXhlcyA9IGMoJy5jb3InLCcucm1zZScpKSkKYGBgCgpgYGB7cn0KZGYuYm90aCRjZWxsX3R5cGUgPC0gYXMuZmFjdG9yKGRmLmJvdGgkY2VsbF90eXBlKQpmcmFjdGlvbnNfZGYkY2VsbHR5cGUgPC0gYXMuZmFjdG9yKGZyYWN0aW9uc19kZiRjZWxsdHlwZSkKCmZyYWN0aW9uc19kZiA8LSBmcmFjdGlvbnNfZGYgJT4lIAogIG11dGF0ZShtZXRob2QgPSByZWNvZGUobWV0aG9kLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2F1dG9nZW5lcyc9J0F1dG9HZW5lUycsCiAgICAgICAgICAgICAgICAgICAgICAgICAnYmF5ZXNwcmlzbSc9J0JheWVzUHJpc20nLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2Jpc3F1ZSc9J0Jpc3F1ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAnY2liZXJzb3J0eCc9J0NJQkVSU09SVHgnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2R3bHMnPSdEV0xTJywKICAgICAgICAgICAgICAgICAgICAgICAgICdtdXNpYyc9J011U2lDJywKICAgICAgICAgICAgICAgICAgICAgICAgICdzY2FkZW4nPSdTY2FkZW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgJ3NjZGMnPSdTQ0RDJykpCmZyYWN0aW9uc19kZiA8LSBmcmFjdGlvbnNfZGYgJT4lCiAgbXV0YXRlKGJ1bGtfZHMgPSByZWNvZGUoYnVsa19kcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZW4iID0gIkNoZW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiY2hlbi1zaW11bGF0aW9uIiA9ICJDaGVuU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImZpbm90ZWxsbyIgPSAiRmlub3RlbGxvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImZpbm90ZWxsby1zaW11bGF0aW9uIiA9ICJGaW5vdGVsbG9TaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9layIgPSAiSG9layIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJob2VrLXNpbXVsYXRpb24iID0gIkhvZWtTaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAicGV0aXRwcmV6IiA9ICJQZXRpdHByZXoiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAicGV0aXRwcmV6LXNpbXVsYXRpb24iID0gIlBldGl0cHJlelNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbHRtYW4iPSJBbHRtYW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAibW9yYW5kaW5pIj0iTW9yYW5kaW5pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImFsdG1hbi1zaW11bGF0aW9uIj0iQWx0bWFuU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vcmFuZGluaS1zaW11bGF0aW9uIj0iTW9yYW5kaW5pU2ltIikpCmRmLmJvdGggPC0gZGYuYm90aCAlPiUKICBtdXRhdGUoYnVsa19kcyA9ICByZWNvZGUoYnVsa19kcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZW4iID0gIkNoZW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiY2hlbi1zaW11bGF0aW9uIiA9ICJDaGVuU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImZpbm90ZWxsbyIgPSAiRmlub3RlbGxvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImZpbm90ZWxsby1zaW11bGF0aW9uIiA9ICJGaW5vdGVsbG9TaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9layIgPSAiSG9layIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJob2VrLXNpbXVsYXRpb24iID0gIkhvZWtTaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAicGV0aXRwcmV6IiA9ICJQZXRpdHByZXoiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAicGV0aXRwcmV6LXNpbXVsYXRpb24iID0gIlBldGl0cHJlelNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbHRtYW4iPSJBbHRtYW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAibW9yYW5kaW5pIj0iTW9yYW5kaW5pIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImFsdG1hbi1zaW11bGF0aW9uIj0iQWx0bWFuU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vcmFuZGluaS1zaW11bGF0aW9uIj0iTW9yYW5kaW5pU2ltIikpCmRmLmJvdGggPC0gZGYuYm90aCAlPiUgCiAgbXV0YXRlKG1ldGhvZCA9IHJlY29kZShtZXRob2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAnYXV0b2dlbmVzJz0nQXV0b0dlbmVTJywKICAgICAgICAgICAgICAgICAgICAgICAgICdiYXllc3ByaXNtJz0nQmF5ZXNQcmlzbScsCiAgICAgICAgICAgICAgICAgICAgICAgICAnYmlzcXVlJz0nQmlzcXVlJywKICAgICAgICAgICAgICAgICAgICAgICAgICdjaWJlcnNvcnR4Jz0nQ0lCRVJTT1JUeCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAnZHdscyc9J0RXTFMnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ211c2ljJz0nTXVTaUMnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ3NjYWRlbic9J1NjYWRlbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAnc2NkYyc9J1NDREMnKSkKCmZyYWN0aW9uc19kZiA8LSBmcmFjdGlvbnNfZGYgJT4lCiAgbXV0YXRlKHNjX2RzID0gcmVjb2RlKHNjX2RzLAogICAgICAgICAgICAgICAgICAgICAgICAgICJoYW8tc2FtcGxlZC0zIiA9ICJIYW9TdWIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJIYW8tc2FtcGxlZCIgPSAiSGFvU3ViIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAidGFidWxhLW11cmlzIiA9ICJUTSIpKQpgYGAKCiMgRmlnMmEKCmBgYHtyfQpmaWdfMmEgPC0gZnJhY3Rpb25zX2RmICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0hvZWsnLCdGaW5vdGVsbG8nLCdNb3JhbmRpbmknKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyh4PWZyYWN0aW9uLnRydWUsIHk9ZnJhY3Rpb24uZXN0aW1hdGUpKSsKICBnZW9tX2FibGluZShsaW5ldHlwZT0nZGFzaGVkJykrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Y2VsbHR5cGUpLCBzaXplPTIsIGFscGhhPS43KSsKICBmYWNldF9ncmlkKGJ1bGtfZHMgfiBtZXRob2QpKwogIHhsYWIoJ0dyb3VuZCB0cnV0aCBjZWxsLXR5cGUgZnJhY3Rpb24nKSsKICB5bGFiKCdFc3RpbWF0ZWQgY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMS4yKSwgYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4yNSkpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAndG9wJywKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnd2hpdGUnKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3BhbGV0dGUsIGRyb3AgPSBUKSsKICBnZW9tX3RleHQoZGF0YT1kZi5ib3RoICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0hvZWsnLCdGaW5vdGVsbG8nLCdNb3JhbmRpbmknKSAmIGNlbGxfdHlwZSA9PSAnYWxsJyksIAogICAgICAgICAgICBhZXMobGFiZWw9cGFzdGUwKCdSOiAnLHJvdW5kKGNvciwgMyksJ1xuUk1TRTogJywgcm91bmQoUk1TRSwgMykpKSwgeD0uMDMsIHk9MS4xMywgc2l6ZT0zLCBoanVzdD0wKSsKICBsYWJzKGNvbG9yPSdDZWxsdHlwZScpCgpmaWdfMmEKCmBgYAoKYGBge3J9Cmdnc2F2ZSgnLi4vLi4vcmV2aXNpb24vdmlzdWFsaXphdGlvbi9maWcyL2ZpZ18yYS5wZGYnLCBwbG90PWZpZ18yYSwgd2lkdGggPSAxOCwgaGVpZ2h0ID0gOSkKYGBgCgoKIyBGaWcyYgoKYGBge3J9CnByZXBhcmVfbWV0cmljX2RmIDwtIGZ1bmN0aW9uKGRmLCBkcywgbWV0cmljLCB0cmFuc2Zvcm1fZm4gPSBpZGVudGl0eSkgewogIGRmIHw+CiAgICBmaWx0ZXIoYnVsa19kcyA9PSBkcywgY2VsbF90eXBlICE9ICJhbGwiKSB8PgogICAgc2VsZWN0KG1ldGhvZCwgY2VsbF90eXBlLCBidWxrX2RzLCB2YWx1ZSA9IGFsbF9vZihtZXRyaWMpKSB8PgogICAgbXV0YXRlKHZhbHVlID0gdHJhbnNmb3JtX2ZuKHZhbHVlKSkgfD4KICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjZWxsX3R5cGUsIHZhbHVlc19mcm9tID0gdmFsdWUpIHw+CiAgICBzZWxlY3QoLWJ1bGtfZHMpIHw+CiAgICByZXBsYWNlKGlzLm5hKC4pLCAwKSB8PiAKICAgIGFzX3RpYmJsZSgpCn0KCnByZXBhcmVfbWV0cmljX2RmX3Blcl9jZWxsdHlwZSA8LSBmdW5jdGlvbihkZiwgZHMsIG1ldHJpYywgdHJhbnNmb3JtX2ZuID0gaWRlbnRpdHkpIHsKICBkZiB8PgogICAgZmlsdGVyKGJ1bGtfZHMgPT0gZHMsIGNlbGxfdHlwZSAhPSAiYWxsIikgfD4KICAgIHNlbGVjdChtZXRob2QsIGNlbGxfdHlwZSwgYnVsa19kcywgdmFsdWUgPSBhbGxfb2YobWV0cmljKSkgfD4KICAgIG11dGF0ZSh2YWx1ZSA9IHRyYW5zZm9ybV9mbih2YWx1ZSkpIHw+CiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbWV0aG9kLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSB8PgogICAgc2VsZWN0KC1idWxrX2RzKSB8PgogICAgcmVwbGFjZShpcy5uYSguKSwgMCkgfD4gCiAgICBhc190aWJibGUoKQp9Cgpjb21wdXRlX2V4dHJlbWUgPC0gZnVuY3Rpb24oZGYsIGZ1biwgYWRqdXN0ID0gMCkgewogIHJvdW5kKGZ1bihhcHBseShkZlssLTFdLCAyLCBmdW4pLCBuYS5ybSA9IFRSVUUpLCAxKSArIGFkanVzdAp9CgojIEhlbHBlciBmdW5jdGlvbiB0byBjcmVhdGUgcmFkYXIgcGxvdApwbG90X3JhZGFyIDwtIGZ1bmN0aW9uKGRmLCB0aXRsZSwgZ3JpZC5taW4sIGdyaWQubWlkLCBncmlkLm1heCwgdmFsdWVzLnJhZGFyLCBsZWdlbmQucG9zaXRpb249J25vbmUnLCBwYWxldHRlKSB7CiAgZ2dyYWRhcihkZiwKICAgICAgICAgIGdyb3VwLmNvbG91cnMgPSBwYWxldHRlLAogICAgICAgICAgZ3JvdXAucG9pbnQuc2l6ZSA9IDIsCiAgICAgICAgICBncm91cC5saW5lLndpZHRoID0gLjgsCiAgICAgICAgICBncmlkLm1pbiA9IGdyaWQubWluLAogICAgICAgICAgZ3JpZC5taWQgPSBncmlkLm1pZCwKICAgICAgICAgIGdyaWQubWF4ID0gZ3JpZC5tYXgsCiAgICAgICAgICB2YWx1ZXMucmFkYXIgPSB2YWx1ZXMucmFkYXIsCiAgICAgICAgICBmb250LnJhZGFyID0gInNhbnMiLAogICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEwLAogICAgICAgICAgYXhpcy5sYWJlbC5zaXplID0gMy41LAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gbGVnZW5kLnBvc2l0aW9uLAogICAgICAgICAgcGxvdC50aXRsZSA9IHRpdGxlKQp9CgpwbG90X3JhZGFyX2N1c3RvbSA8LSBmdW5jdGlvbihkZiwgdGl0bGUsIGdyaWQubWluLCBncmlkLm1pZCwgZ3JpZC5hZGQsIGdyaWQubWF4LCB2YWx1ZXMucmFkYXIsIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScsIGdyaWRsaW5lLm1pZC5jb2xvdXI9J2dyZXknLCBwYWxldHRlKSB7CiAgZ2dyYWRhcl9jdXN0b20oZGYsCiAgICAgICAgICBncm91cC5jb2xvdXJzID0gcGFsZXR0ZSwKICAgICAgICAgIGdyb3VwLnBvaW50LnNpemUgPSAyLAogICAgICAgICAgZ3JvdXAubGluZS53aWR0aCA9IC41LAogICAgICAgICAgZ3JpZC5taW4gPSBncmlkLm1pbiwKICAgICAgICAgIGdyaWQubWlkID0gZ3JpZC5taWQsCiAgICAgICAgICBncmlkLmFkZCA9IGdyaWQuYWRkLAogICAgICAgICAgZ3JpZC5tYXggPSBncmlkLm1heCwKICAgICAgICAgIHZhbHVlcy5yYWRhciA9IHZhbHVlcy5yYWRhciwgCiAgICAgICAgICBncmlkbGluZS5hZGQuY29sb3VyID0gJ2dyZXknLAogICAgICAgICAgZ3JpZGxpbmUubWlkLmNvbG91ciA9IGdyaWRsaW5lLm1pZC5jb2xvdXIsCiAgICAgICAgICBmb250LnJhZGFyID0gInNhbnMiLAogICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEwLAogICAgICAgICAgYXhpcy5sYWJlbC5zaXplID0gMy41LAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gbGVnZW5kLnBvc2l0aW9uLAogICAgICAgICAgcGxvdC50aXRsZSA9IHRpdGxlKQp9CgpgYGAKCmBgYHtyfQojIERhdGFzZXRzCmRhdGFzZXRzIDwtIGMoIk1vcmFuZGluaSIsICJGaW5vdGVsbG8iLCAiSG9layIpCgptZXRob2Rfb3JkZXIgPC0gZGYuYm90aCB8PiAKICBzdWJzZXQoYnVsa19kcyAlaW4lIGRhdGFzZXRzKSB8PiAKICBkcGx5cjo6Z3JvdXBfYnkobWV0aG9kKSB8PiAKICBkcGx5cjo6c3VtbWFyaXplKHN1bT1zdW0oY29yLCBuYS5ybT1UKSkgfD4gCiAgYXJyYW5nZShzdW0pIHw+IAogIHNlbGVjdChtZXRob2QpIHw+IAogIHVubGlzdCgpCgpybXNlX3Bsb3RzIDwtIGxhcHBseShkYXRhc2V0cywgZnVuY3Rpb24oZHMpIHsKICBkZl9ybXNlIDwtIHByZXBhcmVfbWV0cmljX2RmX3Blcl9jZWxsdHlwZShkZi5ib3RoLCBkcywgIlJNU0UiICxmdW5jdGlvbih4KSBsb2coMSAvIHgpKVssYygnY2VsbF90eXBlJyxtZXRob2Rfb3JkZXIpXQogIG1heF92YWwgPC0gY29tcHV0ZV9leHRyZW1lKGRmX3Jtc2UsIG1heCwgYWRqdXN0ID0gMC4xKQogIHBsb3RfcmFkYXJfY3VzdG9tKGRmX3Jtc2UsCiAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgibG9nKDEvUk1TRSkgIiwgZHMpLAogICAgICAgICAgICAgZ3JpZC5taW4gPSAwLAogICAgICAgICAgICAgZ3JpZC5taWQgPSByb3VuZChtYXhfdmFsICogLjMzLCAyKSwKICAgICAgICAgICAgIGdyaWQuYWRkID0gcm91bmQobWF4X3ZhbCAqIC42NiwgMiksCiAgICAgICAgICAgICBncmlkLm1heCA9IHJvdW5kKG1heF92YWwsIDIpLAogICAgICAgICAgICAgdmFsdWVzLnJhZGFyID0gYygiMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIocm91bmQobWF4X3ZhbCAqIC4zMywgMikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKHJvdW5kKG1heF92YWwgKiAuNjYsIDIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKHJvdW5kKG1heF92YWwsIDIpKSksCiAgICAgICAgICAgICBwYWxldHRlID0gY29sb3JfcGFsZXR0ZVthcy5jaGFyYWN0ZXIoZGZfcm1zZSRjZWxsX3R5cGUpXSkKfSkKCiMgR2VuZXJhdGUgY29ycmVsYXRpb24gcGxvdHMKY29yX3Bsb3RzIDwtIGxhcHBseShkYXRhc2V0cywgZnVuY3Rpb24oZHMpIHsKICBkZl9jb3IgPC0gcHJlcGFyZV9tZXRyaWNfZGZfcGVyX2NlbGx0eXBlKGRmLmJvdGgsIGRzLCAiY29yIilbLGMoJ2NlbGxfdHlwZScsbWV0aG9kX29yZGVyKV0KICBtaW5fdmFsIDwtIGNvbXB1dGVfZXh0cmVtZShkZl9jb3IsIG1pbiwgYWRqdXN0ID0gLTAuMSkKICBkZl9jb3JbaXMubmEoZGZfY29yKV0gPC0gbWluX3ZhbCAtICgoMS85KSAqICgxIC0gbWluX3ZhbCkpCiAgcGxvdF9yYWRhcl9jdXN0b20oZGZfY29yLAogICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZTAoIkNvcnJlbGF0aW9uICIsIGRzKSwKICAgICAgICAgICAgIGdyaWQubWluID0gaWZlbHNlKG1pbl92YWwgPCAwLCBtaW5fdmFsLCAwKSwKICAgICAgICAgICAgIGdyaWQubWlkID0gaWZlbHNlKG1pbl92YWwgPCAwLCAwLCBtaW5fdmFsKSwKICAgICAgICAgICAgIGdyaWQuYWRkID0gMC41LAogICAgICAgICAgICAgZ3JpZC5tYXggPSAxLAogICAgICAgICAgICAgdmFsdWVzLnJhZGFyID0gYyhhcy5jaGFyYWN0ZXIobWluX3ZhbCksICIwIiwgIjAuNSIsICIxIiksCiAgICAgICAgICAgICBncmlkbGluZS5taWQuY29sb3VyPSdibGFjaycsCiAgICAgICAgICAgICBwYWxldHRlID0gY29sb3JfcGFsZXR0ZVthcy5jaGFyYWN0ZXIoZGZfY29yJGNlbGxfdHlwZSldKQp9KQoKIyBBc3NpZ24gcGxvdHMgdG8gbmFtZWQgdmFyaWFibGVzIGlmIG5lZWRlZApuYW1lcyhybXNlX3Bsb3RzKSA8LSBwYXN0ZTAoInBfcm1zZV8iLCB0b2xvd2VyKGRhdGFzZXRzKSkKbmFtZXMoY29yX3Bsb3RzKSAgPC0gcGFzdGUwKCJwX2Nvcl8iLCB0b2xvd2VyKGRhdGFzZXRzKSkKYGBgCgoKCmBgYHtyfQpmaWdfMmIgPC0gKHJtc2VfcGxvdHMkcF9ybXNlX21vcmFuZGluaSArIHJtc2VfcGxvdHMkcF9ybXNlX2Zpbm90ZWxsbyArIHJtc2VfcGxvdHMkcF9ybXNlX2hvZWspIC8gKGNvcl9wbG90cyRwX2Nvcl9tb3JhbmRpbmkgKyBjb3JfcGxvdHMkcF9jb3JfZmlub3RlbGxvICsgY29yX3Bsb3RzJHBfY29yX2hvZWspCgpnZ3NhdmUoJy9uZnMvcHJvai9vbW5pZGVjb252X2JlbmNobWFya2luZy9vbW5pZGVjb252L2JlbmNobWFyay9yZXZpc2lvbi92aXN1YWxpemF0aW9uL2ZpZzIvZmlnXzJiLnBkZicsIHBsb3QgPSBmaWdfMmIsIHdpZHRoID0gMjAsIGhlaWdodCA9IDEwKQpgYGAKCgoKIyBGaWcgUzIKCmBgYHtyfQpmaWdfczJhIDwtIGZyYWN0aW9uc19kZiAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdDaGVuJywnUGV0aXRwcmV6JywnQWx0bWFuJykpICU+JQogIGdncGxvdCguLCBhZXMoeD1mcmFjdGlvbi50cnVlLCB5PWZyYWN0aW9uLmVzdGltYXRlKSkrCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNlbGx0eXBlKSwgc2l6ZT0yLCBhbHBoYT0uNykrCiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKSsKICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgeWxhYignRXN0aW1hdGVkIGNlbGwtdHlwZSBmcmFjdGlvbicpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl9wYWxldHRlLCBkcm9wID0gVCkrCiAgZ2VvbV90ZXh0KGRhdGE9ZGYuYm90aCAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdDaGVuJywnUGV0aXRwcmV6JywnQWx0bWFuJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCgnUjogJyxyb3VuZChjb3IsIDMpLCdcblJNU0U6ICcsIHJvdW5kKFJNU0UsIDMpKSksIHg9LjAzLCB5PTEuMTMsIHNpemU9MywgaGp1c3Q9MCkrCiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKQoKCmZpZ19zMmIgPC0gZnJhY3Rpb25zX2RmICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykpICU+JQogIGdncGxvdCguLCBhZXMoeD1mcmFjdGlvbi50cnVlLCB5PWZyYWN0aW9uLmVzdGltYXRlKSkrCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNlbGx0eXBlKSwgc2l6ZT0yLCBhbHBoYT0uMikrCiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKSsKICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgeWxhYignRXN0aW1hdGVkIGNlbGwtdHlwZSBmcmFjdGlvbicpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUsIGFscGhhPTEpKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3BhbGV0dGUsIGRyb3AgPSBUKSsKICBnZW9tX3RleHQoZGF0YT1kZi5ib3RoICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCgnUjogJyxyb3VuZChjb3IsIDMpLCdcblJNU0U6ICcsIHJvdW5kKFJNU0UsIDMpKSksIHg9LjAzLCB5PTEuMTMsIHNpemU9MywgaGp1c3Q9MCkrCiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKQoKZmlnX3MyIDwtIHBsb3RfZ3JpZCgKICBmaWdfczJhICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgZmlnX3MyYiwKICBhbGlnbiA9ICdoJywKICBsYWJlbHMgPSBjKCJBIiwgIkIiKSwgCiAgbGFiZWxfc2l6ZSA9IDE1LCAKICBoanVzdCA9IC0xLAogIG5yb3cgPSAyLCBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoLjQ1LCAuNzUpCikKCmdnc2F2ZShwbG90ID0gZmlnX3MyLCBmaWxlbmFtZSA9ICcvbmZzL3Byb2ovb21uaWRlY29udl9iZW5jaG1hcmtpbmcvb21uaWRlY29udi9iZW5jaG1hcmsvcmV2aXNpb24vdmlzdWFsaXphdGlvbi9maWcyL2ZpZ19zMi5wZGYnLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxNykKYGBgCgojIEZpZyBTMwoKYGBge3J9CmRhdGFzZXRzIDwtIGMoIk1vcmFuZGluaSIsICJGaW5vdGVsbG8iLCAiSG9layIsICJBbHRtYW4iLCdDaGVuJywnUGV0aXRwcmV6JywnQ2hlblNpbScsJ1BldGl0cHJlelNpbScsJ0Zpbm90ZWxsb1NpbScsJ0hvZWtTaW0nLCdNb3JhbmRpbmlTaW0nLCdBbHRtYW5TaW0nKQoKZGYuaGVhdG1hcCA8LSBkZi5ib3RoIHw+IHN1YnNldChidWxrX2RzICVpbiUgZGF0YXNldHMgJiBjZWxsX3R5cGUgIT0gJ2FsbCcpIHw+IHNlbGVjdChjZWxsX3R5cGUsIG1ldGhvZCwgYnVsa19kcywgY29yLCBSTVNFKQoKZGZfbG9uZyA8LSBkZi5oZWF0bWFwICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhjb3IsIFJNU0UpLCBuYW1lc190byA9ICJtZXRyaWMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQp4X2xldmVscyA8LSB1bmlxdWUoZGYuaGVhdG1hcCRjZWxsX3R5cGUpCnlfbGV2ZWxzIDwtIHVuaXF1ZShkZi5oZWF0bWFwJG1ldGhvZCkKZGZfbG9uZyA8LSBkZl9sb25nICU+JQogIG11dGF0ZSgKICAgIHhfbnVtID0gYXMubnVtZXJpYyhmYWN0b3IoY2VsbF90eXBlLCBsZXZlbHMgPSB4X2xldmVscykpLAogICAgeV9udW0gPSBhcy5udW1lcmljKGZhY3RvcihtZXRob2QsIGxldmVscyA9IHJldih5X2xldmVscykpKSAgIyBSZXZlcnNlIGZvciBoZWF0bWFwIGxheW91dAogICkKCmdldF90cmlfY29vcmRzIDwtIGZ1bmN0aW9uKHgsIHksIG1ldHJpYykgewogIGlmIChtZXRyaWMgPT0gImNvciIpIHsKICAgIHRpYmJsZSgKICAgICAgeF9jb29yZCA9IGMoeCAtIDAuNSwgeCArIDAuNSwgeCAtIDAuNSksCiAgICAgIHlfY29vcmQgPSBjKHkgKyAwLjUsIHkgKyAwLjUsIHkgLSAwLjUpCiAgICApCiAgfSBlbHNlIHsKICAgIHRpYmJsZSgKICAgICAgeF9jb29yZCA9IGMoeCArIDAuNSwgeCArIDAuNSwgeCAtIDAuNSksCiAgICAgIHlfY29vcmQgPSBjKHkgKyAwLjUsIHkgLSAwLjUsIHkgLSAwLjUpCiAgICApCiAgfQp9CgpkZl9wb2x5IDwtIGRmX2xvbmcgJT4lCiAgZHBseXI6Om11dGF0ZShjb29yZHMgPSBwbWFwKGxpc3QoeF9udW0sIHlfbnVtLCBtZXRyaWMpLCBnZXRfdHJpX2Nvb3JkcykpICU+JQogIHVubmVzdChjb29yZHMpICU+JQogIGdyb3VwX2J5KGNlbGxfdHlwZSwgbWV0aG9kLCBidWxrX2RzLCBtZXRyaWMpICU+JQogIGRwbHlyOjptdXRhdGUodGlsZV9pZCA9IGN1cl9ncm91cF9pZCgpKSAlPiUKICB1bmdyb3VwKCkKCmRmX2xhYmVscyA8LSBkZl9sb25nICU+JQogIG11dGF0ZSgKICAgIGxhYmVsID0gaWZlbHNlKG1ldHJpYyA9PSAiY29yIiwKICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmYiLCB2YWx1ZSksCiAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlLjJmIiwgdmFsdWUpKSwKICAgIHhfbGFiZWwgPSB4X251bSArIGlmZWxzZShtZXRyaWMgPT0gImNvciIsIC0wLjIsIDAuMiksCiAgICB5X2xhYmVsID0geV9udW0gKyBpZmVsc2UobWV0cmljID09ICJjb3IiLCAwLjIsIC0wLjIpCiAgKQoKZGZfciA8LSBkZl9wb2x5ICU+JSBmaWx0ZXIobWV0cmljID09ICJjb3IiKQpkZl9ybXNlIDwtIGRmX3BvbHkgJT4lIGZpbHRlcihtZXRyaWMgPT0gIlJNU0UiKQoKdHJpYW5nbGVfaGVhdG1hcCA8LSBnZ3Bsb3QoKSArCiAgIyBSIHRyaWFuZ2xlcwogIGdlb21fcG9seWdvbihkYXRhID0gZGZfciwgYWVzKHggPSB4X2Nvb3JkLCB5ID0geV9jb29yZCwgZ3JvdXAgPSB0aWxlX2lkLCBmaWxsID0gdmFsdWUpLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50MihtaWQgPSAnZGFya3JlZCcsIGxvdyA9ICJibGFjayIsIGhpZ2ggPSAic3RlZWxibHVlIiwgbmFtZSA9ICJSIikgKwogIG5ld19zY2FsZV9maWxsKCkgKwogICMgUk1TRSB0cmlhbmdsZXMKICBnZW9tX3BvbHlnb24oZGF0YSA9IGRmX3Jtc2UsIGFlcyh4ID0geF9jb29yZCwgeSA9IHlfY29vcmQsIGdyb3VwID0gdGlsZV9pZCwgZmlsbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAic3RlZWxibHVlIiwgaGlnaCA9ICJkYXJrcmVkIiwgbmFtZSA9ICJSTVNFIikgKwogIGdlb21fdGV4dChkYXRhID0gZGZfbGFiZWxzLCBhZXMoeCA9IHhfbGFiZWwsIHkgPSB5X2xhYmVsLCBsYWJlbCA9IGxhYmVsLCBncm91cCA9IG1ldHJpYyksIHNpemUgPSAyLCBjb2xvcj0nd2hpdGUnKSArCiAgZmFjZXRfd3JhcCh+YnVsa19kcywgc2NhbGVzID0gJ2ZyZWUnLCBuY29sID0gMykgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkKICApICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IHhfbGV2ZWxzKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYoeV9sZXZlbHMpKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiIikKCmdnc2F2ZSgnL25mcy9wcm9qL29tbmlkZWNvbnZfYmVuY2htYXJraW5nL29tbmlkZWNvbnYvYmVuY2htYXJrL3JldmlzaW9uL3Zpc3VhbGl6YXRpb24vZmlnMi9maWdfczNfdjIucGRmJywgcGxvdCA9IHRyaWFuZ2xlX2hlYXRtYXAsIHdpZHRoID0gMTQsIGhlaWdodCA9IDE2KQpgYGAKCg==
+
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgiLi4vaGVscGVyX2Z1bmN0aW9ucy5SIikKc291cmNlKCdnZ3JhZGFyX2N1c3RvbS5SJykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ25ld3NjYWxlKQoKY29sb3JfcGFsZXR0ZSA8LSBjKCdCIGNlbGxzJz0nIzk5OTkzMycsCiAgICAgICAgICAgICAgICAgICAnTWFjcm9waGFnZXMnPScjQ0M2Njc3JywKICAgICAgICAgICAgICAgICAgICdtREMnPScjODgyMjU1JywKICAgICAgICAgICAgICAgICAgICdNb25vY3l0ZXMnPScjQUE0NDk5JywKICAgICAgICAgICAgICAgICAgICdOSyBjZWxscyc9JyNERENDNzcnLAogICAgICAgICAgICAgICAgICAgJ1QgY2VsbCc9JyMzMzIyODgnLAogICAgICAgICAgICAgICAgICAgJ0NENCBUIGNlbGxzJz0nIzExNzczMycsCiAgICAgICAgICAgICAgICAgICAnQ0Q4IFQgY2VsbHMnPScjNDRBQTk5JywKICAgICAgICAgICAgICAgICAgICdUcmVncyc9JyM4OENDRUUnLAogICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMnPScjMzMyMjg4JywKICAgICAgICAgICAgICAgICAgICdMeW1waG9jeXRlcycgPSAnIzY2MDBDQycpCgptZXRob2RfcGFsZXR0ZSA8LSBwYWxldHRlLmNvbG9ycyhwYWxldHRlID0gIk9rYWJlLUl0byIpWzE6OF0KbmFtZXMobWV0aG9kX3BhbGV0dGUpIDwtIGMoJ0F1dG9HZW5lUycsJ0JheWVzUHJpc20nLCdCaXNxdWUnLCdDSUJFUlNPUlR4JywnRFdMUycsJ011U2lDJywnU2NhZGVuJywnU0NEQycpCmBgYAoKYGBge3J9Cm1ldGhvZHMgPC0gYygnYXV0b2dlbmVzJywnYmF5ZXNwcmlzbScsJ2Jpc3F1ZScsJ2NpYmVyc29ydHgnLCdkd2xzJywnbXVzaWMnLCdzY2FkZW4nLCdzY2RjJykKc2Nfbm9ybSA8LSBjKCdjcG0nLCByZXAoJ2NvdW50cycsIDIpLCdjcG0nLHJlcCgnY291bnRzJyw0KSkKYnVsa19ub3JtIDwtIGMoJ3RwbScsIHJlcCgnY291bnRzJywgMiksIHJlcCgndHBtJyw1KSkKbWV0aG9kX3BhcmFtZXRlcl9kZiA8LSBkYXRhLmZyYW1lKG1ldGhvZD1tZXRob2RzLCBzY19ub3JtPXNjX25vcm0sIGJ1bGtfbm9ybT1idWxrX25vcm0pCm1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kX25vcm1fY29tYmkgPC0gcGFzdGUwKG1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kLCBtZXRob2RfcGFyYW1ldGVyX2RmJHNjX25vcm0sIG1ldGhvZF9wYXJhbWV0ZXJfZGYkYnVsa19ub3JtKQoKZnJhY3Rpb25zX2RmX21vdXNlIDwtIGdldF9mcmFjdGlvbnMoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21vdXNlLycsICcwJywgJ3RhYnVsYS1tdXJpcycsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCmZyYWN0aW9uc19kZl9tb3VzZSRvcmcgPC0gJ21tJwpmcmFjdGlvbnNfZGZfaGFvIDwtIGdldF9hbGxfZnJhY3Rpb25zKCcvbmZzL2RhdGEvb21uaWRlY29udl9iZW5jaG1hcmtpbmdfY2xlYW4vYmVuY2htYXJrX3Jlc3VsdHMvcmVzdWx0c19tYWluMy8nLCAnMCcsICdIYW9DbGVhbmVkLXNhbXBsZWQnLCBtZXRob2RfcGFyYW1ldGVyX2RmKQpmcmFjdGlvbnNfZGZfaGFvJG9yZyA8LSAnaHMnCmZyYWN0aW9uc19kZiA8LSByYmluZChmcmFjdGlvbnNfZGZfaGFvLCBmcmFjdGlvbnNfZGZfbW91c2UpCmZyYWN0aW9uc19kZiA8LSBzdWJzZXQoZnJhY3Rpb25zX2RmLCBtZXRob2Rfbm9ybV9jb21iaSAlaW4lIG1ldGhvZF9wYXJhbWV0ZXJfZGYkbWV0aG9kX25vcm1fY29tYmkpCgpmcmFjdGlvbnNfZGYkY2VsbHR5cGUgPC0gcmVjb2RlKGZyYWN0aW9uc19kZiRjZWxsdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVCBjZWxsJyA9ICdUIGNlbGxzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVCBjZWxscyBDRDQgY29udicgPSAnQ0Q0IFQgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENENCcgPSAnQ0Q0IFQgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENEOCcgPSAnQ0Q4IFQgY2VsbHMnKQoKcGVyZm9ybWFuY2VfZGZfbW91c2UgPC0gZ2V0X3BlcmZvcm1hbmNlX21ldHJpY3MoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21vdXNlLycsICcwJywgJ3RhYnVsYS1tdXJpcycsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCnBlcmZvcm1hbmNlX2RmX21vdXNlJG9yZyA8LSAnbW0nCnBlcmZvcm1hbmNlX2RmX2hhbyA8LSBnZXRfYWxsX3BlcmZvcm1hbmNlX21ldHJpY3MoJy9uZnMvZGF0YS9vbW5pZGVjb252X2JlbmNobWFya2luZ19jbGVhbi9iZW5jaG1hcmtfcmVzdWx0cy9yZXN1bHRzX21haW4zLycsICcwJywgJ0hhb0NsZWFuZWQtc2FtcGxlZCcsIG1ldGhvZF9wYXJhbWV0ZXJfZGYpCnBlcmZvcm1hbmNlX2RmX2hhbyRvcmcgPC0gJ2hzJwpwZXJmb3JtYW5jZV9kZiA8LSByYmluZChwZXJmb3JtYW5jZV9kZl9oYW8sIHBlcmZvcm1hbmNlX2RmX21vdXNlKQpwZXJmb3JtYW5jZV9kZiA8LSBzdWJzZXQocGVyZm9ybWFuY2VfZGYsIG1ldGhvZF9ub3JtX2NvbWJpICVpbiUgbWV0aG9kX3BhcmFtZXRlcl9kZiRtZXRob2Rfbm9ybV9jb21iaSkKCnBlcmZvcm1hbmNlX2RmJGNlbGxfdHlwZSA8LSByZWNvZGUocGVyZm9ybWFuY2VfZGYkY2VsbF90eXBlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGwnID0gJ1QgY2VsbHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUIGNlbGxzIENENCBjb252JyA9ICdDRDQgVCBjZWxscycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMgQ0Q0JyA9ICdDRDQgVCBjZWxscycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1QgY2VsbHMgQ0Q4JyA9ICdDRDggVCBjZWxscycpCgpkZi5jb3IgPC0gZGF0YV9zdW1tYXJ5KHBlcmZvcm1hbmNlX2RmLCAnY29yJywgYygnY2VsbF90eXBlJywnbWV0aG9kJywnYnVsa19kcycsJ29yZycpKQpkZi5ybXNlIDwtIGRhdGFfc3VtbWFyeShwZXJmb3JtYW5jZV9kZiwgJ1JNU0UnLCBjKCdjZWxsX3R5cGUnLCdtZXRob2QnLCdidWxrX2RzJywnb3JnJykpCmRmLmJvdGggPC0gZGF0YS50YWJsZShtZXJnZShkZi5jb3IsIGRmLnJtc2UsIGJ5ID0gYygnY2VsbF90eXBlJywnbWV0aG9kJywnYnVsa19kcycsJ29yZycpLCBzdWZmaXhlcyA9IGMoJy5jb3InLCcucm1zZScpKSkKYGBgCgoKYGBge3J9CmRmLmJvdGgkY2VsbF90eXBlIDwtIGFzLmZhY3RvcihkZi5ib3RoJGNlbGxfdHlwZSkKZnJhY3Rpb25zX2RmJGNlbGx0eXBlIDwtIGFzLmZhY3RvcihmcmFjdGlvbnNfZGYkY2VsbHR5cGUpCgpmcmFjdGlvbnNfZGYgPC0gZnJhY3Rpb25zX2RmICU+JSAKICBtdXRhdGUobWV0aG9kID0gcmVjb2RlKG1ldGhvZCwKICAgICAgICAgICAgICAgICAgICAgICAgICdhdXRvZ2VuZXMnPSdBdXRvR2VuZVMnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2JheWVzcHJpc20nPSdCYXllc1ByaXNtJywKICAgICAgICAgICAgICAgICAgICAgICAgICdiaXNxdWUnPSdCaXNxdWUnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2NpYmVyc29ydHgnPSdDSUJFUlNPUlR4JywKICAgICAgICAgICAgICAgICAgICAgICAgICdkd2xzJz0nRFdMUycsCiAgICAgICAgICAgICAgICAgICAgICAgICAnbXVzaWMnPSdNdVNpQycsCiAgICAgICAgICAgICAgICAgICAgICAgICAnc2NhZGVuJz0nU2NhZGVuJywKICAgICAgICAgICAgICAgICAgICAgICAgICdzY2RjJz0nU0NEQycpKQpmcmFjdGlvbnNfZGYgPC0gZnJhY3Rpb25zX2RmICU+JQogIG11dGF0ZShidWxrX2RzID0gcmVjb2RlKGJ1bGtfZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjaGVuIiA9ICJDaGVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZW4tc2ltdWxhdGlvbiIgPSAiQ2hlblNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaW5vdGVsbG8iID0gIkZpbm90ZWxsbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaW5vdGVsbG8tc2ltdWxhdGlvbiIgPSAiRmlub3RlbGxvU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImhvZWsiID0gIkhvZWsiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9lay1zaW11bGF0aW9uIiA9ICJIb2VrU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgInBldGl0cHJleiIgPSAiUGV0aXRwcmV6IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgInBldGl0cHJlei1zaW11bGF0aW9uIiA9ICJQZXRpdHByZXpTaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiYWx0bWFuIj0iQWx0bWFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vcmFuZGluaSI9Ik1vcmFuZGluaSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbHRtYW4tc2ltdWxhdGlvbiI9IkFsdG1hblNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb3JhbmRpbmktc2ltdWxhdGlvbiI9Ik1vcmFuZGluaVNpbSIpKQpkZi5ib3RoIDwtIGRmLmJvdGggJT4lCiAgbXV0YXRlKGJ1bGtfZHMgPSAgcmVjb2RlKGJ1bGtfZHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjaGVuIiA9ICJDaGVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZW4tc2ltdWxhdGlvbiIgPSAiQ2hlblNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaW5vdGVsbG8iID0gIkZpbm90ZWxsbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaW5vdGVsbG8tc2ltdWxhdGlvbiIgPSAiRmlub3RlbGxvU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgImhvZWsiID0gIkhvZWsiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiaG9lay1zaW11bGF0aW9uIiA9ICJIb2VrU2ltIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgInBldGl0cHJleiIgPSAiUGV0aXRwcmV6IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgInBldGl0cHJlei1zaW11bGF0aW9uIiA9ICJQZXRpdHByZXpTaW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiYWx0bWFuIj0iQWx0bWFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1vcmFuZGluaSI9Ik1vcmFuZGluaSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbHRtYW4tc2ltdWxhdGlvbiI9IkFsdG1hblNpbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb3JhbmRpbmktc2ltdWxhdGlvbiI9Ik1vcmFuZGluaVNpbSIpKQpkZi5ib3RoIDwtIGRmLmJvdGggJT4lIAogIG11dGF0ZShtZXRob2QgPSByZWNvZGUobWV0aG9kLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2F1dG9nZW5lcyc9J0F1dG9HZW5lUycsCiAgICAgICAgICAgICAgICAgICAgICAgICAnYmF5ZXNwcmlzbSc9J0JheWVzUHJpc20nLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2Jpc3F1ZSc9J0Jpc3F1ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAnY2liZXJzb3J0eCc9J0NJQkVSU09SVHgnLAogICAgICAgICAgICAgICAgICAgICAgICAgJ2R3bHMnPSdEV0xTJywKICAgICAgICAgICAgICAgICAgICAgICAgICdtdXNpYyc9J011U2lDJywKICAgICAgICAgICAgICAgICAgICAgICAgICdzY2FkZW4nPSdTY2FkZW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgJ3NjZGMnPSdTQ0RDJykpCgpmcmFjdGlvbnNfZGYgPC0gZnJhY3Rpb25zX2RmICU+JQogIG11dGF0ZShzY19kcyA9IHJlY29kZShzY19kcywKICAgICAgICAgICAgICAgICAgICAgICAgICAiaGFvLXNhbXBsZWQtMyIgPSAiSGFvU3ViIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiSGFvLXNhbXBsZWQiID0gIkhhb1N1YiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgInRhYnVsYS1tdXJpcyIgPSAiVE0iKSkKYGBgCgojIEZpZzJhCgpgYGB7cn0KZmlnXzJhIDwtIGZyYWN0aW9uc19kZiAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdIb2VrJywnRmlub3RlbGxvJywnTW9yYW5kaW5pJykpICU+JQogIGdncGxvdCguLCBhZXMoeD1mcmFjdGlvbi50cnVlLCB5PWZyYWN0aW9uLmVzdGltYXRlKSkrCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNlbGx0eXBlKSwgc2l6ZT0yLCBhbHBoYT0uNykrCiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKSsKICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgeWxhYignRXN0aW1hdGVkIGNlbGwtdHlwZSBmcmFjdGlvbicpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl9wYWxldHRlLCBkcm9wID0gVCkrCiAgZ2VvbV90ZXh0KGRhdGE9ZGYuYm90aCAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdIb2VrJywnRmlub3RlbGxvJywnTW9yYW5kaW5pJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCgnUjogJyxyb3VuZChjb3IsIDMpLCdcblJNU0U6ICcsIHJvdW5kKFJNU0UsIDMpKSksIHg9LjAzLCB5PTEuMTMsIHNpemU9MywgaGp1c3Q9MCkrCiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKQoKZmlnXzJhCgpgYGAKCmBgYHtyfQpnZ3NhdmUoJy4uLy4uL3JldmlzaW9uMi92aXN1YWxpemF0aW9uL2ZpZzIvZmlnXzJhLnBkZicsIHBsb3Q9ZmlnXzJhLCB3aWR0aCA9IDE4LCBoZWlnaHQgPSA5KQpgYGAKCgojIEZpZzJiCgpgYGB7cn0KcHJlcGFyZV9tZXRyaWNfZGYgPC0gZnVuY3Rpb24oZGYsIGRzLCBtZXRyaWMsIHRyYW5zZm9ybV9mbiA9IGlkZW50aXR5KSB7CiAgZGYgfD4KICAgIGZpbHRlcihidWxrX2RzID09IGRzLCBjZWxsX3R5cGUgIT0gImFsbCIpIHw+CiAgICBzZWxlY3QobWV0aG9kLCBjZWxsX3R5cGUsIGJ1bGtfZHMsIHZhbHVlID0gYWxsX29mKG1ldHJpYykpIHw+CiAgICBtdXRhdGUodmFsdWUgPSB0cmFuc2Zvcm1fZm4odmFsdWUpKSB8PgogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNlbGxfdHlwZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgfD4KICAgIHNlbGVjdCgtYnVsa19kcykgfD4KICAgIHJlcGxhY2UoaXMubmEoLiksIDApIHw+IAogICAgYXNfdGliYmxlKCkKfQoKcHJlcGFyZV9tZXRyaWNfZGZfcGVyX2NlbGx0eXBlIDwtIGZ1bmN0aW9uKGRmLCBkcywgbWV0cmljLCB0cmFuc2Zvcm1fZm4gPSBpZGVudGl0eSkgewogIGRmIHw+CiAgICBmaWx0ZXIoYnVsa19kcyA9PSBkcywgY2VsbF90eXBlICE9ICJhbGwiKSB8PgogICAgc2VsZWN0KG1ldGhvZCwgY2VsbF90eXBlLCBidWxrX2RzLCB2YWx1ZSA9IGFsbF9vZihtZXRyaWMpKSB8PgogICAgbXV0YXRlKHZhbHVlID0gdHJhbnNmb3JtX2ZuKHZhbHVlKSkgfD4KICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtZXRob2QsIHZhbHVlc19mcm9tID0gdmFsdWUpIHw+CiAgICBzZWxlY3QoLWJ1bGtfZHMpIHw+CiAgICByZXBsYWNlKGlzLm5hKC4pLCAwKSB8PiAKICAgIGFzX3RpYmJsZSgpCn0KCmNvbXB1dGVfZXh0cmVtZSA8LSBmdW5jdGlvbihkZiwgZnVuLCBhZGp1c3QgPSAwKSB7CiAgcm91bmQoZnVuKGFwcGx5KGRmWywtMV0sIDIsIGZ1biksIG5hLnJtID0gVFJVRSksIDEpICsgYWRqdXN0Cn0KCiMgSGVscGVyIGZ1bmN0aW9uIHRvIGNyZWF0ZSByYWRhciBwbG90CnBsb3RfcmFkYXIgPC0gZnVuY3Rpb24oZGYsIHRpdGxlLCBncmlkLm1pbiwgZ3JpZC5taWQsIGdyaWQubWF4LCB2YWx1ZXMucmFkYXIsIGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScsIHBhbGV0dGUpIHsKICBnZ3JhZGFyKGRmLAogICAgICAgICAgZ3JvdXAuY29sb3VycyA9IHBhbGV0dGUsCiAgICAgICAgICBncm91cC5wb2ludC5zaXplID0gMiwKICAgICAgICAgIGdyb3VwLmxpbmUud2lkdGggPSAuOCwKICAgICAgICAgIGdyaWQubWluID0gZ3JpZC5taW4sCiAgICAgICAgICBncmlkLm1pZCA9IGdyaWQubWlkLAogICAgICAgICAgZ3JpZC5tYXggPSBncmlkLm1heCwKICAgICAgICAgIHZhbHVlcy5yYWRhciA9IHZhbHVlcy5yYWRhciwKICAgICAgICAgIGZvbnQucmFkYXIgPSAic2FucyIsCiAgICAgICAgICBsZWdlbmQudGV4dC5zaXplID0gMTAsCiAgICAgICAgICBheGlzLmxhYmVsLnNpemUgPSAzLjUsCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBsZWdlbmQucG9zaXRpb24sCiAgICAgICAgICBwbG90LnRpdGxlID0gdGl0bGUpCn0KCnBsb3RfcmFkYXJfY3VzdG9tIDwtIGZ1bmN0aW9uKGRmLCB0aXRsZSwgZ3JpZC5taW4sIGdyaWQubWlkLCBncmlkLmFkZCwgZ3JpZC5tYXgsIHZhbHVlcy5yYWRhciwgbGVnZW5kLnBvc2l0aW9uPSdub25lJywgZ3JpZGxpbmUubWlkLmNvbG91cj0nZ3JleScsIHBhbGV0dGUpIHsKICBnZ3JhZGFyX2N1c3RvbShkZiwKICAgICAgICAgIGdyb3VwLmNvbG91cnMgPSBwYWxldHRlLAogICAgICAgICAgZ3JvdXAucG9pbnQuc2l6ZSA9IDIsCiAgICAgICAgICBncm91cC5saW5lLndpZHRoID0gLjUsCiAgICAgICAgICBncmlkLm1pbiA9IGdyaWQubWluLAogICAgICAgICAgZ3JpZC5taWQgPSBncmlkLm1pZCwKICAgICAgICAgIGdyaWQuYWRkID0gZ3JpZC5hZGQsCiAgICAgICAgICBncmlkLm1heCA9IGdyaWQubWF4LAogICAgICAgICAgdmFsdWVzLnJhZGFyID0gdmFsdWVzLnJhZGFyLCAKICAgICAgICAgIGdyaWRsaW5lLmFkZC5jb2xvdXIgPSAnZ3JleScsCiAgICAgICAgICBncmlkbGluZS5taWQuY29sb3VyID0gZ3JpZGxpbmUubWlkLmNvbG91ciwKICAgICAgICAgIGZvbnQucmFkYXIgPSAic2FucyIsCiAgICAgICAgICBsZWdlbmQudGV4dC5zaXplID0gMTAsCiAgICAgICAgICBheGlzLmxhYmVsLnNpemUgPSAzLjUsCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBsZWdlbmQucG9zaXRpb24sCiAgICAgICAgICBwbG90LnRpdGxlID0gdGl0bGUpCn0KCmBgYAoKYGBge3J9CiMgRGF0YXNldHMKZGF0YXNldHMgPC0gYygiTW9yYW5kaW5pIiwgIkZpbm90ZWxsbyIsICJIb2VrIikKCm1ldGhvZF9vcmRlciA8LSBkZi5ib3RoIHw+IAogIHN1YnNldChidWxrX2RzICVpbiUgZGF0YXNldHMpIHw+IAogIGRwbHlyOjpncm91cF9ieShtZXRob2QpIHw+IAogIGRwbHlyOjpzdW1tYXJpemUoc3VtPXN1bShjb3IsIG5hLnJtPVQpKSB8PiAKICBhcnJhbmdlKHN1bSkgfD4gCiAgc2VsZWN0KG1ldGhvZCkgfD4gCiAgdW5saXN0KCkKCnJtc2VfcGxvdHMgPC0gbGFwcGx5KGRhdGFzZXRzLCBmdW5jdGlvbihkcykgewogIGRmX3Jtc2UgPC0gcHJlcGFyZV9tZXRyaWNfZGZfcGVyX2NlbGx0eXBlKGRmLmJvdGgsIGRzLCAiUk1TRSIgLGZ1bmN0aW9uKHgpIGxvZygxIC8geCkpWyxjKCdjZWxsX3R5cGUnLG1ldGhvZF9vcmRlcildCiAgbWF4X3ZhbCA8LSBjb21wdXRlX2V4dHJlbWUoZGZfcm1zZSwgbWF4LCBhZGp1c3QgPSAwLjEpCiAgcGxvdF9yYWRhcl9jdXN0b20oZGZfcm1zZSwKICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKCJsb2coMS9STVNFKSAiLCBkcyksCiAgICAgICAgICAgICBncmlkLm1pbiA9IDAsCiAgICAgICAgICAgICBncmlkLm1pZCA9IHJvdW5kKG1heF92YWwgKiAuMzMsIDIpLAogICAgICAgICAgICAgZ3JpZC5hZGQgPSByb3VuZChtYXhfdmFsICogLjY2LCAyKSwKICAgICAgICAgICAgIGdyaWQubWF4ID0gcm91bmQobWF4X3ZhbCwgMiksCiAgICAgICAgICAgICB2YWx1ZXMucmFkYXIgPSBjKCIwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3Rlcihyb3VuZChtYXhfdmFsICogLjMzLCAyKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIocm91bmQobWF4X3ZhbCAqIC42NiwgMikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIocm91bmQobWF4X3ZhbCwgMikpKSwKICAgICAgICAgICAgIHBhbGV0dGUgPSBjb2xvcl9wYWxldHRlW2FzLmNoYXJhY3RlcihkZl9ybXNlJGNlbGxfdHlwZSldKQp9KQoKIyBHZW5lcmF0ZSBjb3JyZWxhdGlvbiBwbG90cwpjb3JfcGxvdHMgPC0gbGFwcGx5KGRhdGFzZXRzLCBmdW5jdGlvbihkcykgewogIGRmX2NvciA8LSBwcmVwYXJlX21ldHJpY19kZl9wZXJfY2VsbHR5cGUoZGYuYm90aCwgZHMsICJjb3IiKVssYygnY2VsbF90eXBlJyxtZXRob2Rfb3JkZXIpXQogIG1pbl92YWwgPC0gY29tcHV0ZV9leHRyZW1lKGRmX2NvciwgbWluLCBhZGp1c3QgPSAtMC4xKQogIGRmX2Nvcltpcy5uYShkZl9jb3IpXSA8LSBtaW5fdmFsIC0gKCgxLzkpICogKDEgLSBtaW5fdmFsKSkKICBwbG90X3JhZGFyX2N1c3RvbShkZl9jb3IsCiAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgiQ29ycmVsYXRpb24gIiwgZHMpLAogICAgICAgICAgICAgZ3JpZC5taW4gPSBpZmVsc2UobWluX3ZhbCA8IDAsIG1pbl92YWwsIDApLAogICAgICAgICAgICAgZ3JpZC5taWQgPSBpZmVsc2UobWluX3ZhbCA8IDAsIDAsIG1pbl92YWwpLAogICAgICAgICAgICAgZ3JpZC5hZGQgPSAwLjUsCiAgICAgICAgICAgICBncmlkLm1heCA9IDEsCiAgICAgICAgICAgICB2YWx1ZXMucmFkYXIgPSBjKGFzLmNoYXJhY3RlcihtaW5fdmFsKSwgIjAiLCAiMC41IiwgIjEiKSwKICAgICAgICAgICAgIGdyaWRsaW5lLm1pZC5jb2xvdXI9J2JsYWNrJywKICAgICAgICAgICAgIHBhbGV0dGUgPSBjb2xvcl9wYWxldHRlW2FzLmNoYXJhY3RlcihkZl9jb3IkY2VsbF90eXBlKV0pCn0pCgojIEFzc2lnbiBwbG90cyB0byBuYW1lZCB2YXJpYWJsZXMgaWYgbmVlZGVkCm5hbWVzKHJtc2VfcGxvdHMpIDwtIHBhc3RlMCgicF9ybXNlXyIsIHRvbG93ZXIoZGF0YXNldHMpKQpuYW1lcyhjb3JfcGxvdHMpICA8LSBwYXN0ZTAoInBfY29yXyIsIHRvbG93ZXIoZGF0YXNldHMpKQpgYGAKCgoKYGBge3J9CmZpZ18yYiA8LSAocm1zZV9wbG90cyRwX3Jtc2VfbW9yYW5kaW5pICsgcm1zZV9wbG90cyRwX3Jtc2VfZmlub3RlbGxvICsgcm1zZV9wbG90cyRwX3Jtc2VfaG9laykgLyAoY29yX3Bsb3RzJHBfY29yX21vcmFuZGluaSArIGNvcl9wbG90cyRwX2Nvcl9maW5vdGVsbG8gKyBjb3JfcGxvdHMkcF9jb3JfaG9laykKCmdnc2F2ZSgnL25mcy9wcm9qL29tbmlkZWNvbnZfYmVuY2htYXJraW5nL29tbmlkZWNvbnYvYmVuY2htYXJrL3JldmlzaW9uMi92aXN1YWxpemF0aW9uL2ZpZzIvZmlnXzJiLnBkZicsIHBsb3QgPSBmaWdfMmIsIHdpZHRoID0gMjAsIGhlaWdodCA9IDEwKQpgYGAKCgoKIyBGaWcgUzIKCmBgYHtyfQpmaWdfczJhIDwtIGZyYWN0aW9uc19kZiAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdDaGVuJywnUGV0aXRwcmV6JywnQWx0bWFuJykpICU+JQogIGdncGxvdCguLCBhZXMoeD1mcmFjdGlvbi50cnVlLCB5PWZyYWN0aW9uLmVzdGltYXRlKSkrCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNlbGx0eXBlKSwgc2l6ZT0yLCBhbHBoYT0uNykrCiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKSsKICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgeWxhYignRXN0aW1hdGVkIGNlbGwtdHlwZSBmcmFjdGlvbicpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl9wYWxldHRlLCBkcm9wID0gVCkrCiAgZ2VvbV90ZXh0KGRhdGE9ZGYuYm90aCAlPiUgc3Vic2V0KGJ1bGtfZHMgJWluJSBjKCdDaGVuJywnUGV0aXRwcmV6JywnQWx0bWFuJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCgnUjogJyxyb3VuZChjb3IsIDMpLCdcblJNU0U6ICcsIHJvdW5kKFJNU0UsIDMpKSksIHg9LjAzLCB5PTEuMTMsIHNpemU9MywgaGp1c3Q9MCkrCiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKQoKCmZpZ19zMmIgPC0gZnJhY3Rpb25zX2RmICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykpICU+JQogIGdncGxvdCguLCBhZXMoeD1mcmFjdGlvbi50cnVlLCB5PWZyYWN0aW9uLmVzdGltYXRlKSkrCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9J2Rhc2hlZCcpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEpKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNlbGx0eXBlKSwgc2l6ZT0yLCBhbHBoYT0uMikrCiAgZmFjZXRfZ3JpZChidWxrX2RzIH4gbWV0aG9kKSsKICB4bGFiKCdHcm91bmQgdHJ1dGggY2VsbC10eXBlIGZyYWN0aW9uJykrCiAgeWxhYignRXN0aW1hdGVkIGNlbGwtdHlwZSBmcmFjdGlvbicpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEuMiksIGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSsKICB0aGVtZV9idygpKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUsIGFscGhhPTEpKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3BhbGV0dGUsIGRyb3AgPSBUKSsKICBnZW9tX3RleHQoZGF0YT1kZi5ib3RoICU+JSBzdWJzZXQoYnVsa19kcyAlaW4lIGMoJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykgJiBjZWxsX3R5cGUgPT0gJ2FsbCcpLCAKICAgICAgICAgICAgYWVzKGxhYmVsPXBhc3RlMCgnUjogJyxyb3VuZChjb3IsIDMpLCdcblJNU0U6ICcsIHJvdW5kKFJNU0UsIDMpKSksIHg9LjAzLCB5PTEuMTMsIHNpemU9MywgaGp1c3Q9MCkrCiAgbGFicyhjb2xvcj0nQ2VsbHR5cGUnKQoKZmlnX3MyIDwtIHBsb3RfZ3JpZCgKICBmaWdfczJhICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgZmlnX3MyYiwKICBhbGlnbiA9ICdoJywKICBsYWJlbHMgPSBjKCJBIiwgIkIiKSwgCiAgbGFiZWxfc2l6ZSA9IDE1LCAKICBoanVzdCA9IC0xLAogIG5yb3cgPSAyLCBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoLjQ1LCAuNzUpCikKCmdnc2F2ZShwbG90ID0gZmlnX3MyLCBmaWxlbmFtZSA9ICcvbmZzL3Byb2ovb21uaWRlY29udl9iZW5jaG1hcmtpbmcvb21uaWRlY29udi9iZW5jaG1hcmsvcmV2aXNpb24yL3Zpc3VhbGl6YXRpb24vZmlnMi9maWdfczJfdjIucGRmJywgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTcpCmBgYAoKIyBGaWcgUzMKCmBgYHtyfQpkYXRhc2V0cyA8LSBjKCJNb3JhbmRpbmkiLCAiRmlub3RlbGxvIiwgIkhvZWsiLCAiQWx0bWFuIiwnQ2hlbicsJ1BldGl0cHJleicsJ0NoZW5TaW0nLCdQZXRpdHByZXpTaW0nLCdGaW5vdGVsbG9TaW0nLCdIb2VrU2ltJywnTW9yYW5kaW5pU2ltJywnQWx0bWFuU2ltJykKCmRmLmhlYXRtYXAgPC0gZGYuYm90aCB8PiBzdWJzZXQoYnVsa19kcyAlaW4lIGRhdGFzZXRzICYgY2VsbF90eXBlICE9ICdhbGwnKSB8PiBzZWxlY3QoY2VsbF90eXBlLCBtZXRob2QsIGJ1bGtfZHMsIGNvciwgUk1TRSkKCmRmX2xvbmcgPC0gZGYuaGVhdG1hcCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoY29yLCBSTVNFKSwgbmFtZXNfdG8gPSAibWV0cmljIiwgdmFsdWVzX3RvID0gInZhbHVlIikKeF9sZXZlbHMgPC0gdW5pcXVlKGRmLmhlYXRtYXAkY2VsbF90eXBlKQp5X2xldmVscyA8LSB1bmlxdWUoZGYuaGVhdG1hcCRtZXRob2QpCmRmX2xvbmcgPC0gZGZfbG9uZyAlPiUKICBtdXRhdGUoCiAgICB4X251bSA9IGFzLm51bWVyaWMoZmFjdG9yKGNlbGxfdHlwZSwgbGV2ZWxzID0geF9sZXZlbHMpKSwKICAgIHlfbnVtID0gYXMubnVtZXJpYyhmYWN0b3IobWV0aG9kLCBsZXZlbHMgPSByZXYoeV9sZXZlbHMpKSkgICMgUmV2ZXJzZSBmb3IgaGVhdG1hcCBsYXlvdXQKICApCgpnZXRfdHJpX2Nvb3JkcyA8LSBmdW5jdGlvbih4LCB5LCBtZXRyaWMpIHsKICBpZiAobWV0cmljID09ICJjb3IiKSB7CiAgICB0aWJibGUoCiAgICAgIHhfY29vcmQgPSBjKHggLSAwLjUsIHggKyAwLjUsIHggLSAwLjUpLAogICAgICB5X2Nvb3JkID0gYyh5ICsgMC41LCB5ICsgMC41LCB5IC0gMC41KQogICAgKQogIH0gZWxzZSB7CiAgICB0aWJibGUoCiAgICAgIHhfY29vcmQgPSBjKHggKyAwLjUsIHggKyAwLjUsIHggLSAwLjUpLAogICAgICB5X2Nvb3JkID0gYyh5ICsgMC41LCB5IC0gMC41LCB5IC0gMC41KQogICAgKQogIH0KfQoKZGZfcG9seSA8LSBkZl9sb25nICU+JQogIGRwbHlyOjptdXRhdGUoY29vcmRzID0gcG1hcChsaXN0KHhfbnVtLCB5X251bSwgbWV0cmljKSwgZ2V0X3RyaV9jb29yZHMpKSAlPiUKICB1bm5lc3QoY29vcmRzKSAlPiUKICBncm91cF9ieShjZWxsX3R5cGUsIG1ldGhvZCwgYnVsa19kcywgbWV0cmljKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRpbGVfaWQgPSBjdXJfZ3JvdXBfaWQoKSkgJT4lCiAgdW5ncm91cCgpCgpkZl9sYWJlbHMgPC0gZGZfbG9uZyAlPiUKICBtdXRhdGUoCiAgICBsYWJlbCA9IGlmZWxzZShtZXRyaWMgPT0gImNvciIsCiAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCIlLjJmIiwgdmFsdWUpLAogICAgICAgICAgICAgICAgICAgc3ByaW50ZigiJS4yZiIsIHZhbHVlKSksCiAgICB4X2xhYmVsID0geF9udW0gKyBpZmVsc2UobWV0cmljID09ICJjb3IiLCAtMC4yLCAwLjIpLAogICAgeV9sYWJlbCA9IHlfbnVtICsgaWZlbHNlKG1ldHJpYyA9PSAiY29yIiwgMC4yLCAtMC4yKQogICkKCmRmX3IgPC0gZGZfcG9seSAlPiUgZmlsdGVyKG1ldHJpYyA9PSAiY29yIikKZGZfcm1zZSA8LSBkZl9wb2x5ICU+JSBmaWx0ZXIobWV0cmljID09ICJSTVNFIikKCnRyaWFuZ2xlX2hlYXRtYXAgPC0gZ2dwbG90KCkgKwogICMgUiB0cmlhbmdsZXMKICBnZW9tX3BvbHlnb24oZGF0YSA9IGRmX3IsIGFlcyh4ID0geF9jb29yZCwgeSA9IHlfY29vcmQsIGdyb3VwID0gdGlsZV9pZCwgZmlsbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobWlkID0gJ2RhcmtyZWQnLCBsb3cgPSAiYmxhY2siLCBoaWdoID0gInN0ZWVsYmx1ZSIsIG5hbWUgPSAiUiIpICsKICBuZXdfc2NhbGVfZmlsbCgpICsKICAjIFJNU0UgdHJpYW5nbGVzCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBkZl9ybXNlLCBhZXMoeCA9IHhfY29vcmQsIHkgPSB5X2Nvb3JkLCBncm91cCA9IHRpbGVfaWQsIGZpbGwgPSB2YWx1ZSksIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInN0ZWVsYmx1ZSIsIGhpZ2ggPSAiZGFya3JlZCIsIG5hbWUgPSAiUk1TRSIpICsKICBnZW9tX3RleHQoZGF0YSA9IGRmX2xhYmVscywgYWVzKHggPSB4X2xhYmVsLCB5ID0geV9sYWJlbCwgbGFiZWwgPSBsYWJlbCwgZ3JvdXAgPSBtZXRyaWMpLCBzaXplID0gMiwgY29sb3I9J3doaXRlJykgKwogIGZhY2V0X3dyYXAofmJ1bGtfZHMsIHNjYWxlcyA9ICdmcmVlJywgbmNvbCA9IDMpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpCiAgKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSB4X2xldmVscykgKwogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KHlfbGV2ZWxzKSkgKwogIGxhYnMoeCA9ICIiLCB5ID0gIiIpCgpnZ3NhdmUoJy9uZnMvcHJvai9vbW5pZGVjb252X2JlbmNobWFya2luZy9vbW5pZGVjb252L2JlbmNobWFyay9yZXZpc2lvbjIvdmlzdWFsaXphdGlvbi9maWcyL2ZpZ19zM192My5wZGYnLCBwbG90ID0gdHJpYW5nbGVfaGVhdG1hcCwgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTYpCmBgYAoK
diff --git a/visualisation/fig5/fig_5D.R b/visualisation/fig5/fig_5D.R index 0775b2f..7c336e2 100755 --- a/visualisation/fig5/fig_5D.R +++ b/visualisation/fig5/fig_5D.R @@ -9,7 +9,7 @@ bulk_norm <- c('tpm', rep('counts', 2), rep('tpm',5)) # 1: List directories, methods, cell types -unknown.content.deconv.results <- list.files('/vol/omnideconv_results/results_unknown_content', full.names=F, recursive=T) +unknown.content.deconv.results <- list.files('/nfs/data/omnideconv_benchmarking_clean/benchmark_results/results_unkown_content/results_unknown_content/', full.names=F, recursive=T) unknown.content.deconv.results <- unknown.content.deconv.results[grep('replicate', unknown.content.deconv.results)] unknown.content.deconv.results <- unknown.content.deconv.results[grep('lambrechts', unknown.content.deconv.results)] @@ -37,10 +37,10 @@ metadata.table <- metadata.table[metadata.table$unknown_fraction %in% vector.fra #2: Combine these in a unique dataframe data <- NULL for(i in 1:nrow(metadata.table)){ - result <- readRDS(paste0('/vol/omnideconv_results/results_unknown_content/', metadata.table$path[i])) %>% + result <- readRDS(paste0('/nfs/data/omnideconv_benchmarking_clean/benchmark_results/results_unkown_content/results_unknown_content/', metadata.table$path[i])) %>% .$deconvolution %>% as.data.frame() - true.fractions <- readRDS(paste0('/vol/omnideconv_results/results_unknown_content/', metadata.table$path[i])) %>% + true.fractions <- readRDS(paste0('/nfs/data/omnideconv_benchmarking_clean/benchmark_results/results_unkown_content/results_unknown_content/', metadata.table$path[i])) %>% .$true_cell_fractions %>% as.data.frame() %>% .[!(row.names(.) == 'Tumor cells'), ]