load libraries
load seurat object
# 1. Reload clean object
L2 <- readRDS("../../../0-RDS_Cell_lines/L2_clustered.rds")
DefaultAssay(L2) <- "SCT"
Idents(L2) <- "SCT_snn_res.0.2"
Error Fix
my_GetAssayData <- function(
object,
assay = NULL,
layer = NULL,
slot = NULL,
...
) {
# Map old 'slot' to new 'layer'
if (is.null(layer) && !is.null(slot)) {
layer <- slot
}
if (is.null(layer)) {
layer <- "data"
}
# If a Seurat object is provided, get the assay object
if (inherits(object, "Seurat")) {
if (is.null(assay)) assay <- Seurat::DefaultAssay(object)
assay_obj <- object[[assay]]
} else {
assay_obj <- object
}
# Seurat v5 assays: use LayerData
if (inherits(assay_obj, "Assay5") || inherits(assay_obj, "StdAssay")) {
return(SeuratObject::LayerData(assay_obj, layer = layer))
}
# Seurat v4 assays: fall back to slots
if (inherits(assay_obj, "Assay")) {
return(methods::slot(assay_obj, layer))
}
stop("Unsupported object class: ", paste(class(object), collapse = ", "))
}
assignInNamespace("GetAssayData", my_GetAssayData, ns = "SeuratObject")
Liana analysis using
scPubr
# Run LIANA with multiple methods
liana_output <- liana::liana_wrap(sce = L2,
method = c("natmi", "connectome", "logfc", "sca", "cellphonedb", "CellChat"),
idents_col = NULL,
verbose = FALSE,
assay = "SCT")
# Compute consensus aggregate ranking
liana_aggregate <- liana::liana_aggregate(liana_output)
Save Results
# Create output directory
dir.create("LIANA_L2", showWarnings = FALSE)
# Save R object (for future use)
saveRDS(liana_output, "LIANA_L2/liana_L2_output.rds")
# Save aggregate results (for comparative analysis across all cell lines)
write.csv(liana_aggregate,
"LIANA_L2/liana_L2_aggregate_results.csv",
row.names = FALSE)
# Save individual methods
for (name in names(liana_output)) {
write.csv(liana_output[[name]],
paste0("LIANA_L2/liana_L2_", name, "_results.csv"),
row.names = FALSE)
}
cat("✓ Results saved to LIANA_L2/\n")
✓ Results saved to LIANA_L2/
Main Figure: Chord
Diagrams
# Generate chord diagrams (TOP 25 interactions by aggregate_rank)
chord_output <- SCpubr::do_LigandReceptorPlot(
liana_output = liana_output,
top_interactions = 10,
arrange_interactions_by = "aggregate_rank",
compute_ChordDiagrams = TRUE
)
# Display chord diagrams
chord_output$chord_total_interactions
chord_output$chord_ligand_receptor


Save Chord
Diagrams
# Save Chord Diagram 1: Total interactions by cluster
pdf("LIANA_L2/L2_Chord_Total_Interactions.pdf", width = 10, height = 8)
print(chord_output$chord_total_interactions)
dev.off()
null device
1
# Save Chord Diagram 2: Specific ligand-receptor pairs
pdf("LIANA_L2/L2_Chord_Ligand_Receptor.pdf", width = 10, height = 8)
print(chord_output$chord_ligand_receptor)
dev.off()
null device
1
png("LIANA_L2/L2_Chord_Total_Interactions.png", width = 3000, height = 2400, res = 300)
print(chord_output$chord_total_interactions)
dev.off()
null device
1
png("LIANA_L2/L2_Chord_Ligand_Receptor.png", width = 3000, height = 2400, res = 300)
print(chord_output$chord_ligand_receptor)
dev.off()
null device
1
cat("✓ Chord diagrams saved\n")
✓ Chord diagrams saved
Summary Table
# Top 10 interactions for manuscript table
top10_table <- liana_aggregate %>%
arrange(aggregate_rank) %>%
select(source, target, ligand.complex, receptor.complex,
aggregate_rank, natmi.edge_specificity, sca.LRscore) %>%
head(10)
# Display
print(top10_table)
# A tibble: 10 × 7
source target ligand.complex receptor.complex aggregate_rank natmi.edge_specificity sca.LRscore
<chr> <chr> <chr> <chr> <dbl> <dbl> <dbl>
1 0 2 B2M KIR3DL1 0.0000173 0.119 0.891
2 1 1 GRN NTRK1 0.0000925 0.231 0.432
3 1 0 CD70 CD27 0.000121 0.233 0.501
4 1 1 LGALS1 PTPRC 0.000629 0.124 0.859
5 0 2 HLA-A KIR3DL1 0.000779 0.120 0.858
6 1 0 CD59 CD2 0.00103 0.289 0.385
7 1 1 ANXA1 DYSF 0.00103 0.264 0.297
8 1 0 CD48 CD2 0.00103 0.258 0.574
9 1 1 SPINT1 ST14 0.00103 0.237 0.460
10 1 1 TNFSF12 TNFRSF8 0.00103 0.226 0.322
# Save as CSV
write.csv(top10_table,
"LIANA_L2/L2_Top10_Interactions_Table.csv",
row.names = FALSE)
cat("✓ Summary table saved\n")
✓ Summary table saved
# Print statistics
cat("\n=== SUMMARY STATISTICS ===\n")
=== SUMMARY STATISTICS ===
cat("Total interactions with aggregate_rank ≤ 0.05:",
sum(liana_aggregate$aggregate_rank <= 0.05), "\n")
Total interactions with aggregate_rank ≤ 0.05: 240
cat("Total interactions with aggregate_rank ≤ 0.01:",
sum(liana_aggregate$aggregate_rank <= 0.01), "\n")
Total interactions with aggregate_rank ≤ 0.01: 94
Session Info
sessionInfo()
R version 4.5.2 (2025-10-31)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.3 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
locale:
[1] LC_CTYPE=en_GB.UTF-8 LC_NUMERIC=C LC_TIME=fr_FR.UTF-8 LC_COLLATE=en_GB.UTF-8
[5] LC_MONETARY=fr_FR.UTF-8 LC_MESSAGES=en_GB.UTF-8 LC_PAPER=fr_FR.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C
time zone: Europe/Paris
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] ggplot2_4.0.2 SCpubr_1.1.1.9000 liana_0.1.14 dplyr_1.2.0 Seurat_5.4.0 SeuratObject_5.3.0
[7] sp_2.2-0
loaded via a namespace (and not attached):
[1] fs_1.6.6 matrixStats_1.5.0 spatstat.sparse_3.1-0 lubridate_1.9.5
[5] httr_1.4.7 RColorBrewer_1.1-3 doParallel_1.0.17 tools_4.5.2
[9] sctransform_0.4.3 backports_1.5.0 utf8_1.2.6 R6_2.6.1
[13] lazyeval_0.2.2 uwot_0.2.4 GetoptLong_1.1.0 withr_3.0.2
[17] prettyunits_1.2.0 gridExtra_2.3 progressr_0.18.0 textshaping_1.0.4
[21] cli_3.6.5 Biobase_2.70.0 spatstat.explore_3.7-0 fastDummies_1.7.5
[25] labeling_0.4.3 sass_0.4.10 S7_0.2.1 spatstat.data_3.1-9
[29] readr_2.1.6 ggridges_0.5.7 pbapply_1.7-4 systemfonts_1.3.1
[33] R.utils_2.13.0 scater_1.38.0 dichromat_2.0-0.1 parallelly_1.46.1
[37] sessioninfo_1.2.3 limma_3.66.0 readxl_1.4.5 rstudioapi_0.18.0
[41] RSQLite_2.4.6 generics_0.1.4 shape_1.4.6.1 ica_1.0-3
[45] spatstat.random_3.4-4 zip_2.3.3 Matrix_1.7-4 ggbeeswarm_0.7.3
[49] S4Vectors_0.48.0 logger_0.4.1 abind_1.4-8 R.methodsS3_1.8.2
[53] lifecycle_1.0.5 yaml_2.3.12 edgeR_4.8.2 SummarizedExperiment_1.40.0
[57] SparseArray_1.10.8 Rtsne_0.17 grid_4.5.2 blob_1.3.0
[61] promises_1.5.0 dqrng_0.4.1 crayon_1.5.3 dir.expiry_1.18.0
[65] miniUI_0.1.2 lattice_0.22-7 beachmat_2.26.0 cowplot_1.2.0
[69] metapod_1.18.0 pillar_1.11.1 knitr_1.51 ComplexHeatmap_2.26.1
[73] GenomicRanges_1.62.1 tcltk_4.5.2 rjson_0.2.23 future.apply_1.20.1
[77] codetools_0.2-20 glue_1.8.0 spatstat.univar_3.1-6 data.table_1.18.2.1
[81] vctrs_0.7.1 png_0.1-8 spam_2.11-3 cellranger_1.1.0
[85] gtable_0.3.6 assertthat_0.2.1 cachem_1.1.0 OmnipathR_3.19.1
[89] xfun_0.56 S4Arrays_1.10.1 mime_0.13 Seqinfo_1.0.0
[93] survival_3.8-3 SingleCellExperiment_1.32.0 iterators_1.0.14 statmod_1.5.1
[97] bluster_1.20.0 fitdistrplus_1.2-6 ROCR_1.0-12 nlme_3.1-168
[101] bit64_4.6.0-1 progress_1.2.3 filelock_1.0.3 RcppAnnoy_0.0.23
[105] bslib_0.10.0 irlba_2.3.7 vipor_0.4.7 KernSmooth_2.23-26
[109] otel_0.2.0 colorspace_2.1-2 BiocGenerics_0.56.0 DBI_1.2.3
[113] tidyselect_1.2.1 bit_4.6.0 compiler_4.5.2 curl_7.0.0
[117] rvest_1.0.5 httr2_1.2.2 BiocNeighbors_2.4.0 xml2_1.5.2
[121] DelayedArray_0.36.0 plotly_4.12.0 checkmate_2.3.4 scales_1.4.0
[125] lmtest_0.9-40 rappdirs_0.3.4 stringr_1.6.0 digest_0.6.39
[129] goftest_1.2-3 spatstat.utils_3.2-1 rmarkdown_2.30 basilisk_1.23.0
[133] XVector_0.50.0 htmltools_0.5.9 pkgconfig_2.0.3 sparseMatrixStats_1.22.0
[137] MatrixGenerics_1.22.0 fastmap_1.2.0 rlang_1.1.7 GlobalOptions_0.1.3
[141] htmlwidgets_1.6.4 shiny_1.12.1 farver_2.1.2 jquerylib_0.1.4
[145] zoo_1.8-15 jsonlite_2.0.0 BiocParallel_1.44.0 R.oo_1.27.1
[149] BiocSingular_1.26.1 magrittr_2.0.4 scuttle_1.20.0 dotCall64_1.2
[153] patchwork_1.3.2 Rcpp_1.1.1 viridis_0.6.5 reticulate_1.44.1
[157] stringi_1.8.7 MASS_7.3-65 plyr_1.8.9 parallel_4.5.2
[161] listenv_0.10.0 ggrepel_0.9.6 forcats_1.0.1 deldir_2.0-4
[165] splines_4.5.2 tensor_1.5.1 hms_1.1.4 circlize_0.4.17
[169] locfit_1.5-9.12 igraph_2.2.1 spatstat.geom_3.7-0 RcppHNSW_0.6.0
[173] reshape2_1.4.5 stats4_4.5.2 ScaledMatrix_1.18.0 XML_3.99-0.20
[177] evaluate_1.0.5 scran_1.38.0 tzdb_0.5.0 foreach_1.5.2
[181] httpuv_1.6.16 RANN_2.6.2 tidyr_1.3.2 purrr_1.2.1
[185] polyclip_1.10-7 future_1.69.0 clue_0.3-66 scattermore_1.2
[189] rsvd_1.0.5 xtable_1.8-4 RSpectra_0.16-2 later_1.4.5
[193] ragg_1.5.0 viridisLite_0.4.3 tibble_3.3.1 beeswarm_0.4.0
[197] memoise_2.0.1 IRanges_2.44.0 cluster_2.1.8.1 timechange_0.4.0
[201] globals_0.19.0
LS0tCnRpdGxlOiAiTGlhbmEgYW5hbHlzaXMgTDItVGhlc2lzIgphdXRob3I6ICJOYXNpciBNYWhtb29kIEFiYmFzaSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgdGhlbWU6IGpvdXJuYWwKLS0tCgoKIyBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCgpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogICAgbGlicmFyeShTZXVyYXQpICAgICAgIyBTZXVyYXQgb2JqZWN0IGhhbmRsaW5nCiAgICBsaWJyYXJ5KGRwbHlyKSAgICAgICAjIERhdGEgbWFuaXB1bGF0aW9uCiAgICBsaWJyYXJ5KGxpYW5hKSAgICAgICAjIExpZ2FuZC1yZWNlcHRvciBhbmFseXNpcwogICAgbGlicmFyeShTQ3B1YnIpICAgICAgIyBWaXN1YWxpemF0aW9uCn0pCgpgYGAKCgojIGxvYWQgc2V1cmF0IG9iamVjdApgYGB7ciBsb2FkX3NldXJhdH0KIyAxLiBSZWxvYWQgY2xlYW4gb2JqZWN0CkwyIDwtIHJlYWRSRFMoIi4uLy4uLy4uLzAtUkRTX0NlbGxfbGluZXMvTDJfY2x1c3RlcmVkLnJkcyIpCkRlZmF1bHRBc3NheShMMikgPC0gIlNDVCIKCklkZW50cyhMMikgPC0gIlNDVF9zbm5fcmVzLjAuMiIKCgpgYGAKCiMgRXJyb3IgRml4CmBgYHtyIH0KbXlfR2V0QXNzYXlEYXRhIDwtIGZ1bmN0aW9uKAogIG9iamVjdCwKICBhc3NheSA9IE5VTEwsCiAgbGF5ZXIgPSBOVUxMLAogIHNsb3QgPSBOVUxMLAogIC4uLgopIHsKICAjIE1hcCBvbGQgJ3Nsb3QnIHRvIG5ldyAnbGF5ZXInCiAgaWYgKGlzLm51bGwobGF5ZXIpICYmICFpcy5udWxsKHNsb3QpKSB7CiAgICBsYXllciA8LSBzbG90CiAgfQogIGlmIChpcy5udWxsKGxheWVyKSkgewogICAgbGF5ZXIgPC0gImRhdGEiCiAgfQoKICAjIElmIGEgU2V1cmF0IG9iamVjdCBpcyBwcm92aWRlZCwgZ2V0IHRoZSBhc3NheSBvYmplY3QKICBpZiAoaW5oZXJpdHMob2JqZWN0LCAiU2V1cmF0IikpIHsKICAgIGlmIChpcy5udWxsKGFzc2F5KSkgYXNzYXkgPC0gU2V1cmF0OjpEZWZhdWx0QXNzYXkob2JqZWN0KQogICAgYXNzYXlfb2JqIDwtIG9iamVjdFtbYXNzYXldXQogIH0gZWxzZSB7CiAgICBhc3NheV9vYmogPC0gb2JqZWN0CiAgfQoKICAjIFNldXJhdCB2NSBhc3NheXM6IHVzZSBMYXllckRhdGEKICBpZiAoaW5oZXJpdHMoYXNzYXlfb2JqLCAiQXNzYXk1IikgfHwgaW5oZXJpdHMoYXNzYXlfb2JqLCAiU3RkQXNzYXkiKSkgewogICAgcmV0dXJuKFNldXJhdE9iamVjdDo6TGF5ZXJEYXRhKGFzc2F5X29iaiwgbGF5ZXIgPSBsYXllcikpCiAgfQoKICAjIFNldXJhdCB2NCBhc3NheXM6IGZhbGwgYmFjayB0byBzbG90cwogIGlmIChpbmhlcml0cyhhc3NheV9vYmosICJBc3NheSIpKSB7CiAgICByZXR1cm4obWV0aG9kczo6c2xvdChhc3NheV9vYmosIGxheWVyKSkKICB9CgogIHN0b3AoIlVuc3VwcG9ydGVkIG9iamVjdCBjbGFzczogIiwgcGFzdGUoY2xhc3Mob2JqZWN0KSwgY29sbGFwc2UgPSAiLCAiKSkKfQoKYXNzaWduSW5OYW1lc3BhY2UoIkdldEFzc2F5RGF0YSIsIG15X0dldEFzc2F5RGF0YSwgbnMgPSAiU2V1cmF0T2JqZWN0IikKCgpgYGAKCgoKIyBMaWFuYSBhbmFseXNpcyB1c2luZyBzY1B1YnIKYGBge3J9CgojIFJ1biBMSUFOQSB3aXRoIG11bHRpcGxlIG1ldGhvZHMKbGlhbmFfb3V0cHV0IDwtIGxpYW5hOjpsaWFuYV93cmFwKHNjZSA9ICBMMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IGMoIm5hdG1pIiwgImNvbm5lY3RvbWUiLCAibG9nZmMiLCAic2NhIiwgImNlbGxwaG9uZWRiIiwgIkNlbGxDaGF0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudHNfY29sID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIpCgojIENvbXB1dGUgY29uc2Vuc3VzIGFnZ3JlZ2F0ZSByYW5raW5nCmxpYW5hX2FnZ3JlZ2F0ZSA8LSBsaWFuYTo6bGlhbmFfYWdncmVnYXRlKGxpYW5hX291dHB1dCkKCmBgYAoKIyMgU2F2ZSBSZXN1bHRzCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CgojIENyZWF0ZSBvdXRwdXQgZGlyZWN0b3J5CmRpci5jcmVhdGUoIkxJQU5BX0wyIiwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgojIFNhdmUgUiBvYmplY3QgKGZvciBmdXR1cmUgdXNlKQpzYXZlUkRTKGxpYW5hX291dHB1dCwgIkxJQU5BX0wyL2xpYW5hX0wyX291dHB1dC5yZHMiKQoKIyBTYXZlIGFnZ3JlZ2F0ZSByZXN1bHRzIChmb3IgY29tcGFyYXRpdmUgYW5hbHlzaXMgYWNyb3NzIGFsbCBjZWxsIGxpbmVzKQp3cml0ZS5jc3YobGlhbmFfYWdncmVnYXRlLCAKICAgICAgICAgICJMSUFOQV9MMi9saWFuYV9MMl9hZ2dyZWdhdGVfcmVzdWx0cy5jc3YiLCAKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQoKIyBTYXZlIGluZGl2aWR1YWwgbWV0aG9kcwpmb3IgKG5hbWUgaW4gbmFtZXMobGlhbmFfb3V0cHV0KSkgewogICAgd3JpdGUuY3N2KGxpYW5hX291dHB1dFtbbmFtZV1dLCAKICAgICAgICAgICAgICBwYXN0ZTAoIkxJQU5BX0wyL2xpYW5hX0wyXyIsIG5hbWUsICJfcmVzdWx0cy5jc3YiKSwgCiAgICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpCn0KCmNhdCgi4pyTIFJlc3VsdHMgc2F2ZWQgdG8gTElBTkFfTDIvXG4iKQpgYGAKIyMgU3VwcGxlbWVudGFyeSBGaWd1cmU6IERldGFpbGVkIERvdHBsb3QKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQpsaWJyYXJ5KGdncGxvdDIpCgojIFRvcCAxMCBpbnRlcmFjdGlvbnMgYnkgYWdncmVnYXRlX3JhbmsKcF9kb3RwbG90IDwtIFNDcHVicjo6ZG9fTGlnYW5kUmVjZXB0b3JQbG90KAogICAgbGlhbmFfb3V0cHV0ID0gbGlhbmFfb3V0cHV0LAogICAgYXJyYW5nZV9pbnRlcmFjdGlvbnNfYnkgPSAiYWdncmVnYXRlX3JhbmsiLAogICAgdG9wX2ludGVyYWN0aW9ucyA9IDEwCikKCnBfZG90cGxvdAoKIyBTYXZlIGFzIFBERgpnZ3NhdmUoCiAgZmlsZW5hbWUgPSAiTElBTkFfTDIvTDJfRG90cGxvdF9Ub3AxMF9BZ2dyZWdhdGVSYW5rLnBkZiIsCiAgcGxvdCA9IHBfZG90cGxvdCwKICB3aWR0aCA9IDEwLAogIGhlaWdodCA9IDgKKQoKIyBTYXZlIGFzIFBORyAoc2V0IGRwaSBleHBsaWNpdGx5IOKAlCBvdGhlcndpc2UgZmlndXJlcyBsb29rIGFtYXRldXJpc2gpCmdnc2F2ZSgKICBmaWxlbmFtZSA9ICJMSUFOQV9MMi9MMl9Eb3RwbG90X1RvcDEwX0FnZ3JlZ2F0ZVJhbmsucG5nIiwKICBwbG90ID0gcF9kb3RwbG90LAogIHdpZHRoID0gMTAsCiAgaGVpZ2h0ID0gOCwKICBkcGkgPSAzMDAKKQoKY2F0KCLinJMgRG90cGxvdCBzYXZlZCBhcyBQREYgYW5kIFBOR1xuIikKCgpgYGAKCiMgTWFpbiBGaWd1cmU6IENob3JkIERpYWdyYW1zCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCiMgR2VuZXJhdGUgY2hvcmQgZGlhZ3JhbXMgKFRPUCAyNSBpbnRlcmFjdGlvbnMgYnkgYWdncmVnYXRlX3JhbmspCmNob3JkX291dHB1dCA8LSBTQ3B1YnI6OmRvX0xpZ2FuZFJlY2VwdG9yUGxvdCgKICAgIGxpYW5hX291dHB1dCA9IGxpYW5hX291dHB1dCwKICAgIHRvcF9pbnRlcmFjdGlvbnMgPSAxMCwKICAgIGFycmFuZ2VfaW50ZXJhY3Rpb25zX2J5ID0gImFnZ3JlZ2F0ZV9yYW5rIiwKICAgIGNvbXB1dGVfQ2hvcmREaWFncmFtcyA9IFRSVUUKKQoKIyBEaXNwbGF5IGNob3JkIGRpYWdyYW1zCmNob3JkX291dHB1dCRjaG9yZF90b3RhbF9pbnRlcmFjdGlvbnMKY2hvcmRfb3V0cHV0JGNob3JkX2xpZ2FuZF9yZWNlcHRvcgoKYGBgCgoKCgoKIyMgU2F2ZSBDaG9yZCBEaWFncmFtcwpgYGB7cn0KCgojIFNhdmUgQ2hvcmQgRGlhZ3JhbSAxOiBUb3RhbCBpbnRlcmFjdGlvbnMgYnkgY2x1c3RlcgpwZGYoIkxJQU5BX0wyL0wyX0Nob3JkX1RvdGFsX0ludGVyYWN0aW9ucy5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQpwcmludChjaG9yZF9vdXRwdXQkY2hvcmRfdG90YWxfaW50ZXJhY3Rpb25zKQpkZXYub2ZmKCkKCiMgU2F2ZSBDaG9yZCBEaWFncmFtIDI6IFNwZWNpZmljIGxpZ2FuZC1yZWNlcHRvciBwYWlycwpwZGYoIkxJQU5BX0wyL0wyX0Nob3JkX0xpZ2FuZF9SZWNlcHRvci5wZGYiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4KQpwcmludChjaG9yZF9vdXRwdXQkY2hvcmRfbGlnYW5kX3JlY2VwdG9yKQpkZXYub2ZmKCkKCgpwbmcoIkxJQU5BX0wyL0wyX0Nob3JkX1RvdGFsX0ludGVyYWN0aW9ucy5wbmciLCB3aWR0aCA9IDMwMDAsIGhlaWdodCA9IDI0MDAsIHJlcyA9IDMwMCkKcHJpbnQoY2hvcmRfb3V0cHV0JGNob3JkX3RvdGFsX2ludGVyYWN0aW9ucykKZGV2Lm9mZigpCgpwbmcoIkxJQU5BX0wyL0wyX0Nob3JkX0xpZ2FuZF9SZWNlcHRvci5wbmciLCB3aWR0aCA9IDMwMDAsIGhlaWdodCA9IDI0MDAsIHJlcyA9IDMwMCkKcHJpbnQoY2hvcmRfb3V0cHV0JGNob3JkX2xpZ2FuZF9yZWNlcHRvcikKZGV2Lm9mZigpCgpjYXQoIuKckyBDaG9yZCBkaWFncmFtcyBzYXZlZFxuIikKCgpgYGAKCgoKCgojIFN1bW1hcnkgVGFibGUKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQoKIyBUb3AgMTAgaW50ZXJhY3Rpb25zIGZvciBtYW51c2NyaXB0IHRhYmxlCnRvcDEwX3RhYmxlIDwtIGxpYW5hX2FnZ3JlZ2F0ZSAlPiUKICBhcnJhbmdlKGFnZ3JlZ2F0ZV9yYW5rKSAlPiUKICBzZWxlY3Qoc291cmNlLCB0YXJnZXQsIGxpZ2FuZC5jb21wbGV4LCByZWNlcHRvci5jb21wbGV4LCAKICAgICAgICAgYWdncmVnYXRlX3JhbmssIG5hdG1pLmVkZ2Vfc3BlY2lmaWNpdHksIHNjYS5MUnNjb3JlKSAlPiUKICBoZWFkKDEwKQoKIyBEaXNwbGF5CnByaW50KHRvcDEwX3RhYmxlKQoKIyBTYXZlIGFzIENTVgp3cml0ZS5jc3YodG9wMTBfdGFibGUsIAogICAgICAgICAgIkxJQU5BX0wyL0wyX1RvcDEwX0ludGVyYWN0aW9uc19UYWJsZS5jc3YiLCAKICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFKQoKY2F0KCLinJMgU3VtbWFyeSB0YWJsZSBzYXZlZFxuIikKCiMgUHJpbnQgc3RhdGlzdGljcwpjYXQoIlxuPT09IFNVTU1BUlkgU1RBVElTVElDUyA9PT1cbiIpCmNhdCgiVG90YWwgaW50ZXJhY3Rpb25zIHdpdGggYWdncmVnYXRlX3Jhbmsg4omkIDAuMDU6IiwgCiAgICBzdW0obGlhbmFfYWdncmVnYXRlJGFnZ3JlZ2F0ZV9yYW5rIDw9IDAuMDUpLCAiXG4iKQpjYXQoIlRvdGFsIGludGVyYWN0aW9ucyB3aXRoIGFnZ3JlZ2F0ZV9yYW5rIOKJpCAwLjAxOiIsIAogICAgc3VtKGxpYW5hX2FnZ3JlZ2F0ZSRhZ2dyZWdhdGVfcmFuayA8PSAwLjAxKSwgIlxuIikKCmBgYAoKCgojIyBTZXNzaW9uIEluZm8KYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQoKc2Vzc2lvbkluZm8oKQoKYGBgCgoKCg==